diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt b/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt index 2014b9baa7c..0be54f87eed 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/CMakeLists.txt @@ -12,3 +12,4 @@ create_single_source_cgal_program("triangle_soup_wrap.cpp") create_single_source_cgal_program("point_set_wrap.cpp") create_single_source_cgal_program("wrap_from_cavity.cpp") create_single_source_cgal_program("mixed_inputs_wrap.cpp") +create_single_source_cgal_program("volumetric_wrap.cpp") diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp index be64a8febbd..ffcedc7f1cb 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/mixed_inputs_wrap.cpp @@ -16,9 +16,9 @@ using K = CGAL::Exact_predicates_inexact_constructions_kernel; using Point_3 = K::Point_3; using Segment_3 = K::Segment_3; -using Face = std::array; using Segments = std::vector; using Points = std::vector; +using Face = std::array; using Faces = std::vector; using Mesh = CGAL::Surface_mesh; diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp new file mode 100644 index 00000000000..113215b631a --- /dev/null +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/volumetric_wrap.cpp @@ -0,0 +1,173 @@ +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include +#include + +namespace PMP = CGAL::Polygon_mesh_processing; +namespace AW3i = CGAL::Alpha_wraps_3::internal; + +using K = CGAL::Exact_predicates_inexact_constructions_kernel; +using Point_3 = K::Point_3; + +using Points = std::vector; +using Face = std::array; +using Faces = std::vector; + +using Mesh = CGAL::Surface_mesh; + +// If we provide a triangulation, AW3 uses its Gt, so we have to make the Gt stack explicit +using Gtb = AW3i::Alpha_wrap_AABB_geom_traits; // provides Ball_3 +using Gt = CGAL::Robust_circumcenter_filtered_traits_3; // better inexact constructions (not mandatory) + +// Since we are going to use tetrahedral remeshing on the underlying triangulation, +// we need special vertex and cell base types that meets the requirements of the +// tetrahedral remeshing concepts +using Vbbb = AW3i::Alpha_wrap_triangulation_vertex_base_3; +using Vbb = CGAL::Simplicial_mesh_vertex_base_3; +using Vb = CGAL::Tetrahedral_remeshing::Remeshing_vertex_base_3; + +using Cbbb = AW3i::Alpha_wrap_triangulation_cell_base_3; +using Cbb = CGAL::Simplicial_mesh_cell_base_3; +using Cb = CGAL::Tetrahedral_remeshing::Remeshing_cell_base_3; + +using Tds = CGAL::Triangulation_data_structure_3; + +using Delaunay_triangulation = CGAL::Delaunay_triangulation_3; + +// because the Fast_location does all kinds of rebinding shenanigans + T3_hierarchy is in the stack... +using Triangulation = CGAL::Triangulation_3; + +using Facet = Triangulation::Facet; + +int main(int argc, char** argv) +{ + // Read the input + const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/bull.off"); + std::cout << "Reading " << filename << "..." << std::endl; + + Points points; + Faces faces; + if(!CGAL::IO::read_polygon_soup(filename, points, faces) || faces.empty()) + { + std::cerr << "Invalid input." << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Input: " << points.size() << " vertices, " << faces.size() << " faces" << std::endl; + + // Compute the alpha and offset values + const double relative_alpha = (argc > 2) ? std::stod(argv[2]) : 20.; + const double relative_offset = (argc > 3) ? std::stod(argv[3]) : 600.; + + CGAL::Bbox_3 bbox; + for(const Point_3& p : points) + bbox += p.bbox(); + + const double diag_length = std::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) + + CGAL::square(bbox.ymax() - bbox.ymin()) + + CGAL::square(bbox.zmax() - bbox.zmin())); + + const double alpha = diag_length / relative_alpha; + const double offset = diag_length / relative_offset; + std::cout << "alpha: " << alpha << ", offset: " << offset << std::endl; + + // Construct the wrap + CGAL::Real_timer t; + t.start(); + + using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle; + + Oracle oracle(K{}); + oracle.add_triangle_soup(points, faces, CGAL::parameters::default_values()); + + CGAL::Alpha_wraps_3::internal::Alpha_wrap_3 aw3(oracle); + Mesh wrap; + aw3(alpha, offset, wrap); + + t.stop(); + std::cout << "Result: " << num_vertices(wrap) << " vertices, " << num_faces(wrap) << " faces" << std::endl; + std::cout << "Took " << t.time() << " s." << std::endl; + + // Get the interior tetrahedrization + auto dt = aw3.triangulation(); + + // Save the result + std::string input_name = std::string(filename); + input_name = input_name.substr(input_name.find_last_of("/") + 1, input_name.length() - 1); + input_name = input_name.substr(0, input_name.find_last_of(".")); + std::string output_name = input_name + + "_" + std::to_string(static_cast(relative_alpha)) + + "_" + std::to_string(static_cast(relative_offset)) + ".off"; + std::cout << "Writing to " << output_name << std::endl; + CGAL::IO::write_polygon_mesh(output_name, wrap, CGAL::parameters::stream_precision(17)); + + // Remesh the interior of the wrap + const Delaunay_triangulation& aw3_dt = aw3.triangulation(); + const Triangulation& aw3_tr = static_cast(aw3_dt); + Triangulation tr = aw3_tr; // intentional copy + + std::cout << "BEFORE: " << tr.number_of_vertices() << " vertices, " << tr.number_of_cells() << " cells" << std::endl; + + // Set up the c3t3 information + for(auto v : tr.finite_vertex_handles()) + v->set_dimension(3); + + for(auto c : tr.finite_cell_handles()) + { + if(c->is_outside()) + c->set_subdomain_index(0); + else + c->set_subdomain_index(1); + + // if the neighboring cell has a different outside info, put the vertices + // of the common face on the surface boundary + for(int i=0; i<4; ++i) + { + if(c->neighbor(i)->is_outside() != c->is_outside()) + { + c->set_surface_patch_index(i, 1); + for(int j=1; j<4; ++j) + c->vertex((i+j)%4)->set_dimension(2); + } + } + } + + std::ofstream out_before("before_remeshing.mesh"); + CGAL::IO::write_MEDIT(out_before, tr); + + // edge length of equilateral triangle with circumradius alpha + // const double l = 2 * alpha * 0.8660254037844386; // sqrt(3)/2 + + // edge length of regular tetrahedron with circumradius alpha + const double l = 1.6329931618554521 * alpha; // sqrt(8/3) + + CGAL::tetrahedral_isotropic_remeshing(tr, l, CGAL::parameters::remesh_boundaries(false)); + + std::cout << "AFTER: " << tr.number_of_vertices() << " vertices, " << tr.number_of_cells() << " cells" << std::endl; + + std::ofstream out_after("after_remeshing.mesh"); + CGAL::IO::write_MEDIT(out_after, tr); + + return EXIT_SUCCESS; +} diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h index f12ad06804b..04b30cf7678 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_3.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2022 Google LLC (USA). +// Copyright (c) 2019-2023 Google LLC (USA). // All rights reserved. // // This file is part of CGAL (www.cgal.org). @@ -29,16 +29,25 @@ #include +#include +#include #include #include #include #include +#include +#include +#include +#include +#include + #include #include #include #include +#include #include #include #include @@ -50,16 +59,9 @@ #include // only if non-manifoldness is not treated #include #include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include #include #include #include @@ -74,30 +76,11 @@ namespace CGAL { namespace Alpha_wraps_3 { namespace internal { -template -class Cell_base_with_timestamp - : public Cb -{ - std::size_t time_stamp_; +namespace { -public: - template - Cell_base_with_timestamp(const Args&... args) : Cb(args...), time_stamp_(-1) { } +namespace AW3i = ::CGAL::Alpha_wraps_3::internal; - Cell_base_with_timestamp(const Cell_base_with_timestamp& other) : Cb(other), time_stamp_(other.time_stamp_) { } - - typedef CGAL::Tag_true Has_timestamp; - - std::size_t time_stamp() const { return time_stamp_; } - void set_time_stamp(const std::size_t& ts) { time_stamp_ = ts; } - - template - struct Rebind_TDS - { - typedef typename Cb::template Rebind_TDS::Other Cb2; - typedef Cell_base_with_timestamp Other; - }; -}; +} // unnamed namespace struct Wrapping_default_visitor { @@ -125,11 +108,34 @@ struct Wrapping_default_visitor void on_alpha_wrapping_end(const AlphaWrapper&) { }; }; -template +template class Alpha_wrap_3 { + using Oracle = Oracle_; + + // Triangulation using Base_GT = typename Oracle::Geom_traits; - using Geom_traits = Robust_circumcenter_filtered_traits_3; + using Default_Gt = CGAL::Robust_circumcenter_filtered_traits_3; + + using Default_Vb = Alpha_wrap_triangulation_vertex_base_3; + using Default_Cb = Alpha_wrap_triangulation_cell_base_3; + using Default_Cbt = Cell_base_with_timestamp; // determinism + using Default_Tds = CGAL::Triangulation_data_structure_3; + using Default_Triangulation = CGAL::Delaunay_triangulation_3; + + using Triangulation = typename Default::Get::type; + + using Cell_handle = typename Triangulation::Cell_handle; + using Facet = typename Triangulation::Facet; + using Vertex_handle = typename Triangulation::Vertex_handle; + using Locate_type = typename Triangulation::Locate_type; + + using Gate = internal::Gate; + using Alpha_PQ = Modifiable_priority_queue, CGAL_BOOST_PAIRING_HEAP>; + + // Use the geom traits from the triangulation, and trust the (advanced) user that provided it + using Geom_traits = typename Triangulation::Geom_traits; using FT = typename Geom_traits::FT; using Point_3 = typename Geom_traits::Point_3; @@ -143,34 +149,6 @@ class Alpha_wrap_3 using SC_Iso_cuboid_3 = SC::Iso_cuboid_3; using SC2GT = Cartesian_converter; - struct Cell_info - { - bool is_outside = false; - }; - - enum Vertex_info - { - DEFAULT = 0, - BBOX_VERTEX, - SEED_VERTEX - }; - - using Vb = Triangulation_vertex_base_3; - using Vbi = Triangulation_vertex_base_with_info_3; - using Cbb = Delaunay_triangulation_cell_base_3; - using Cb = Delaunay_triangulation_cell_base_with_circumcenter_3; - using Cbi = Triangulation_cell_base_with_info_3; - using Cbt = Cell_base_with_timestamp; - using Tds = Triangulation_data_structure_3; - using Dt = Delaunay_triangulation_3; - - using Cell_handle = typename Dt::Cell_handle; - using Facet = typename Dt::Facet; - using Vertex_handle = typename Dt::Vertex_handle; - using Locate_type = typename Dt::Locate_type; - - using Gate = internal::Gate
; - using Alpha_PQ = Modifiable_priority_queue, CGAL_BOOST_PAIRING_HEAP>; protected: const Oracle m_oracle; @@ -179,7 +157,7 @@ protected: FT m_alpha, m_sq_alpha; FT m_offset, m_sq_offset; - Dt m_dt; + Triangulation m_tr; Alpha_PQ m_queue; public: @@ -187,7 +165,7 @@ public: Alpha_wrap_3(const Oracle& oracle) : m_oracle(oracle), - m_dt(Geom_traits(oracle.geom_traits())), + m_tr(Geom_traits(oracle.geom_traits())), // used to set up the initial MPQ, use some arbitrary not-too-small value m_queue(4096) { @@ -197,9 +175,9 @@ public: } public: - const Geom_traits& geom_traits() const { return m_dt.geom_traits(); } - Dt& triangulation() { return m_dt; } - const Dt& triangulation() const { return m_dt; } + const Geom_traits& geom_traits() const { return m_tr.geom_traits(); } + Triangulation& triangulation() { return m_tr; } + const Triangulation& triangulation() const { return m_tr; } const Alpha_PQ& queue() const { return m_queue; } double default_alpha() const @@ -216,13 +194,13 @@ private: const Point_3& circumcenter(const Cell_handle c) const { // We only cross an infinite facet once, so this isn't going to be recomputed many times - if(m_dt.is_infinite(c)) + if(m_tr.is_infinite(c)) { - const int inf_index = c->index(m_dt.infinite_vertex()); + const int inf_index = c->index(m_tr.infinite_vertex()); c->set_circumcenter( - geom_traits().construct_circumcenter_3_object()(m_dt.point(c, (inf_index+1)&3), - m_dt.point(c, (inf_index+2)&3), - m_dt.point(c, (inf_index+3)&3))); + geom_traits().construct_circumcenter_3_object()(m_tr.point(c, (inf_index+1)&3), + m_tr.point(c, (inf_index+2)&3), + m_tr.point(c, (inf_index+3)&3))); } return c->circumcenter(geom_traits()); @@ -418,11 +396,11 @@ private: for(int i=0; i<8; ++i) { const Point_3 bp = SC2GT()(m_bbox.vertex(i)); - Vertex_handle bv = m_dt.insert(bp); + Vertex_handle bv = m_tr.insert(bp); #ifdef CGAL_AW3_DEBUG_INITIALIZATION std::cout << "\t" << bp << std::endl; #endif - bv->info() = BBOX_VERTEX; + bv->type() = AW3i::Vertex_type:: BBOX_VERTEX; } } @@ -433,7 +411,7 @@ private: // that the refinement point is separated from the existing point set. bool cavity_cell_outside_tag(const Cell_handle ch) { - CGAL_precondition(!m_dt.is_infinite(ch)); + CGAL_precondition(!m_tr.is_infinite(ch)); const Tetrahedron_with_outside_info tet(ch, geom_traits()); if(m_oracle.do_intersect(tet)) @@ -536,8 +514,8 @@ private: // This problem only appears when the seed and icosahedron vertices are close to the offset surface, // which usually happens for large alpha values. - Vertex_handle seed_v = m_dt.insert(seed_p); - seed_v->info() = SEED_VERTEX; + Vertex_handle seed_v = m_tr.insert(seed_p); + seed_v->type() = AW3i::Vertex_type:: SEED_VERTEX; seed_vs.push_back(seed_v); // Icosahedron vertices (see also BGL::make_icosahedron()) @@ -573,8 +551,8 @@ private: if(bbox.has_on_unbounded_side(seed_neighbor_p)) continue; - Vertex_handle ico_v = m_dt.insert(seed_neighbor_p, seed_v /*hint*/); - ico_v->info() = SEED_VERTEX; + Vertex_handle ico_v = m_tr.insert(seed_neighbor_p, seed_v /*hint*/); + ico_v->type() = AW3i::Vertex_type:: SEED_VERTEX; } } @@ -587,26 +565,26 @@ private: } #ifdef CGAL_AW3_DEBUG_INITIALIZATION - std::cout << m_dt.number_of_vertices() - 8 /*bbox*/ << " vertice(s) due to seeds" << std::endl; + std::cout << m_tr.number_of_vertices() - 8 /*bbox*/ << " vertice(s) due to seeds" << std::endl; #endif for(Vertex_handle seed_v : seed_vs) { std::vector inc_cells; inc_cells.reserve(64); - m_dt.incident_cells(seed_v, std::back_inserter(inc_cells)); + m_tr.incident_cells(seed_v, std::back_inserter(inc_cells)); for(Cell_handle ch : inc_cells) - ch->info().is_outside = cavity_cell_outside_tag(ch); + ch->is_outside() = cavity_cell_outside_tag(ch); } // Might as well go through the full triangulation since only seeds should have been inserted - for(Cell_handle ch : m_dt.all_cell_handles()) + for(Cell_handle ch : m_tr.all_cell_handles()) { - if(!ch->info().is_outside) + if(!ch->is_outside()) continue; // When the algorithm starts from a manually dug hole, infinite cells are tagged "inside" - CGAL_assertion(!m_dt.is_infinite(ch)); + CGAL_assertion(!m_tr.is_infinite(ch)); for(int i=0; i<4; ++i) push_facet(std::make_pair(ch, i)); @@ -627,17 +605,17 @@ private: // init queue with all convex hull facets bool initialize_from_infinity() { - for(Cell_handle ch : m_dt.all_cell_handles()) + for(Cell_handle ch : m_tr.all_cell_handles()) { - if(m_dt.is_infinite(ch)) + if(m_tr.is_infinite(ch)) { - ch->info().is_outside = true; - const int inf_index = ch->index(m_dt.infinite_vertex()); + ch->is_outside() = true; + const int inf_index = ch->index(m_tr.infinite_vertex()); push_facet(std::make_pair(ch, inf_index)); } else { - ch->info().is_outside = false; + ch->is_outside() = false; } } @@ -659,13 +637,13 @@ public: clear(output_mesh); - CGAL_assertion_code(for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit)) + CGAL_assertion_code(for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit)) CGAL_assertion(cit->tds_data().is_clear()); - for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit) + for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit) { Cell_handle seed = cit; - if(seed->info().is_outside || seed->tds_data().processed()) + if(seed->is_outside() || seed->tds_data().processed()) continue; std::queue to_visit; @@ -678,7 +656,7 @@ public: while(!to_visit.empty()) { const Cell_handle cell = to_visit.front(); - CGAL_assertion(!cell->info().is_outside && !m_dt.is_infinite(cell)); + CGAL_assertion(!cell->is_outside() && !m_tr.is_infinite(cell)); to_visit.pop(); @@ -690,17 +668,17 @@ public: for(int fid=0; fid<4; ++fid) { const Cell_handle neighbor = cell->neighbor(fid); - if(neighbor->info().is_outside) + if(neighbor->is_outside()) { // There shouldn't be any artificial vertex on the inside/outside boundary // (past initialization) -// CGAL_assertion(cell->vertex((fid + 1)&3)->info() == DEFAULT); -// CGAL_assertion(cell->vertex((fid + 2)&3)->info() == DEFAULT); -// CGAL_assertion(cell->vertex((fid + 3)&3)->info() == DEFAULT); +// CGAL_assertion(cell->vertex((fid + 1)&3)->type() == AW3i::Vertex_type:: DEFAULT); +// CGAL_assertion(cell->vertex((fid + 2)&3)->type() == AW3i::Vertex_type:: DEFAULT); +// CGAL_assertion(cell->vertex((fid + 3)&3)->type() == AW3i::Vertex_type:: DEFAULT); - points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 0))); - points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 1))); - points.push_back(m_dt.point(cell, Dt::vertex_triple_index(fid, 2))); + points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 0))); + points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 1))); + points.push_back(m_tr.point(cell, Triangulation::vertex_triple_index(fid, 2))); faces.push_back({idx, idx + 1, idx + 2}); idx += 3; } @@ -722,7 +700,7 @@ public: CGAL_assertion(is_closed(output_mesh)); } - for(auto cit=m_dt.finite_cells_begin(), cend=m_dt.finite_cells_end(); cit!=cend; ++cit) + for(auto cit=m_tr.finite_cells_begin(), cend=m_tr.finite_cells_end(); cit!=cend; ++cit) cit->tds_data().clear(); CGAL_postcondition(!is_empty(output_mesh)); @@ -742,7 +720,7 @@ public: std::cout << "> Extract wrap... ()" << std::endl; #endif - CGAL_assertion_code(for(Vertex_handle v : m_dt.finite_vertex_handles())) + CGAL_assertion_code(for(Vertex_handle v : m_tr.finite_vertex_handles())) CGAL_assertion(!is_non_manifold(v)); clear(output_mesh); @@ -754,26 +732,26 @@ public: std::unordered_map vertex_to_id; std::size_t nv = 0; - for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit) + for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) { Facet f = *fit; - if(!f.first->info().is_outside) - f = m_dt.mirror_facet(f); + if(!f.first->is_outside()) + f = m_tr.mirror_facet(f); const Cell_handle c = f.first; const int s = f.second; const Cell_handle nh = c->neighbor(s); - if(c->info().is_outside == nh->info().is_outside) + if(c->is_outside() == nh->is_outside()) continue; std::array ids; for(int pos=0; pos<3; ++pos) { - Vertex_handle vh = c->vertex(Dt::vertex_triple_index(s, pos)); + Vertex_handle vh = c->vertex(Triangulation::vertex_triple_index(s, pos)); auto insertion_res = vertex_to_id.emplace(vh, nv); if(insertion_res.second) // successful insertion, never-seen-before vertex { - points.push_back(m_dt.point(vh)); + points.push_back(m_tr.point(vh)); ++nv; } @@ -817,14 +795,14 @@ public: private: bool is_traversable(const Facet& f) const { - return less_squared_radius_of_min_empty_sphere(m_sq_alpha, f, m_dt); + return less_squared_radius_of_min_empty_sphere(m_sq_alpha, f, m_tr); } bool compute_steiner_point(const Cell_handle ch, const Cell_handle neighbor, Point_3& steiner_point) const { - CGAL_precondition(!m_dt.is_infinite(neighbor)); + CGAL_precondition(!m_tr.is_infinite(neighbor)); typename Geom_traits::Construct_ball_3 ball = geom_traits().construct_ball_3_object(); typename Geom_traits::Construct_vector_3 vector = geom_traits().construct_vector_3_object(); @@ -920,7 +898,7 @@ private: // e.g. from DT3 Facet_queue_status facet_status(const Facet& f) const { - CGAL_precondition(!m_dt.is_infinite(f)); + CGAL_precondition(!m_tr.is_infinite(f)); #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "facet status: " @@ -933,10 +911,10 @@ private: const Cell_handle ch = f.first; const int id = f.second; const Cell_handle nh = ch->neighbor(id); - if(m_dt.is_infinite(nh)) + if(m_tr.is_infinite(nh)) return TRAVERSABLE; - if(nh->info().is_outside) + if(nh->is_outside()) { #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "Neighbor already outside" << std::endl; @@ -947,8 +925,9 @@ private: // push if facet is connected to artificial vertices for(int i=0; i<3; ++i) { - const Vertex_handle vh = ch->vertex(Dt::vertex_triple_index(id, i)); - if(vh->info() == BBOX_VERTEX || vh->info() == SEED_VERTEX) + const Vertex_handle vh = ch->vertex(Triangulation::vertex_triple_index(id, i)); + if(vh->type() == AW3i::Vertex_type:: BBOX_VERTEX || + vh->type() == AW3i::Vertex_type:: SEED_VERTEX) { #ifdef CGAL_AW3_DEBUG_FACET_STATUS std::cout << "artificial facet due to artificial vertex #" << i << std::endl; @@ -974,7 +953,7 @@ private: bool push_facet(const Facet& f) { - CGAL_precondition(f.first->info().is_outside); + CGAL_precondition(f.first->is_outside()); // skip if f is already in queue if(m_queue.contains_with_bounds_check(Gate(f))) @@ -986,9 +965,9 @@ private: const Cell_handle ch = f.first; const int id = f.second; - const Point_3& p0 = m_dt.point(ch, (id+1)&3); - const Point_3& p1 = m_dt.point(ch, (id+2)&3); - const Point_3& p2 = m_dt.point(ch, (id+3)&3); + const Point_3& p0 = m_tr.point(ch, (id+1)&3); + const Point_3& p1 = m_tr.point(ch, (id+2)&3); + const Point_3& p2 = m_tr.point(ch, (id+3)&3); // @todo should prob be the real value we compare to alpha instead of squared_radius const FT sqr = geom_traits().compute_squared_radius_3_object()(p0, p1, p2); @@ -1022,7 +1001,7 @@ private: m_offset = FT(offset); m_sq_offset = square(m_offset); - m_dt.clear(); + m_tr.clear(); m_queue.clear(); insert_bbox_corners(); @@ -1052,7 +1031,7 @@ private: // const& to something that will be popped, but safe as `ch` && `id` are extracted before the pop const Gate& gate = m_queue.top(); const Facet& f = gate.facet(); - CGAL_precondition(!m_dt.is_infinite(f)); + CGAL_precondition(!m_tr.is_infinite(f)); const Cell_handle ch = f.first; const int id = f.second; @@ -1060,11 +1039,11 @@ private: #ifdef CGAL_AW3_DEBUG_QUEUE static int fid = 0; - std::cout << m_dt.number_of_vertices() << " DT vertices" << std::endl; + std::cout << m_tr.number_of_vertices() << " DT vertices" << std::endl; std::cout << m_queue.size() << " facets in the queue" << std::endl; std::cout << "Face " << fid++ << "\n" - << "c = " << &*ch << " (" << m_dt.is_infinite(ch) << "), n = " << &*neighbor << " (" << m_dt.is_infinite(neighbor) << ")" << "\n" - << m_dt.point(ch, (id+1)&3) << "\n" << m_dt.point(ch, (id+2)&3) << "\n" << m_dt.point(ch, (id+3)&3) << std::endl; + << "c = " << &*ch << " (" << m_tr.is_infinite(ch) << "), n = " << &*neighbor << " (" << m_tr.is_infinite(neighbor) << ")" << "\n" + << m_tr.point(ch, (id+1)&3) << "\n" << m_tr.point(ch, (id+2)&3) << "\n" << m_tr.point(ch, (id+3)&3) << std::endl; std::cout << "Priority: " << gate.priority() << std::endl; #endif @@ -1080,13 +1059,13 @@ private: std::string face_name = "results/steps/face_" + std::to_string(static_cast(i++)) + ".xyz"; std::ofstream face_out(face_name); face_out.precision(17); - face_out << "3\n" << m_dt.point(ch, (id+1)&3) << "\n" << m_dt.point(ch, (id+2)&3) << "\n" << m_dt.point(ch, (id+3)&3) << std::endl; + face_out << "3\n" << m_tr.point(ch, (id+1)&3) << "\n" << m_tr.point(ch, (id+2)&3) << "\n" << m_tr.point(ch, (id+3)&3) << std::endl; face_out.close(); #endif - if(m_dt.is_infinite(neighbor)) + if(m_tr.is_infinite(neighbor)) { - neighbor->info().is_outside = true; + neighbor->is_outside() = true; continue; } @@ -1100,14 +1079,16 @@ private: // locate cells that are going to be destroyed and remove their facet from the queue int li, lj = 0; Locate_type lt; - const Cell_handle conflict_cell = m_dt.locate(steiner_point, lt, li, lj, neighbor); - CGAL_assertion(lt != Dt::VERTEX); + const Cell_handle conflict_cell = m_tr.locate(steiner_point, lt, li, lj, neighbor); + CGAL_assertion(lt != Triangulation::VERTEX); + // Using small vectors like in Triangulation_3 does not bring any runtime improvement std::vector boundary_facets; std::vector conflict_zone; boundary_facets.reserve(32); conflict_zone.reserve(32); - m_dt.find_conflicts(steiner_point, conflict_cell, + + m_tr.find_conflicts(steiner_point, conflict_cell, std::back_inserter(boundary_facets), std::back_inserter(conflict_zone)); @@ -1125,7 +1106,7 @@ private: for(const Facet& f : boundary_facets) { - const Facet mf = m_dt.mirror_facet(f); // boundary facets have incident cells in the CZ + const Facet mf = m_tr.mirror_facet(f); // boundary facets have incident cells in the CZ if(m_queue.contains_with_bounds_check(Gate(mf))) m_queue.erase(Gate(mf)); } @@ -1133,18 +1114,20 @@ private: visitor.before_Steiner_point_insertion(*this, steiner_point); // Actual insertion of the Steiner point - Vertex_handle vh = m_dt.insert(steiner_point, lt, conflict_cell, li, lj); - vh->info() = DEFAULT; + // We could use TDS functions to avoid recomputing the conflict zone, but in practice + // it does not bring any runtime improvements + Vertex_handle vh = m_tr.insert(steiner_point, lt, conflict_cell, li, lj); + vh->type() = AW3i::Vertex_type:: DEFAULT; visitor.after_Steiner_point_insertion(*this, vh); std::vector new_cells; new_cells.reserve(32); - m_dt.incident_cells(vh, std::back_inserter(new_cells)); + m_tr.incident_cells(vh, std::back_inserter(new_cells)); for(const Cell_handle& ch : new_cells) { // std::cout << "new cell has time stamp " << ch->time_stamp() << std::endl; - ch->info().is_outside = m_dt.is_infinite(ch); + ch->is_outside() = m_tr.is_infinite(ch); } // Push all new boundary facets to the queue. @@ -1156,25 +1139,25 @@ private: { for(int i=0; i<4; ++i) { - if(m_dt.is_infinite(ch, i)) + if(m_tr.is_infinite(ch, i)) continue; const Cell_handle nh = ch->neighbor(i); - if(nh->info().is_outside == ch->info().is_outside) // not on the boundary + if(nh->is_outside() == ch->is_outside()) // not on the boundary continue; const Facet boundary_f = std::make_pair(ch, i); - if(ch->info().is_outside) + if(ch->is_outside()) push_facet(boundary_f); else - push_facet(m_dt.mirror_facet(boundary_f)); + push_facet(m_tr.mirror_facet(boundary_f)); } } } else { // tag neighbor as OUTSIDE - neighbor->info().is_outside = true; + neighbor->is_outside() = true; // for each finite facet of neighbor, push it to the queue for(int i=0; i<4; ++i) @@ -1188,10 +1171,10 @@ private: visitor.on_flood_fill_end(*this); // Check that no useful facet has been ignored - CGAL_postcondition_code(for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit) {) - CGAL_postcondition_code( if(fit->first->info().is_outside == fit->first->neighbor(fit->second)->info().is_outside) continue;) + CGAL_postcondition_code(for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) {) + CGAL_postcondition_code( if(fit->first->is_outside() == fit->first->neighbor(fit->second)->is_outside()) continue;) CGAL_postcondition_code( Facet f = *fit;) - CGAL_postcondition_code( if(!fit->first->info().is_outside) f = m_dt.mirror_facet(f);) + CGAL_postcondition_code( if(!fit->first->is_outside()) f = m_tr.mirror_facet(f);) CGAL_postcondition( facet_status(f) == IRRELEVANT); CGAL_postcondition_code(}) } @@ -1199,13 +1182,13 @@ private: private: bool is_non_manifold(Vertex_handle v) const { - CGAL_precondition(!m_dt.is_infinite(v)); + CGAL_precondition(!m_tr.is_infinite(v)); bool is_non_manifold = false; std::vector inc_cells; inc_cells.reserve(64); - m_dt.incident_cells(v, std::back_inserter(inc_cells)); + m_tr.incident_cells(v, std::back_inserter(inc_cells)); // Flood one inside and outside CC. // Process both an inside and an outside CC to also detect edge pinching. @@ -1218,7 +1201,7 @@ private: for(Cell_handle ic : inc_cells) { ic->tds_data().clear(); - if(ic->info().is_outside) + if(ic->is_outside()) outside_start = ic; else if(inside_start == Cell_handle()) inside_start = ic; @@ -1253,7 +1236,7 @@ private: CGAL_assertion(neigh_c->has_vertex(v)); if(neigh_c->tds_data().processed() || - neigh_c->info().is_outside != curr_c->info().is_outside) // do not cross the boundary + neigh_c->is_outside() != curr_c->is_outside()) // do not cross the boundary continue; cells_to_visit.push(neigh_c); @@ -1278,7 +1261,7 @@ private: bool is_non_manifold(Cell_handle c) const { - CGAL_precondition(!m_dt.is_infinite(c)); + CGAL_precondition(!m_tr.is_infinite(c)); for(int i=0; i<4; ++i) { @@ -1294,7 +1277,7 @@ private: { // Not the best complexity, but it's not important: this function is purely for information // Better complexity --> see PMP::non_manifold_vertices + throw - for(const Vertex_handle v : m_dt.finite_vertex_handles()) + for(const Vertex_handle v : m_tr.finite_vertex_handles()) if(is_non_manifold(v)) return true; @@ -1307,18 +1290,18 @@ private: bool remove_bbox_vertices() { bool do_remove = true; - auto vit = m_dt.finite_vertices_begin(); + auto vit = m_tr.finite_vertices_begin(); for(std::size_t i=0; i<8; ++i) { Vertex_handle v = vit++; std::vector inc_cells; inc_cells.reserve(64); - m_dt.finite_incident_cells(v, std::back_inserter(inc_cells)); + m_tr.finite_incident_cells(v, std::back_inserter(inc_cells)); for(Cell_handle c : inc_cells) { - if(!c->info().is_outside) + if(!c->is_outside()) { do_remove = false; break; @@ -1333,11 +1316,11 @@ private: if(!do_remove) return false; - vit = m_dt.finite_vertices_begin(); + vit = m_tr.finite_vertices_begin(); for(std::size_t i=0; i<8; ++i) { Vertex_handle v = vit++; - m_dt.remove(v); + m_tr.remove(v); } return true; @@ -1355,7 +1338,7 @@ public: // remove_bbox_vertices(); std::stack non_manifold_vertices; // @todo sort somehow? - for(Vertex_handle v : m_dt.finite_vertex_handles()) + for(Vertex_handle v : m_tr.finite_vertex_handles()) { if(is_non_manifold(v)) non_manifold_vertices.push(v); @@ -1365,15 +1348,20 @@ public: auto has_artificial_vertex = [](Cell_handle c) -> bool { for(int i=0; i<4; ++i) - if(c->vertex(i)->info() == BBOX_VERTEX || c->vertex(i)->info() == SEED_VERTEX) + { + if(c->vertex(i)->type() == AW3i::Vertex_type:: BBOX_VERTEX || + c->vertex(i)->type() == AW3i::Vertex_type:: SEED_VERTEX) + { return true; + } + } return false; }; auto is_on_boundary = [](Cell_handle c, int i) -> bool { - return (c->info().is_outside != c->neighbor(i)->info().is_outside); + return (c->is_outside() != c->neighbor(i)->is_outside()); }; auto count_boundary_facets = [&](Cell_handle c, Vertex_handle v) -> int @@ -1395,17 +1383,17 @@ public: // auto sq_circumradius = [&](Cell_handle c) -> FT // { // const Point_3& cc = circumcenter(c); -// return geom_traits().compute_squared_distance_3_object()(m_dt.point(c, 0), cc); +// return geom_traits().compute_squared_distance_3_object()(m_tr.point(c, 0), cc); // }; auto sq_longest_edge = [&](Cell_handle c) -> FT { - return (std::max)({ squared_distance(m_dt.point(c, 0), m_dt.point(c, 1)), - squared_distance(m_dt.point(c, 0), m_dt.point(c, 2)), - squared_distance(m_dt.point(c, 0), m_dt.point(c, 3)), - squared_distance(m_dt.point(c, 1), m_dt.point(c, 2)), - squared_distance(m_dt.point(c, 3), m_dt.point(c, 3)), - squared_distance(m_dt.point(c, 2), m_dt.point(c, 3)) }); + return (std::max)({ squared_distance(m_tr.point(c, 0), m_tr.point(c, 1)), + squared_distance(m_tr.point(c, 0), m_tr.point(c, 2)), + squared_distance(m_tr.point(c, 0), m_tr.point(c, 3)), + squared_distance(m_tr.point(c, 1), m_tr.point(c, 2)), + squared_distance(m_tr.point(c, 3), m_tr.point(c, 3)), + squared_distance(m_tr.point(c, 2), m_tr.point(c, 3)) }); }; #ifdef CGAL_AW3_DEBUG_MANIFOLDNESS @@ -1450,7 +1438,7 @@ public: std::vector inc_cells; inc_cells.reserve(64); - m_dt.finite_incident_cells(v, std::back_inserter(inc_cells)); + m_tr.finite_incident_cells(v, std::back_inserter(inc_cells)); #define CGAL_AW3_USE_BRUTE_FORCE_MUTABLE_PRIORITY_QUEUE #ifndef CGAL_AW3_USE_BRUTE_FORCE_MUTABLE_PRIORITY_QUEUE @@ -1464,10 +1452,10 @@ public: std::sort(cit, cend, comparer); #endif Cell_handle ic = *cit; - CGAL_assertion(!m_dt.is_infinite(ic)); + CGAL_assertion(!m_tr.is_infinite(ic)); // This is where new material is added - ic->info().is_outside = false; + ic->is_outside() = false; #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP static int i = 0; @@ -1484,14 +1472,14 @@ public: std::vector adj_vertices; adj_vertices.reserve(64); - m_dt.finite_adjacent_vertices(v, std::back_inserter(adj_vertices)); + m_tr.finite_adjacent_vertices(v, std::back_inserter(adj_vertices)); for(Vertex_handle nv : adj_vertices) if(is_non_manifold(nv)) non_manifold_vertices.push(nv); } - CGAL_assertion_code(for(Vertex_handle v : m_dt.finite_vertex_handles())) + CGAL_assertion_code(for(Vertex_handle v : m_tr.finite_vertex_handles())) CGAL_assertion(!is_non_manifold(v)); } @@ -1508,12 +1496,12 @@ private: const Facet& current_f = current_gate.facet(); const Cell_handle ch = current_f.first; const int id = current_f.second; - const Point_3& p0 = m_dt.point(ch, (id+1)&3); - const Point_3& p1 = m_dt.point(ch, (id+2)&3); - const Point_3& p2 = m_dt.point(ch, (id+3)&3); + const Point_3& p0 = m_tr.point(ch, (id+1)&3); + const Point_3& p1 = m_tr.point(ch, (id+2)&3); + const Point_3& p2 = m_tr.point(ch, (id+3)&3); const FT sqr = geom_traits().compute_squared_radius_3_object()(p0, p1, p2); - std::cout << "At Facet with VID " << get(Gate_ID_PM
(), current_gate) << std::endl; + std::cout << "At Facet with VID " << get(Gate_ID_PM(), current_gate) << std::endl; if(current_gate.priority() != sqr) std::cerr << "Error: facet in queue has wrong priority" << std::endl; @@ -1546,13 +1534,13 @@ private: std::size_t nv = 0; std::size_t nf = 0; - for(auto fit=m_dt.finite_facets_begin(), fend=m_dt.finite_facets_end(); fit!=fend; ++fit) + for(auto fit=m_tr.finite_facets_begin(), fend=m_tr.finite_facets_end(); fit!=fend; ++fit) { Cell_handle c = fit->first; int s = fit->second; Cell_handle nc = c->neighbor(s); - if(only_boundary_faces && (c->info().is_outside == nc->info().is_outside)) + if(only_boundary_faces && (c->is_outside() == nc->is_outside())) continue; std::array ids; @@ -1562,7 +1550,7 @@ private: auto insertion_res = vertex_to_id.emplace(v, nv); if(insertion_res.second) { - vertices_ss << m_dt.point(v) << "\n"; + vertices_ss << m_tr.point(v) << "\n"; ++nv; } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_geom_traits.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_geom_traits.h index 22c64e9b5e2..80a403c258e 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_geom_traits.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_geom_traits.h @@ -36,24 +36,24 @@ struct Tetrahedron_with_outside_info using Triangle_3 = typename Kernel::Triangle_3; template - Tetrahedron_with_outside_info(const CellHandle ch, const K& k) + Tetrahedron_with_outside_info(const CellHandle c, const K& k) { typename K::Construct_bbox_3 bbox = k.construct_bbox_3_object(); typename K::Construct_tetrahedron_3 tetrahedron = k.construct_tetrahedron_3_object(); typename K::Construct_triangle_3 triangle = k.construct_triangle_3_object(); - m_tet = tetrahedron(ch->vertex(0)->point(), ch->vertex(1)->point(), - ch->vertex(2)->point(), ch->vertex(3)->point()); + m_tet = tetrahedron(c->vertex(0)->point(), c->vertex(1)->point(), + c->vertex(2)->point(), c->vertex(3)->point()); m_bbox = bbox(m_tet); for(int i=0; i<4; ++i) { - if(ch->neighbor(i)->info().is_outside) + if(c->neighbor(i)->is_outside()) m_b.set(i, true); - m_triangles[i] = triangle(ch->vertex((i+1)& 3)->point(), - ch->vertex((i+2)& 3)->point(), - ch->vertex((i+3)& 3)->point()); + m_triangles[i] = triangle(c->vertex((i+1)& 3)->point(), + c->vertex((i+2)& 3)->point(), + c->vertex((i+3)& 3)->point()); m_tbox[i] = bbox(m_triangles[i]); } } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h new file mode 100644 index 00000000000..db1df61c8f6 --- /dev/null +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_cell_base_3.h @@ -0,0 +1,97 @@ +// Copyright (c) 2019-2023 Google LLC (USA). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Mael Rouxel-Labbé + +#ifndef CGAL_ALPHA_WRAP_TRIANGULATION_CELL_BASE_3_H +#define CGAL_ALPHA_WRAP_TRIANGULATION_CELL_BASE_3_H + +#include + +#include + +namespace CGAL { +namespace Alpha_wraps_3 { +namespace internal { + +template < typename GT, + typename Cb = CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3 > +class Alpha_wrap_triangulation_cell_base_3 + : public Cb +{ +private: + bool outside = false; + +public: + typedef typename Cb::Vertex_handle Vertex_handle; + typedef typename Cb::Cell_handle Cell_handle; + + template < typename TDS2 > + struct Rebind_TDS + { + using Cb2 = typename Cb::template Rebind_TDS::Other; + using Other = Alpha_wrap_triangulation_cell_base_3; + }; + + Alpha_wrap_triangulation_cell_base_3() + : Cb() + {} + + Alpha_wrap_triangulation_cell_base_3(Vertex_handle v0, Vertex_handle v1, + Vertex_handle v2, Vertex_handle v3) + : Cb(v0, v1, v2, v3) + {} + + Alpha_wrap_triangulation_cell_base_3(Vertex_handle v0, Vertex_handle v1, + Vertex_handle v2, Vertex_handle v3, + Cell_handle n0, Cell_handle n1, + Cell_handle n2, Cell_handle n3) + : Cb(v0, v1, v2, v3, n0, n1, n2, n3) + {} + + bool is_outside() const { return outside; } + bool& is_outside() { return outside; } +}; + +template +class Cell_base_with_timestamp + : public Cb +{ + std::size_t time_stamp_; + +public: + using Has_timestamp = CGAL::Tag_true; + + template + struct Rebind_TDS + { + using Cb2 = typename Cb::template Rebind_TDS::Other; + using Other = Cell_base_with_timestamp; + }; + +public: + template + Cell_base_with_timestamp(const Args&... args) + : Cb(args...), time_stamp_(-1) + { } + + Cell_base_with_timestamp(const Cell_base_with_timestamp& other) + : Cb(other), time_stamp_(other.time_stamp_) + { } + +public: + std::size_t time_stamp() const { return time_stamp_; } + void set_time_stamp(const std::size_t& ts) { time_stamp_ = ts; } +}; + +} // namespace internal +} // namespace Alpha_wraps_3 +} // namespace CGAL + +#endif // CGAL_ALPHA_WRAP_TRIANGULATION_CELL_BASE_3_H diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h new file mode 100644 index 00000000000..3743edffbc7 --- /dev/null +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_triangulation_vertex_base_3.h @@ -0,0 +1,71 @@ +// Copyright (c) 2019-2023 Google LLC (USA). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Mael Rouxel-Labbé + +#ifndef CGAL_ALPHA_WRAP_TRIANGULATION_VERTEX_BASE_3_H +#define CGAL_ALPHA_WRAP_TRIANGULATION_VERTEX_BASE_3_H + +#include + +#include + +namespace CGAL { +namespace Alpha_wraps_3 { +namespace internal { + +enum class Vertex_type +{ + DEFAULT = 0, + BBOX_VERTEX, + SEED_VERTEX +}; + +template > +class Alpha_wrap_triangulation_vertex_base_3 + : public Vb +{ +private: + Vertex_type vertex_type = Vertex_type::DEFAULT; + +public: + using Cell_handle = typename Vb::Cell_handle; + using Point = typename Vb::Point; + + template + struct Rebind_TDS + { + using Vb2 = typename Vb::template Rebind_TDS::Other; + using Other = Alpha_wrap_triangulation_vertex_base_3; + }; + +public: + Alpha_wrap_triangulation_vertex_base_3() + : Vb() {} + + Alpha_wrap_triangulation_vertex_base_3(const Point& p) + : Vb(p) {} + + Alpha_wrap_triangulation_vertex_base_3(const Point& p, Cell_handle c) + : Vb(p, c) {} + + Alpha_wrap_triangulation_vertex_base_3(Cell_handle c) + : Vb(c) {} + +public: + const Vertex_type& type() const { return vertex_type; } + Vertex_type& type() { return vertex_type; } +}; + +} // namespace internal +} // namespace Alpha_wraps_3 +} // namespace CGAL + +#endif // CGAL_ALPHA_WRAP_TRIANGULATION_VERTEX_BASE_3_H diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h b/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h index c4903e1c816..411dda8c5e8 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_geodesic_arc_on_sphere_traits_2.h @@ -39,9 +39,86 @@ namespace CGAL { +/*! Represent an extended 3D direction that is used in turn to represent a + * spherical-arc endpoint. The extended data consists of two flags that + * indicate whether the point is on the x and on a y boundaries, + * respectively. + */ +template +class Arr_extended_direction_3 : public Kernel::Direction_3 { +public: + using FT = typename Kernel::FT; + using Direction_3 = typename Kernel::Direction_3; + + /*! Enumeration of discontinuity type */ + enum Location_type { + NO_BOUNDARY_LOC = 0, + MIN_BOUNDARY_LOC, + MID_BOUNDARY_LOC, + MAX_BOUNDARY_LOC + }; + +private: + using Direction_2 = typename Kernel::Direction_2; + + //! The point discontinuity type + Location_type m_location; + + inline Sign x_sign(Direction_3 d) const { return CGAL::sign(d.dx()); } + + inline Sign y_sign(Direction_3 d) const { return CGAL::sign(d.dy()); } + + inline Sign z_sign(Direction_3 d) const { return CGAL::sign(d.dz()); } + +public: + /*! Default constructor */ + Arr_extended_direction_3() : + Direction_3(0, 0, 1), + m_location(MAX_BOUNDARY_LOC) + {} + + /*! Constructor */ + Arr_extended_direction_3(const Direction_3& dir, Location_type location) : + Direction_3(dir), + m_location(location) + {} + + /*! Copy constructor */ + Arr_extended_direction_3(const Arr_extended_direction_3& other) : + Direction_3(static_cast(other)) + { m_location = other.discontinuity_type(); } + + /*! Assignment operator */ + Arr_extended_direction_3& operator=(const Arr_extended_direction_3& other) { + *(static_cast(this)) = static_cast(other); + m_location = other.discontinuity_type(); + return (*this); + } + + /*! Set the location type of the point. + */ + void set_location(Location_type location) { m_location = location; } + + /*! Obtain the location type of the point. + */ + Location_type location() const { return m_location; } + + /*! Obtain the discontinuity type of the point. + * \todo deprecate this one; use the above instead. + */ + Location_type discontinuity_type() const { return m_location; } + + bool is_no_boundary() const { return (m_location == NO_BOUNDARY_LOC); } + + bool is_min_boundary() const { return (m_location == MIN_BOUNDARY_LOC); } + + bool is_mid_boundary() const { return (m_location == MID_BOUNDARY_LOC); } + + bool is_max_boundary() const { return (m_location == MAX_BOUNDARY_LOC); } +}; + template class Arr_x_monotone_geodesic_arc_on_sphere_3; template class Arr_geodesic_arc_on_sphere_3; -template class Arr_extended_direction_3; /*! A traits class-template for constructing and maintaining arcs of great * circles embedded on spheres. It is parameterized from a (linear) geometry @@ -54,44 +131,43 @@ class Arr_geodesic_arc_on_sphere_traits_2 : public Kernel_ { friend class Arr_extended_direction_3; public: - typedef Kernel_ Kernel; + using Kernel = Kernel_; // Category tags: - typedef Tag_true Has_left_category; - typedef Tag_true Has_merge_category; - typedef Tag_false Has_do_intersect_category; + using Has_left_category = Tag_true; + using Has_merge_category = Tag_true; + using Has_do_intersect_category = Tag_false; - typedef Arr_identified_side_tag Left_side_category; - typedef Arr_contracted_side_tag Bottom_side_category; - typedef Arr_contracted_side_tag Top_side_category; - typedef Arr_identified_side_tag Right_side_category; + using Left_side_category = Arr_identified_side_tag; + using Bottom_side_category = Arr_contracted_side_tag; + using Top_side_category = Arr_contracted_side_tag; + using Right_side_category = Arr_identified_side_tag; - typedef std::integral_constant Zero_atan_y; + using Zero_atan_y = std::integral_constant; // Traits objects - typedef Arr_extended_direction_3 Point_2; - typedef Arr_x_monotone_geodesic_arc_on_sphere_3 X_monotone_curve_2; - typedef Arr_geodesic_arc_on_sphere_3 Curve_2; - typedef unsigned int Multiplicity; + using Point_2 = Arr_extended_direction_3; + using X_monotone_curve_2 = Arr_x_monotone_geodesic_arc_on_sphere_3; + using Curve_2 = Arr_geodesic_arc_on_sphere_3; + using Multiplicity = std::size_t; /*! Default constructor */ Arr_geodesic_arc_on_sphere_traits_2() {} protected: - typedef typename Kernel::FT FT; + using FT = typename Kernel::FT; - typedef typename Kernel::Direction_3 Direction_3; - typedef typename Kernel::Vector_3 Vector_3; - typedef typename Kernel::Direction_2 Direction_2; - typedef typename Kernel::Vector_2 Vector_2; + using Direction_3 = typename Kernel::Direction_3; + using Vector_3 = typename Kernel::Vector_3; + using Direction_2 = typename Kernel::Direction_2; + using Vector_2 = typename Kernel::Vector_2; /*! Obtain the intersection of the identification arc and the xy plane. * By default, it is the vector directed along the negative x axis * (x = -infinity). * \return the intersection of the identification arc and the xy plane. */ - inline static const Direction_2& identification_xy() - { + inline static const Direction_2& identification_xy() { static const Direction_2 d(atan_x, atan_y); return d; } @@ -101,8 +177,7 @@ protected: * (y = infinity). * \return the normal of the plane that contains the identification arc. */ - inline static const Direction_3& identification_normal() - { + inline static const Direction_3& identification_normal() { static const Direction_3 d(atan_y, -atan_x, 0); return d; } @@ -110,8 +185,7 @@ protected: /*! Obtain the 2D direction directed along the negative x axis * \return the direction directed at x = -infinity */ - inline static const Direction_2& neg_x_2() - { + inline static const Direction_2& neg_x_2() { CGAL_STATIC_THREAD_LOCAL_VARIABLE_2(Direction_2, d, -1, 0); return d; } @@ -119,8 +193,7 @@ protected: /*! Obtain the 2D direction directed along the negative y axis * \return the direction directed at y = -infinity */ - inline static const Direction_2& neg_y_2() - { + inline static const Direction_2& neg_y_2() { CGAL_STATIC_THREAD_LOCAL_VARIABLE_2(Direction_2, d, 0, -1); return d; } @@ -186,8 +259,7 @@ protected: * \param dir the direction. */ inline Oriented_side oriented_side(const Direction_3& normal, - const Direction_3 dir) const - { + const Direction_3 dir) const { FT dot = normal.vector() * dir.vector(); return CGAL::sign(dot); } @@ -197,9 +269,8 @@ protected: * \param d2 the second direction. * \return the relative orientation of d1 and d2. */ - inline Orientation orientation(const Direction_2& d1, const Direction_2& d2) - const - { + inline Orientation orientation(const Direction_2& d1, + const Direction_2& d2) const { const Kernel& kernel(*this); return kernel.orientation_2_object()(d1.vector(), d2.vector()); } @@ -209,8 +280,7 @@ protected: * \param d2 the second direction. */ inline Direction_3 construct_normal_3(const Direction_3& d1, - const Direction_3& d2) const - { + const Direction_3& d2) const { const Kernel& kernel(*this); Vector_3 v = kernel.construct_cross_product_vector_3_object()(d1.vector(), d2.vector()); @@ -224,8 +294,7 @@ protected: * \return true if dir is contained in plane; false otherwise. * \pre the plane contains the origin. */ - inline bool has_on(const Direction_3& normal, const Direction_3& dir) const - { + inline bool has_on(const Direction_3& normal, const Direction_3& dir) const { FT dot = normal.vector() * dir.vector(); return CGAL::sign(dot) == ZERO; } @@ -239,8 +308,7 @@ public: * LARGER - v(d1) > v(d2). */ inline Comparison_result compare_y(const Direction_3& d1, - const Direction_3& d2) const - { + const Direction_3& d2) const { Vector_3 v1 = d1.vector(); Vector_3 v2 = d2.vector(); @@ -274,8 +342,7 @@ public: * LARGER - u(d1) > u(d2). */ inline Comparison_result compare_x(const Direction_2& d1, - const Direction_2& d2) const - { + const Direction_2& d2) const { const Kernel& kernel = *this; if (kernel.equal_2_object()(d1, d2)) return EQUAL; const Direction_2& d = identification_xy(); @@ -293,8 +360,7 @@ public: * \pre d2 does not coincide with any pole. */ inline Comparison_result compare_x(const Direction_3& d1, - const Direction_3& d2) const - { + const Direction_3& d2) const { // Compare the projections onto the xy plane: Direction_2 d1_2 = project_xy(d1); Direction_2 d2_2 = project_xy(d2); @@ -313,8 +379,7 @@ public: * \pre d2 does not lie on the discontinuity arc. */ inline Comparison_result compare_xy(const Direction_3& d1, - const Direction_3& d2) const - { + const Direction_3& d2) const { Comparison_result res = compare_x(d1, d2); if (res == EQUAL) return compare_y(d1, d2); return res; @@ -327,9 +392,9 @@ public: * false otherwise. * \pre point does not coincide with one of the poles */ - bool is_in_x_range(const X_monotone_curve_2& xcv, const Point_2& point) const - { - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + bool is_in_x_range(const X_monotone_curve_2& xcv, + const Point_2& point) const { + using Traits = Arr_geodesic_arc_on_sphere_traits_2; CGAL_precondition(!point.is_min_boundary()); CGAL_precondition(!point.is_max_boundary()); @@ -358,8 +423,7 @@ public: */ void intersection_with_identification(const X_monotone_curve_2& xcv, Direction_3& dp, - std::true_type) const - { + std::true_type) const { const Direction_3& normal = xcv.normal(); dp = (CGAL::sign(normal.dz()) == POSITIVE) ? Direction_3(-(normal.dz()), 0, normal.dx()) : @@ -371,8 +435,7 @@ public: */ void intersection_with_identification(const X_monotone_curve_2& xcv, Direction_3& dp, - std::false_type) const - { + std::false_type) const { const Direction_3& normal = xcv.normal(); FT z((atan_x * normal.dx() + atan_y * normal.dy()) / -(normal.dz())); @@ -383,8 +446,7 @@ public: * \param[in] cv the curve */ bool overlap_with_identification(const X_monotone_curve_2& xcv, - std::true_type) const - { + std::true_type) const { const Direction_3& normal = xcv.normal(); return ((x_sign(normal) == ZERO) && (((y_sign(normal) == NEGATIVE) && !xcv.is_directed_right()) || @@ -395,8 +457,7 @@ public: * \param[in] cv the curve */ bool overlap_with_identification(const X_monotone_curve_2& xcv, - std::false_type) const - { + std::false_type) const { const Direction_3& normal = xcv.normal(); const Direction_3& iden_normal = identification_normal(); const Direction_2 iden_normal_xy = project_xy(iden_normal); @@ -417,9 +478,9 @@ public: /*! A functor that constructs a point on the sphere. */ class Construct_point_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -436,8 +497,7 @@ public: * \param[in] y the y coordinate * \param[in] z the z coordinate */ - Point_2 operator()(const FT& x, const FT& y, const FT& z) - { + Point_2 operator()(const FT& x, const FT& y, const FT& z) { Point_2 p; Direction_3& d(p); d = Direction_3(x, y, z); @@ -449,8 +509,7 @@ public: * direction. * \param other the other direction */ - Point_2 operator()(const Direction_3& other) - { + Point_2 operator()(const Direction_3& other) { Point_2 p; Direction_3& d(p); d = Direction_3(other); @@ -461,8 +520,7 @@ public: /*! Initialize a point on the sphere, * \param[in] p the point to initialize. */ - void init(Point_2& p, std::true_type) const - { + void init(Point_2& p, std::true_type) const { const Direction_3& dir = p; if (y_sign(dir) != ZERO) { p.set_location(Point_2::NO_BOUNDARY_LOC); @@ -480,8 +538,7 @@ public: /*! Initialize a point on the sphere, * \param[in] p the point to initialize. */ - void init(Point_2& p, std::false_type) const - { + void init(Point_2& p, std::false_type) const { const Direction_3& dir = p; if ((x_sign(dir) == ZERO) && (y_sign(dir) == ZERO)) { typename Point_2::Location_type location = (z_sign(dir) == NEGATIVE) ? @@ -508,9 +565,9 @@ public: /*! A functor that constructs an x-monotone geodesic arc on the sphere. */ class Construct_x_monotone_curve_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -536,9 +593,8 @@ public: * \pre the source and target must not coincide. * \pre the source and target cannot be antipodal. */ - X_monotone_curve_2 operator()(const Point_2& source, const Point_2& target) - const - { + X_monotone_curve_2 operator()(const Point_2& source, + const Point_2& target) const { X_monotone_curve_2 xcv; xcv.set_source(source); @@ -561,8 +617,7 @@ public: * \param plane the containing plane. * \pre the plane is not vertical */ - X_monotone_curve_2 operator()(const Direction_3& normal) const - { + X_monotone_curve_2 operator()(const Direction_3& normal) const { X_monotone_curve_2 xcv; xcv.set_normal(normal); @@ -608,12 +663,11 @@ public: * \param target the target point. * \pre the source and target cannot be equal. */ - void init(X_monotone_curve_2& xcv) const - { + void init(X_monotone_curve_2& xcv) const { const Point_2& source = xcv.source(); const Point_2& target = xcv.target(); - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; const Kernel& kernel(m_traits); CGAL_precondition(!kernel.equal_3_object()(Direction_3(source), @@ -701,9 +755,9 @@ public: /*! A functor that constructs a geodesic arc on the sphere. */ class Construct_curve_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -728,8 +782,7 @@ public: * \pre the source and target cannot be equal. * \pre the source and target cannot be the opoosite of each other. */ - Curve_2 operator()(const Point_2& source, const Point_2& target) - { + Curve_2 operator()(const Point_2& source, const Point_2& target) { Curve_2 cv; cv.set_source(source); cv.set_target(target); @@ -794,8 +847,7 @@ public: Orientation orient = m_traits.orientation(s, t); const Kernel& kernel = m_traits; - typename Kernel::Counterclockwise_in_between_2 cc_in_between = - kernel.counterclockwise_in_between_2_object(); + auto cc_in_between = kernel.counterclockwise_in_between_2_object(); const Direction_2& d = Traits::identification_xy(); if (orient == LEFT_TURN) { @@ -819,8 +871,7 @@ public: * \pre Both endpoints lie on the given plane. */ Curve_2 operator()(const Point_2& source, const Point_2& target, - const Direction_3& normal) - { + const Direction_3& normal) { Curve_2 cv; cv.set_source(source); @@ -829,7 +880,7 @@ public: cv.set_is_degenerate(false); cv.set_is_empty(false); - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; CGAL_precondition(m_traits.has_on(normal, source)); CGAL_precondition(m_traits.has_on(normal, target)); @@ -912,8 +963,7 @@ public: Direction_2 s = project(source); Direction_2 t = project(target); const Direction_2& ny = Traits::neg_y_2(); - typename Kernel::Counterclockwise_in_between_2 ccib = - kernel.counterclockwise_in_between_2_object(); + auto ccib = kernel.counterclockwise_in_between_2_object(); cv.set_is_x_monotone((plane_is_positive && !ccib(ny, s, t)) || (!plane_is_positive && !ccib(ny, t, s))); @@ -929,8 +979,7 @@ public: const Direction_2& d = Traits::identification_xy(); Direction_2 s = Traits::project_xy(source); Direction_2 t = Traits::project_xy(target); - typename Kernel::Counterclockwise_in_between_2 ccib = - kernel.counterclockwise_in_between_2_object(); + auto ccib = kernel.counterclockwise_in_between_2_object(); bool plane_is_positive = (z_sign(normal) == POSITIVE); cv.set_is_x_monotone((plane_is_positive && !ccib(d, s, t)) || (!plane_is_positive && !ccib(d, t, s))); @@ -961,9 +1010,9 @@ public: /*! A functor that compares the x-coordinates of two directional points */ class Compare_x_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -983,8 +1032,7 @@ public: * \pre p1 does not lie on the boundary. * \pre p2 does not lie on the boundary. */ - Comparison_result operator()(const Point_2& p1, const Point_2& p2) const - { + Comparison_result operator()(const Point_2& p1, const Point_2& p2) const { CGAL_precondition(p1.is_no_boundary()); CGAL_precondition(p2.is_no_boundary()); @@ -996,8 +1044,7 @@ protected: /*! Obtain the positive (north) pole * \return the positive (north) pole */ - inline static const Point_2& pos_pole() - { + inline static const Point_2& pos_pole() { static const Point_2 p(Direction_3(0, 0, 1), Point_2::MAX_BOUNDARY_LOC); return p; } @@ -1005,8 +1052,7 @@ protected: /*! Obtain the negative (south) pole * \return the negative (south) pole */ - inline static const Point_2& neg_pole() - { + inline static const Point_2& neg_pole() { static const Point_2 p(Direction_3(0, 0, -1), Point_2::MIN_BOUNDARY_LOC); return p; } @@ -1020,9 +1066,9 @@ public: */ class Compare_xy_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1044,8 +1090,7 @@ public: * \pre p1 does not lie on the boundary. * \pre p2 does not lie on the boundary. */ - Comparison_result operator()(const Point_2& p1, const Point_2& p2) const - { + Comparison_result operator()(const Point_2& p1, const Point_2& p2) const { CGAL_precondition(p1.is_no_boundary()); CGAL_precondition(p2.is_no_boundary()); @@ -1094,8 +1139,7 @@ public: * \return true if the curve is a vertical spherical_arc; false otherwise. * \pre the arc is not degenerate (consists of a single point) */ - bool operator()(const X_monotone_curve_2& xc) const - { + bool operator()(const X_monotone_curve_2& xc) const { CGAL_precondition(!xc.is_degenerate()); return xc.is_vertical(); } @@ -1109,9 +1153,9 @@ public: */ class Compare_y_at_x_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1132,8 +1176,7 @@ public: * \pre p is in the x-range of xc. */ Comparison_result operator()(const Point_2& p, - const X_monotone_curve_2& xc) const - { + const X_monotone_curve_2& xc) const { CGAL_precondition(!p.is_min_boundary() && !p.is_max_boundary()); CGAL_precondition(m_traits.is_in_x_range(xc, p)); @@ -1169,9 +1212,9 @@ public: */ class Compare_y_at_x_left_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1195,8 +1238,7 @@ public: */ Comparison_result operator()(const X_monotone_curve_2& xc1, const X_monotone_curve_2& xc2, - const Point_2& p) const - { + const Point_2& p) const { CGAL_precondition(! xc1.is_degenerate()); CGAL_precondition(! xc2.is_degenerate()); CGAL_precondition(p == xc1.right()); @@ -1227,8 +1269,7 @@ public: auto opposite_3 = kernel.construct_opposite_direction_3_object(); Direction_3 opposite_p = opposite_3(p); if (kernel.equal_3_object()(opposite_p, Direction_3(l1)) || - kernel.equal_3_object()(opposite_p, Direction_3(l2))) - { + kernel.equal_3_object()(opposite_p, Direction_3(l2))) { Sign xsign = Traits::x_sign(p); Sign ysign = Traits::y_sign(p); Project project = (xsign == ZERO) ? @@ -1286,9 +1327,9 @@ public: */ class Compare_y_at_x_right_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1312,8 +1353,7 @@ public: */ Comparison_result operator()(const X_monotone_curve_2& xc1, const X_monotone_curve_2& xc2, - const Point_2& p) const - { + const Point_2& p) const { CGAL_precondition(! xc1.is_degenerate()); CGAL_precondition(! xc2.is_degenerate()); @@ -1335,8 +1375,7 @@ public: auto opposite_3 = kernel.construct_opposite_direction_3_object(); Direction_3 opposite_p = opposite_3(p); if (kernel.equal_3_object()(opposite_p, Direction_3(r1)) || - kernel.equal_3_object()(opposite_p, Direction_3(r2))) - { + kernel.equal_3_object()(opposite_p, Direction_3(r2))) { Sign xsign = Traits::x_sign(p); Sign ysign = Traits::y_sign(p); Project project = (xsign == ZERO) ? @@ -1402,9 +1441,9 @@ public: */ class Equal_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1422,10 +1461,9 @@ public: * \return true if the two curves are the same; false otherwise. */ bool operator()(const X_monotone_curve_2& xc1, - const X_monotone_curve_2& xc2) const - { + const X_monotone_curve_2& xc2) const { const Kernel& kernel = m_traits; - typename Kernel::Equal_3 equal_3 = kernel.equal_3_object(); + auto equal_3 = kernel.equal_3_object(); if (xc1.is_full() || xc2.is_full()) { if (!xc1.is_full() || !xc2.is_full()) return false; auto opposite_3 = kernel.construct_opposite_direction_3_object(); @@ -1447,8 +1485,7 @@ public: * \param p2 the second point. * \return true if the two point are the same; false otherwise. */ - bool operator()(const Point_2& p1, const Point_2& p2) const - { + bool operator()(const Point_2& p1, const Point_2& p2) const { const Kernel& kernel = m_traits; return kernel.equal_3_object()(Direction_3(p1), Direction_3(p2)); } @@ -1466,9 +1503,9 @@ public: */ class Parameter_space_in_x_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1498,8 +1535,7 @@ public: * \pre xcv does not coincide with the identification */ Arr_parameter_space operator()(const X_monotone_curve_2& xcv, - Arr_curve_end ce) const - { + Arr_curve_end ce) const { CGAL_precondition(!m_traits.is_on_y_identification_2_object()(xcv)); // vertical, but not on identification! if (xcv.is_vertical()) return ARR_INTERIOR; @@ -1516,8 +1552,7 @@ public: * \param p the point. * \return the parameter space at p. */ - Arr_parameter_space operator()(const Point_2& p) const - { + Arr_parameter_space operator()(const Point_2& p) const { CGAL_precondition(p.is_no_boundary()); CGAL_USE(p); return ARR_INTERIOR; @@ -1551,8 +1586,7 @@ public: * maximal end. */ Arr_parameter_space operator()(const X_monotone_curve_2& xcv, - Arr_curve_end ce) const - { + Arr_curve_end ce) const { return (ce == ARR_MIN_END) ? ((xcv.left().is_min_boundary()) ? ARR_BOTTOM_BOUNDARY: ARR_INTERIOR) : ((xcv.right().is_max_boundary()) ? ARR_TOP_BOUNDARY : ARR_INTERIOR); @@ -1565,8 +1599,7 @@ public: * \param p the point. * \return the parameter space at p. */ - Arr_parameter_space operator()(const Point_2& p) const - { + Arr_parameter_space operator()(const Point_2& p) const { return (p.is_min_boundary()) ? ARR_BOTTOM_BOUNDARY : (p.is_max_boundary()) ? ARR_TOP_BOUNDARY : ARR_INTERIOR; @@ -1583,9 +1616,9 @@ public: */ class Compare_x_on_boundary_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1613,8 +1646,8 @@ public: */ Comparison_result operator()(const Point_2& point, const X_monotone_curve_2& xcv, - Arr_curve_end CGAL_precondition_code(ce)) const - { + Arr_curve_end CGAL_precondition_code(ce)) + const { CGAL_precondition(point.is_no_boundary()); CGAL_precondition_code (const Point_2& p2 = (ce == ARR_MIN_END) ? xcv.left() : xcv.right();); @@ -1659,8 +1692,8 @@ public: Comparison_result operator()(const X_monotone_curve_2& xcv1, Arr_curve_end CGAL_precondition_code(ce1), const X_monotone_curve_2& xcv2, - Arr_curve_end CGAL_precondition_code(ce2)) const - { + Arr_curve_end CGAL_precondition_code(ce2)) + const { CGAL_precondition_code (const Point_2& p1 = (ce1 == ARR_MIN_END) ? xcv1.left() : xcv1.right();); CGAL_precondition(!p1.is_no_boundary()); @@ -1695,9 +1728,7 @@ public: */ Comparison_result operator()(const Point_2& /* p1 */, const Point_2& /* p2 */) const - { - CGAL_error(); return EQUAL; - } + { CGAL_error(); return EQUAL; } }; /*! Obtain a Compare_x_on_boundary_2 function object. @@ -1710,9 +1741,9 @@ public: */ class Compare_x_near_boundary_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1746,8 +1777,8 @@ public: CGAL_precondition_code(xcv1), const X_monotone_curve_2& CGAL_precondition_code(xcv2), - Arr_curve_end CGAL_precondition_code(ce)) const - { + Arr_curve_end CGAL_precondition_code(ce)) + const { CGAL_precondition_code (const Point_2& p1 = (ce == ARR_MIN_END) ? xcv1.left() : xcv1.right();); CGAL_precondition(!p1.is_no_boundary()); @@ -1774,9 +1805,9 @@ public: */ class Compare_y_near_boundary_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1800,8 +1831,7 @@ public: */ Comparison_result operator()(const X_monotone_curve_2& xcv1, const X_monotone_curve_2& xcv2, - Arr_curve_end ce) const - { + Arr_curve_end ce) const { CGAL_precondition(! xcv1.is_degenerate()); CGAL_precondition(! xcv2.is_degenerate()); @@ -1918,9 +1948,9 @@ public: */ class Is_on_y_identification_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -1944,8 +1974,7 @@ public: * \return a Boolean indicating whether xcv coincides with the vertical * identification arc. */ - bool operator()(const X_monotone_curve_2& xcv) const - { + bool operator()(const X_monotone_curve_2& xcv) const { /* If the curve is not vertical and non of its endpoints lie on the * boundary, the arc itself cannot lie on the identification arc. */ @@ -1977,9 +2006,9 @@ public: */ class Compare_y_on_boundary_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2000,8 +2029,7 @@ public: * \pre p1 lies on the vertical identification arc including the poles! * \pre p2 lies on the vertical identification arc including the poles! */ - Comparison_result operator()(const Point_2& p1, const Point_2& p2) const - { + Comparison_result operator()(const Point_2& p1, const Point_2& p2) const { // first deal with the 'degenerate' case of poles! if (p1.is_min_boundary()) { if (p2.is_min_boundary()) return EQUAL; @@ -2039,9 +2067,9 @@ public: */ class Make_x_monotone_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2063,8 +2091,8 @@ public: */ template OutputIterator operator()(const Curve_2& c, OutputIterator oi) const { - typedef std::variant - Make_x_monotone_result; + using Make_x_monotone_result = std::variant; + // std::cout << "full: " << c.is_full() << std::endl; // std::cout << "vert: " << c.is_vertical() << std::endl; // std::cout << "xmon: " << c.is_x_monotone() << std::endl; @@ -2199,9 +2227,9 @@ public: /*! A functor that splits an x-monotone arc at a directional point. */ class Split_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2223,14 +2251,12 @@ public: * \pre xc is not degenerate */ void operator()(const X_monotone_curve_2& xc, const Point_2& p, - X_monotone_curve_2& xc1, X_monotone_curve_2& xc2) const - { + X_monotone_curve_2& xc1, X_monotone_curve_2& xc2) const { CGAL_precondition(!xc.is_degenerate()); const Point_2& source = xc.source(); const Point_2& target = xc.target(); CGAL_precondition_code(const Kernel& kernel = m_traits); - CGAL_precondition_code - (typename Kernel::Equal_3 equal_3 = kernel.equal_3_object()); + CGAL_precondition_code(auto equal_3 = kernel.equal_3_object()); CGAL_precondition(!equal_3(Direction_3(p), Direction_3(source))); CGAL_precondition(!equal_3(Direction_3(p), Direction_3(target))); @@ -2268,9 +2294,9 @@ public: /*! The clockwise-in-between function object */ class Clockwise_in_between_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2282,8 +2308,7 @@ public: public: bool operator()(const Direction_2& d, - const Direction_2& d1, const Direction_2& d2) const - { + const Direction_2& d1, const Direction_2& d2) const { const Kernel& kernel = m_traits; return kernel.counterclockwise_in_between_2_object()(d, d2, d1); } @@ -2318,9 +2343,8 @@ public: bool vertical, const In_between& in_between, Project project, - OutputIterator oi) const - { - typedef std::pair Intersection_point; + OutputIterator oi) const { + using Intersection_point = std::pair; const Kernel& kernel = m_traits; typename Kernel::Equal_2 equal = kernel.equal_2_object(); @@ -2472,8 +2496,7 @@ public: * \pre point lies in the underlying plane of xc. */ bool is_in_between(const Point_2& point, - const X_monotone_curve_2& xc) const - { + const X_monotone_curve_2& xc) const { const Kernel& kernel = m_traits; CGAL_precondition(m_traits.has_on(xc.normal(), point)); @@ -2522,9 +2545,9 @@ public: } protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2547,22 +2570,17 @@ public: template OutputIterator operator()(const X_monotone_curve_2& xc1, const X_monotone_curve_2& xc2, - OutputIterator oi) const - { + OutputIterator oi) const { // std::cout << "xc1: " << xc1 << std::endl // << "xc2: " << xc2 << std::endl; CGAL_precondition(!xc1.is_degenerate()); CGAL_precondition(!xc2.is_degenerate()); - typedef typename Kernel::Counterclockwise_in_between_2 - Counterclockwise_in_between_2; - typedef typename Kernel::Equal_3 Equal_3; - - typedef std::pair Intersection_point; + using Intersection_point = std::pair; const Kernel& kernel = m_traits; - Equal_3 equal_3 = kernel.equal_3_object(); + auto equal_3 = kernel.equal_3_object(); const Direction_3& normal1 = xc1.normal(); const Direction_3& normal2 = xc2.normal(); @@ -2571,7 +2589,7 @@ public: if (equal_3(normal1, normal2) || equal_3(opposite_normal1, normal2)) { // The underlying planes are the same - Counterclockwise_in_between_2 ccib = kernel.counterclockwise_in_between_2_object(); + auto ccib = kernel.counterclockwise_in_between_2_object(); auto cib = m_traits.clockwise_in_between_2_object(); if (xc1.is_vertical()) { @@ -2659,9 +2677,9 @@ public: /*! A functor that tests whether two x-monotone arcs can be merged. */ class Are_mergeable_2 { - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2681,14 +2699,13 @@ public: * 2. share a common endpoint that is not on the identification arc */ bool operator()(const X_monotone_curve_2& xc1, - const X_monotone_curve_2& xc2) const - { + const X_monotone_curve_2& xc2) const { if (xc1.is_empty() || xc2.is_empty()) return true; if ((xc1.is_full() || xc1.is_meridian()) && (xc2.is_full() || xc2.is_meridian())) return false; const Kernel& kernel = m_traits; - typename Kernel::Equal_3 equal = kernel.equal_3_object(); + auto equal = kernel.equal_3_object(); // Down cast to pass to kernel member functions const Direction_3& xc1_left = xc1.left(); @@ -2731,9 +2748,9 @@ public: /*! A functor that merges two x-monotone arcs into one */ class Merge_2 { protected: - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; - /*! The traits (in case it has state) */ + //! The traits (in case it has state) const Traits& m_traits; /*! Constructor @@ -2752,8 +2769,7 @@ public: */ void operator()(const X_monotone_curve_2& xc1, const X_monotone_curve_2& xc2, - X_monotone_curve_2& xc) const - { + X_monotone_curve_2& xc) const { CGAL_precondition (m_traits.are_mergeable_2_object()(xc1, xc2) == true); if (xc1.is_degenerate() || xc1.is_empty()) { @@ -2767,7 +2783,7 @@ public: } const Kernel& kernel = m_traits; - typename Kernel::Equal_3 equal = kernel.equal_3_object(); + auto equal = kernel.equal_3_object(); // Down cast to pass to kernel member functions const Direction_3& xc1_right = xc1.right(); @@ -2832,9 +2848,11 @@ public: /// \name Functor definitions for the landmarks point-location strategy. //@{ - typedef double Approximate_number_type; - typedef CGAL::Cartesian Approximate_kernel; - typedef Approximate_kernel::Point_2 Approximate_point_2; + using Approximate_number_type = double; + using Approximate_kernel = CGAL::Cartesian; + using Approximate_point_2 = Arr_extended_direction_3; + using Approximate_kernel_vector_3 = Approximate_kernel::Vector_3; + using Approximate_kernel_direction_3 = Approximate_kernel::Direction_3; class Approximate_2 { public: @@ -2846,21 +2864,116 @@ public: * approximation of p's y-coordinate (if i == 1). */ Approximate_number_type operator()(const Point_2& p, int i) const { - CGAL_precondition((i == 0) || (i == 1)); - return (i == 0) ? CGAL::to_double(p.x()) : CGAL::to_double(p.y()); + CGAL_precondition((i == 0) || (i == 1) || (i == 2)); + return (i == 0) ? CGAL::to_double(p.dx()) : + ((i == 1) ? CGAL::to_double(p.dy()) : CGAL::to_double(p.dz())); } /*! Obtain an approximation of a point. */ - Approximate_point_2 operator()(const Point_2& p) const - { return Approximate_point_2(operator()(p, 0), operator()(p, 1)); } + Approximate_point_2 operator()(const Point_2& p) const { + Approximate_kernel::Direction_3 dir(operator()(p, 0), operator()(p, 1), + operator()(p, 2)); + auto loc = static_cast(p.location()); + return Approximate_point_2(dir, loc); + } /*! Obtain an approximation of an \f$x\f$-monotone curve. */ template - OutputIterator operator()(const X_monotone_curve_2& /* xcv */, double /* error */, - OutputIterator /* oi */, bool /* l2r */ = true) const { - CGAL_error_msg("Not implemented yet!"); + OutputIterator operator()(const X_monotone_curve_2& xcv, + Approximate_number_type error, + OutputIterator oi, bool l2r = true) const { + const auto& s = xcv.source(); + const auto& t = xcv.target(); + const auto& n = xcv.normal(); + const auto dx = CGAL::to_double(n.dx()); + const auto dy = CGAL::to_double(n.dy()); + const auto dz = CGAL::to_double(n.dz()); + + Approximate_point_2 as, at; + Approximate_kernel_vector_3 vn; + if (xcv.is_directed_right() == l2r) { + // Get the approximate points + as = (*this)(s); + at = (*this)(t); + vn = Approximate_kernel_vector_3(dx, dy, dz); + } + else { + // Get the approximate points + as = (*this)(t); + at = (*this)(s); + vn = Approximate_kernel_vector_3(-dx, -dy, -dz); + } + + // convert the approximate points to vectors with approximate-kernel + auto vs = approximate_vector_3(as); + auto vt = approximate_vector_3(at); + + // normalize the vectors + auto normalize = [](auto& x) { x /= std::sqrt(x.squared_length()); }; + normalize(vs); + normalize(vt); + normalize(vn); + + // Define the spanning vectors of the coordinate system where we are + // going to make the approximation: + auto axis_x = vs; // x-axis will coincide with the vector from the + // origin to the normalized SOURCE-vector + auto axis_z = vn; // this will make sure that the orientation of the + // approximated curve is consistent with the curve + auto axis_y = CGAL::cross_product(axis_z, axis_x); + normalize(axis_y); + + // In this coordinate system the source has local coords (0,0), hence its + // initial angle with the X-axis is 0 degrees (radians) + // Compute the local coordinates and the angle it makes with the X-axis + Approximate_number_type theta; + if (xcv.is_full()) theta = 2.0 * CGAL_PI; + else { + auto ltx = CGAL::scalar_product(axis_x, vt); + auto lty = CGAL::scalar_product(axis_y, vt); + theta = std::atan2(lty, ltx); + if (theta < 0) + theta += 2.0 * CGAL_PI; + } + + // compute the number of divisions given the requested error + const Approximate_number_type R = 1.0; // radius is always 1 + Approximate_number_type dtheta = 2.0 * std::acos(1 - error / R); + int num_segs = std::ceil(theta / dtheta); + dtheta = theta / num_segs; + + // generate the points approximating the curve + const auto loc = Approximate_point_2::NO_BOUNDARY_LOC; + *oi++ = approximate_point_2(vs, loc); // source vector + for (int i = 1; i < num_segs; ++i) { + const Approximate_number_type angle = i * dtheta; + auto p = std::cos(angle) * axis_x + std::sin(angle) * axis_y; + *oi++ = approximate_point_2(p, loc); + } + *oi++ = approximate_point_2(vt, loc); // target vector + + return oi; + } + + private: + Approximate_kernel_vector_3 + approximate_vector_3(const Approximate_point_2& p) const + { return Approximate_kernel_vector_3(p.dx(), p.dy(), p.dz()); }; + + Approximate_kernel_vector_3 + approximate_vector_3(const Direction_3& d) const { + return Approximate_kernel_vector_3(CGAL::to_double(d.dx()), + CGAL::to_double(d.dy()), + CGAL::to_double(d.dz())); + }; + + Approximate_point_2 + approximate_point_2(const Approximate_kernel_vector_3& v, + const Approximate_point_2::Location_type loc) const { + Approximate_kernel_direction_3 d(v.x(), v.y(), v.z()); + return Approximate_point_2(d, loc); } }; @@ -2874,9 +2987,7 @@ public: class Compare_endpoints_xy_2 { public: - - /*! - * Compare the endpoints of an $x$-monotone curve lexicographically. + /*! Compare the endpoints of an $x$-monotone curve lexicographically. * (assuming the curve has a designated source and target points). * \param xc the curve. * \return SMALLER if the curve is directed right; @@ -2908,8 +3019,7 @@ public: #if 0 /*! Inserter for the spherical_arc class used by the traits-class */ template - friend OutputStream& operator<<(OutputStream& os, const Point_2& p) - { + friend OutputStream& operator<<(OutputStream& os, const Point_2& p) { CGAL::To_double todouble; os << static_cast(todouble(p.dx())) << ", " << static_cast(todouble(p.dy())) << ", " @@ -2920,101 +3030,20 @@ public: /*! Inserter for the spherical_arc class used by the traits-class */ template friend OutputStream& operator<<(OutputStream& os, - const X_monotone_curve_2& xc) - { + const X_monotone_curve_2& xc) { os << "(" << xc.left() << "), (" << xc.right() << ")"; return os; } /*! Extractor for the spherical_arc class used by the traits-class */ template - friend InputStream& operator>>(InputStream& is, X_monotone_curve_2& arc) - { + friend InputStream& operator>>(InputStream& is, X_monotone_curve_2& arc) { CGAL_error_msg("Not implemented yet!"); return is; } #endif }; -/*! Represent an extended 3D direction that is used in turn to represent a - * spherical-arc endpoint. The extended data consists of two flags that - * indicate whether the point is on the x and on a y boundaries, - * respectively. - */ -template -class Arr_extended_direction_3 : public Kernel::Direction_3 { -public: - typedef typename Kernel::FT FT; - typedef typename Kernel::Direction_3 Direction_3; - - /*! Enumeration of discontinuity type */ - enum Location_type { - NO_BOUNDARY_LOC = 0, - MIN_BOUNDARY_LOC, - MID_BOUNDARY_LOC, - MAX_BOUNDARY_LOC - }; - -private: - typedef typename Kernel::Direction_2 Direction_2; - - /*! The point discontinuity type */ - Location_type m_location; - - inline Sign x_sign(Direction_3 d) const { return CGAL::sign(d.dx()); } - - inline Sign y_sign(Direction_3 d) const { return CGAL::sign(d.dy()); } - - inline Sign z_sign(Direction_3 d) const { return CGAL::sign(d.dz()); } - -public: - /*! Default constructor */ - Arr_extended_direction_3() : - Direction_3(0, 0, 1), - m_location(MAX_BOUNDARY_LOC) - {} - - /*! Constructor */ - Arr_extended_direction_3(const Direction_3& dir, Location_type location) : - Direction_3(dir), - m_location(location) - {} - - /*! Copy constructor */ - Arr_extended_direction_3(const Arr_extended_direction_3& other) : - Direction_3(static_cast(other)) - { m_location = other.discontinuity_type(); } - - /*! Assignment operator */ - Arr_extended_direction_3& operator=(const Arr_extended_direction_3& other) - { - *(static_cast(this)) = static_cast(other); - m_location = other.discontinuity_type(); - return (*this); - } - - /*! Set the location of the point. - */ - void set_location(Location_type location) { m_location = location; } - - /*! Obtain the location of the point. - */ - Location_type location() const { return m_location; } - - /*! Obtain the discontinuity type of the point. - * \todo deprecate this one; use the above instead. - */ - Location_type discontinuity_type() const { return m_location; } - - bool is_no_boundary() const { return (m_location == NO_BOUNDARY_LOC); } - - bool is_min_boundary() const { return (m_location == MIN_BOUNDARY_LOC); } - - bool is_mid_boundary() const { return (m_location == MID_BOUNDARY_LOC); } - - bool is_max_boundary() const { return (m_location == MAX_BOUNDARY_LOC); } -}; - /*! A Representation of an x-monotone great circular arc embedded on a sphere, * as used by the Arr_geodesic_arc_on_sphere_traits_2 traits-class * An x-monotone great circular arc cannot cross the closed hemi-circle arc of @@ -3026,38 +3055,38 @@ public: template class Arr_x_monotone_geodesic_arc_on_sphere_3 { public: - typedef Kernel_ Kernel; - typedef typename Kernel::Direction_3 Direction_3; - typedef typename Kernel::Plane_3 Plane_3; - typedef typename Kernel::Vector_3 Vector_3; - typedef typename Kernel::Direction_2 Direction_2; + using Kernel = Kernel_; + using Direction_3 = typename Kernel::Direction_3; + using Plane_3 = typename Kernel::Plane_3; + using Vector_3 = typename Kernel::Vector_3; + using Direction_2 = typename Kernel::Direction_2; protected: // For some reason compilation under Windows fails without the qualifier - typedef CGAL::Arr_extended_direction_3 Arr_extended_direction_3; + using Arr_extended_direction_3 = CGAL::Arr_extended_direction_3; - /*! The source point of the arc. */ + //! The source point of the arc. Arr_extended_direction_3 m_source; - /*! The target point of the arc. */ + //! The target point of the arc. Arr_extended_direction_3 m_target; - /*! The direction of the plane that contains the arc. */ + //! The direction of the plane that contains the arc. Direction_3 m_normal; - /*! The arc is vertical. */ + //! The arc is vertical. bool m_is_vertical; - /*! Target (lexicographically) larger than source. */ + //! Target (lexicographically) larger than source. bool m_is_directed_right; - /*! The arc is a full circle. */ + //! The arc is a full circle. bool m_is_full; - /* The arc is degenerate - it consists of a single point. */ + //! The arc is degenerate - it consists of a single point. bool m_is_degenerate; - /*! The arc is empty. */ + //! The arc is empty. bool m_is_empty; inline Sign x_sign(Direction_3 d) const { return CGAL::sign(d.dx()); } @@ -3106,8 +3135,7 @@ public: * \param other the other arc */ Arr_x_monotone_geodesic_arc_on_sphere_3 - (const Arr_x_monotone_geodesic_arc_on_sphere_3& other) - { + (const Arr_x_monotone_geodesic_arc_on_sphere_3& other) { m_source = other.m_source; m_target = other.m_target; m_normal = other.m_normal; @@ -3120,8 +3148,7 @@ public: /*! Assignment operator */ Arr_x_monotone_geodesic_arc_on_sphere_3& operator= - (const Arr_x_monotone_geodesic_arc_on_sphere_3& other) - { + (const Arr_x_monotone_geodesic_arc_on_sphere_3& other) { m_source = other.m_source; m_target = other.m_target; m_normal = other.m_normal; @@ -3147,9 +3174,8 @@ public: * \param target the target point. * \pre the source and target cannot be equal. */ - void init() - { - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + void init() { + using Traits = Arr_geodesic_arc_on_sphere_traits_2; Kernel kernel; CGAL_precondition(!kernel.equal_3_object()(Direction_3(m_source), @@ -3238,8 +3264,7 @@ public: m_is_directed_right(z_sign(normal) == POSITIVE), m_is_full(true), m_is_degenerate(false), - m_is_empty(false) - { + m_is_empty(false) { CGAL_precondition(z_sign(normal) != ZERO); #if (CGAL_IDENTIFICATION_XY == CGAL_X_MINUS_1_Y_0) @@ -3247,8 +3272,8 @@ public: Direction_3(-(normal.dz()), 0, normal.dx()) : Direction_3(normal.dz(), 0, -(normal.dx())); #else - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; - typedef typename Kernel::FT FT; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; + using FT = typename Kernel::FT; const Direction_2& xy = Traits::identification_xy(); FT x = xy.dx(); @@ -3274,8 +3299,7 @@ public: m_is_directed_right(z_sign(normal) == POSITIVE), m_is_full(true), m_is_degenerate(false), - m_is_empty(false) - { + m_is_empty(false) { CGAL_precondition(has_on(point)); CGAL_precondition(z_sign(normal) != ZERO); #if !defined(CGAL_FULL_X_MONOTONE_GEODESIC_ARC_ON_SPHERE_IS_SUPPORTED) @@ -3300,8 +3324,7 @@ public: m_normal(normal), m_is_full(false), m_is_degenerate(false), - m_is_empty(false) - { + m_is_empty(false) { CGAL_precondition(has_on(source)); CGAL_precondition(has_on(target)); @@ -3411,8 +3434,7 @@ public: #if 0 /*! Create a bounding box for the spherical_arc */ - Bbox_2 bbox() const - { + Bbox_2 bbox() const { Kernel kernel; Segment_2 seg = kernel.construct_spherical_arc_2_object()(this->m_source, this->m_target); @@ -3421,8 +3443,7 @@ public: #endif /*! Flip the spherical_arc (swap it source and target) */ - Arr_x_monotone_geodesic_arc_on_sphere_3 opposite() const - { + Arr_x_monotone_geodesic_arc_on_sphere_3 opposite() const { Arr_x_monotone_geodesic_arc_on_sphere_3 opp; opp.m_source = this->m_target; opp.m_target = this->m_source; @@ -3441,8 +3462,7 @@ public: * \return true if dir is contained in plane; false otherwise. * \pre the plane contains the origin. */ - inline bool has_on(const Direction_3& dir) const - { + inline bool has_on(const Direction_3& dir) const { typename Kernel::FT dot = normal().vector() * dir.vector(); return CGAL::sign(dot) == ZERO; } @@ -3460,25 +3480,25 @@ template class Arr_geodesic_arc_on_sphere_3 : public Arr_x_monotone_geodesic_arc_on_sphere_3 { public: - typedef Kernel_ Kernel; + using Kernel = Kernel_; protected: - typedef Arr_x_monotone_geodesic_arc_on_sphere_3 Base; + using Base = Arr_x_monotone_geodesic_arc_on_sphere_3; public: - typedef typename Base::Plane_3 Plane_3; - typedef typename Base::Direction_3 Direction_3; - typedef typename Base::Direction_2 Direction_2; + using Plane_3 = typename Base::Plane_3; + using Direction_3 = typename Base::Direction_3; + using Direction_2 = typename Base::Direction_2; protected: // For some reason compilation under Windows fails without the qualifier - typedef CGAL::Arr_extended_direction_3 Arr_extended_direction_3; + using Arr_extended_direction_3 = CGAL::Arr_extended_direction_3; using Base::x_sign; using Base::y_sign; using Base::z_sign; - /*! Indicates whether the arc is x-monotone */ + //! Indicates whether the arc is x-monotone bool m_is_x_monotone; public: @@ -3534,8 +3554,7 @@ public: */ Arr_geodesic_arc_on_sphere_3(const Arr_extended_direction_3& source, const Arr_extended_direction_3& target, - const Direction_3& normal) - { + const Direction_3& normal) { Kernel kernel; this->set_source(source); @@ -3544,7 +3563,7 @@ public: this->set_is_degenerate(false); this->set_is_empty(false); - typedef Arr_geodesic_arc_on_sphere_traits_2 Traits; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; CGAL_precondition(this->has_on(source)); CGAL_precondition(this->has_on(target)); @@ -3624,8 +3643,7 @@ public: Direction_2 s = project(source); Direction_2 t = project(target); const Direction_2& ny = Traits::neg_y_2(); - typename Kernel::Counterclockwise_in_between_2 ccib = - kernel.counterclockwise_in_between_2_object(); + auto ccib = kernel.counterclockwise_in_between_2_object(); set_is_x_monotone((plane_is_positive && !ccib(ny, s, t)) || (!plane_is_positive && !ccib(ny, t, s))); @@ -3641,8 +3659,7 @@ public: const Direction_2& d = Traits::identification_xy(); Direction_2 s = Traits::project_xy(source); Direction_2 t = Traits::project_xy(target); - typename Kernel::Counterclockwise_in_between_2 ccib = - kernel.counterclockwise_in_between_2_object(); + auto ccib = kernel.counterclockwise_in_between_2_object(); bool plane_is_positive = (z_sign(normal) == POSITIVE); set_is_x_monotone((plane_is_positive && !ccib(d, s, t)) || (!plane_is_positive && !ccib(d, t, s))); @@ -3651,8 +3668,7 @@ public: /*! Construct a full spherical_arc from a normal to a plane. * \param normal the normal to the plane containing the arc. */ - Arr_geodesic_arc_on_sphere_3(const Direction_3& normal) - { + Arr_geodesic_arc_on_sphere_3(const Direction_3& normal) { this->normal(normal); this->set_is_vertical(CGAL::sign(normal.dz()) == ZERO); this->set_is_directed_right(true); @@ -3676,8 +3692,7 @@ public: /*! Inserter for the spherical_arc class used by the traits-class */ template OutputStream& operator<<(OutputStream& os, - const Arr_extended_direction_3& ed) -{ + const Arr_extended_direction_3& ed) { #if defined(CGAL_ARR_GEODESIC_ARC_ON_SPHERE_DETAILS) os << "(" << ed.dx() << ", " << ed.dy() << ", " << ed.dz(); @@ -3700,8 +3715,7 @@ OutputStream& operator<<(OutputStream& os, template OutputStream& operator<<(OutputStream& os, - const Arr_x_monotone_geodesic_arc_on_sphere_3& arc) -{ + const Arr_x_monotone_geodesic_arc_on_sphere_3& arc) { #if defined(CGAL_ARR_GEODESIC_ARC_ON_SPHERE_DETAILS) os << "(" << "(" << arc.source() << "), (" << arc.target() << ")" @@ -3721,10 +3735,9 @@ operator<<(OutputStream& os, /*! Extractor for the spherical-arc point class used by the traits-class */ template InputStream& -operator>>(InputStream& is, Arr_extended_direction_3& point) -{ - typedef Kernel_ Kernel; - typedef Arr_extended_direction_3 Point; +operator>>(InputStream& is, Arr_extended_direction_3& point) { + using Kernel = Kernel_; + using Point = Arr_extended_direction_3; // CGAL_error_msg("Importing a geodesic point is not supported!"); typename Kernel::Direction_3 d; is >> d; @@ -3738,10 +3751,9 @@ operator>>(InputStream& is, Arr_extended_direction_3& point) template InputStream& operator>>(InputStream& is, - Arr_x_monotone_geodesic_arc_on_sphere_3& arc) -{ - typedef Kernel_ Kernel; - typedef Arr_extended_direction_3 Point; + Arr_x_monotone_geodesic_arc_on_sphere_3& arc) { + using Kernel = Kernel_; + using Point = Arr_extended_direction_3; // CGAL_error_msg("Importing a geodesic arc is not supported!\n"); diff --git a/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_zone_2_impl.h b/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_zone_2_impl.h index 5d1e19f73c7..2889f219237 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_zone_2_impl.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_2/Arrangement_zone_2_impl.h @@ -28,8 +28,7 @@ namespace CGAL { // template void Arrangement_zone_2:: -init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj) -{ +init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj) { #if defined(ARR_ZONE_VERBOSE) std::cout << "init_with_hint()" << std::endl; #endif @@ -80,8 +79,7 @@ init_with_hint(const X_monotone_curve_2& cv, Pl_result_type obj) // notifications for the visitor. // template -void Arrangement_zone_2::compute_zone() -{ +void Arrangement_zone_2::compute_zone() { #if defined(ARR_ZONE_VERBOSE) std::cout << "compute_zone()" << std::endl; #endif @@ -137,7 +135,7 @@ void Arrangement_zone_2::compute_zone() if (m_found_overlap) { // In this case m_cv overlaps the curve associated with m_intersect_he. // Compute the overlapping subcurve. - bool dummy; + Arr_parameter_space dummy; auto obj = _compute_next_intersection(m_intersect_he, false, dummy); m_overlap_cv = std::get(*obj); @@ -153,7 +151,7 @@ void Arrangement_zone_2::compute_zone() // overlaps the curve associated with this edge. m_intersect_he = m_arr.non_const_handle(*hh); - bool dummy; + Arr_parameter_space dummy; auto obj = _compute_next_intersection(m_intersect_he, false, dummy); m_overlap_cv = std::get(*obj); @@ -211,7 +209,7 @@ void Arrangement_zone_2::compute_zone() if (m_found_overlap) { // In this case m_cv overlaps the curve associated with m_intersect_he. // Compute the overlapping subcurve to the right of curr_v. - bool dummy; + Arr_parameter_space dummy; auto obj = _compute_next_intersection(m_intersect_he, false, dummy); m_overlap_cv = std::get(*obj); @@ -253,8 +251,7 @@ template bool Arrangement_zone_2:: do_overlap_impl(const X_monotone_curve_2& cv1, const X_monotone_curve_2& cv2, - const Point_2& p, Arr_not_all_sides_oblivious_tag) const -{ + const Point_2& p, Arr_not_all_sides_oblivious_tag) const { typename Traits_adaptor_2::Compare_y_at_x_right_2 cmp_right = m_geom_traits->compare_y_at_x_right_2_object(); @@ -307,8 +304,7 @@ do_overlap_impl(const X_monotone_curve_2& cv1, // template bool Arrangement_zone_2:: -_find_prev_around_vertex(Vertex_handle v, Halfedge_handle& he) -{ +_find_prev_around_vertex(Vertex_handle v, Halfedge_handle& he) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_find_prev_around_vertex(" << v->point() << ")" << std::endl; #endif @@ -393,8 +389,7 @@ typename Arrangement_zone_2::Halfedge_handle Arrangement_zone_2:: _direct_intersecting_edge_to_right(const X_monotone_curve_2& cv_ins, const Point_2& cv_left_pt, - Halfedge_handle query_he) -{ + Halfedge_handle query_he) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_direct_intersecting_edge_to_right() " << cv_left_pt << std::endl; @@ -446,8 +441,7 @@ template typename Arrangement_zone_2::Halfedge_handle Arrangement_zone_2:: _direct_intersecting_edge_to_left(const X_monotone_curve_2& cv_ins, - Halfedge_handle query_he) -{ + Halfedge_handle query_he) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_direct_intersecting_edge_to_left()" << std::endl; #endif @@ -505,6 +499,74 @@ _direct_intersecting_edge_to_left(const X_monotone_curve_2& cv_ins, } } +//! Implementation for no boundary conditions. +template +bool Arrangement_zone_2:: +is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& /* intersection_location */, + Arr_all_sides_oblivious_tag) const +{ return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER); } + +//! Implementation for left and right identified boundaries. +template +bool Arrangement_zone_2:: +is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& intersection_location, + Arr_has_identified_side_tag) const { + auto equal = m_geom_traits->equal_2_object(); + auto is_on_y_ident = m_geom_traits->is_on_y_identification_2_object(); + // Case 1: the curve lies on the y-identification + if (is_on_y_ident(m_cv)) { + if (equal(ip, m_left_pt)) return false; + // We set the location to be on the left as a convention + intersection_location = ARR_LEFT_BOUNDARY; + return true; + } + + // Case 2: The left-end lies on the left boundary + // (It cannot lie on the right boundary) + // If the intersection point is not equal to the left-end, it must lie to + // its right; thus valid. + if (m_left_on_boundary) return ! equal(ip, m_left_pt); + + // Case 3: The right-end lies on the right boundary + if (m_right_on_boundary && equal(ip, m_right_pt)) { + intersection_location = ARR_RIGHT_BOUNDARY; + return true; + } + + // We have a simple intersection point; + // make sure it lies to the right of m_left_pt. + return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER); +} + +/*! Implementation for all the rest. + * It would be better to split into the various cases, which is the cartesian + * product of (contructed, closed, open) X (contructed, closed, open) + */ +template +bool Arrangement_zone_2:: +is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& intersection_location, + Arr_boundary_cond_tag) const { + auto equal = m_geom_traits->equal_2_object(); + if (m_left_on_boundary) { + // The left-end lies on the left boundary. If the intersection point is not + // equal to the left-end, the intersection is valid, because it must lie to + // its right. + if (m_has_left_pt) return ! equal(ip, m_left_pt); + else return true; + } + if (m_has_right_pt && m_right_on_boundary && equal(ip, m_right_pt)) { + intersection_location = ARR_RIGHT_BOUNDARY; + return true; + } + + // We have a simple intersection point; + // make sure it lies to the right of m_left_pt. + return (m_geom_traits->compare_xy_2_object()(ip, m_left_pt) == LARGER); +} + //----------------------------------------------------------------------------- // Get the next intersection of cv with the given halfedge. // @@ -513,14 +575,12 @@ typename Arrangement_zone_2::Optional_intersection Arrangement_zone_2:: _compute_next_intersection(Halfedge_handle he, bool skip_first_point, - bool& intersection_on_right_boundary) -{ + Arr_parameter_space& intersection_location) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_compute_next_intersection(" << he->curve() << ", " << skip_first_point << ")" << std::endl; #endif - auto equal = m_geom_traits->equal_2_object(); auto compare_xy = m_geom_traits->compare_xy_2_object(); auto ctr_min = m_geom_traits->construct_min_vertex_2_object(); auto is_closed = m_geom_traits->is_closed_2_object(); @@ -529,12 +589,12 @@ _compute_next_intersection(Halfedge_handle he, const X_monotone_curve_2* p_curve = &(he->curve()); // Try to locate the intersections with this curve in the intersections map. - Intersect_map_iterator iter = m_inter_map.find(p_curve); + auto iter = m_inter_map.find(p_curve); const Intersection_point* ip; const X_monotone_curve_2* icv; bool valid_intersection; - intersection_on_right_boundary = false; + intersection_location = ARR_INTERIOR; if (iter != m_inter_map.end()) { // The intersections with the curve have already been computed. // Retrieve the intersections list from the map. @@ -548,25 +608,9 @@ _compute_next_intersection(Halfedge_handle he, // Compare that current object with m_left_pt (if exists). ip = std::get_if(&(inter_list.front())); if (ip != nullptr) { - // We have an intersection point - if (m_left_on_boundary) { - // The left-end lies on the left boundary. If the intersection point - // is not equal to the left-end, the intersection is valid, because - // it must lie to its right. - if (m_has_left_pt) valid_intersection = ! equal(ip->first, m_left_pt); - else valid_intersection = true; - } - else if (m_has_right_pt && m_right_on_boundary && - equal(ip->first, m_right_pt)) - { - valid_intersection = true; - intersection_on_right_boundary = true; - } - else { - // We have a simple intersection point - make sure it lies to the - // right of m_left_pt. - valid_intersection = (compare_xy(ip->first, m_left_pt) == LARGER); - } + // We have an intersection point - + valid_intersection = + is_intersection_valid(ip->first, intersection_location); } else { // We have an overlapping subcurve. @@ -576,7 +620,8 @@ _compute_next_intersection(Halfedge_handle he, if (is_closed(*icv, ARR_MIN_END)) { // The curve has a valid left point - make sure it lies to the // right of m_left_pt. - valid_intersection = (compare_xy(ctr_min(*icv), m_left_pt) != SMALLER); + valid_intersection = + (compare_xy(ctr_min(*icv), m_left_pt) != SMALLER); } // In this case the overlap is not valid. else valid_intersection = false; @@ -613,23 +658,8 @@ _compute_next_intersection(Halfedge_handle he, if (ip != nullptr) { // We have an intersection point - // Check whether we need to skip the first intersection - if (is_first && skip_first_point) valid_intersection = false; - else if (m_left_on_boundary) { - // The left-end lies on the left boundary. If the intersection point - // is not equal to the left-end, the intersection is valid, because - // it must lie to its right. - if (m_has_left_pt) valid_intersection = ! equal(ip->first, m_left_pt); - else valid_intersection = true; - } - else if (m_right_on_boundary && m_has_right_pt && - equal(ip->first, m_right_pt)) - { - valid_intersection = true; - intersection_on_right_boundary = true; - } - else { - valid_intersection = (compare_xy(ip->first, m_left_pt) == LARGER); - } + valid_intersection = (is_first && skip_first_point) ? false : + is_intersection_valid(ip->first, intersection_location); } else if (m_left_on_boundary) { // The left end is on the boundary, so all overlapping curves are valid, @@ -671,13 +701,12 @@ _compute_next_intersection(Halfedge_handle he, // template void Arrangement_zone_2:: -_remove_next_intersection(Halfedge_handle he) -{ +_remove_next_intersection(Halfedge_handle he) { // Get a pointer to the curve associated with the halfedge. const X_monotone_curve_2* p_curve = &(he->curve()); // Locate the intersections with this curve in the intersections map. - Intersect_map_iterator iter = m_inter_map.find(p_curve); + auto iter = m_inter_map.find(p_curve); CGAL_assertion(iter != m_inter_map.end()); CGAL_assertion(! iter->second.empty()); @@ -692,8 +721,7 @@ _remove_next_intersection(Halfedge_handle he) template bool Arrangement_zone_2:: _is_to_left_impl(const Point_2& p, Halfedge_handle he, - Arr_not_all_sides_oblivious_tag) const -{ + Arr_not_all_sides_oblivious_tag) const { #if defined(ARR_ZONE_VERBOSE) std::cout << "_is_to_left_impl(" << p << "," << he->curve() << ")" << std::endl; @@ -708,12 +736,12 @@ _is_to_left_impl(const Point_2& p, Halfedge_handle he, if (ps_x_min == ARR_LEFT_BOUNDARY) return false; auto ps_in_y = m_geom_traits->parameter_space_in_y_2_object(); - auto ps_y = ps_in_y(he->curve(), ARR_MIN_END); - if (ps_y != ARR_INTERIOR) { + auto ps_y_min = ps_in_y(he->curve(), ARR_MIN_END); + if (ps_y_min != ARR_INTERIOR) { // Check if p is to the left of the minimal curve-end: auto cmp_x = m_geom_traits->compare_x_point_curve_end_2_object(); const auto res = cmp_x(p, he->curve(), ARR_MIN_END); - return ((res == SMALLER) || (res == EQUAL && ps_y == ARR_TOP_BOUNDARY)); + return ((res == SMALLER) || (res == EQUAL && ps_y_min == ARR_TOP_BOUNDARY)); } // In case the minimal curve-end does not have boundary conditions, simply @@ -724,13 +752,13 @@ _is_to_left_impl(const Point_2& p, Halfedge_handle he, } //----------------------------------------------------------------------------- -// Determine whether a given point lies completely to the right of a given curve. +// Determine whether a given point lies completely to the right of a given +// curve. // template bool Arrangement_zone_2:: _is_to_right_impl(const Point_2& p, Halfedge_handle he, - Arr_not_all_sides_oblivious_tag) const -{ + Arr_not_all_sides_oblivious_tag) const { #if defined(ARR_ZONE_VERBOSE) std::cout << "_is_to_right_impl(" << p << "," << he->curve() << ")" << std::endl; @@ -747,12 +775,12 @@ _is_to_right_impl(const Point_2& p, Halfedge_handle he, if (ps_x_max == ARR_LEFT_BOUNDARY) return true; auto ps_in_y = m_geom_traits->parameter_space_in_y_2_object(); - auto ps_y = ps_in_y(he->curve(), ARR_MAX_END); - if (ps_y != ARR_INTERIOR) { + auto ps_y_max = ps_in_y(he->curve(), ARR_MAX_END); + if (ps_y_max != ARR_INTERIOR) { // Check if p is to the right of the maximal curve-end: auto cmp_x = m_geom_traits->compare_x_point_curve_end_2_object(); auto res = cmp_x(p, he->curve(), ARR_MAX_END); - return ((res == LARGER) || (res == EQUAL && ps_y == ARR_BOTTOM_BOUNDARY)); + return ((res == LARGER) || (res == EQUAL && ps_y_max == ARR_BOTTOM_BOUNDARY)); } // In case the maximal curve-end does not have boundary conditions, simply @@ -768,8 +796,7 @@ _is_to_right_impl(const Point_2& p, Halfedge_handle he, template void Arrangement_zone_2:: _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, - bool& leftmost_on_right_boundary) -{ + Arr_parameter_space& leftmost_location) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_leftmost_intersection(" << he_curr->curve() << ", " << on_boundary << ")" << std::endl; @@ -793,7 +820,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, // entirely to the right of m_intersect_p, its intersection with m_cv (if any) // cannot lie to the left of this point. We therefore do not need to compute // this intersection. - if (m_found_intersect && ! leftmost_on_right_boundary && + if (m_found_intersect && (leftmost_location == ARR_INTERIOR) && _is_to_left(m_intersect_p, he_curr)) return; @@ -821,13 +848,14 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, // do not intersect. if (! left_equals_curr_endpoint && ((! m_left_on_boundary && _is_to_right(m_left_pt, he_curr)) || - ! is_in_x_range(m_cv, he_curr->curve()))) + ! is_in_x_range(m_cv, he_curr->curve()))) { return; + } // Compute the next intersection of m_cv and the current halfedge. - bool intersection_on_right_boundary; + Arr_parameter_space intersection_location; auto iobj = _compute_next_intersection(he_curr, left_equals_curr_endpoint, - intersection_on_right_boundary); + intersection_location); if (iobj) { // We have found an intersection (either a simple point or an @@ -839,8 +867,8 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, // Found a simple intersection point. Check if it is the leftmost // intersection point so far. if (! m_found_intersect || - (! intersection_on_right_boundary && - (leftmost_on_right_boundary || + ((intersection_location != ARR_RIGHT_BOUNDARY) && + ((leftmost_location == ARR_RIGHT_BOUNDARY) || compare_xy(ip, m_intersect_p) == SMALLER))) { // Store the leftmost intersection point and the halfedge handle. @@ -848,7 +876,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, m_ip_multiplicity = int_p->second; m_intersect_he = he_curr; m_found_overlap = false; - leftmost_on_right_boundary = intersection_on_right_boundary; + leftmost_location = intersection_location; } } else { @@ -880,8 +908,7 @@ _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, // template void Arrangement_zone_2:: -_leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) -{ +_leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_leftmost_intersection_with_face_boundary(" << on_boundary << ")" << std::endl; @@ -895,25 +922,23 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) auto compare_xy = m_geom_traits->compare_xy_2_object(); auto is_in_x_range = m_geom_traits->is_in_x_range_2_object(); - bool leftmost_on_right_boundary = false; + Arr_parameter_space leftmost_location = ARR_INTERIOR; // Traverse the face outer-boundaries; iterate through all outer CCBs. for (auto occb_it = face->outer_ccbs_begin(); - occb_it != face->outer_ccbs_end(); ++occb_it) - { + occb_it != face->outer_ccbs_end(); ++occb_it) { Ccb_halfedge_circulator he_first = *occb_it; Ccb_halfedge_circulator he_curr = he_first; - do _leftmost_intersection(he_curr, on_boundary, leftmost_on_right_boundary); + do _leftmost_intersection(he_curr, on_boundary, leftmost_location); while (++he_curr != he_first); } // Traverse the face inner-boundaries; iterate through all inner CCBs (holes). for (auto iccb_it = face->inner_ccbs_begin(); - iccb_it != face->inner_ccbs_end(); ++iccb_it) - { + iccb_it != face->inner_ccbs_end(); ++iccb_it) { Ccb_halfedge_circulator he_first = *iccb_it; Ccb_halfedge_circulator he_curr = he_first; - do _leftmost_intersection(he_curr, on_boundary, leftmost_on_right_boundary); + do _leftmost_intersection(he_curr, on_boundary, leftmost_location); while (++he_curr != he_first); } @@ -921,17 +946,17 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) // Traverse the isolated vertices inside the face (if there exist any), and // check whether an isolated vertex lies on the curve. - typedef typename Arrangement_2::Isolated_vertex_iterator - Isolated_vertex_iterator; - for (Isolated_vertex_iterator iv_it = face->isolated_vertices_begin(); - iv_it != face->isolated_vertices_end(); ++iv_it) - { + // MSVC17 requires an explicit (non-const) type for the iterator. + typename Arrangement_2::Isolated_vertex_iterator iv_it; + for (iv_it = face->isolated_vertices_begin(); + iv_it != face->isolated_vertices_end(); ++iv_it) { // If the isolated vertex is not in the x-range of our curve, disregard it. if (! is_in_x_range(m_cv, iv_it->point())) continue; // If we already have an intersection point, compare it to the current // isolated vertex, in order to filter unnecessary computations. - if (m_found_intersect && compare_xy(iv_it->point(), m_intersect_p) == LARGER) + if (m_found_intersect && + (compare_xy(iv_it->point(), m_intersect_p) == LARGER)) continue; // In case the isolated vertex lies on the curve, update the intersection @@ -960,8 +985,7 @@ _leftmost_intersection_with_face_boundary(Face_handle face, bool on_boundary) // template bool Arrangement_zone_2:: -_zone_in_face(Face_handle face, bool on_boundary) -{ +_zone_in_face(Face_handle face, bool on_boundary) { #if defined(ARR_ZONE_VERBOSE) std::cout << "_zone_in_face(" << on_boundary << ")" << std::endl; #endif @@ -1095,7 +1119,7 @@ _zone_in_face(Face_handle face, bool on_boundary) // Associate the intersection list of the original curve with the // right subcurve, while we can associate an empty list with the // left subcurve, as we are now done with it. - Intersect_map_iterator iter = m_inter_map.find(p_orig_curve); + auto iter = m_inter_map.find(p_orig_curve); Intersect_list empty_inter_list; m_inter_map[p_right_subcurve] = iter->second; @@ -1190,8 +1214,7 @@ _zone_in_face(Face_handle face, bool on_boundary) // curve currently associated with m_intersect_he. // template -bool Arrangement_zone_2::_zone_in_overlap() -{ +bool Arrangement_zone_2::_zone_in_overlap() { #if defined(ARR_ZONE_VERBOSE) std::cout << "_zone_in_overlap()" << std::endl; #endif diff --git a/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h b/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h index c32deb11eca..cb0e7117833 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_zone_2.h @@ -55,65 +55,68 @@ namespace CGAL { template class Arrangement_zone_2 { public: - typedef Arrangement_ Arrangement_2; - typedef typename Arrangement_2::Geometry_traits_2 Geometry_traits_2; - typedef typename Arrangement_2::Topology_traits Topology_traits; + using Arrangement_2 = Arrangement_; + using Geometry_traits_2 = typename Arrangement_2::Geometry_traits_2; + using Topology_traits = typename Arrangement_2::Topology_traits; protected: - typedef Arr_traits_adaptor_2 Traits_adaptor_2; + using Traits_adaptor_2 = Arr_traits_adaptor_2; - typedef typename Traits_adaptor_2::Left_side_category Left_side_category; - typedef typename Traits_adaptor_2::Bottom_side_category Bottom_side_category; - typedef typename Traits_adaptor_2::Top_side_category Top_side_category; - typedef typename Traits_adaptor_2::Right_side_category Right_side_category; + using Left_side_category = typename Traits_adaptor_2::Left_side_category; + using Bottom_side_category = typename Traits_adaptor_2::Bottom_side_category; + using Top_side_category = typename Traits_adaptor_2::Top_side_category; + using Right_side_category = typename Traits_adaptor_2::Right_side_category; static_assert(Arr_sane_identified_tagging::value); + // Categories for dispatching + using Are_all_sides_oblivious_category = + typename Arr_all_sides_oblivious_category::result; + + using Left_or_right_sides_category = + typename Arr_two_sides_category::result; public: - typedef ZoneVisitor_ Visitor; + using Visitor = ZoneVisitor_; - typedef typename Arrangement_2::Vertex_handle Vertex_handle; - typedef typename Arrangement_2::Halfedge_handle Halfedge_handle; - typedef typename Arrangement_2::Face_handle Face_handle; + using Vertex_handle = typename Arrangement_2::Vertex_handle; + using Halfedge_handle = typename Arrangement_2::Halfedge_handle; + using Face_handle = typename Arrangement_2::Face_handle; - typedef std::pair Visitor_result; + using Visitor_result = std::pair; - typedef typename Geometry_traits_2::Point_2 Point_2; - typedef typename Geometry_traits_2::X_monotone_curve_2 X_monotone_curve_2; - typedef typename Geometry_traits_2::Multiplicity Multiplicity; + using Point_2 = typename Geometry_traits_2::Point_2; + using X_monotone_curve_2 = typename Geometry_traits_2::X_monotone_curve_2; + using Multiplicity = typename Geometry_traits_2::Multiplicity; protected: - typedef typename Arr_all_sides_oblivious_category::result - Are_all_sides_oblivious_category; + // General types + using Vertex_const_handle = typename Arrangement_2::Vertex_const_handle; + using Halfedge_const_handle = typename Arrangement_2::Halfedge_const_handle; + using Face_const_handle = typename Arrangement_2::Face_const_handle; - typedef typename Arrangement_2::Vertex_const_handle Vertex_const_handle; - typedef typename Arrangement_2::Halfedge_const_handle Halfedge_const_handle; - typedef typename Arrangement_2::Face_const_handle Face_const_handle; - - typedef typename Arrangement_2::Ccb_halfedge_circulator - Ccb_halfedge_circulator; + using Ccb_halfedge_circulator = + typename Arrangement_2::Ccb_halfedge_circulator; // Types used for caching intersection points: - typedef std::pair Intersection_point; - typedef std::variant - Intersection_result; - typedef std::optional Optional_intersection; - typedef std::list Intersect_list; - typedef std::map - Intersect_map; - typedef typename Intersect_map::iterator Intersect_map_iterator; + using Intersection_point = std::pair; + using Intersection_result = + std::variant; + using Optional_intersection = std::optional; + using Intersect_list = std::list; + using Intersect_map = std::map; - typedef std::set Curves_set; - typedef typename Curves_set::iterator Curves_set_iterator; + using Curves_set = std::set; + using Curves_set_iterator = typename Curves_set::iterator; - typedef Arr_point_location_result Pl_result; - typedef typename Pl_result::Type Pl_result_type; + using Pl_result = Arr_point_location_result; + using Pl_result_type = typename Pl_result::Type; // Data members: Arrangement_2& m_arr; // The associated arrangement. @@ -193,8 +196,7 @@ public: * \param pl A point-location object associated with the arrangement. */ template - void init(const X_monotone_curve_2& cv, const PointLocation& pl) - { + void init(const X_monotone_curve_2& cv, const PointLocation& pl) { // Set the curve and check whether its left end has boundary conditions. m_cv = cv; @@ -267,8 +269,7 @@ private: */ bool do_overlap_impl(const X_monotone_curve_2& cv1, const X_monotone_curve_2& cv2, - const Point_2& p, Arr_all_sides_oblivious_tag) const - { + const Point_2& p, Arr_all_sides_oblivious_tag) const { return m_geom_traits->compare_y_at_x_right_2_object()(cv1, cv2, p) == EQUAL; } @@ -336,7 +337,7 @@ private: Optional_intersection _compute_next_intersection(Halfedge_handle he, bool skip_first_point, - bool& intersect_on_right_boundary); + Arr_parameter_space& intersection_location); /*! Remove the next intersection of m_cv with the given halfedge from the map. * \param he A handle to the halfedge. @@ -381,8 +382,7 @@ private: { return (_is_to_right_impl(p, he, Are_all_sides_oblivious_category())); } bool _is_to_right_impl(const Point_2& p, Halfedge_handle he, - Arr_all_sides_oblivious_tag) const - { + Arr_all_sides_oblivious_tag) const { return (((he->direction() == ARR_LEFT_TO_RIGHT) && m_geom_traits->compare_xy_2_object()(p, he->target()->point()) == LARGER) || @@ -394,12 +394,33 @@ private: bool _is_to_right_impl(const Point_2& p, Halfedge_handle he, Arr_not_all_sides_oblivious_tag) const; + /*! Check whether an intersection point is valid. A valid intersection point + * must be to the left of the left end of the curve involved. + */ + bool is_intersection_valid(const Point_2& ip, + Arr_parameter_space& intersection_location) const { + return is_intersection_valid_impl(ip, intersection_location, + Left_or_right_sides_category()); + } + + bool is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& intersection_location, + Arr_all_sides_oblivious_tag) const; + + bool is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& intersection_location, + Arr_has_identified_side_tag) const; + + bool is_intersection_valid_impl(const Point_2& ip, + Arr_parameter_space& intersection_location, + Arr_boundary_cond_tag) const; + /*! Compute the (lexicographically) leftmost intersection of the query * curve with a given halfedge on the boundary of a face in the arrangement. */ void _leftmost_intersection(Ccb_halfedge_circulator he_curr, bool on_boundary, - bool& leftmost_on_right_boundary); + Arr_parameter_space& leftmost_location); /*! Compute the (lexicographically) leftmost intersection of the query * curve with the boundary of a given face in the arrangement. diff --git a/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h b/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h index c7637f04b91..76e2eaf3283 100644 --- a/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h +++ b/Arrangement_on_surface_2/include/CGAL/draw_arrangement_2.h @@ -29,7 +29,9 @@ #include #include +#include #include +#include namespace CGAL { @@ -46,32 +48,32 @@ struct Default_color_generator { }; // Viewer class for`< Polygon_2 -template -class Arr_2_basic_viewer_qt : public Basic_viewer_qt { - using Arr = Arrangement_2_; +class Aos_2_basic_viewer_qt : public Basic_viewer_qt { + using Aos = ArrangementOnSurface_2; using Color_generator = ColorGenerator; using Base = Basic_viewer_qt; - using Gt = typename Arr::Geometry_traits_2; - using Point = typename Arr::Point_2; - using X_monotone_curve = typename Arr::X_monotone_curve_2; - using Vertex_const_handle = typename Arr::Vertex_const_handle; - using Halfedge_const_handle = typename Arr::Halfedge_const_handle; - using Face_const_handle = typename Arr::Face_const_handle; + using Gt = typename Aos::Geometry_traits_2; + using Point = typename Aos::Point_2; + using X_monotone_curve = typename Aos::X_monotone_curve_2; + using Vertex_const_handle = typename Aos::Vertex_const_handle; + using Halfedge_const_handle = typename Aos::Halfedge_const_handle; + using Face_const_handle = typename Aos::Face_const_handle; using Ccb_halfedge_const_circulator = - typename Arr::Ccb_halfedge_const_circulator; + typename Aos::Ccb_halfedge_const_circulator; public: /// Construct the viewer. /// @param arr the arrangement to view /// @param title the title of the window - Arr_2_basic_viewer_qt(QWidget* parent, const Arr& arr, + Aos_2_basic_viewer_qt(QWidget* parent, const Aos& aos, Color_generator color_generator, const char* title = "2D Arrangement Basic Viewer", bool draw_vertices = false) : // First draw: vertices; edges, faces; multi-color; no inverse normal Base(parent, title, draw_vertices, true, true, false, false), - m_arr(arr), + m_aos(aos), m_color_generator(color_generator) { // mimic the computation of Camera::pixelGLRatio() @@ -154,32 +156,47 @@ public: */ CGAL::Bbox_2 bounding_box() { CGAL::Bbox_2 bbox; - const auto* traits = this->m_arr.geometry_traits(); + const auto* traits = this->m_aos.geometry_traits(); // At this point we assume that the arrangement is not open, and thus the // bounding box is defined by the vertices. - for (auto it = m_arr.vertices_begin(); it != m_arr.vertices_end(); ++it) + for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it) bounding_box_impl1(bbox, it->point(), *traits, 0); return bbox; } + /*! Add all faces. + */ + template + void add_faces(const Traits&) { + for (auto it = m_aos.unbounded_faces_begin(); + it != m_aos.unbounded_faces_end(); ++it) + add_face(it); + } + + /*! Add all faces. + */ + template + void + add_faces(Arr_geodesic_arc_on_sphere_traits_2 const&) + { add_face(m_aos.faces_begin()); } + /*! Add all elements to be drawn. */ void add_elements() { + // std::cout << "add_elements()\n"; // std::cout << "ratio: " << this->pixel_ratio() << std::endl; clear(); m_visited.clear(); - if (m_arr.is_empty()) return; - for (auto it = m_arr.unbounded_faces_begin(); - it != m_arr.unbounded_faces_end(); ++it) - add_face(it); + if (m_aos.is_empty()) return; + add_faces(*(this->m_aos.geometry_traits())); - // Add edges that do not separe faces. - for (auto it = m_arr.edges_begin(); it != m_arr.edges_end(); ++it) + // Add edges that do not separate faces. + for (auto it = m_aos.edges_begin(); it != m_aos.edges_end(); ++it) if (it->face() == it->twin()->face()) draw_curve(it->curve()); // Add all points - for (auto it = m_arr.vertices_begin(); it != m_arr.vertices_end(); ++it) + for (auto it = m_aos.vertices_begin(); it != m_aos.vertices_end(); ++it) draw_point(it->point()); m_visited.clear(); @@ -190,11 +207,20 @@ public: double pixel_ratio() const { return m_pixel_ratio; } protected: + template + Halfedge_const_handle + find_smallest(Ccb_halfedge_const_circulator circ, + Arr_geodesic_arc_on_sphere_traits_2 const&) + { return circ; } + /*! Find the halfedge incident to the lexicographically smallest vertex * along the CCB, such that there is no other halfedge underneath. */ - Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ) { - const auto* traits = this->m_arr.geometry_traits(); + template + Halfedge_const_handle find_smallest(Ccb_halfedge_const_circulator circ, + const Traits&) { + // std::cout << "find_smallest()\n"; + const auto* traits = this->m_aos.geometry_traits(); auto cmp_xy = traits->compare_xy_2_object(); auto cmp_y = traits->compare_y_at_x_right_2_object(); @@ -241,6 +267,7 @@ protected: template void draw_approximate_region(Halfedge_const_handle curr, const Approximate& approx) { + // std::cout << "draw_approximate_region()\n"; std::vector polyline; double error(this->pixel_ratio()); bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT; @@ -258,7 +285,7 @@ protected: */ template void draw_exact_curve(const XMonotoneCurve& curve) { - const auto* traits = this->m_arr.geometry_traits(); + const auto* traits = this->m_aos.geometry_traits(); auto ctr_min = traits->construct_min_vertex_2_object(); auto ctr_max = traits->construct_max_vertex_2_object(); this->add_segment(ctr_min(curve), ctr_max(curve)); @@ -267,7 +294,7 @@ protected: /*! Draw an exact region. */ void draw_exact_region(Halfedge_const_handle curr) { - this->add_point_in_face(curr->source()->point()); + // this->add_point_in_face(curr->source()->point()); draw_exact_curve(curr->curve()); } @@ -300,9 +327,46 @@ protected: { draw_approximate_region(curr, traits.approximate_2_object()); } #endif + template + void draw_region_impl1 + (Halfedge_const_handle curr, + Arr_geodesic_arc_on_sphere_traits_2 const& traits, + int) { + // std::cout << "draw_region_impl1()\n"; + auto approx = traits.approximate_2_object(); + using Kernel = Kernel_; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; + using Ak = typename Traits::Approximate_kernel; + using Ap = typename Traits::Approximate_point_2; + using Approx_point_3 = typename Ak::Point_3; + + std::vector polyline; + double error(0.01); + bool l2r = curr->direction() == ARR_LEFT_TO_RIGHT; + approx(curr->curve(), error, std::back_inserter(polyline), l2r); + if (polyline.empty()) return; + auto it = polyline.begin(); + auto x = it->dx(); + auto y = it->dy(); + auto z = it->dz(); + auto l = std::sqrt(x*x + y*y + z*z); + Approx_point_3 prev(x/l, y/l, z/l); + for (++it; it != polyline.end(); ++it) { + auto x = it->dx(); + auto y = it->dy(); + auto z = it->dz(); + auto l = std::sqrt(x*x + y*y + z*z); + Approx_point_3 next(x/l, y/l, z/l); + this->add_segment(prev, next); + prev = next; + // this->add_point_in_face(*prev); + } + } + /*! Draw a region. */ void draw_region(Ccb_halfedge_const_circulator circ) { + // std::cout << "draw_region()\n"; /* Check whether the traits has a member function called * approximate_2_object() and if so check whether the return type, namely * `Approximate_2` has an appropriate operator. @@ -321,8 +385,8 @@ protected: auto color = m_color_generator(circ->face()); this->face_begin(color); - const auto* traits = this->m_arr.geometry_traits(); - auto ext = find_smallest(circ); + const auto* traits = this->m_aos.geometry_traits(); + auto ext = find_smallest(circ, *traits); auto curr = ext; do { @@ -382,6 +446,37 @@ protected: { draw_approximate_curve(xcv, traits.approximate_2_object()); } #endif + template + void draw_curve_impl1 + (const X_monotone_curve& xcv, + Arr_geodesic_arc_on_sphere_traits_2 const& traits, + int) { + auto approx = traits.approximate_2_object(); + using Kernel = Kernel_; + using Traits = Arr_geodesic_arc_on_sphere_traits_2; + using Ak = typename Traits::Approximate_kernel; + using Ap = typename Traits::Approximate_point_2; + using Approx_point_3 = typename Ak::Point_3; + std::vector apoints; + double error(0.01); + approx(xcv, error, std::back_inserter(apoints)); + auto it = apoints.begin(); + auto x = it->dx(); + auto y = it->dy(); + auto z = it->dz(); + auto l = std::sqrt(x*x + y*y + z*z); + Approx_point_3 prev(x/l, y/l, z/l); + for (++it; it != apoints.end(); ++it) { + auto x = it->dx(); + auto y = it->dy(); + auto z = it->dz(); + auto l = std::sqrt(x*x + y*y + z*z); + Approx_point_3 next(x/l, y/l, z/l); + this->add_segment(prev, next); + prev = next; + } + } + /*! Draw a curve. */ template @@ -404,14 +499,14 @@ protected: #if 0 if constexpr (std::experimental::is_detected_v) { - const auto* traits = this->m_arr.geometry_traits(); + const auto* traits = this->m_aos.geometry_traits(); auto approx = traits->approximate_2_object(); draw_approximate_curve(curve, approx); return; } draw_exact_curve(curve); #else - const auto* traits = this->m_arr.geometry_traits(); + const auto* traits = this->m_aos.geometry_traits(); draw_curve_impl1(curve, *traits, 0); #endif } @@ -442,16 +537,35 @@ protected: { add_point(traits.approximate_2_object()(p)); } #endif + template + void draw_point_impl1 + (const Point& p, + Arr_geodesic_arc_on_sphere_traits_2 const& traits, + int) { + auto approx = traits.approximate_2_object(); + using Traits = Arr_geodesic_arc_on_sphere_traits_2; + using Ak = typename Traits::Approximate_kernel; + using Approx_point_3 = typename Ak::Point_3; + auto ap = approx(p); + auto x = ap.dx(); + auto y = ap.dy(); + auto z = ap.dz(); + auto l = std::sqrt(x*x + y*y + z*z); + Approx_point_3 p3(x/l, y/l, z/l); + add_point(p3); + } + /*! Draw a point. */ void draw_point(const Point& p) { - const auto* traits = m_arr.geometry_traits(); + const auto* traits = m_aos.geometry_traits(); draw_point_impl1(p, *traits, 0); } /*! Add a Connected Component of the Boundary. */ void add_ccb(Ccb_halfedge_const_circulator circ) { + // std::cout << "add_ccb()\n"; auto curr = circ; do { auto new_face = curr->twin()->face(); @@ -464,8 +578,9 @@ protected: /*! Add a face. */ void add_face(Face_const_handle face) { - using Inner_ccb_const_iterator = typename Arr::Inner_ccb_const_iterator; - using Outer_ccb_const_iterator = typename Arr::Outer_ccb_const_iterator; + // std::cout << "add_face()\n"; + using Inner_ccb_const_iterator = typename Aos::Inner_ccb_const_iterator; + using Outer_ccb_const_iterator = typename Aos::Outer_ccb_const_iterator; for (Inner_ccb_const_iterator it = face->inner_ccbs_begin(); it != face->inner_ccbs_end(); ++it) @@ -505,7 +620,7 @@ protected: double m_pixel_ratio = 1; //! The arrangement to draw. - const Arr& m_arr; + const Aos& m_aos; //! The color generator. Color_generator m_color_generator; @@ -514,32 +629,63 @@ protected: }; //! Basic viewer of a 2D arrangement. -template -class Arr_2_viewer_qt : public Arr_2_basic_viewer_qt { public: - using Arr = Arrangement_2_; + using Aos = ArrangementOnSurface_2; using Color_generator = ColorGenerator; - using Base = Arr_2_basic_viewer_qt; - using Point = typename Arr::Point_2; - using X_monotone_curve = typename Arr::X_monotone_curve_2; - using Halfedge_const_handle = typename Arr::Halfedge_const_handle; - using Face_const_handle = typename Arr::Face_const_handle; + using Base = Aos_2_basic_viewer_qt; + using Point = typename Aos::Point_2; + using X_monotone_curve = typename Aos::X_monotone_curve_2; + using Halfedge_const_handle = typename Aos::Halfedge_const_handle; + using Face_const_handle = typename Aos::Face_const_handle; using Ccb_halfedge_const_circulator = - typename Arr::Ccb_halfedge_const_circulator; + typename Aos::Ccb_halfedge_const_circulator; /// Construct the viewer. /// @param arr the arrangement to view /// @param title the title of the window - Arr_2_viewer_qt(QWidget* parent, const Arr& arr, + Aos_2_viewer_qt(QWidget* parent, const Aos& aos, Color_generator color_generator, - const char* title = "2D Arrangement Basic Viewer", + const char* title = "2D Arrangement on Surface Basic Viewer", bool draw_vertices = false) : - Base(parent, arr, color_generator, title, draw_vertices) + Base(parent, aos, color_generator, title, draw_vertices) {} }; +/*! Draw an arrangement on surface. + */ +template +void draw(const Arrangement_on_surface_2& aos, + const char* title = "2D Arrangement on Surface Basic Viewer", + bool draw_vertices = false) { +#if defined(CGAL_TEST_SUITE) + bool cgal_test_suite=true; +#else + bool cgal_test_suite = qEnvironmentVariableIsSet("CGAL_TEST_SUITE"); +#endif + + if (cgal_test_suite) return; + using Gt = GeometryTraits_2; + using Tt = TopologyTraits; + using Aos = CGAL::Arrangement_on_surface_2; + using Viewer = Aos_2_viewer_qt; + + CGAL::Qt::init_ogl_context(4,3); + + int argc = 1; + const char* argv[2] = {"t2_viewer", nullptr}; + QApplication app(argc, const_cast(argv)); + Default_color_generator color_generator; + Viewer mainwindow(app.activeWindow(), aos, color_generator, title, + draw_vertices); + mainwindow.add_elements(); + mainwindow.show(); + app.exec(); +} + /*! Draw an arrangement. */ template @@ -555,7 +701,7 @@ void draw(const Arrangement_2& arr, if (cgal_test_suite) return; using Gt = GeometryTraits_2; using Arr = CGAL::Arrangement_2; - using Viewer = Arr_2_viewer_qt; + using Viewer = Aos_2_viewer_qt; CGAL::Qt::init_ogl_context(4,3); @@ -589,7 +735,7 @@ void draw(const Arrangement_2& arr, using Color_generator = ColorGenerator; using Gt = GeometryTraits_2; using Arr = CGAL::Arrangement_2; - using Viewer = Arr_2_viewer_qt; + using Viewer = Aos_2_viewer_qt; CGAL::Qt::init_ogl_context(4,3); diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/test_construction/geodesic_arcs_on_sphere/test40.txt b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/test_construction/geodesic_arcs_on_sphere/test40.txt new file mode 100644 index 00000000000..adccf6ecad9 --- /dev/null +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/data/test_construction/geodesic_arcs_on_sphere/test40.txt @@ -0,0 +1,17 @@ +5 +0 -1 0 0 0 -1 0 +0 0 -1 0 0 0 -1 +0 0 0 -1 0 1 0 +0 0 1 0 -1 0 0 +0 0 0 -1 -1 0 0 +0 +4 5 3 +0 0 -1 +-1 0 0 +0 -1 0 +0 1 0 +0 0 0 -1 -1 0 0 1 +0 -1 0 0 0 -1 0 1 +0 0 -1 0 0 0 -1 1 +0 0 0 -1 0 1 0 1 +0 0 1 0 -1 0 0 1 diff --git a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_construction.geodesic_arcs_on_sphere.cmd b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_construction.geodesic_arcs_on_sphere.cmd index 547aa518864..d995644a095 100644 --- a/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_construction.geodesic_arcs_on_sphere.cmd +++ b/Arrangement_on_surface_2/test/Arrangement_on_surface_2/test_construction.geodesic_arcs_on_sphere.cmd @@ -37,3 +37,4 @@ data/test_construction/geodesic_arcs_on_sphere/test36.txt data/test_construction/geodesic_arcs_on_sphere/test37.txt data/test_construction/geodesic_arcs_on_sphere/test38.txt data/test_construction/geodesic_arcs_on_sphere/test39.txt +data/test_construction/geodesic_arcs_on_sphere/test40.txt diff --git a/Classification/include/CGAL/Classification/Planimetric_grid.h b/Classification/include/CGAL/Classification/Planimetric_grid.h index 2fd1adf5773..673727f2df9 100644 --- a/Classification/include/CGAL/Classification/Planimetric_grid.h +++ b/Classification/include/CGAL/Classification/Planimetric_grid.h @@ -59,7 +59,7 @@ private: using Image_bool = Image; const PointRange* m_points; - PointMap m_point_map; + std::optional m_point_map; Iso_cuboid_3 m_bbox; float m_resolution; @@ -342,7 +342,7 @@ public: { if (m_lower_scale == nullptr) { - const Point_3& p = get(m_point_map, *(m_points->begin()+index)); + const Point_3& p = get(m_point_map.value(), *(m_points->begin()+index)); return (std::size_t)((p.x() - m_bbox.xmin()) / m_resolution); } @@ -356,7 +356,7 @@ public: { if (m_lower_scale == nullptr) { - const Point_3& p = get(m_point_map, *(m_points->begin()+index)); + const Point_3& p = get(m_point_map.value(), *(m_points->begin()+index)); return (std::size_t)((p.y() - m_bbox.ymin()) / m_resolution); } diff --git a/Classification/include/CGAL/Classification/Point_set_neighborhood.h b/Classification/include/CGAL/Classification/Point_set_neighborhood.h index c27c874f0c2..4527ab53f05 100644 --- a/Classification/include/CGAL/Classification/Point_set_neighborhood.h +++ b/Classification/include/CGAL/Classification/Point_set_neighborhood.h @@ -69,7 +69,7 @@ class Point_set_neighborhood using key_type = std::uint32_t; using category = boost::readable_property_map_tag; - My_point_property_map () { } + //My_point_property_map () { } My_point_property_map (const PointRange *input, PointMap point_map) : input (input), point_map (point_map) { } @@ -88,7 +88,7 @@ class Point_set_neighborhood using Knn = Orthogonal_k_neighbor_search; std::shared_ptr m_tree; - Distance m_distance; + std::optional m_distance; public: @@ -300,7 +300,7 @@ private: void k_neighbors (const Point& query, const unsigned int k, OutputIterator output) const { CGAL_assertion (m_tree != nullptr); - Knn search (*m_tree, query, k, 0, true, m_distance); + Knn search (*m_tree, query, k, 0, true, m_distance.value()); for (typename Knn::iterator it = search.begin(); it != search.end(); ++ it) *(output ++) = it->first; } diff --git a/Classification/include/CGAL/Classification/property_maps.h b/Classification/include/CGAL/Classification/property_maps.h index f03e837d806..bad32f9d7ee 100644 --- a/Classification/include/CGAL/Classification/property_maps.h +++ b/Classification/include/CGAL/Classification/property_maps.h @@ -59,8 +59,6 @@ private: public: - Face_descriptor_to_center_of_mass_map () - : m_mesh (nullptr) { } Face_descriptor_to_center_of_mass_map (const FaceGraph* mesh) : m_mesh (mesh), m_vpm (get (vertex_point, *m_mesh)) { } Face_descriptor_to_center_of_mass_map (const FaceGraph* mesh, VertexPointMap vpm) diff --git a/Documentation/doc/Documentation/Tutorials/Tutorial_hello_world.txt b/Documentation/doc/Documentation/Tutorials/Tutorial_hello_world.txt index da30ca174cc..a006447c79a 100644 --- a/Documentation/doc/Documentation/Tutorials/Tutorial_hello_world.txt +++ b/Documentation/doc/Documentation/Tutorials/Tutorial_hello_world.txt @@ -73,7 +73,7 @@ seems that the points are collinear, or perform a right turn. If you must ensure that your numbers get interpreted at their full precision you can use a \cgal kernel that performs exact predicates and -extract constructions. +exact constructions. \cgalExample{Kernel_23/exact.cpp} diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 01485063f19..8ee04d38577 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -35,6 +35,10 @@ Release date: October 2023 - Removed the class templates `Gray_image_mesh_domain_3`, `Implicit_mesh_domain_3`, and `Labeled_image_mesh_domain_3` which are deprecated since CGAL-4.13. +### [2D Arrangements](https://doc.cgal.org/6.0/Manual/packages.html#PkgArrangementOnSurface2) +- Fixed a bug in the zone construction code applied to arrangements of geodesic arcs on a sphere, + when inserting an arc that lies on the identification curve. + ### [Tetrahedral Remeshing](https://doc.cgal.org/6.0/Manual/packages.html#PkgTetrahedralRemeshing) - **Breaking change**: The template parameters of `CGAL::Tetrahedral_remeshing::Remeshing_cell_base_3` diff --git a/Kinetic_shape_reconstruction/include/CGAL/KSR_3/Initializer.h b/Kinetic_shape_reconstruction/include/CGAL/KSR_3/Initializer.h index e4d91382d8c..98f8a7049f3 100644 --- a/Kinetic_shape_reconstruction/include/CGAL/KSR_3/Initializer.h +++ b/Kinetic_shape_reconstruction/include/CGAL/KSR_3/Initializer.h @@ -708,10 +708,11 @@ private: const Polygon_2& polygon = pair.first; const Indices& input_indices = pair.second; m_data.add_input_polygon(support_plane_idx, input_indices, polygon); - if (m_parameters.debug) - dump_polygons(m_data, polygons, m_data.prefix() + "inserted-polygons"); } + //if (m_parameters.debug) + dump_polygons(m_data, polygons, m_data.prefix() + "inserted-polygons.ply"); + CGAL_assertion(m_data.number_of_support_planes() >= 6); if (m_parameters.verbose) { std::cout << "* provided input polygons: " << m_data.input_polygons().size() << std::endl; diff --git a/Kinetic_shape_reconstruction/include/CGAL/Kinetic_shape_partition_3.h b/Kinetic_shape_reconstruction/include/CGAL/Kinetic_shape_partition_3.h index fb47505a697..387a7fbac96 100644 --- a/Kinetic_shape_reconstruction/include/CGAL/Kinetic_shape_partition_3.h +++ b/Kinetic_shape_reconstruction/include/CGAL/Kinetic_shape_partition_3.h @@ -1084,7 +1084,8 @@ public: \param it output iterator. - \warning Removed\n Replaced by `for (auto d : CMap::darts_of_cell<2, 3>(d)) *it++ = to_inexact(CMap::attribute<0>(d).point);` + \warning Removed\n Replaced by `for (auto vd : CMap::darts_of_cell<2, 2>(fd)) *it++ = to_inexact(CMap::attribute<0>(vd).point);` + alternatively a loop with beta(1) to be sure the vertices are in correct order \pre successful partition */ @@ -1106,7 +1107,7 @@ public: \param it output iterator. - \warning Replaced by `CMap::darts_of_cell<2, 3>(d)` + \warning Replaced by `CMap::darts_of_cell<2, 2>(d)` \pre successful partition */ @@ -1182,7 +1183,7 @@ public: \param it output iterator. - \warning Replaced by `CMap::one_dart_per_incident_cell<2, 3, 3>(d)` + \warning Replaced by `CMap::one_dart_per_incident_cell<2, 3, 3>(vol_d)` \pre successful partition */ @@ -1237,7 +1238,8 @@ public: @return pair of adjacent volumes. - \warning Replaced by `beta<3>(d)` as d is part of one 3-cell already + \warning Replaced by `beta<3>(vol_d)` as d is part of one 3-cell already + bbox sides should be stored in the Face_property \pre successful partition */ @@ -1353,6 +1355,11 @@ public: //auto vertex_range = m_data.pvertices_of_pface(vol.pfaces[i]); ib.begin_facet(); + bool outward; + + PVertex vtx = *m_data.pvertices_of_pface(volume.pfaces[i]).begin(); + volume.pface_oriented_outwards[i] = ((m_data.point_3(vtx) - volume.centroid) * m_data.support_plane(volume.pfaces[i]).plane().orthogonal_vector() < 0); + if (!vol.pface_oriented_outwards[j]) std::reverse(vtx_of_face.begin(), vtx_of_face.end()); @@ -1360,15 +1367,16 @@ public: ib.add_vertex_to_facet(static_cast(mapped_vertices[v])); auto face_dart = ib.end_facet(); // returns a dart to the face - LCC_Properties::Face_property face_prop; - face_prop.Input_polygon_index = 5; - face_prop.Part_of_initial_polygon = true; - m_lcc.info<2>(face_dart) = face_prop; + m_lcc.set_attribute<2>(face_dart, m_lcc.create_attribute<2>()); + m_lcc.info<2>(face_dart).Input_polygon_index = 5; + m_lcc.info<2>(face_dart).Part_of_initial_polygon = true; vtx_of_face.clear(); } auto vol_dart = ib.end_surface(); // returns a dart to the volume + m_lcc.set_attribute<3>(vol_dart, m_lcc.create_attribute<3>()); + m_lcc.info<3>(vol_dart).barycenter; int num_faces = m_lcc.one_dart_per_cell<2>().size(); faces_of_volume.clear(); } diff --git a/Kinetic_shape_reconstruction/include/CGAL/Kinetic_shape_reconstruction_3.h b/Kinetic_shape_reconstruction/include/CGAL/Kinetic_shape_reconstruction_3.h index f4be0b46aa4..5cd6405b2f8 100644 --- a/Kinetic_shape_reconstruction/include/CGAL/Kinetic_shape_reconstruction_3.h +++ b/Kinetic_shape_reconstruction/include/CGAL/Kinetic_shape_reconstruction_3.h @@ -1216,6 +1216,17 @@ private: .maximum_angle(angle_tolerance) .maximum_offset(maximum_offset));*/ + // Merge coplanar regions + for (std::size_t i = 0; i < m_regions.size() - 1; i++) { + for (std::size_t j = i + 1; j < m_regions.size(); j++) { + if (m_regions[i].first == m_regions[j].first || m_regions[i].first.opposite() == m_regions[j].first) { + std::move(m_regions[j].second.begin(), m_regions[j].second.begin(), std::back_inserter(m_regions[i].second)); + m_regions.remove(m_regions.begin() + j); + j-- + } + } + } + std::vector pl; std::size_t idx = 0; diff --git a/Orthtree/doc/Orthtree/Orthtree.txt b/Orthtree/doc/Orthtree/Orthtree.txt index 1f40d39d5c5..6abe414ea5f 100644 --- a/Orthtree/doc/Orthtree/Orthtree.txt +++ b/Orthtree/doc/Orthtree/Orthtree.txt @@ -293,4 +293,4 @@ provided kind help and advice all the way through. */ -} +} \ No newline at end of file diff --git a/Orthtree/examples/Orthtree/octree_build_from_point_vector.cpp b/Orthtree/examples/Orthtree/octree_build_from_point_vector.cpp index 754fcaa3553..1081e155df3 100644 --- a/Orthtree/examples/Orthtree/octree_build_from_point_vector.cpp +++ b/Orthtree/examples/Orthtree/octree_build_from_point_vector.cpp @@ -23,7 +23,7 @@ int main() { points.emplace_back(-1, 1, 1); // Create an octree from the points - Octree octree({points}); + Octree octree(points); // Build the octree octree.refine(10, 1); diff --git a/Orthtree/examples/Orthtree/octree_grade.cpp b/Orthtree/examples/Orthtree/octree_grade.cpp index ae41079ea87..5bb410d7e33 100644 --- a/Orthtree/examples/Orthtree/octree_grade.cpp +++ b/Orthtree/examples/Orthtree/octree_grade.cpp @@ -30,7 +30,7 @@ int main() { points.emplace_back(-1.0001, 1, 1); // Create an octree from the points - Octree octree({points}); + Octree octree(points); // Build the octree with a small bucket size, so we get a deep node octree.refine(10, 2); diff --git a/Orthtree/examples/Orthtree/quadtree_build_from_point_vector.cpp b/Orthtree/examples/Orthtree/quadtree_build_from_point_vector.cpp index 45a9b2a80f5..bd40ace0423 100644 --- a/Orthtree/examples/Orthtree/quadtree_build_from_point_vector.cpp +++ b/Orthtree/examples/Orthtree/quadtree_build_from_point_vector.cpp @@ -18,7 +18,7 @@ int main() points_2d.emplace_back(r.get_double(-1., 1.), r.get_double(-1., 1.)); - Quadtree quadtree({points_2d}); + Quadtree quadtree(points_2d); quadtree.refine(10, 5); return EXIT_SUCCESS; diff --git a/Orthtree/include/CGAL/Orthtree/Nearest_neighbors.h b/Orthtree/include/CGAL/Orthtree/Nearest_neighbors.h index 190a49fd70f..270ac53179c 100644 --- a/Orthtree/include/CGAL/Orthtree/Nearest_neighbors.h +++ b/Orthtree/include/CGAL/Orthtree/Nearest_neighbors.h @@ -129,6 +129,7 @@ namespace Orthtrees { \tparam Tree must be an orthtree with traits which are a model of CollectionPartitioningOrthtreeTraits \tparam OutputIterator must be a model of `OutputIterator` that accepts points + \param orthtree the tree to search within \param query_sphere the region to search within \param k the number of points to find @@ -172,6 +173,7 @@ OutputIterator nearest_k_neighbors_in_radius( \tparam Tree must be an orthtree with traits which are a model of CollectionPartitioningOrthtreeTraits \tparam OutputIterator a model of `OutputIterator` that accept `Point_d` objects. + \param orthtree the tree to search within \param query query point. \param k number of neighbors. @@ -193,6 +195,7 @@ OutputIterator nearest_neighbors(const Tree& orthtree, const typename Tree::Poin \tparam Tree must be an orthtree with traits which are a model of CollectionPartitioningOrthtreeTraits \tparam OutputIterator a model of `OutputIterator` that accept `Point_d` objects. + \param orthtree the tree to search within \param query query sphere. \param output output iterator. diff --git a/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/hypothesis.h b/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/hypothesis.h index 19ee7849a78..e4c1f4e004a 100644 --- a/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/hypothesis.h +++ b/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/hypothesis.h @@ -747,7 +747,7 @@ namespace CGAL { if (v == Polygon_mesh::null_vertex()) // failed splitting edge return Polygon_mesh::null_halfedge(); - typename Polygon_mesh::template Property_map& coords = mesh.points(); + auto &coords = mesh.points(); coords[v] = *ep.pos; Edge_descriptor e1 = mesh.edge(h); diff --git a/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/point_set_with_planes.h b/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/point_set_with_planes.h index 09d628e7f4e..2061ed13b25 100644 --- a/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/point_set_with_planes.h +++ b/Polygonal_surface_reconstruction/include/CGAL/Polygonal_surface_reconstruction/internal/point_set_with_planes.h @@ -142,7 +142,7 @@ namespace CGAL { std::size_t idx = 0; for (typename PointRange::const_iterator it = points.begin(); it != points.end(); ++it) { Base_class::m_points[idx] = get(point_map, *it); - Base_class::m_normals[idx] = get(normal_map, *it); + Base_class::m_normals.value()[idx] = get(normal_map, *it); int plane_index = get(plane_index_map, *it); if (plane_index != -1) { auto it_and_bool = plane_index_remap.emplace(plane_index, planar_segments_.size()); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp index a105d1ba12e..a1b29fd5689 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/Alpha_wrap_3_plugin.cpp @@ -153,13 +153,13 @@ public: for(auto fit=wrapper.triangulation().finite_facets_begin(), fend=wrapper.triangulation().finite_facets_end(); fit!=fend; ++fit) { Facet f = *fit; - if(!f.first->info().is_outside) + if(!f.first->is_outside()) f = wrapper.triangulation().mirror_facet(f); const Cell_handle c = f.first; const int s = f.second; const Cell_handle nh = c->neighbor(s); - if(c->info().is_outside == nh->info().is_outside) + if(c->is_outside() == nh->is_outside()) continue; std::array ids; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp index b26135e231a..2c861f7c0c7 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.cpp @@ -30,9 +30,8 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po backup_existing_colors_and_add_new(); - bool cluster_found = false; - boost::tie (m_cluster_id, cluster_found) = m_points->point_set()->property_map("shape"); - if (!cluster_found) + auto m_cluster_id = m_points->point_set()->property_map("shape"); + if (!m_cluster_id) { std::cerr << "Error! Cluster not found!" << std::endl; abort(); @@ -40,7 +39,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po CGAL::Classification::create_clusters_from_indices (*(m_points->point_set()), m_points->point_set()->point_map(), - m_cluster_id, + m_cluster_id.value(), m_clusters); std::cerr << m_clusters.size() << " cluster(s) found" << std::endl; @@ -57,20 +56,20 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po if (!classif_found) { - Point_set::Property_map las_classif; - boost::tie (las_classif, las_found) = m_points->point_set()->property_map("classification"); - if (las_found) + auto las_classif = m_points->point_set()->property_map("classification"); + las_found = las_classif.has_value(); + if (las_classif) { m_input_is_las = true; for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - unsigned char uc = las_classif[*it]; - m_classif[*it] = int(uc); + unsigned char uc = las_classif.value()[*it]; + m_classif.value()[*it] = int(uc); if (!training_found) - m_training[*it] = int(uc); + m_training.value()[*it] = int(uc); } - m_points->point_set()->remove_property_map (las_classif); + m_points->point_set()->remove_property_map (las_classif.value()); classif_found = true; training_found = true; } @@ -85,7 +84,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po { if (training_found) { - int l = m_training[*it]; + int l = m_training.value()[*it]; if (l >= 0) { if (std::size_t(l) >= used_indices.size()) @@ -95,7 +94,7 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po } if (classif_found) { - int l = m_classif[*it]; + int l = m_classif.value()[*it]; if (l >= 0) { if (std::size_t(l) >= used_indices.size()) @@ -125,31 +124,31 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int c = m_cluster_id[*it]; + int c = m_cluster_id.value()[*it]; if (training_found) { if (std::size_t(current_idx) != used_indices.size()) // Empty indices -> reorder indices in point set { - if (las_found && (m_training[*it] == 0 || m_training[*it] == 1)) // Unclassified class in LAS - m_training[*it] = -1; - else if (m_training[*it] != -1) - m_training[*it] = used_indices[std::size_t(m_training[*it])]; + if (las_found && (m_training.value()[*it] == 0 || m_training.value()[*it] == 1)) // Unclassified class in LAS + m_training.value()[*it] = -1; + else if (m_training.value()[*it] != -1) + m_training.value()[*it] = used_indices[std::size_t(m_training.value()[*it])]; } - if (c != -1 && m_training[*it] != -1) - m_clusters[c].training() = m_training[*it]; + if (c != -1 && m_training.value()[*it] != -1) + m_clusters[c].training() = m_training.value()[*it]; } if (classif_found) { if (std::size_t(current_idx) != used_indices.size()) // Empty indices -> reorder indices in point set { - if (las_found && (m_classif[*it] == 0 || m_classif[*it] == 1)) // Unclassified class in LAS - m_classif[*it] = -1; - else if (m_classif[*it] != -1) - m_classif[*it] = used_indices[std::size_t(m_classif[*it])]; + if (las_found && (m_classif.value()[*it] == 0 || m_classif.value()[*it] == 1)) // Unclassified class in LAS + m_classif.value()[*it] = -1; + else if (m_classif.value()[*it] != -1) + m_classif.value()[*it] = used_indices[std::size_t(m_classif.value()[*it])]; } - if (c != -1 && m_classif[*it] != -1) - m_clusters[c].label() = m_classif[*it]; + if (c != -1 && m_classif.value()[*it] != -1) + m_clusters[c].label() = m_classif.value()[*it]; } } @@ -240,11 +239,11 @@ Cluster_classification::Cluster_classification(Scene_points_with_normal_item* po Delaunay dt (boost::make_transform_iterator (m_points->point_set()->begin(), Point_set_with_cluster_info (m_points->point_set(), - m_cluster_id)), + m_cluster_id.value())), boost::make_transform_iterator (m_points->point_set()->end(), Point_set_with_cluster_info (m_points->point_set(), - m_cluster_id))); + m_cluster_id.value()))); std::set > adjacencies; @@ -294,16 +293,16 @@ Cluster_classification::~Cluster_classification() for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int c = m_cluster_id[*it]; + int c = m_cluster_id.value()[*it]; if (c != -1) { - m_training[*it] = m_clusters[c].training(); - m_classif[*it] = m_clusters[c].label(); + m_training.value()[*it] = m_clusters[c].training(); + m_classif.value()[*it] = m_clusters[c].label(); } else { - m_training[*it] = -1; - m_classif[*it] = -1; + m_training.value()[*it] = -1; + m_classif.value()[*it] = -1; } } @@ -359,22 +358,22 @@ Cluster_classification::~Cluster_classification() for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int c = m_classif[*it]; + int c = m_classif.value()[*it]; unsigned char lc = 1; // unclassified in LAS standard if (c != -1) lc = label_indices[std::size_t(c)]; las_classif[*it] = lc; - int t = m_training[*it]; + int t = m_training.value()[*it]; unsigned char lt = 1; // unclassified in LAS standard if (t != -1) lt = label_indices[std::size_t(t)]; - m_training[*it] = int(lt); + m_training.value()[*it] = int(lt); } - m_points->point_set()->remove_property_map (m_classif); + m_points->point_set()->remove_property_map (m_classif.value()); } @@ -391,7 +390,7 @@ void Cluster_classification::backup_existing_colors_and_add_new() m_color = m_points->point_set()->add_property_map("real_color").first; for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_color[*it] = CGAL::IO::Color ((unsigned char)(255 * m_points->point_set()->red(*it)), + m_color.value()[*it] = CGAL::IO::Color ((unsigned char)(255 * m_points->point_set()->red(*it)), (unsigned char)(255 * m_points->point_set()->green(*it)), (unsigned char)(255 * m_points->point_set()->blue(*it))); @@ -403,15 +402,15 @@ void Cluster_classification::backup_existing_colors_and_add_new() void Cluster_classification::reset_colors() { - if (m_color == Point_set::Property_map()) + if (!m_color) m_points->point_set()->remove_colors(); else { for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_points->point_set()->set_color(*it, m_color[*it]); + m_points->point_set()->set_color(*it, m_color.value()[*it]); - m_points->point_set()->remove_property_map(m_color); + m_points->point_set()->remove_property_map(m_color.value()); } } @@ -438,7 +437,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_points->point_set()->set_color(*it, m_color[*it]); + m_points->point_set()->set_color(*it, m_color.value()[*it]); } else if (index_color == 1) // classif { @@ -446,7 +445,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) it != m_points->point_set()->first_selected(); ++ it) { QColor color (0, 0, 0); - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { std::size_t c = m_clusters[cid].label(); @@ -464,7 +463,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) it != m_points->point_set()->first_selected(); ++ it) { QColor color (0, 0, 0); - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; float div = 1; if (cid != -1) @@ -486,7 +485,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { @@ -516,7 +515,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { float v = (std::max) (0.f, (std::min)(1.f, m_label_probabilities[corrected_index][cid])); @@ -553,7 +552,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { if (feature->value(cid) > max) @@ -567,7 +566,7 @@ void Cluster_classification::change_color (int index, float* vmin, float* vmax) for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { float v = (feature->value(cid) - min) / (max - min); @@ -598,15 +597,14 @@ int Cluster_classification::real_index_color() const { int out = m_index_color; - if (out == 0 && m_color == Point_set::Property_map()) + if (out == 0 && !m_color) out = -1; return out; } void Cluster_classification::reset_indices () { - Point_set::Property_map indices - = m_points->point_set()->property_map("index").first; + auto indices = m_points->point_set()->property_map("index").value(); m_points->point_set()->unselect_all(); Point_set::Index idx; @@ -629,18 +627,16 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe m_features.clear(); - Point_set::Vector_map normal_map; + std::optional normal_map; bool normals = m_points->point_set()->has_normal_map(); if (normals) normal_map = m_points->point_set()->normal_map(); - bool colors = (m_color != Point_set::Property_map()); + bool colors = m_color.has_value(); - Point_set::Property_map echo_map; - bool echo; - boost::tie (echo_map, echo) = m_points->point_set()->template property_map("echo"); - if (!echo) - boost::tie (echo_map, echo) = m_points->point_set()->template property_map("number_of_returns"); + auto echo_map = m_points->point_set()->template property_map("echo"); + if (!echo_map) + echo_map = m_points->point_set()->template property_map("number_of_returns").value(); Feature_set pointwise_features; @@ -655,11 +651,11 @@ void Cluster_classification::compute_features (std::size_t nb_scales, float voxe generator.generate_point_based_features(pointwise_features); if (normals) - generator.generate_normal_based_features (pointwise_features, normal_map); + generator.generate_normal_based_features (pointwise_features, normal_map.value()); if (colors) - generator.generate_color_based_features (pointwise_features, m_color); - if (echo) - generator.generate_echo_based_features (pointwise_features, echo_map); + generator.generate_color_based_features (pointwise_features, m_color.value()); + if (echo_map) + generator.generate_echo_based_features (pointwise_features, echo_map.value()); #ifdef CGAL_LINKED_WITH_TBB pointwise_features.end_parallel_additions(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h index ef4d006e2ce..c89e25e747b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Cluster_classification.h @@ -125,13 +125,12 @@ class Cluster_classification : public Item_classification_base { typedef typename Point_set::template Property_map Pmap; bool okay = false; - Pmap pmap; - boost::tie (pmap, okay) = m_points->point_set()->template property_map(name.c_str()); - if (okay) + auto pmap = m_points->point_set()->template property_map(name.c_str()); + if (pmap) feature_set.template add > - (*(m_points->point_set()), pmap, name.c_str()); + (*(m_points->point_set()), pmap.value(), name.c_str()); - return okay; + return pmap.has_value(); } void add_selection_to_training_set (std::size_t label) @@ -139,7 +138,7 @@ class Cluster_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { m_clusters[cid].training() = int(label); @@ -165,7 +164,7 @@ class Cluster_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { m_clusters[cid].training() = -1; @@ -187,7 +186,7 @@ class Cluster_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) m_clusters[cid].training() = m_clusters[cid].label(); } @@ -212,7 +211,7 @@ class Cluster_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { int c = m_clusters[cid].label(); @@ -238,7 +237,7 @@ class Cluster_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int cid = m_cluster_id[*it]; + int cid = m_cluster_id.value()[*it]; if (cid != -1) { int c = m_clusters[cid].label(); @@ -376,13 +375,10 @@ class Cluster_classification : public Item_classification_base std::vector m_clusters; - Point_set::Property_map m_red; - Point_set::Property_map m_green; - Point_set::Property_map m_blue; - Point_set::Property_map m_color; - Point_set::Property_map m_cluster_id; - Point_set::Property_map m_training; - Point_set::Property_map m_classif; + std::optional> m_color; + std::optional> m_cluster_id; + std::optional> m_training; + std::optional> m_classif; std::vector > m_label_probabilities; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp index 12bc858fea9..3c827920cb5 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.cpp @@ -16,23 +16,20 @@ #include Point_set_item_classification::Point_set_item_classification(Scene_points_with_normal_item* points) - : m_points (points) - , m_generator (nullptr) - , m_input_is_las (false) -{ + : m_points(points), m_generator(nullptr), m_input_is_las(false), + m_training(), + m_classif(){ m_index_color = 1; reset_indices(); - Point_set::Property_map cluster_id; - bool cluster_found = false; - boost::tie (cluster_id, cluster_found) = m_points->point_set()->property_map("shape"); - if (cluster_found) + auto cluster_id = m_points->point_set()->property_map("shape"); + if (cluster_id) { for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - int c = cluster_id[*it]; + int c = cluster_id.value()[*it]; if (c == -1) continue; if (std::size_t(c) >= m_clusters.size()) @@ -54,20 +51,20 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n if (!classif_found) { - Point_set::Property_map las_classif; - boost::tie (las_classif, las_found) = m_points->point_set()->property_map("classification"); - if (las_found) + auto las_classif = m_points->point_set()->property_map("classification"); + las_found = las_classif.has_value(); + if (las_classif) { m_input_is_las = true; for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - unsigned char uc = las_classif[*it]; - m_classif[*it] = int(uc); + unsigned char uc = las_classif.value()[*it]; + m_classif.value()[*it] = int(uc); if (!training_found) - m_training[*it] = int(uc); + m_training.value()[*it] = int(uc); } - m_points->point_set()->remove_property_map (las_classif); + m_points->point_set()->remove_property_map (las_classif.value()); classif_found = true; training_found = true; } @@ -82,7 +79,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n { if (training_found) { - int l = m_training[*it]; + int l = m_training.value()[*it]; if (l >= 0) { if (std::size_t(l) >= used_indices.size()) @@ -92,7 +89,7 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n } if (classif_found) { - int l = m_classif[*it]; + int l = m_classif.value()[*it]; if (l >= 0) { if (std::size_t(l) >= used_indices.size()) @@ -125,17 +122,17 @@ Point_set_item_classification::Point_set_item_classification(Scene_points_with_n { if (training_found) { - if (las_found && (m_training[*it] == 0 || m_training[*it] == 1)) // Unclassified class in LAS - m_training[*it] = -1; - else if (m_training[*it] != -1) - m_training[*it] = used_indices[std::size_t(m_training[*it])]; + if (las_found && (m_training.value()[*it] == 0 || m_training.value()[*it] == 1)) // Unclassified class in LAS + m_training.value()[*it] = -1; + else if (m_training.value()[*it] != -1) + m_training.value()[*it] = used_indices[std::size_t(m_training.value()[*it])]; } if (classif_found) { - if (las_found && (m_classif[*it] == 0 || m_classif[*it] == 1)) // Unclassified class in LAS - m_classif[*it] = -1; - else if (m_classif[*it] != -1) - m_classif[*it] = used_indices[std::size_t(m_classif[*it])]; + if (las_found && (m_classif.value()[*it] == 0 || m_classif.value()[*it] == 1)) // Unclassified class in LAS + m_classif.value()[*it] = -1; + else if (m_classif.value()[*it] != -1) + m_classif.value()[*it] = used_indices[std::size_t(m_classif.value()[*it])]; } } } @@ -295,22 +292,22 @@ Point_set_item_classification::~Point_set_item_classification() for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int c = m_classif[*it]; + int c = m_classif.value()[*it]; unsigned char lc = 1; // unclassified in LAS standard if (c != -1) lc = label_indices[std::size_t(c)]; las_classif[*it] = lc; - int t = m_training[*it]; + int t = m_training.value()[*it]; unsigned char lt = 1; // unclassified in LAS standard if (t != -1) lt = label_indices[std::size_t(t)]; - m_training[*it] = int(lt); + m_training.value()[*it] = int(lt); } - m_points->point_set()->remove_property_map (m_classif); + m_points->point_set()->remove_property_map (m_classif.value()); } reset_colors(); @@ -327,7 +324,7 @@ void Point_set_item_classification::backup_existing_colors_and_add_new() m_color = m_points->point_set()->add_property_map("real_color").first; for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_color[*it] = CGAL::IO::Color((unsigned char)(255 * m_points->point_set()->red(*it)), + m_color.value()[*it] = CGAL::IO::Color((unsigned char)(255 * m_points->point_set()->red(*it)), (unsigned char)(255 * m_points->point_set()->green(*it)), (unsigned char)(255 * m_points->point_set()->blue(*it))); @@ -339,15 +336,15 @@ void Point_set_item_classification::backup_existing_colors_and_add_new() void Point_set_item_classification::reset_colors() { - if (m_color == Point_set::Property_map()) + if (!m_color) m_points->point_set()->remove_colors(); else { for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_points->point_set()->set_color(*it, m_color[*it]); + m_points->point_set()->set_color(*it, m_color.value()[*it]); - m_points->point_set()->remove_property_map(m_color); + m_points->point_set()->remove_property_map(m_color.value()); } } @@ -374,7 +371,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_points->point_set()->set_color(*it, m_color[*it]); + m_points->point_set()->set_color(*it, m_color.value()[*it]); } else if (index_color == 1) // classif { @@ -382,7 +379,7 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* it != m_points->point_set()->first_selected(); ++ it) { QColor color (0, 0, 0); - std::size_t c = m_classif[*it]; + std::size_t c = m_classif.value()[*it]; if (c != std::size_t(-1)) color = label_qcolor (m_labels[c]); @@ -396,8 +393,8 @@ void Point_set_item_classification::change_color (int index, float* vmin, float* it != m_points->point_set()->first_selected(); ++ it) { QColor color (0, 0, 0); - int c = m_training[*it]; - int c2 = m_classif[*it]; + int c = m_training.value()[*it]; + int c2 = m_classif.value()[*it]; if (c != -1) color = label_qcolor (m_labels[std::size_t(c)]); @@ -490,15 +487,14 @@ int Point_set_item_classification::real_index_color() const { int out = m_index_color; - if (out == 0 && m_color == Point_set::Property_map()) + if (out == 0 && !m_color) out = -1; return out; } void Point_set_item_classification::reset_indices () { - Point_set::Property_map indices - = m_points->point_set()->property_map("index").first; + auto indices = m_points->point_set()->property_map("index").value(); m_points->point_set()->unselect_all(); Point_set::Index idx; @@ -524,18 +520,16 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo m_features.clear(); - Point_set::Vector_map normal_map; + std::optional normal_map; bool normals = m_points->point_set()->has_normal_map(); if (normals) normal_map = m_points->point_set()->normal_map(); - bool colors = (m_color != Point_set::Property_map()); + bool colors = m_color.has_value(); - Point_set::Property_map echo_map; - bool echo; - boost::tie (echo_map, echo) = m_points->point_set()->template property_map("echo"); - if (!echo) - boost::tie (echo_map, echo) = m_points->point_set()->template property_map("number_of_returns"); + auto echo_map = m_points->point_set()->template property_map("echo"); + if (!echo_map) + echo_map = m_points->point_set()->template add_property_map("number_of_returns").first; m_generator = new Generator (*(m_points->point_set()), m_points->point_set()->point_map(), nb_scales, voxel_size); @@ -548,11 +542,11 @@ void Point_set_item_classification::compute_features (std::size_t nb_scales, flo m_generator->generate_point_based_features(m_features); if (normals) - m_generator->generate_normal_based_features (m_features, normal_map); + m_generator->generate_normal_based_features (m_features, normal_map.value()); if (colors) - m_generator->generate_color_based_features (m_features, m_color); - if (echo) - m_generator->generate_echo_based_features (m_features, echo_map); + m_generator->generate_color_based_features (m_features, m_color.value()); + if (echo_map) + m_generator->generate_echo_based_features (m_features, echo_map.value()); #ifdef CGAL_LINKED_WITH_TBB m_features.end_parallel_additions(); @@ -709,7 +703,7 @@ void Point_set_item_classification::train(int classifier, const QMultipleInputDi for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - training[*it] = m_training[*it]; + training[*it] = m_training.value()[*it]; if (training[*it] != -1) { nb_label[std::size_t(training[*it])] ++; @@ -758,7 +752,7 @@ void Point_set_item_classification::train(int classifier, const QMultipleInputDi for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) - m_classif[*it] = indices[*it]; + m_classif.value()[*it] = indices[*it]; if (m_index_color == 1 || m_index_color == 2) change_color (m_index_color); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h index f52e2438aab..0b0f21e96f6 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Point_set_item_classification.h @@ -47,13 +47,9 @@ class Point_set_item_classification : public Item_classification_base Point_set::Property_map cluster_id; std::vector* clusters; - Cluster_neighborhood (Point_set* point_set, - std::vector& clusters) - : point_set (point_set) - , clusters (&clusters) - { - cluster_id = point_set->property_map("shape").first; - } + Cluster_neighborhood(Point_set* point_set, + std::vector& clusters) + : point_set(point_set), clusters(&clusters), cluster_id(point_set->add_property_map("shape").first) {} template OutputIterator operator() (const Point_set::Index& idx, @@ -147,18 +143,16 @@ class Point_set_item_classification : public Item_classification_base bool try_adding_simple_feature (const std::string& name) { typedef typename Point_set::template Property_map Pmap; - bool okay = false; - Pmap pmap; - boost::tie (pmap, okay) = m_points->point_set()->template property_map(name.c_str()); - if (okay) + auto pmap = m_points->point_set()->template property_map(name.c_str()); + if (pmap) { std::cerr << "Adding property<" << CGAL::demangle(typeid(Type).name()) << ">(" << name << ") as feature" << std::endl; m_features.template add > - (*(m_points->point_set()), pmap, name.c_str()); + (*(m_points->point_set()), pmap.value(), name.c_str()); } - return okay; + return pmap.has_value(); } void add_selection_to_training_set (std::size_t label) @@ -166,8 +160,8 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) { - m_training[*it] = int(label); - m_classif[*it] = int(label); + m_training.value()[*it] = int(label); + m_classif.value()[*it] = int(label); } m_points->resetSelection(); @@ -178,8 +172,8 @@ class Point_set_item_classification : public Item_classification_base { for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) - if (m_training[*it] == int(label)) - m_training[*it] = -1; + if (m_training.value()[*it] == int(label)) + m_training.value()[*it] = -1; if (m_index_color == 1 || m_index_color == 2) change_color (m_index_color); } @@ -188,8 +182,8 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) { - m_training[*it] = -1; - m_classif[*it] = -1; + m_training.value()[*it] = -1; + m_classif.value()[*it] = -1; } if (m_index_color == 1 || m_index_color == 2) change_color (m_index_color); @@ -198,7 +192,7 @@ class Point_set_item_classification : public Item_classification_base { for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) - m_training[*it] = -1; + m_training.value()[*it] = -1; if (m_index_color == 1 || m_index_color == 2) change_color (m_index_color); } @@ -206,7 +200,7 @@ class Point_set_item_classification : public Item_classification_base { for (Point_set::const_iterator it = m_points->point_set()->first_selected(); it != m_points->point_set()->end(); ++ it) - m_training[*it] = m_classif[*it]; + m_training.value()[*it] = m_classif.value()[*it]; m_points->resetSelection(); if (m_index_color == 1 || m_index_color == 2) @@ -229,7 +223,7 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int c = m_classif[*it]; + int c = m_classif.value()[*it]; if (c == label) points_item->point_set()->insert (m_points->point_set()->point(*it)); } @@ -251,7 +245,7 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - int c = m_classif[*it]; + int c = m_classif.value()[*it]; if (c != -1) points_item[c]->point_set()->insert (m_points->point_set()->point(*it)); } @@ -271,15 +265,15 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->end(); ++ it) { - if (m_training[*it] == int(position)) - m_training[*it] = -1; - else if (m_training[*it] > int(position)) - m_training[*it] --; + if (m_training.value()[*it] == int(position)) + m_training.value()[*it] = -1; + else if (m_training.value()[*it] > int(position)) + m_training.value()[*it] --; - if (m_classif[*it] == int(position)) - m_classif[*it] = -1; - else if (m_classif[*it] > int(position)) - m_classif[*it] --; + if (m_classif.value()[*it] == int(position)) + m_classif.value()[*it] = -1; + else if (m_classif.value()[*it] > int(position)) + m_classif.value()[*it] --; } update_comments_of_point_set_item(); } @@ -364,8 +358,8 @@ class Point_set_item_classification : public Item_classification_base for (Point_set::const_iterator it = m_points->point_set()->begin(); it != m_points->point_set()->first_selected(); ++ it) { - m_classif[*it] = indices[*it]; - ground_truth[*it] = m_training[*it]; + m_classif.value()[*it] = indices[*it]; + ground_truth[*it] = m_training.value()[*it]; } if (m_index_color == 1 || m_index_color == 2) @@ -396,14 +390,11 @@ class Point_set_item_classification : public Item_classification_base std::vector m_clusters; - Point_set::Property_map m_red; - Point_set::Property_map m_green; - Point_set::Property_map m_blue; - Point_set::Property_map m_color; + std::optional> m_color; std::vector > m_label_probabilities; - Point_set::Property_map m_training; - Point_set::Property_map m_classif; + std::optional> m_training; + std::optional> m_classif; Generator* m_generator; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp index 4880c0917db..00a9e29a532 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.cpp @@ -15,13 +15,13 @@ Surface_mesh_item_classification::Surface_mesh_item_classification(Scene_surface_mesh_item* mesh) : m_mesh (mesh), m_selection (nullptr), - m_generator (nullptr) + m_generator (nullptr), + m_training(m_mesh->polyhedron()->add_property_map("f:training", std::size_t(-1)).first), + m_classif(m_mesh->polyhedron()->add_property_map("f:label", std::size_t(-1)).first) { m_index_color = 1; backup_existing_colors_and_add_new(); - m_training = m_mesh->polyhedron()->add_property_map("f:training", std::size_t(-1)).first; - m_classif = m_mesh->polyhedron()->add_property_map("f:label", std::size_t(-1)).first; m_labels.add("ground"); m_labels.add("vegetation"); @@ -64,8 +64,8 @@ void Surface_mesh_item_classification::backup_existing_colors_and_add_new() = m_mesh->polyhedron()->add_property_map("f:real_color").first; for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) { - m_real_color[fd] = m_color[fd]; - m_color[fd] = CGAL::IO::Color(128, 128, 128); + m_real_color.value()[fd] = m_color.value()[fd]; + m_color.value()[fd] = CGAL::IO::Color(128, 128, 128); } } else @@ -77,7 +77,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo { m_index_color = index; int index_color = index; - if (index == 0 && m_real_color == Mesh::Property_map()) + if (index == 0 && !m_real_color) index_color = -1; static Color_ramp ramp; @@ -86,12 +86,12 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo if (index_color == -1) // item color { for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) - m_color[fd] = CGAL::IO::Color(128,128,128); + m_color.value()[fd] = CGAL::IO::Color(128,128,128); } else if (index_color == 0) // real colors { for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) - m_color[fd] = m_real_color[fd]; + m_color.value()[fd] = m_real_color.value()[fd]; } else if (index_color == 1) // classif { @@ -103,7 +103,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo if (c != std::size_t(-1)) color = label_qcolor (m_labels[c]); - m_color[fd] = CGAL::IO::Color(color.red(), color.green(), color.blue()); + m_color.value()[fd] = CGAL::IO::Color(color.red(), color.green(), color.blue()); } } else if (index_color == 2) // training @@ -120,7 +120,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo float div = 1; if (c != c2) div = 2; - m_color[fd] = CGAL::IO::Color(color.red() / div, + m_color.value()[fd] = CGAL::IO::Color(color.red() / div, color.green() / div, color.blue() / div); } @@ -135,7 +135,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo { for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) { - m_color[fd] = CGAL::IO::Color((unsigned char)(128), + m_color.value()[fd] = CGAL::IO::Color((unsigned char)(128), (unsigned char)(128), (unsigned char)(128)); } @@ -145,7 +145,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo for(face_descriptor fd : faces(*(m_mesh->polyhedron()))) { float v = (std::max) (0.f, (std::min)(1.f, m_label_probabilities[corrected_index][fd])); - m_color[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255), + m_color.value()[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255), (unsigned char)(ramp.g(v) * 255), (unsigned char)(ramp.b(v) * 255)); } @@ -189,7 +189,7 @@ void Surface_mesh_item_classification::change_color (int index, float* vmin, flo if (v < 0.f) v = 0.f; if (v > 1.f) v = 1.f; - m_color[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255), + m_color.value()[fd] = CGAL::IO::Color((unsigned char)(ramp.r(v) * 255), (unsigned char)(ramp.g(v) * 255), (unsigned char)(ramp.b(v) * 255)); } diff --git a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h index 797e88de438..df71c098b74 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h +++ b/Polyhedron/demo/Polyhedron/Plugins/Classification/Surface_mesh_item_classification.h @@ -200,8 +200,9 @@ protected: Scene_polyhedron_selection_item* m_selection; Mesh::Property_map m_training; Mesh::Property_map m_classif; - Mesh::Property_map m_color; - Mesh::Property_map m_real_color; + + std::optional> m_color; + std::optional> m_real_color; std::vector > m_label_probabilities; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Display/Heat_method_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Display/Heat_method_plugin.cpp index fc6d564379b..c5cffdac60b 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Display/Heat_method_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Display/Heat_method_plugin.cpp @@ -730,11 +730,9 @@ private: return; // Here we only target the property maps added by this plugin, so 'double' is fine - SMesh::Property_map property; - bool found; - std::tie(property, found) = sm->property_map(property_name); - if(found) - sm->remove_property_map(property); + auto property = sm->get_property_map(property_name); + if(property) + sm->remove_property_map(property.value()); } void removePluginProperties(Scene_item* item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp index 9257317215e..c17f4879f1d 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Mesh_3_plugin.cpp @@ -1035,7 +1035,7 @@ treat_result(Scene_item& source_item, float((bbox.ymin() + bbox.ymax())/2.f), float((bbox.zmin() + bbox.zmax())/2.f)); - result_item->setColor(default_mesh_color); + result_item->setColor(source_item.color()); result_item->setRenderingMode(source_item.renderingMode()); result_item->set_data_item(&source_item); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_advancing_front_impl.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_advancing_front_impl.cpp index a8c93069b29..38dffa910f2 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_advancing_front_impl.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_advancing_front_impl.cpp @@ -19,9 +19,8 @@ struct Construct{ template Construct(SMesh& mesh, const PointRange& points) - : mesh(mesh) + : mesh(mesh), vpmap(get(boost::vertex_point, mesh)) { - vpmap = get(boost::vertex_point, mesh); for (const auto& p : points) { typename boost::graph_traits::vertex_descriptor v; @@ -192,8 +191,7 @@ SMesh* advancing_front (const Point_set& points, if (structuring) // todo { - Point_set::Property_map shape_map - = points.property_map("shape").first; + auto shape_map = points.property_map("shape").value(); typedef CGAL::Point_set_with_structure Structuring; std::vector planes; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_polygonal_impl.cpp b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_polygonal_impl.cpp index 3e320160372..8e075d26ce4 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_polygonal_impl.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Point_set/Surface_reconstruction_polygonal_impl.cpp @@ -26,11 +26,9 @@ SMesh* polygonal_reconstruct (const Point_set& points, CGAL_USE (model_complexity); CGAL_USE (solver_name); - Point_set::Property_map shape_map - = points.property_map("shape").first; + auto shape_map = points.property_map("shape").value(); - Polygonal_surface_reconstruction poly - (points, points.point_map(), points.normal_map(), shape_map); + Polygonal_surface_reconstruction poly(points, points.point_map(), points.normal_map(), shape_map); SMesh* mesh = new SMesh; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp index fffd332a832..596a315eb74 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Surface_mesh/Parameterization_plugin.cpp @@ -269,10 +269,9 @@ public : pen.setWidth(0); painter->setPen(pen); painter->setBrush(brush); - SMesh::Property_map u,v; - u = graph->add_property_map("h:u", 0.0f).first; - v = graph->add_property_map("h:v", 0.0f).first; + auto u = graph->add_property_map("h:u", 0.0f).first; + auto v = graph->add_property_map("h:v", 0.0f).first; for( Component::iterator fi = components->at(m_current_component).begin(); @@ -926,11 +925,8 @@ void Polyhedron_demo_parameterization_plugin::parameterize(const Parameterizatio QApplication::restoreOverrideCursor(); QPointF pmin(FLT_MAX, FLT_MAX), pmax(-FLT_MAX, -FLT_MAX); - SMesh::Property_map umap; - SMesh::Property_map vmap; - - umap = tMesh.add_property_map("h:u", 0.0f).first; - vmap = tMesh.add_property_map("h:v", 0.0f).first; + auto umap = tMesh.add_property_map("h:u", 0.0f).first; + auto vmap = tMesh.add_property_map("h:v", 0.0f).first; tMesh.property_stats(std::cerr); Base_face_graph::Halfedge_iterator it; diff --git a/Polyhedron/demo/Polyhedron/Scene_image_item.cpp b/Polyhedron/demo/Polyhedron/Scene_image_item.cpp index d98a21abba0..bdcf80a5091 100644 --- a/Polyhedron/demo/Polyhedron/Scene_image_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_image_item.cpp @@ -24,7 +24,7 @@ template class Image_accessor { public: - Image_accessor(const Image& im, int dx=1, int dy=1, int dz=1); + Image_accessor(const Image& im, int dx=1, int dy=1, int dz=1, const QColor& default_color = QColor()); bool is_vertex_active(std::size_t i, std::size_t j, std::size_t k) const; const QColor& vertex_color(std::size_t i, std::size_t j, std::size_t k) const; @@ -64,12 +64,12 @@ private: }; template -Image_accessor::Image_accessor(const Image& im, int dx, int dy, int dz) +Image_accessor::Image_accessor(const Image& im, int dx, int dy, int dz, const QColor& default_color) : im_(&im) , dx_(dx) , dy_(dy) , dz_(dz) -, default_color_() +, default_color_(default_color) , colors_() { const std::size_t xdim = im_->xdim(); @@ -88,14 +88,15 @@ Image_accessor::Image_accessor(const Image& im, int dx, int dy, int d } } - double i=0; - const double starting_hue = 45./360.; // magenta + const double nb_Colors = colors_.size()+1; + double i=1; + const double starting_hue = default_color.hueF(); for ( auto it = colors_.begin(), end = colors_.end() ; it != end ; ++it, i += 1.) { - double hue = starting_hue + 1./double(colors_.size()) * i; + double hue = starting_hue + 1./nb_Colors * i; if ( hue > 1. ) { hue -= 1.; } - it->second = QColor::fromHsvF(hue, .75, .75); + it->second = QColor::fromHsvF(hue, default_color.saturationF(), default_color.valueF()); } } @@ -762,6 +763,11 @@ void Scene_image_item::drawEdges(Viewer_interface *viewer) const bool Scene_image_item::isGray() { return d->is_hidden;} +void Scene_image_item::setColor(QColor c) { + color_ = c; + invalidateOpenGLBuffers(); +} + void Scene_image_item::invalidateOpenGLBuffers() { setBuffersFilled(false); @@ -788,9 +794,9 @@ void Scene_image_item::initializeBuffers(Viewer_interface *v) const template internal::Vertex_buffer_helper* -init_helper(const Image &im, int dx, int dy, int dz, bool is_ogl_4_3) +init_helper(const Image &im, int dx, int dy, int dz, bool is_ogl_4_3, const QColor& default_color = QColor()) { - internal::Image_accessor image_data_accessor(im, dx, dy, dz); + internal::Image_accessor image_data_accessor(im, dx, dy, dz, default_color); return new internal::Vertex_buffer_helper_impl(std::move(image_data_accessor), is_ogl_4_3); } @@ -809,7 +815,8 @@ void Scene_image_item::computeElements() const CGAL_IMAGE_IO_CASE(m_image->image(), d->helper = init_helper(*m_image, d->m_voxel_scale, d->m_voxel_scale, d->m_voxel_scale, - d->is_ogl_4_3)); + d->is_ogl_4_3, + color_)); d->helper->fill_buffer_data(); getTriangleContainer(0)->allocate( Tc::Smooth_vertices, diff --git a/Polyhedron/demo/Polyhedron/Scene_image_item.h b/Polyhedron/demo/Polyhedron/Scene_image_item.h index 1dffd5ba32d..30f2ba1eb8f 100644 --- a/Polyhedron/demo/Polyhedron/Scene_image_item.h +++ b/Polyhedron/demo/Polyhedron/Scene_image_item.h @@ -50,6 +50,8 @@ public: float sigma_weights() const; float default_sigma_weights() const; + void setColor(QColor c); + void invalidateOpenGLBuffers(); void initializeBuffers(Viewer_interface *) const; void computeElements() const; diff --git a/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp b/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp index 7dc8c51f1ce..91e88fb6ae2 100644 --- a/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_triangulation_3_item.cpp @@ -442,6 +442,7 @@ struct Scene_triangulation_3_item_priv { typedef std::set Indices; Indices surface_patch_indices_; Indices subdomain_indices_; + std::unordered_map visible_surface_patch_to_subdomain; std::unordered_map id_to_compact; QSlider* tet_Slider; bool is_filterable; @@ -643,6 +644,7 @@ Scene_triangulation_3_item::triangulation_changed() // Fill indices map and get max subdomain value d->surface_patch_indices_.clear(); d->subdomain_indices_.clear(); + d->visible_surface_patch_to_subdomain.clear(); d->visible_subdomain.clear(); d->id_to_compact.clear(); @@ -664,7 +666,18 @@ Scene_triangulation_3_item::triangulation_changed() end = triangulation().finite_facets_end(); fit != end; ++fit) { max = (std::max)(max, fit->first->surface_patch_index(fit->second)); - d->surface_patch_indices_.insert(fit->first->surface_patch_index(fit->second)); + int index = fit->first->surface_patch_index(fit->second); + d->surface_patch_indices_.insert(index); + int dom0 = fit->first->subdomain_index(); + int dom1 = fit->first->neighbor(fit->second)->subdomain_index(); + if (dom0 == 0) // if cell is not in complex + { + d->visible_surface_patch_to_subdomain[index] = dom1; + } + else if (dom1 == 0) // if opposite cell is not in complex + { + d->visible_surface_patch_to_subdomain[index] = dom0; + } } d->colors.resize(max + 1); @@ -882,12 +895,19 @@ Scene_triangulation_3_item_priv::compute_color_map(const QColor& c) } const size_type nb_patch_indices = surface_patch_indices_.size(); i = 0; + double patch_hsv_value = fmod(c.valueF() + .5, 1.); for (Indices::iterator it = surface_patch_indices_.begin(), end = surface_patch_indices_.end(); it != end; ++it, i += 1.) { double hue = c.hueF() + 1. / double(nb_patch_indices) * i; if (hue > 1) { hue -= 1.; } - colors[*it] = QColor::fromHsvF(hue, c.saturationF(), c.valueF()); + colors[*it] = QColor::fromHsvF(hue, c.saturationF(), patch_hsv_value); + } + + for (std::unordered_map::iterator it = visible_surface_patch_to_subdomain.begin(), + end = visible_surface_patch_to_subdomain.end(); it != end; ++it) + { + colors[it->first] = colors_subdomains[it->second]; } } diff --git a/Polyhedron/demo/Polyhedron/include/Point_set_3.h b/Polyhedron/demo/Polyhedron/include/Point_set_3.h index 64f5a31be31..c3b00ac3258 100644 --- a/Polyhedron/demo/Polyhedron/include/Point_set_3.h +++ b/Polyhedron/demo/Polyhedron/include/Point_set_3.h @@ -295,17 +295,17 @@ public: void set_color (const Index& index, const QColor& color) { - m_red[index] = color.red(); - m_green[index] = color.green(); - m_blue[index] = color.blue(); + m_red.value()[index] = color.red(); + m_green.value()[index] = color.green(); + m_blue.value()[index] = color.blue(); } template void set_color (const Index& index, const ColorRange& color) { - m_red[index] = color[0]; - m_green[index] = color[1]; - m_blue[index] = color[2]; + m_red.value()[index] = color[0]; + m_green.value()[index] = color[1]; + m_blue.value()[index] = color[2]; } diff --git a/Spatial_searching/include/CGAL/Search_traits_adapter.h b/Spatial_searching/include/CGAL/Search_traits_adapter.h index ff640dc639a..a43dca7bd30 100644 --- a/Spatial_searching/include/CGAL/Search_traits_adapter.h +++ b/Spatial_searching/include/CGAL/Search_traits_adapter.h @@ -66,13 +66,15 @@ struct Get_iso_box_d template class Search_traits_adapter : public Base_traits{ - PointPropertyMap ppmap; + std::optional ppmap; public: typedef Base_traits Base; typedef typename internal::Get_iso_box_d::type Iso_box_d; - Search_traits_adapter(const PointPropertyMap& ppmap_=PointPropertyMap(), + Search_traits_adapter() {} + + Search_traits_adapter(const PointPropertyMap& ppmap_, const Base_traits& base=Base_traits() ):Base_traits(base),ppmap(ppmap_){} @@ -246,28 +248,30 @@ public: } Iso_box_d operator() (const Point_with_info& p, const Point_with_info& q) const { - return Base_functor::operator() (get(ppmap,p),get(ppmap,q)); + return Base_functor::operator() (get(ppmap.value(),p),get(ppmap.value(),q)); } }; - const PointPropertyMap& point_property_map() const {return ppmap;} + const PointPropertyMap& point_property_map() const {return ppmap.value();} Construct_cartesian_const_iterator_d construct_cartesian_const_iterator_d_object() const { return Construct_cartesian_const_iterator_d( Base::construct_cartesian_const_iterator_d_object(), - ppmap); + ppmap.value()); } }; template class Distance_adapter : public Base_distance { - PointPropertyMap ppmap; + std::optional ppmap; public: - Distance_adapter( const PointPropertyMap& ppmap_=PointPropertyMap(), - const Base_distance& distance=Base_distance() - ):Base_distance(distance),ppmap(ppmap_){} + Distance_adapter() {} + + Distance_adapter(const PointPropertyMap& ppmap_, + const Base_distance& distance = Base_distance()) + : Base_distance(distance), ppmap(ppmap_) {} using Base_distance::transformed_distance; @@ -275,11 +279,11 @@ public: typedef Point_with_info Point_d; typedef typename Base_distance::Query_item Query_item; - const PointPropertyMap& point_property_map() const {return ppmap;} + const PointPropertyMap& point_property_map() const {return ppmap.value();} FT transformed_distance(const Query_item& p1, const Point_with_info& p2) const { - return Base_distance::transformed_distance(p1,get(ppmap,p2)); + return Base_distance::transformed_distance(p1,get(ppmap.value(),p2)); } template diff --git a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h index 9b0acad0868..7411c8889ee 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h @@ -59,7 +59,7 @@ namespace CGAL { class SM_Index { public: - typedef std::uint32_t size_type; + typedef std::uint32_t size_type; /// Constructor. %Default construction creates an invalid index. /// We write -1, which is /// (std::numeric_limits::max)() @@ -341,7 +341,6 @@ class Surface_mesh public: #ifndef DOXYGEN_RUNNING - template using Property_container = Properties::Property_container; @@ -353,299 +352,311 @@ public: #endif // DOXYGEN_RUNNING - /// \name Basic Types - /// - ///@{ + /// \name Basic Types + /// + ///@{ - /// The point type. - typedef P Point; + /// The point type. + typedef P Point; - /// The type used to represent an index. - typedef std::uint32_t size_type; + /// The type used to represent an index. + typedef std::uint32_t size_type; - ///@} + ///@} - /// \name Basic Elements - /// - ///@{ + /// \name Basic Elements + /// + ///@{ #ifdef DOXYGEN_RUNNING - /// This class represents a vertex. - /// \cgalModels{Index,LessThanComparable,Hashable} - /// \sa `Halfedge_index`, `Edge_index`, `Face_index` - class Vertex_index - { - public: - /// %Default constructor. - Vertex_index(){} + /// This class represents a vertex. + /// \cgalModels{Index,LessThanComparable,Hashable} + /// \sa `Halfedge_index`, `Edge_index`, `Face_index` + class Vertex_index + { + public: + /// %Default constructor. + Vertex_index(){} - Vertex_index(size_type _idx){} + Vertex_index(size_type _idx){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Vertex_index const& v) - {} - }; + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Vertex_index const& v) + {} + }; #else typedef SM_Vertex_index Vertex_index; #endif #ifdef DOXYGEN_RUNNING - /// This class represents a halfedge. - /// \cgalModels{Index,LessThanComparable,Hashable} - /// \sa `Vertex_index`, `Edge_index`, `Face_index` - class Halfedge_index - { - public: - /// %Default constructor - Halfedge_index(){} + /// This class represents a halfedge. + /// \cgalModels{Index,LessThanComparable,Hashable} + /// \sa `Vertex_index`, `Edge_index`, `Face_index` + class Halfedge_index + { + public: + /// %Default constructor + Halfedge_index(){} - Halfedge_index(size_type _idx){} + Halfedge_index(size_type _idx){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Halfedge_index const& h) - { - } + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Halfedge_index const& h) + { + } - }; + }; #else typedef SM_Halfedge_index Halfedge_index; #endif #ifdef DOXYGEN_RUNNING - /// This class represents a face - /// \cgalModels{Index,LessThanComparable,Hashable} - /// \sa `Vertex_index`, `Halfedge_index`, `Edge_index` - class Face_index - { - public: - /// %Default constructor - Face_index(){} + /// This class represents a face + /// \cgalModels{Index,LessThanComparable,Hashable} + /// \sa `Vertex_index`, `Halfedge_index`, `Edge_index` + class Face_index + { + public: + /// %Default constructor + Face_index(){} - Face_index(size_type _idx){} + Face_index(size_type _idx){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Face_index const& f) - {} - }; + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Face_index const& f) + {} + }; #else typedef SM_Face_index Face_index; #endif #ifdef DOXYGEN_RUNNING - /// This class represents an edge. - /// \cgalModels{Index,LessThanComparable,Hashable} - /// \sa `Vertex_index`, `Halfedge_index`, `Face_index` - class Edge_index - { - public: - /// %Default constructor - Edge_index(){} + /// This class represents an edge. + /// \cgalModels{Index,LessThanComparable,Hashable} + /// \sa `Vertex_index`, `Halfedge_index`, `Face_index` + class Edge_index + { + public: + /// %Default constructor + Edge_index(){} - Edge_index(size_type idx){} + Edge_index(size_type idx){} - /// constructs an `Edge_index` from a halfedge. - Edge_index(Halfedge_index he){} + /// constructs an `Edge_index` from a halfedge. + Edge_index(Halfedge_index he){} - /// prints the index and a short identification string to an ostream. - friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Edge_index const& e) - {} - }; + /// prints the index and a short identification string to an ostream. + friend std::ostream& operator<<(std::ostream& os, typename Surface_mesh::Edge_index const& e) + {} + }; #else typedef SM_Edge_index Edge_index; #endif - ///@} + ///@} #ifndef CGAL_TEST_SURFACE_MESH private: //-------------------------------------------------- connectivity types #endif - /// This type stores the vertex connectivity - /// \sa `Halfedge_connectivity`, `Face_connectivity` - struct Vertex_connectivity { - /// an incoming halfedge per vertex (it will be a border halfedge for border vertices) - Halfedge_index halfedge_; - }; + /// This type stores the vertex connectivity + /// \sa `Halfedge_connectivity`, `Face_connectivity` + struct Vertex_connectivity + { + /// an incoming halfedge per vertex (it will be a border halfedge for border vertices) + Halfedge_index halfedge_; + }; - /// This type stores the halfedge connectivity - /// \sa `Vertex_connectivity`, `Face_connectivity` - struct Halfedge_connectivity { - /// face incident to halfedge - Face_index face_; - /// vertex the halfedge points to - Vertex_index vertex_; - /// next halfedge within a face (or along a border) - Halfedge_index next_halfedge_; - /// previous halfedge within a face (or along a border) - Halfedge_index prev_halfedge_; - }; + /// This type stores the halfedge connectivity + /// \sa `Vertex_connectivity`, `Face_connectivity` + struct Halfedge_connectivity + { + /// face incident to halfedge + Face_index face_; + /// vertex the halfedge points to + Vertex_index vertex_; + /// next halfedge within a face (or along a border) + Halfedge_index next_halfedge_; + /// previous halfedge within a face (or along a border) + Halfedge_index prev_halfedge_; + }; - /// This type stores the face connectivity - /// \sa `Vertex_connectivity`, `Halfedge_connectivity` - struct Face_connectivity { - /// a halfedge that is part of the face - Halfedge_index halfedge_; - }; + /// This type stores the face connectivity + /// \sa `Vertex_connectivity`, `Halfedge_connectivity` + struct Face_connectivity + { + /// a halfedge that is part of the face + Halfedge_index halfedge_; + }; private: //------------------------------------------------------ iterator types - template - class Index_iterator - : public boost::iterator_facade, - Index_, - std::random_access_iterator_tag, - Index_ - > { - typedef boost::iterator_facade, - Index_, - std::random_access_iterator_tag, - Index_> Facade; - public: - Index_iterator() : hnd_(), mesh_(nullptr) {} - - Index_iterator(const Index_& h, const Surface_mesh* m) - : hnd_(h), mesh_(m) { - if (mesh_ && mesh_->has_garbage()) { - while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; - } - } - - private: - friend class boost::iterator_core_access; - - void increment() { - ++hnd_; - CGAL_assertion(mesh_ != nullptr); - - if (mesh_->has_garbage()) - while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; - } - - void decrement() { - --hnd_; - CGAL_assertion(mesh_ != nullptr); - if (mesh_->has_garbage()) - while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) --hnd_; - } - - void advance(std::ptrdiff_t n) { - CGAL_assertion(mesh_ != nullptr); - - if (mesh_->has_garbage()) { - if (n > 0) - for (std::ptrdiff_t i = 0; i < n; ++i) - increment(); - else - for (std::ptrdiff_t i = 0; i < -n; ++i) - decrement(); - } else - hnd_ += n; - } - - std::ptrdiff_t distance_to(const Index_iterator& other) const { - if (mesh_->has_garbage()) { - bool forward = (other.hnd_ > hnd_); - - std::ptrdiff_t out = 0; - Index_iterator it = *this; - while (!it.equal(other)) { - if (forward) { - ++it; - ++out; - } else { - --it; - --out; + template + class Index_iterator + : public boost::iterator_facade< Index_iterator, + Index_, + std::random_access_iterator_tag, + Index_ + > + { + typedef boost::iterator_facade< Index_iterator, + Index_, + std::random_access_iterator_tag, + Index_> Facade; + public: + Index_iterator() : hnd_(), mesh_(nullptr) {} + Index_iterator(const Index_& h, const Surface_mesh* m) + : hnd_(h), mesh_(m) { + if (mesh_ && mesh_->has_garbage()){ + while (mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; } } - return out; - } + private: + friend class boost::iterator_core_access; + void increment() + { + ++hnd_; + CGAL_assertion(mesh_ != nullptr); - // else - return std::ptrdiff_t(other.hnd_) - std::ptrdiff_t(this->hnd_); - } + if(mesh_->has_garbage()) + while ( mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) ++hnd_; + } - bool equal(const Index_iterator& other) const { - return this->hnd_ == other.hnd_; - } + void decrement() + { + --hnd_; + CGAL_assertion(mesh_ != nullptr); + if(mesh_->has_garbage()) + while ( mesh_->has_valid_index(hnd_) && mesh_->is_removed(hnd_)) --hnd_; + } - Index_ dereference() const { return hnd_; } + void advance(std::ptrdiff_t n) + { + CGAL_assertion(mesh_ != nullptr); - Index_ hnd_; - const Surface_mesh* mesh_; + if (mesh_->has_garbage()) + { + if (n > 0) + for (std::ptrdiff_t i = 0; i < n; ++ i) + increment(); + else + for (std::ptrdiff_t i = 0; i < -n; ++ i) + decrement(); + } + else + hnd_ += n; + } - }; + std::ptrdiff_t distance_to(const Index_iterator& other) const + { + if (mesh_->has_garbage()) + { + bool forward = (other.hnd_ > hnd_); + std::ptrdiff_t out = 0; + Index_iterator it = *this; + while (!it.equal(other)) + { + if (forward) + { + ++ it; + ++ out; + } + else + { + -- it; + -- out; + } + } + return out; + } + + // else + return std::ptrdiff_t(other.hnd_) - std::ptrdiff_t(this->hnd_); + } + + bool equal(const Index_iterator& other) const + { + return this->hnd_ == other.hnd_; + } + + Index_ dereference() const { return hnd_; } + + Index_ hnd_; + const Surface_mesh* mesh_; + + }; public: - /// \name Range Types - /// - /// Each range `R` in this section has a nested type `R::iterator`, - /// is convertible to `std::pair`, so that one can use `boost::tie()`, - /// and can be used with `BOOST_FOREACH()`, as well as with the C++11 range based for-loop. + /// \name Range Types + /// + /// Each range `R` in this section has a nested type `R::iterator`, + /// is convertible to `std::pair`, so that one can use `boost::tie()`, + /// and can be used with `BOOST_FOREACH()`, as well as with the C++11 range based for-loop. - ///@{ + ///@{ #ifndef DOXYGEN_RUNNING - typedef Index_iterator Vertex_iterator; + typedef Index_iterator Vertex_iterator; #endif - /// \brief The range over all vertex indices. - /// - /// A model of BidirectionalRange with value type `Vertex_index`. - /// \sa `vertices()` - /// \sa `Halfedge_range`, `Edge_range`, `Face_range` + /// \brief The range over all vertex indices. + /// + /// A model of BidirectionalRange with value type `Vertex_index`. + /// \sa `vertices()` + /// \sa `Halfedge_range`, `Edge_range`, `Face_range` #ifdef DOXYGEN_RUNNING - typedef unspecified_type Vertex_range; + typedef unspecified_type Vertex_range; #else - typedef Iterator_range Vertex_range; + typedef Iterator_range Vertex_range; #endif #ifndef DOXYGEN_RUNNING - typedef Index_iterator Halfedge_iterator; + typedef Index_iterator Halfedge_iterator; #endif - /// \brief The range over all halfedge indices. - /// - /// A model of BidirectionalRange with value type `Halfedge_index`. - /// \sa `halfedges()` - /// \sa `Vertex_range`, `Edge_range`, `Face_range` + /// \brief The range over all halfedge indices. + /// + /// A model of BidirectionalRange with value type `Halfedge_index`. + /// \sa `halfedges()` + /// \sa `Vertex_range`, `Edge_range`, `Face_range` #ifdef DOXYGEN_RUNNING - typedef unspecified_type Halfedge_range; + typedef unspecified_type Halfedge_range; #else - typedef Iterator_range Halfedge_range; + typedef Iterator_range Halfedge_range; #endif #ifndef DOXYGEN_RUNNING - typedef Index_iterator Edge_iterator; + typedef Index_iterator Edge_iterator; #endif - /// \brief The range over all edge indices. - /// - /// A model of BidirectionalRange with value type `Edge_index`. - /// \sa `edges()` - /// \sa `Halfedge_range`, `Vertex_range`, `Face_range` + /// \brief The range over all edge indices. + /// + /// A model of BidirectionalRange with value type `Edge_index`. + /// \sa `edges()` + /// \sa `Halfedge_range`, `Vertex_range`, `Face_range` #ifdef DOXYGEN_RUNNING - typedef unspecified_type Edge_range; + typedef unspecified_type Edge_range; #else - typedef Iterator_range Edge_range; + typedef Iterator_range Edge_range; #endif #ifndef DOXYGEN_RUNNING - typedef Index_iterator Face_iterator; + typedef Index_iterator Face_iterator; #endif - /// \brief The range over all face indices. - /// - /// A model of BidirectionalRange with value type `Face_index`. - /// \sa `faces()` - /// \sa `Vertex_range`, `Halfedge_range`, `Edge_range` -#ifdef DOXYGEN_RUNNING - typedef unspecified_type Face_range; + /// \brief The range over all face indices. + /// + /// A model of BidirectionalRange with value type `Face_index`. + /// \sa `faces()` + /// \sa `Vertex_range`, `Halfedge_range`, `Edge_range` + #ifdef DOXYGEN_RUNNING + typedef unspecified_type Face_range; #else - typedef Iterator_range Face_range; + typedef Iterator_range Face_range; #endif #ifndef DOXYGEN_RUNNING @@ -653,215 +664,229 @@ public: typedef CGAL::Vertex_around_target_iterator Vertex_around_target_iterator; typedef Iterator_range Vertex_around_target_range; - typedef CGAL::Halfedge_around_target_iterator Halfedge_around_target_iterator; + typedef CGAL::Halfedge_around_target_iterator Halfedge_around_target_iterator; typedef Iterator_range Halfedge_around_target_range; - typedef CGAL::Face_around_target_iterator Face_around_target_iterator; + typedef CGAL::Face_around_target_iterator Face_around_target_iterator; typedef Iterator_range Face_around_target_range; - typedef CGAL::Vertex_around_face_iterator Vertex_around_face_iterator; + typedef CGAL::Vertex_around_face_iterator Vertex_around_face_iterator; typedef Iterator_range Vertex_around_face_range; - typedef CGAL::Halfedge_around_face_iterator Halfedge_around_face_iterator; + typedef CGAL::Halfedge_around_face_iterator Halfedge_around_face_iterator; typedef Iterator_range Halfedge_around_face_range; - typedef CGAL::Face_around_face_iterator Face_around_face_iterator; + typedef CGAL::Face_around_face_iterator Face_around_face_iterator; typedef Iterator_range Face_around_face_range; #endif - /// @cond CGAL_BEGIN_END - /// Start iterator for vertices. - Vertex_iterator vertices_begin() const { - return Vertex_iterator(Vertex_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for vertices. + Vertex_iterator vertices_begin() const + { + return Vertex_iterator(Vertex_index(0), this); + } - /// End iterator for vertices. - Vertex_iterator vertices_end() const { - return Vertex_iterator(Vertex_index(number_of_vertices()), this); - } - /// @endcond + /// End iterator for vertices. + Vertex_iterator vertices_end() const + { + return Vertex_iterator(Vertex_index(num_vertices()), this); + } + /// @endcond - /// returns the iterator range of the vertices of the mesh. - Vertex_range vertices() const { - return make_range(vertices_begin(), vertices_end()); - } + /// returns the iterator range of the vertices of the mesh. + Vertex_range vertices() const { + return make_range(vertices_begin(), vertices_end()); + } - /// @cond CGAL_BEGIN_END - /// Start iterator for halfedges. - Halfedge_iterator halfedges_begin() const { - return Halfedge_iterator(Halfedge_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for halfedges. + Halfedge_iterator halfedges_begin() const + { + return Halfedge_iterator(Halfedge_index(0), this); + } - /// End iterator for halfedges. - Halfedge_iterator halfedges_end() const { - return Halfedge_iterator(Halfedge_index(number_of_halfedges()), this); - } - /// @endcond + /// End iterator for halfedges. + Halfedge_iterator halfedges_end() const + { + return Halfedge_iterator(Halfedge_index(num_halfedges()), this); + } + /// @endcond - /// returns the iterator range of the halfedges of the mesh. - Halfedge_range halfedges() const { - return make_range(halfedges_begin(), halfedges_end()); - } + /// returns the iterator range of the halfedges of the mesh. + Halfedge_range halfedges() const { + return make_range(halfedges_begin(), halfedges_end()); + } - /// @cond CGAL_BEGIN_END - /// Start iterator for edges. - Edge_iterator edges_begin() const { - return Edge_iterator(Edge_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for edges. + Edge_iterator edges_begin() const + { + return Edge_iterator(Edge_index(0), this); + } - /// End iterator for edges. - Edge_iterator edges_end() const { - return Edge_iterator(Edge_index(number_of_edges()), this); - } - /// @endcond + /// End iterator for edges. + Edge_iterator edges_end() const + { + return Edge_iterator(Edge_index(num_edges()), this); + } + /// @endcond - /// returns the iterator range of the edges of the mesh. - Edge_range edges() const { - return make_range(edges_begin(), edges_end()); - } + /// returns the iterator range of the edges of the mesh. + Edge_range edges() const + { + return make_range(edges_begin(), edges_end()); + } - /// @cond CGAL_BEGIN_END - /// Start iterator for faces. - Face_iterator faces_begin() const { - return Face_iterator(Face_index(0), this); - } + /// @cond CGAL_BEGIN_END + /// Start iterator for faces. + Face_iterator faces_begin() const + { + return Face_iterator(Face_index(0), this); + } - /// End iterator for faces. - Face_iterator faces_end() const { - return Face_iterator(Face_index(number_of_faces()), this); - } - /// @endcond + /// End iterator for faces. + Face_iterator faces_end() const + { + return Face_iterator(Face_index(num_faces()), this); + } + /// @endcond - /// returns the iterator range of the faces of the mesh. - Face_range faces() const { - return make_range(faces_begin(), faces_end()); - } + /// returns the iterator range of the faces of the mesh. + Face_range faces() const { + return make_range(faces_begin(), faces_end()); + } #ifndef DOXYGEN_RUNNING + /// returns the iterator range for vertices around vertex `target(h)`, starting at `source(h)`. + Vertex_around_target_range vertices_around_target(Halfedge_index h) const + { + return CGAL::vertices_around_target(h,*this); + } - /// returns the iterator range for vertices around vertex `target(h)`, starting at `source(h)`. - Vertex_around_target_range vertices_around_target(Halfedge_index h) const { - return CGAL::vertices_around_target(h, *this); - } + /// returns the iterator range for incoming halfedges around vertex `target(h)`, starting at `h`. + Halfedge_around_target_range halfedges_around_target(Halfedge_index h) const + { + return CGAL::halfedges_around_target(h,*this); + } - /// returns the iterator range for incoming halfedges around vertex `target(h)`, starting at `h`. - Halfedge_around_target_range halfedges_around_target(Halfedge_index h) const { - return CGAL::halfedges_around_target(h, *this); - } + /// returns the iterator range for faces around vertex `target(h)`, starting at `face(h)`. + Face_around_target_range faces_around_target(Halfedge_index h) const + { + return CGAL::faces_around_target(h,*this); + } - /// returns the iterator range for faces around vertex `target(h)`, starting at `face(h)`. - Face_around_target_range faces_around_target(Halfedge_index h) const { - return CGAL::faces_around_target(h, *this); - } + /// returns the iterator range for vertices around face `face(h)`, starting at `target(h)`. + Vertex_around_face_range vertices_around_face(Halfedge_index h) const + { + return CGAL::vertices_around_face(h,*this); + } - /// returns the iterator range for vertices around face `face(h)`, starting at `target(h)`. - Vertex_around_face_range vertices_around_face(Halfedge_index h) const { - return CGAL::vertices_around_face(h, *this); - } + /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. + Halfedge_around_face_range halfedges_around_face(Halfedge_index h) const + { + return CGAL::halfedges_around_face(h,*this); + } - /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. - Halfedge_around_face_range halfedges_around_face(Halfedge_index h) const { - return CGAL::halfedges_around_face(h, *this); - } - - /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. - Face_around_face_range faces_around_face(Halfedge_index h) const { - return CGAL::faces_around_face(h, *this); - } + /// returns the iterator range for halfedges around face `face(h)`, starting at `h`. + Face_around_face_range faces_around_face(Halfedge_index h) const + { + return CGAL::faces_around_face(h,*this); + } #endif - ///@} + ///@} public: #ifndef DOXYGEN_RUNNING - /// \name Circulator Types - /// - /// The following circulators enable to iterate through the elements around a face or vertex. - /// As explained in the \ref SurfaceMeshOrientation "User Manual", we can speak of a - /// *clockwise* or *counterclockwise* - /// traversal, by looking at the surface from the right side. - ///@{ + /// \name Circulator Types + /// + /// The following circulators enable to iterate through the elements around a face or vertex. + /// As explained in the \ref SurfaceMeshOrientation "User Manual", we can speak of a + /// *clockwise* or *counterclockwise* + /// traversal, by looking at the surface from the right side. + ///@{ - /// \brief This class circulates clockwise through all - /// one-ring neighbors of a vertex. - /// A model of `BidirectionalCirculator` with value type `Vertex_index`. - /// \sa `Halfedge_around_target_circulator`, `Face_around_target_circulator` + /// \brief This class circulates clockwise through all + /// one-ring neighbors of a vertex. + /// A model of `BidirectionalCirculator` with value type `Vertex_index`. + /// \sa `Halfedge_around_target_circulator`, `Face_around_target_circulator` typedef CGAL::Vertex_around_target_circulator Vertex_around_target_circulator; - /// \brief This class circulates clockwise through all incident faces of a vertex. - /// A model of `BidirectionalCirculator` with value type `Face_index`. - /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` + /// \brief This class circulates clockwise through all incident faces of a vertex. + /// A model of `BidirectionalCirculator` with value type `Face_index`. + /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` typedef CGAL::Face_around_target_circulator Face_around_target_circulator; - /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as target. - /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. - /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` + /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as target. + /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. + /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` typedef CGAL::Halfedge_around_target_circulator Halfedge_around_target_circulator; - /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as source. - /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. - /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` + /// \brief This class circulates clockwise through all halfedges around a vertex that have this vertex as source. + /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. + /// \sa `Vertex_around_target_circulator`, `Halfedge_around_target_circulator` typedef CGAL::Halfedge_around_source_circulator Halfedge_around_source_circulator; - /// \brief This class circulates counterclockwise through all vertices around a face. - /// A model of `BidirectionalCirculator` with value type `Vertex_index`. + /// \brief This class circulates counterclockwise through all vertices around a face. + /// A model of `BidirectionalCirculator` with value type `Vertex_index`. - typedef CGAL::Vertex_around_face_circulator Vertex_around_face_circulator; + typedef CGAL::Vertex_around_face_circulator Vertex_around_face_circulator; - /// \brief This class circulates counterclockwise through all halfedges around a face. - /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. + /// \brief This class circulates counterclockwise through all halfedges around a face. + /// A model of `BidirectionalCirculator` with value type `Halfedge_index`. - typedef CGAL::Halfedge_around_face_circulator Halfedge_around_face_circulator; + typedef CGAL::Halfedge_around_face_circulator Halfedge_around_face_circulator; - /// \brief This class circulates counterclockwise through all faces around a face. - /// A model of `BidirectionalCirculator` with value type `Face_index`. - /// Note that the face index is the same after `operator++`, if the neighboring faces share - /// several halfedges. + /// \brief This class circulates counterclockwise through all faces around a face. + /// A model of `BidirectionalCirculator` with value type `Face_index`. + /// Note that the face index is the same after `operator++`, if the neighboring faces share + /// several halfedges. - typedef CGAL::Face_around_face_circulator Face_around_face_circulator; + typedef CGAL::Face_around_face_circulator Face_around_face_circulator; /// @} #endif /// @cond CGAL_DOCUMENT_INTERNALS // typedefs which make it easier to write the partial specialisation of boost::graph_traits - typedef Vertex_index vertex_index; - typedef P vertex_property_type; + typedef Vertex_index vertex_index; + typedef P vertex_property_type; typedef Halfedge_index halfedge_index; - typedef Edge_index edge_index; - typedef Face_index face_index; + typedef Edge_index edge_index; + typedef Face_index face_index; - typedef Vertex_iterator vertex_iterator; - typedef Halfedge_iterator halfedge_iterator; - typedef Edge_iterator edge_iterator; - typedef Face_iterator face_iterator; - typedef CGAL::Out_edge_iterator out_edge_iterator; + typedef Vertex_iterator vertex_iterator; + typedef Halfedge_iterator halfedge_iterator; + typedef Edge_iterator edge_iterator; + typedef Face_iterator face_iterator; + typedef CGAL::Out_edge_iterator out_edge_iterator; - typedef boost::undirected_tag directed_category; + typedef boost::undirected_tag directed_category; typedef boost::disallow_parallel_edge_tag edge_parallel_category; struct traversal_category : public virtual boost::bidirectional_graph_tag, public virtual boost::vertex_list_graph_tag, - public virtual boost::edge_list_graph_tag { - }; + public virtual boost::edge_list_graph_tag + {}; typedef size_type vertices_size_type; typedef size_type halfedges_size_type; @@ -869,288 +894,340 @@ public: typedef size_type faces_size_type; typedef size_type degree_size_type; - /// @endcond + /// @endcond public: - /// \name Construction, Destruction, Assignment - /// - /// Copy constructors as well as assignment do also copy simplices marked as removed. - ///@{ + /// \name Construction, Destruction, Assignment + /// + /// Copy constructors as well as assignment do also copy simplices marked as removed. + ///@{ - /// %Default constructor. - Surface_mesh() : - vconn_(vprops_.add_property("v:connectivity")), - hconn_(hprops_.add_property("h:connectivity")), - fconn_(fprops_.add_property("f:connectivity")), - vpoint_(vprops_.add_property("v:point")), - anonymous_property_(0) {} + /// %Default constructor. + Surface_mesh() : + vconn_(vprops_.add_property("v:connectivity")), + hconn_(hprops_.add_property("h:connectivity")), + fconn_(fprops_.add_property("f:connectivity")), + vpoint_(vprops_.add_property("v:point")), + vremoved_(vprops_.add_property("v:removed")), + eremoved_(eprops_.add_property("e:removed")), + fremoved_(fprops_.add_property("f:removed")), + anonymous_property_(0) {} - /// Copy constructor: copies `rhs` to `*this`. Performs a deep copy of all properties. - Surface_mesh(const Surface_mesh& rhs) : - vprops_(rhs.vprops_), - hprops_(rhs.hprops_), - fprops_(rhs.fprops_), - eprops_(rhs.eprops_), - vconn_(vprops_.get_property("v:connectivity")), - vpoint_(vprops_.get_property("v:point")), - hconn_(hprops_.get_property("h:connectivity")), - fconn_(fprops_.get_property("f:connectivity")), - anonymous_property_(0) {} + /// Copy constructor: copies `rhs` to `*this`. Performs a deep copy of all properties. + Surface_mesh(const Surface_mesh& rhs) : + vprops_(rhs.vprops_) + , hprops_(rhs.hprops_) + , fprops_(rhs.fprops_) + , eprops_(rhs.eprops_) + , vpoint_(vprops_.get_property("v:point")) + , vconn_(vprops_.get_property("v:connectivity")) + , hconn_(hprops_.get_property("h:connectivity")) + , fconn_(fprops_.get_property("f:connectivity")) + , vremoved_(vprops_.get_property("v:removed")) + , eremoved_(eprops_.get_property("e:removed")) + , fremoved_(fprops_.get_property("f:removed")) + , removed_vertices_(rhs.removed_vertices_) + , removed_edges_(rhs.removed_edges_) + , removed_faces_(rhs.removed_faces_) + , vertices_freelist_(rhs.vertices_freelist_) + , edges_freelist_(rhs.edges_freelist_) + , faces_freelist_(rhs.faces_freelist_) + , garbage_(rhs.garbage_) + , recycle_(rhs.recycle_) + , anonymous_property_(rhs.anonymous_property_) + {} - /// Move constructor. - Surface_mesh(Surface_mesh&& sm) : - vprops_(std::move(sm.vprops_)), - hprops_(std::move(sm.hprops_)), - eprops_(std::move(sm.eprops_)), - fprops_(std::move(sm.fprops_)), - vconn_(vprops_.get_property("v:connectivity")), - vpoint_(vprops_.get_property("v:point")), - hconn_(hprops_.get_property("h:connectivity")), - fconn_(fprops_.get_property("f:connectivity")), - anonymous_property_(0) {} + /// Move constructor. + Surface_mesh(Surface_mesh&& sm) + : vprops_(std::move(sm.vprops_)) + , hprops_(std::move(sm.hprops_)) + , eprops_(std::move(sm.eprops_)) + , fprops_(std::move(sm.fprops_)) + , vpoint_(vprops_.get_property("v:point")) + , vconn_(vprops_.get_property("v:connectivity")) + , hconn_(hprops_.get_property("h:connectivity")) + , fconn_(fprops_.get_property("f:connectivity")) + , vremoved_(vprops_.get_property("v:removed")) + , eremoved_(eprops_.get_property("e:removed")) + , fremoved_(fprops_.get_property("f:removed")) + , removed_vertices_(std::exchange(sm.removed_vertices_, 0)) + , removed_edges_(std::exchange(sm.removed_edges_, 0)) + , removed_faces_(std::exchange(sm.removed_faces_, 0)) + , vertices_freelist_(std::exchange(sm.vertices_freelist_,(std::numeric_limits::max)())) + , edges_freelist_(std::exchange(sm.edges_freelist_,(std::numeric_limits::max)())) + , faces_freelist_(std::exchange(sm.faces_freelist_,(std::numeric_limits::max)())) + , garbage_(std::exchange(sm.garbage_, false)) + , recycle_(std::exchange(sm.recycle_, true)) + , anonymous_property_(std::exchange(sm.anonymous_property_, 0)) + {} - /// assigns `rhs` to `*this`. Performs a deep copy of all properties. - Surface_mesh& operator=(const Surface_mesh& rhs); + /// assigns `rhs` to `*this`. Performs a deep copy of all properties. + Surface_mesh& operator=(const Surface_mesh& rhs); - /// move assignment - Surface_mesh& operator=(Surface_mesh&& sm) { - vprops_ = std::move(sm.vprops_); - hprops_ = std::move(sm.hprops_); - eprops_ = std::move(sm.eprops_); - fprops_ = std::move(sm.fprops_); - return *this; - } + /// move assignment + Surface_mesh& operator=(Surface_mesh&& sm) + { + // Moving properties also moves their contents without invalidating references + vprops_ = std::move(sm.vprops_); + hprops_ = std::move(sm.hprops_); + eprops_ = std::move(sm.eprops_); + fprops_ = std::move(sm.fprops_); + return *this; + } - /// assigns `rhs` to `*this`. Does not copy custom properties. - //Surface_mesh& assign(const Surface_mesh& rhs); - - ///@} + ///@} public: - /// \name Adding Vertices, Edges, and Faces - ///@{ + /// \name Adding Vertices, Edges, and Faces + ///@{ - /// adds a new vertex, and resizes vertex properties if necessary. - Vertex_index add_vertex() { - if (recycle_) - return vprops_.emplace(); - else - return vprops_.emplace_back(); - } + /// adds a new vertex, and resizes vertex properties if necessary. + Vertex_index add_vertex() + { + size_type inf = (std::numeric_limits::max)(); + if(recycle_ && (vertices_freelist_ != inf)){ + size_type idx = vertices_freelist_; + vertices_freelist_ = (size_type)vconn_[Vertex_index(vertices_freelist_)].halfedge_; + --removed_vertices_; + vremoved_[Vertex_index(idx)] = false; + vprops_.reset(Vertex_index(idx)); + return Vertex_index(idx); + } else { + return Vertex_index(vprops_.emplace_back()); + } + } + + /// adds a new vertex, resizes vertex properties if necessary, + /// and sets the \em point property to `p`. + /// \note Several vertices may have the same point property. + Vertex_index add_vertex(const Point& p) + { + Vertex_index v = add_vertex(); + vpoint_[v] = p; + return v; + } - /// adds a new vertex, resizes vertex properties if necessary, - /// and sets the \em point property to `p`. - /// \note Several vertices may have the same point property. - Vertex_index add_vertex(const Point& p) { - Vertex_index v = add_vertex(); - vpoint_[v] = p; - return v; - } public: - /// adds a new edge, and resizes edge and halfedge properties if necessary. - Halfedge_index add_edge() { + /// adds a new edge, and resizes edge and halfedge properties if necessary. + Halfedge_index add_edge() + { + Halfedge_index h0, h1; + size_type inf = (std::numeric_limits::max)(); + if(recycle_ && (edges_freelist_ != inf)){ + size_type idx = edges_freelist_; + edges_freelist_ = (size_type)hconn_[Halfedge_index(edges_freelist_)].next_halfedge_; + --removed_edges_; + eremoved_[Edge_index(Halfedge_index(idx))] = false; + hprops_.reset(Halfedge_index(idx)); + hprops_.reset(opposite(Halfedge_index(idx))); + eprops_.reset(Edge_index(Halfedge_index(idx))); + return Halfedge_index(idx); + } else { + eprops_.emplace_back(); + return Halfedge_index(hprops_.emplace_group_back(2)); + } + } - // Add properties for a new edge - if (recycle_) - eprops_.emplace(); - else - eprops_.emplace_back(); + /// adds two opposite halfedges, and resizes edge and halfedge properties if necessary. + /// Sets the targets of the halfedge to the given vertices, but does not modify the halfedge + /// associated to the vertices. + /// \note The function does not check whether there is already an edge between the vertices. + /// \returns the halfedge with `v1` as target - // Add properties for a pair of new half-edges - // The new half-edges are placed adjacently, and we return the index of the first - if (recycle_) - return hprops_.emplace_group(2); - else - return hprops_.emplace_group_back(2); - } + Halfedge_index add_edge(Vertex_index v0, Vertex_index v1) + { + CGAL_assertion(v0 != v1); + Halfedge_index h = add_edge(); - /// adds two opposite halfedges, and resizes edge and halfedge properties if necessary. - /// Sets the targets of the halfedge to the given vertices, but does not modify the halfedge - /// associated to the vertices. - /// \note The function does not check whether there is already an edge between the vertices. - /// \returns the halfedge with `v1` as target + set_target(h, v1); + set_target(opposite(h), v0); - Halfedge_index add_edge(Vertex_index v0, Vertex_index v1) { - CGAL_assertion(v0 != v1); - Halfedge_index h = add_edge(); + return h; + } - set_target(h, v1); - set_target(opposite(h), v0); + /// adds a new face, and resizes face properties if necessary. + Face_index add_face() + { + size_type inf = (std::numeric_limits::max)(); + if(recycle_ && (faces_freelist_ != inf)){ + size_type idx = faces_freelist_; + faces_freelist_ = (size_type)fconn_[Face_index(faces_freelist_)].halfedge_; + --removed_faces_; + fprops_.reset(Face_index(idx)); + fremoved_[Face_index(idx)] = false; + return Face_index(idx); + } else { + return Face_index(fprops_.emplace_back()); + } + } - return h; - } - - /// adds a new face, and resizes face properties if necessary. - Face_index add_face() { - if (recycle_) - return fprops_.emplace(); - else - return fprops_.emplace_back(); - } - - /// if possible, adds a new face with vertices from a range with value type `Vertex_index`. - /// The function adds halfedges between successive vertices if they are not yet indicent to halfedges, - /// or updates the connectivity of halfedges already in place. - /// Resizes halfedge, edge, and face properties if necessary. - /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. - template - Face_index add_face(const Range& vertices); + /// if possible, adds a new face with vertices from a range with value type `Vertex_index`. + /// The function adds halfedges between successive vertices if they are not yet indicent to halfedges, + /// or updates the connectivity of halfedges already in place. + /// Resizes halfedge, edge, and face properties if necessary. + /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. + template + Face_index add_face(const Range& vertices); - /// adds a new triangle connecting vertices `v0`, `v1`, `v2`. - /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. - Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2) { - std::array - v = {{v0, v1, v2}}; - return add_face(v); - } + /// adds a new triangle connecting vertices `v0`, `v1`, `v2`. + /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. + Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2) + { + std::array + v = {{v0, v1, v2}}; + return add_face(v); + } - /// adds a new quad connecting vertices `v0`, `v1`, `v2`, `v3`. - /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. - Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2, Vertex_index v3) { - std::array - v = {{v0, v1, v2, v3}}; - return add_face(v); - } + /// adds a new quad connecting vertices `v0`, `v1`, `v2`, `v3`. + /// \returns the face index of the added face, or `Surface_mesh::null_face()` if the face could not be added. + Face_index add_face(Vertex_index v0, Vertex_index v1, Vertex_index v2, Vertex_index v3) + { + std::array + v = {{v0, v1, v2, v3}}; + return add_face(v); + } - ///@} + ///@} - /// \name Low-Level Removal Functions - /// - /// Although the elements are only marked as removed - /// their connectivity and properties should not be used. - /// - /// \warning Functions in this group do not adjust any of - /// connected elements and usually leave the surface mesh in an - /// invalid state. - /// - /// - /// @{ + /// \name Low-Level Removal Functions + /// + /// Although the elements are only marked as removed + /// their connectivity and properties should not be used. + /// + /// \warning Functions in this group do not adjust any of + /// connected elements and usually leave the surface mesh in an + /// invalid state. + /// + /// + /// @{ - /// removes vertex `v` from the halfedge data structure without - /// adjusting anything. - void remove_vertex(Vertex_index v) { - // todo: confirm this behaves correctly - vprops_.erase(v); - } + /// removes vertex `v` from the halfedge data structure without + /// adjusting anything. + void remove_vertex(Vertex_index v) + { + vremoved_[v] = true; ++removed_vertices_; garbage_ = true; + vconn_[v].halfedge_ = Halfedge_index(vertices_freelist_); + vertices_freelist_ = (size_type)v; + } - /// removes the two halfedges corresponding to `e` from the halfedge data structure without - /// adjusting anything. - void remove_edge(Edge_index e) { - // todo: confirm this behaves correctly - eprops_.erase(e); - } + /// removes the two halfedges corresponding to `e` from the halfedge data structure without + /// adjusting anything. + void remove_edge(Edge_index e) + { + eremoved_[e] = true; ++removed_edges_; garbage_ = true; + hconn_[Halfedge_index((size_type)e << 1)].next_halfedge_ = Halfedge_index(edges_freelist_ ); + edges_freelist_ = ((size_type)e << 1); + } - /// removes face `f` from the halfedge data structure without - /// adjusting anything. + /// removes face `f` from the halfedge data structure without + /// adjusting anything. - void remove_face(Face_index f) { - // todo: confirm this behaves correctly - fprops_.erase(f); - } + void remove_face(Face_index f) + { + fremoved_[f] = true; ++removed_faces_; garbage_ = true; + fconn_[f].halfedge_ = Halfedge_index(faces_freelist_); + faces_freelist_ = (size_type)f; + } - ///@} + ///@} - /// \name Memory Management - /// - /// Functions to check the number of elements, the amount of space - /// allocated for elements, and to clear the structure. - ///@{ - -#ifndef DOXYGEN_RUNNING - /// returns the number of used and removed vertices in the mesh. - size_type num_vertices() const { return (size_type) vprops_.size(); } - - /// returns the number of used and removed halfedges in the mesh. - size_type num_halfedges() const { return (size_type) hprops_.size(); } - - /// returns the number of used and removed edges in the mesh. - size_type num_edges() const { return (size_type) eprops_.size(); } - - /// returns the number of used and removed faces in the mesh. - size_type num_faces() const { return (size_type) fprops_.size(); } - -#endif + /// \name Memory Management + /// + /// Functions to check the number of elements, the amount of space + /// allocated for elements, and to clear the structure. + ///@{ /// returns the number of vertices in the mesh. - size_type number_of_vertices() const { - return vprops_.size(); + size_type number_of_vertices() const + { + return num_vertices() - number_of_removed_vertices(); } /// returns the number of halfedges in the mesh. - size_type number_of_halfedges() const { - return hprops_.size(); + size_type number_of_halfedges() const + { + return num_halfedges() - number_of_removed_halfedges(); } /// returns the number of edges in the mesh. - size_type number_of_edges() const { - return eprops_.size(); + size_type number_of_edges() const + { + return num_edges() - number_of_removed_edges(); } /// returns the number of faces in the mesh. - size_type number_of_faces() const { - return fprops_.size(); + size_type number_of_faces() const + { + return num_faces() - number_of_removed_faces(); } - /// returns `true` iff the mesh is empty, i.e., has no vertices, halfedges and faces. - bool is_empty() const { - return (vprops_.size() == 0 - && hprops_.size() == 0 - && fprops_.size() == 0); + /// returns `true` iff the mesh is empty, i.e., has no vertices, halfedges and faces. + bool is_empty() const + { + return ( num_vertices() == number_of_removed_vertices() + && num_halfedges() == number_of_removed_halfedges() + && num_faces() == number_of_removed_faces()); } - /// removes all vertices, halfedge, edges and faces. Collects garbage and removes all property maps added by a call to `add_property_map()` for all simplex types. - /// - /// After calling this method, the object is the same as a newly constructed object. The additional property maps are also removed and must thus be re-added if needed. - void clear() { - clear_without_removing_property_maps(); - vprops_.remove_all_properties_except({"v:connectivity", "v:point"}); - hprops_.remove_all_properties_except({"h:connectivity"}); - fprops_.remove_all_properties_except({"f:connectivity"}); - eprops_.remove_all_properties_except({}); - } - - void clear_without_removing_property_maps() { + /// removes all vertices, halfedge, edges and faces. Collects garbage but keeps all property maps. + void clear_without_removing_property_maps() + { vprops_.reserve(0); hprops_.reserve(0); eprops_.reserve(0); fprops_.reserve(0); } + /// removes all vertices, halfedge, edges and faces. Collects garbage and removes all property maps added by a call to `add_property_map()` for all simplex types. + /// + /// After calling this method, the object is the same as a newly constructed object. The additional property maps are also removed and must thus be re-added if needed. + void clear() + { + clear_without_removing_property_maps(); + vprops_.remove_all_properties_except({"v:connectivity", "v:point"}); + hprops_.remove_all_properties_except({"h:connectivity"}); + fprops_.remove_all_properties_except({"f:connectivity"}); + eprops_.remove_all_properties_except({}); + } - /// reserves space for vertices, halfedges, edges, faces, and their currently - /// associated properties. - void reserve(size_type nvertices, - size_type nedges, - size_type nfaces) { - vprops_.reserve(nvertices); - hprops_.reserve(2 * nedges); - eprops_.reserve(nedges); - fprops_.reserve(nfaces); - } -// void resize(size_type nvertices, -// size_type nedges, -// size_type nfaces) { -// vprops_.resize(nvertices); -// hprops_.resize(2 * nedges); -// eprops_.resize(nedges); -// fprops_.resize(nfaces); -// } + /// reserves space for vertices, halfedges, edges, faces, and their currently + /// associated properties. + void reserve(size_type nvertices, + size_type nedges, + size_type nfaces ) + { + vprops_.reserve(nvertices); + hprops_.reserve(2*nedges); + eprops_.reserve(nedges); + fprops_.reserve(nfaces); + } + + void resize(size_type nvertices, + size_type nedges, + size_type nfaces ) + { + vprops_.resize(nvertices); + hprops_.resize(2*nedges); + eprops_.resize(nedges); + fprops_.resize(nfaces); + } /// copies the simplices from `other`, and copies values of /// properties that already exist under the same name in `*this`. /// In case `*this` has a property that does not exist in `other` /// the copied simplices get the default value of the property. - bool join(const Surface_mesh& other) { + bool join(const Surface_mesh& other) + { // Record the original sizes of the property maps const size_type nv = number_of_vertices(), nh = number_of_halfedges(), nf = number_of_faces(); @@ -1161,648 +1238,771 @@ public: fprops_.append(other.fprops_); eprops_.append(other.eprops_); - // todo: the below code assumes no gaps were present in the properties! That might be okay for this situation. - // translate halfedge index in vertex -> halfedge - for (size_type i = nv; i < nv + other.number_of_vertices(); i++) { + for(size_type i = nv; i < nv+other.num_vertices(); i++){ Vertex_index vi(i); - if (vconn_[vi].halfedge_ != null_halfedge()) { - vconn_[vi].halfedge_ = Halfedge_index(size_type(vconn_[vi].halfedge_) + nh); + if(vconn_[vi].halfedge_ != null_halfedge()){ + vconn_[vi].halfedge_ = Halfedge_index(size_type(vconn_[vi].halfedge_)+nh); } } // translate halfedge index in face -> halfedge - for (size_type i = nf; i < nf + other.number_of_faces(); i++) { + for(size_type i = nf; i < nf+other.num_faces(); i++){ Face_index fi(i); - if (fconn_[fi].halfedge_ != null_halfedge()) { - fconn_[fi].halfedge_ = Halfedge_index(size_type(fconn_[fi].halfedge_) + nh); + if(fconn_[fi].halfedge_ != null_halfedge()){ + fconn_[fi].halfedge_ = Halfedge_index(size_type(fconn_[fi].halfedge_)+nh); } } // translate indices in halfedge -> face, halfedge -> target, halfedge -> prev, and halfedge -> next - for (size_type i = nh; i < nh + other.number_of_halfedges(); i++) { + for(size_type i = nh; i < nh+other.num_halfedges(); i++){ Halfedge_index hi(i); - if (hconn_[hi].face_ != null_face()) { - hconn_[hi].face_ = Face_index(size_type(hconn_[hi].face_) + nf); + if(hconn_[hi].face_ != null_face()){ + hconn_[hi].face_ = Face_index(size_type(hconn_[hi].face_)+nf); } - if (hconn_[hi].vertex_ != null_vertex()) { - hconn_[hi].vertex_ = Vertex_index(size_type(hconn_[hi].vertex_) + nv); + if( hconn_[hi].vertex_ != null_vertex()){ + hconn_[hi].vertex_ = Vertex_index(size_type(hconn_[hi].vertex_)+nv); } - if (hconn_[hi].next_halfedge_ != null_halfedge()) { - hconn_[hi].next_halfedge_ = Halfedge_index(size_type(hconn_[hi].next_halfedge_) + nh); + if(hconn_[hi].next_halfedge_ != null_halfedge()){ + hconn_[hi].next_halfedge_ = Halfedge_index(size_type(hconn_[hi].next_halfedge_)+nh); } - if (hconn_[hi].prev_halfedge_ != null_halfedge()) { - hconn_[hi].prev_halfedge_ = Halfedge_index(size_type(hconn_[hi].prev_halfedge_) + nh); + if(hconn_[hi].prev_halfedge_ != null_halfedge()){ + hconn_[hi].prev_halfedge_ = Halfedge_index(size_type(hconn_[hi].prev_halfedge_)+nh); } } + size_type inf_value = (std::numeric_limits::max)(); + + // merge vertex free list + if(other.vertices_freelist_ != inf_value){ + Vertex_index vi(nv+other.vertices_freelist_); + Halfedge_index inf((std::numeric_limits::max)()); + // correct the indices in the linked list of free vertices copied (due to vconn_ translation) + while(vconn_[vi].halfedge_ != inf){ + Vertex_index corrected_vi = Vertex_index(size_type(vconn_[vi].halfedge_)+nv-nh); + vconn_[vi].halfedge_ = Halfedge_index(corrected_vi); + vi = corrected_vi; + } + // append the vertex free linked list of `this` to the copy of `other` + vconn_[vi].halfedge_ = Halfedge_index(vertices_freelist_); + // update the begin of the vertex free linked list + vertices_freelist_ = nv + other.vertices_freelist_; + } + // merge face free list + if(other.faces_freelist_ != inf_value){ + Face_index fi(nf+other.faces_freelist_); + Halfedge_index inf((std::numeric_limits::max)()); + // correct the indices in the linked list of free faces copied (due to fconn_ translation) + while(fconn_[fi].halfedge_ != inf){ + Face_index corrected_fi = Face_index(size_type(fconn_[fi].halfedge_)+nf-nh); + fconn_[fi].halfedge_ = Halfedge_index(corrected_fi); + fi = corrected_fi; + } + // append the face free linked list of `this` to the copy of `other` + fconn_[fi].halfedge_ = Halfedge_index(faces_freelist_); + // update the begin of the face free linked list + faces_freelist_ = nf + other.faces_freelist_; + } + // merge edge free list + if(other.edges_freelist_ != inf_value){ + Halfedge_index hi(nh+other.edges_freelist_); + Halfedge_index inf((std::numeric_limits::max)()); + while(hconn_[hi].next_halfedge_ != inf){ + hi = hconn_[hi].next_halfedge_; + } + // append the halfedge free linked list of `this` to the copy of `other` + hconn_[hi].next_halfedge_ = Halfedge_index(edges_freelist_); + // update the begin of the halfedge free linked list + edges_freelist_ = nh + other.edges_freelist_; + } + // update garbage infos + garbage_ = garbage_ || other.garbage_; + removed_vertices_ += other.removed_vertices_; + removed_edges_ += other.removed_edges_; + removed_faces_ += other.removed_faces_; return true; } - ///@} + ///@} - /// \name Garbage Collection - /// - /// While removing elements only marks them as removed - /// garbage collection really removes them. - /// The API in this section allows to check whether - /// an element is removed, to get the number of - /// removed elements, and to collect garbage. - /// The number of elements together with the number of removed elements is - /// an upperbound on the index, and is needed - /// by algorithms that temporarily store a - /// property in a vector of the appropriate size. - /// Note however that by garbage collecting elements get new indices. - /// In case you store indices in an auxiliary data structure - /// or in a property these indices are potentially no longer - /// referring to the right elements. - /// When adding elements, by default elements that are marked as removed - /// are recycled. + /// \name Garbage Collection + /// + /// While removing elements only marks them as removed + /// garbage collection really removes them. + /// The API in this section allows to check whether + /// an element is removed, to get the number of + /// removed elements, and to collect garbage. + /// The number of elements together with the number of removed elements is + /// an upperbound on the index, and is needed + /// by algorithms that temporarily store a + /// property in a vector of the appropriate size. + /// Note however that by garbage collecting elements get new indices. + /// In case you store indices in an auxiliary data structure + /// or in a property these indices are potentially no longer + /// referring to the right elements. + /// When adding elements, by default elements that are marked as removed + /// are recycled. - ///@{ + ///@{ +#ifndef DOXYGEN_RUNNING + /// returns the number of used and removed vertices in the mesh. + size_type num_vertices() const { return (size_type) vprops_.size(); } - /// returns the number of vertices in the mesh which are marked removed. - size_type number_of_removed_vertices() const { return vprops_.capacity() - vprops_.size(); } + /// returns the number of used and removed halfedges in the mesh. + size_type num_halfedges() const { return (size_type) hprops_.size(); } - /// returns the number of halfedges in the mesh which are marked removed. - size_type number_of_removed_halfedges() const { return hprops_.capacity() - hprops_.size(); } + /// returns the number of used and removed edges in the mesh. + size_type num_edges() const { return (size_type) eprops_.size(); } - /// returns the number of edges in the mesh which are marked removed. - size_type number_of_removed_edges() const { return eprops_.capacity() - eprops_.size(); } + /// returns the number of used and removed faces in the mesh. + size_type num_faces() const { return (size_type) fprops_.size(); } - /// returns the number offaces in the mesh which are marked removed. - size_type number_of_removed_faces() const { return fprops_.capacity() - fprops_.size(); } +#endif + + /// returns the number of vertices in the mesh which are marked removed. + size_type number_of_removed_vertices() const { return removed_vertices_; } + + /// returns the number of halfedges in the mesh which are marked removed. + size_type number_of_removed_halfedges() const { return 2*removed_edges_; } + + /// returns the number of edges in the mesh which are marked removed. + size_type number_of_removed_edges() const { return removed_edges_; } + + /// returns the number offaces in the mesh which are marked removed. + size_type number_of_removed_faces() const { return removed_faces_; } - /// returns whether vertex `v` is marked removed. - bool is_removed(Vertex_index v) const { - return vprops_.is_erased(v); - } - /// returns whether halfedge `h` is marked removed. - bool is_removed(Halfedge_index h) const { - return hprops_.is_erased(h); - } - - /// returns whether edge `e` is marked removed. - bool is_removed(Edge_index e) const { - return eprops_.is_erased(e); - } - - /// returns whether face `f` is marked removed. - bool is_removed(Face_index f) const { - return fprops_.is_erased(f); - } - - /// checks if any vertices, halfedges, edges, or faces are marked as removed. - /// \sa collect_garbage - // todo: remove - bool has_garbage() const { - return number_of_removed_vertices() != 0 || - number_of_removed_edges() != 0 || - number_of_removed_halfedges() != 0 || - number_of_removed_faces() != 0; - } - - /// really removes vertices, halfedges, edges, and faces which are marked removed. - /// \sa `has_garbage()` - /// \attention By garbage collecting elements get new indices. - /// In case you store indices in an auxiliary data structure - /// or in a property these indices are potentially no longer - /// referring to the right elements. - void collect_garbage() { - // todo: this should compress the array - } - - // undocumented convenience function that allows to get old-index->new-index information - template - void collect_garbage(Visitor& visitor) { - // todo: this should compress the array and remap indices - } - - /// controls the recycling or not of simplices previously marked as removed - /// upon addition of new elements. - /// When set to `true` (default value), new elements are first picked in the garbage (if any) - /// while if set to `false` only new elements are created. - void set_recycle_garbage(bool b) { recycle_ = b; } - - /// Getter - bool does_recycle_garbage() const { return recycle_; } - - /// @cond CGAL_DOCUMENT_INTERNALS - /// removes unused memory from vectors. This shrinks the storage - /// of all properties to the minimal required size. - /// \attention Invalidates all existing references to properties. - -// void shrink_to_fit() { -// vprops_.shrink_to_fit(); -// hprops_.shrink_to_fit(); -// eprops_.shrink_to_fit(); -// fprops_.shrink_to_fit(); -// } - /// @endcond - - ///@} - - /// @cond CGAL_DOCUMENT_INTERNALS - /// - /// \name Simple Validity Checks - /// - /// Functions in this group check if the index is valid, that is between - /// `0` and the currently allocated maximum amount of the - /// elements. They do not check if an element is marked as removed. - ///@{ - - /// returns whether the index of vertex `v` is valid, that is within the current array bounds. - bool has_valid_index(Vertex_index v) const { - return ((size_type) v < number_of_vertices()); - } - - /// returns whether the index of halfedge `h` is valid, that is within the current array bounds. - bool has_valid_index(Halfedge_index h) const { - return ((size_type) h < number_of_halfedges()); - } - - /// returns whether the index of edge `e` is valid, that is within the current array bounds. - bool has_valid_index(Edge_index e) const { - return ((size_type) e < number_of_edges()); - } - - /// returns whether the index of face `f` is valid, that is within the current array bounds. - bool has_valid_index(Face_index f) const { - return ((size_type) f < number_of_faces()); - } - - /// @} - /// @endcond - - /// \name Validity Checks - /// - /// Functions in this group perform checks for structural - /// consistency of a complete surface mesh, or an individual element. - /// They are expensive and should only be used in debug configurations. - - ///@{ - - /// perform an expensive validity check on the data structure and - /// print found errors to `std::cerr` when `verbose == true`. - bool is_valid(bool verbose = false) const { - bool valid = true; - size_type vcount = 0, hcount = 0, fcount = 0; - for (Halfedge_iterator it = halfedges_begin(); it != halfedges_end(); ++it) { - ++hcount; - valid = valid && next(*it).is_valid(); - valid = valid && opposite(*it).is_valid(); - if (!valid) { - if (verbose) - std::cerr << "Integrity of halfedge " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && (opposite(*it) != *it); - valid = valid && (opposite(opposite(*it)) == *it); - if (!valid) { - if (verbose) - std::cerr << "Integrity of opposite halfedge of " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && (next(prev(*it)) == *it); - if (!valid) { - if (verbose) - std::cerr << "Integrity of previous halfedge of " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && (prev(next(*it)) == *it); - if (!valid) { - if (verbose) - std::cerr << "Integrity of next halfedge of " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && target(*it).is_valid(); - if (!valid) { - if (verbose) - std::cerr << "Integrity of vertex of halfedge " << *it << " corrupted." << std::endl; - break; - } - - valid = valid && (target(*it) == target(opposite(next(*it)))); - if (!valid) { - if (verbose) - std::cerr << "Halfedge vertex of next opposite is not the same for " << *it << "." << std::endl; - break; - } + /// returns whether vertex `v` is marked removed. + /// \sa `collect_garbage()` + bool is_removed(Vertex_index v) const + { + return vremoved_[v]; + } + /// returns whether halfedge `h` is marked removed. + /// \sa `collect_garbage()` + bool is_removed(Halfedge_index h) const + { + return eremoved_[edge(h)]; + } + /// returns whether edge `e` is marked removed. + /// \sa `collect_garbage()` + bool is_removed(Edge_index e) const + { + return eremoved_[e]; + } + /// returns whether face `f` is marked removed. + /// \sa `collect_garbage()` + bool is_removed(Face_index f) const + { + return fremoved_[f]; } - for (Vertex_iterator it = vertices_begin(); it != vertices_end(); ++it) { - ++vcount; - if (halfedge(*it).is_valid()) { - // not an isolated vertex - valid = valid && (target(halfedge(*it)) == *it); - if (!valid) { - if (verbose) - std::cerr << "Halfedge of " << *it << " is not an incoming halfedge." << std::endl; - break; + /// checks if any vertices, halfedges, edges, or faces are marked as removed. + /// \sa collect_garbage + bool has_garbage() const { return garbage_; } + + /// really removes vertices, halfedges, edges, and faces which are marked removed. + /// \sa `has_garbage()` + /// \attention By garbage collecting elements get new indices. + /// In case you store indices in an auxiliary data structure + /// or in a property these indices are potentially no longer + /// referring to the right elements. + void collect_garbage(); + + //undocumented convenience function that allows to get old-index->new-index information + template + void collect_garbage(Visitor& visitor); + + /// controls the recycling or not of simplices previously marked as removed + /// upon addition of new elements. + /// When set to `true` (default value), new elements are first picked in the garbage (if any) + /// while if set to `false` only new elements are created. + void set_recycle_garbage(bool b) { recycle_ = b; } + + /// Getter + bool does_recycle_garbage() const { return recycle_; } + + /// @cond CGAL_DOCUMENT_INTERNALS + /// removes unused memory from vectors. This shrinks the storage + /// of all properties to the minimal required size. + /// \attention Invalidates all existing references to properties. + + void shrink_to_fit() + { + vprops_.shrink_to_fit(); + hprops_.shrink_to_fit(); + eprops_.shrink_to_fit(); + fprops_.shrink_to_fit(); + } + /// @endcond + + ///@} + + /// @cond CGAL_DOCUMENT_INTERNALS + /// + /// \name Simple Validity Checks + /// + /// Functions in this group check if the index is valid, that is between + /// `0` and the currently allocated maximum amount of the + /// elements. They do not check if an element is marked as removed. + ///@{ + + /// returns whether the index of vertex `v` is valid, that is within the current array bounds. + bool has_valid_index(Vertex_index v) const + { + return ((size_type)v < num_vertices()); + } + + /// returns whether the index of halfedge `h` is valid, that is within the current array bounds. + bool has_valid_index(Halfedge_index h) const + { + return ((size_type)h < num_halfedges()); + } + /// returns whether the index of edge `e` is valid, that is within the current array bounds. + bool has_valid_index(Edge_index e) const + { + return ((size_type)e < num_edges()); + } + /// returns whether the index of face `f` is valid, that is within the current array bounds. + bool has_valid_index(Face_index f) const + { + return ((size_type)f < num_faces()); + } + + /// @} + /// @endcond + + /// \name Validity Checks + /// + /// Functions in this group perform checks for structural + /// consistency of a complete surface mesh, or an individual element. + /// They are expensive and should only be used in debug configurations. + + ///@{ + + /// perform an expensive validity check on the data structure and + /// print found errors to `std::cerr` when `verbose == true`. + bool is_valid(bool verbose = false) const + { + bool valid = true; + size_type vcount = 0, hcount = 0, fcount = 0; + for(Halfedge_iterator it = halfedges_begin(); it != halfedges_end(); ++it) { + ++hcount; + valid = valid && next(*it).is_valid(); + valid = valid && opposite(*it).is_valid(); + if(!valid) { + if (verbose) + std::cerr << "Integrity of halfedge " << *it << " corrupted." << std::endl; + break; + } + + valid = valid && (opposite(*it) != *it); + valid = valid && (opposite(opposite(*it)) == *it); + if(!valid) { + if (verbose) + std::cerr << "Integrity of opposite halfedge of " << *it << " corrupted." << std::endl; + break; + } + + valid = valid && (next(prev(*it)) == *it); + if(!valid) { + if (verbose) + std::cerr << "Integrity of previous halfedge of " << *it << " corrupted." << std::endl; + break; + } + + valid = valid && (prev(next(*it)) == *it); + if(!valid) { + if (verbose) + std::cerr << "Integrity of next halfedge of " << *it << " corrupted." << std::endl; + break; + } + + valid = valid && target(*it).is_valid(); + if(!valid) { + if (verbose) + std::cerr << "Integrity of vertex of halfedge " << *it << " corrupted." << std::endl; + break; + } + + valid = valid && (target(*it) == target(opposite(next(*it)))); + if(!valid) { + if (verbose) + std::cerr << "Halfedge vertex of next opposite is not the same for " << *it << "." << std::endl; + break; + } } + + for(Vertex_iterator it = vertices_begin(); it != vertices_end(); ++it) { + ++vcount; + if(halfedge(*it).is_valid()) { + // not an isolated vertex + valid = valid && (target(halfedge(*it)) == *it); + if(!valid) { + if (verbose) + std::cerr << "Halfedge of " << *it << " is not an incoming halfedge." << std::endl; + break; + } + } + } + for(Face_iterator it = faces_begin(); it != faces_end(); ++it) { + ++fcount; + } + + valid = valid && (vcount == number_of_vertices()); + if(!valid && verbose){ + std::cerr << "#vertices: iterated: " << vcount << " vs number_of_vertices(): " << number_of_vertices()<< std::endl; + } + + valid = valid && (hcount == number_of_halfedges()); + if(!valid && verbose){ + std::cerr << "#halfedges: iterated: " << hcount << " vs number_of_halfedges(): " << number_of_halfedges()<< std::endl; + } + + valid = valid && (fcount == number_of_faces()); + if(!valid && verbose){ + std::cerr << "#faces: iterated: " << fcount << " vs number_of_faces(): " << number_of_faces()<< std::endl; + } + + size_type inf = (std::numeric_limits::max)(); + size_type vfl = vertices_freelist_; + size_type rv = 0; + while(vfl != inf){ + vfl = (size_type)vconn_[Vertex_index(vfl)].halfedge_; + rv++; + } + valid = valid && ( rv == removed_vertices_ ); + + + size_type efl = edges_freelist_; + size_type re = 0; + while(efl != inf){ + efl = (size_type)hconn_[Halfedge_index(efl)].next_halfedge_; + re++; + } + valid = valid && ( re == removed_edges_ ); + + size_type ffl = faces_freelist_; + size_type rf = 0; + while(ffl != inf){ + ffl = (size_type)fconn_[Face_index(ffl)].halfedge_; + rf++; + } + valid = valid && ( rf == removed_faces_ ); + + return valid; + } + + /// performs a validity check on a single vertex. + bool is_valid(Vertex_index v, + bool verbose = false) const + { + Verbose_ostream verr(verbose); + + if(!has_valid_index(v)) + { + verr << "Vertex has invalid index: " << (size_type)v << std::endl; + return false; + } + + Halfedge_index h = vconn_[v].halfedge_; + if(h != null_halfedge() && (!has_valid_index(h) || is_removed(h))) { + verr << "Vertex connectivity halfedge error: Vertex " << (size_type)v + << " with " << (size_type)h << std::endl; + return false; + } + return true; + } + + /// performs a validity check on a single halfedge. + bool is_valid(Halfedge_index h, + bool verbose = false) const + { + Verbose_ostream verr(verbose); + + if(!has_valid_index(h)) + { + verr << "Halfedge has invalid index: " << (size_type)h << std::endl; + return false; + } + + Face_index f = hconn_[h].face_; + Vertex_index v = hconn_[h].vertex_; + Halfedge_index hn = hconn_[h].next_halfedge_; + Halfedge_index hp = hconn_[h].prev_halfedge_; + + bool valid = true; + // don't validate the face if this is a border halfedge + if(!is_border(h)) { + if(!has_valid_index(f) || is_removed(f)) { + verr << "Halfedge connectivity error: Face " + << (!has_valid_index(f) ? "invalid" : "removed") + << " in " << (size_type)h << std::endl; + valid = false; + } + } + + if(!has_valid_index(v) || is_removed(v)) { + verr << "Halfedge connectivity error: Vertex " + << (!has_valid_index(v) ? "invalid" : "removed") + << " in " << (size_type)h << std::endl; + valid = false; + } + + if(!has_valid_index(hn) || is_removed(hn)) { + verr << "Halfedge connectivity error: hnext " + << (!has_valid_index(hn) ? "invalid" : "removed") + << " in " << (size_type)h << std::endl; + valid = false; + } + if(!has_valid_index(hp) || is_removed(hp)) { + verr << "Halfedge connectivity error: hprev " + << (!has_valid_index(hp) ? "invalid" : "removed") + << " in " << (size_type)h << std::endl; + valid = false; + } + return valid; + } + + + /// performs a validity check on a single edge. + bool is_valid(Edge_index e, + bool verbose = false) const + { + Verbose_ostream verr(verbose); + + if(!has_valid_index(e)) + { + verr << "Edge has invalid index: " << (size_type)e << std::endl; + return false; + } + + Halfedge_index h = halfedge(e); + return is_valid(h, verbose) && is_valid(opposite(h), verbose); + } + + + /// performs a validity check on a single face. + bool is_valid(Face_index f, + bool verbose = false) const + { + Verbose_ostream verr(verbose); + + if(!has_valid_index(f)) + { + verr << "Face has invalid index: " << (size_type)f << std::endl; + return false; + } + + Halfedge_index h = fconn_[f].halfedge_; + if(!has_valid_index(h) || is_removed(h)) { + verr << "Face connectivity halfedge error: Face " << (size_type)f + << " with " << (size_type)h << std::endl; + return false; + } + return true; + } + + ///@} + + + + /// \name Low-Level Connectivity + ///@{ + + /// returns the vertex the halfedge `h` points to. + Vertex_index target(Halfedge_index h) const + { + return hconn_[h].vertex_; + } + + /// sets the vertex the halfedge `h` points to to `v`. + void set_target(Halfedge_index h, Vertex_index v) + { + hconn_[h].vertex_ = v; + } + + /// returns the face incident to halfedge `h`. + Face_index face(Halfedge_index h) const + { + return hconn_[h].face_; + } + + /// sets the incident face to halfedge `h` to `f`. + void set_face(Halfedge_index h, Face_index f) + { + hconn_[h].face_ = f; + } + + /// returns the next halfedge within the incident face. + Halfedge_index next(Halfedge_index h) const + { + return hconn_[h].next_halfedge_; + } + + /// returns the previous halfedge within the incident face. + Halfedge_index prev(Halfedge_index h) const + { + return hconn_[h].prev_halfedge_; + } + + /// @cond CGAL_DOCUMENT_INTERNALS + // sets the next halfedge of `h` within the face to `nh`. + void set_next_only(Halfedge_index h, Halfedge_index nh) + { + hconn_[h].next_halfedge_ = nh; + } + + // sets previous halfedge of `h` to `nh`. + void set_prev_only(Halfedge_index h, Halfedge_index nh) + { + if(h != null_halfedge()){ + hconn_[h].prev_halfedge_ = nh; } } - for (Face_iterator it = faces_begin(); it != faces_end(); ++it) { - ++fcount; + /// @endcond + + /// sets the next halfedge of `h` within the face to `nh` and + /// the previous halfedge of `nh` to `h`. + void set_next(Halfedge_index h, Halfedge_index nh) + { + set_next_only(h, nh); + set_prev_only(nh, h); } - valid = valid && (vcount == number_of_vertices()); - if (!valid && verbose) { - std::cerr << "#vertices: iterated: " << vcount << " vs number_of_vertices(): " << number_of_vertices() - << std::endl; + /// returns an incoming halfedge of vertex `v`. + /// If `v` is a border vertex this will be a border halfedge. + /// \invariant `target(halfedge(v)) == v` + Halfedge_index halfedge(Vertex_index v) const + { + return vconn_[v].halfedge_; } - valid = valid && (hcount == number_of_halfedges()); - if (!valid && verbose) { - std::cerr << "#halfedges: iterated: " << hcount << " vs number_of_halfedges(): " << number_of_halfedges() - << std::endl; + /// sets the incoming halfedge of vertex `v` to `h`. + void set_halfedge(Vertex_index v, Halfedge_index h) + { + vconn_[v].halfedge_ = h; } - valid = valid && (fcount == number_of_faces()); - if (!valid && verbose) { - std::cerr << "#faces: iterated: " << fcount << " vs number_of_faces(): " << number_of_faces() << std::endl; + + /// returns a halfedge of face `f`. + Halfedge_index halfedge(Face_index f) const + { + return fconn_[f].halfedge_; } - return valid; - } - - /// performs a validity check on a single vertex. - bool is_valid(Vertex_index v, - bool verbose = false) const { - Verbose_ostream verr(verbose); - - if (!has_valid_index(v)) { - verr << "Vertex has invalid index: " << (size_type) v << std::endl; - return false; + /// sets the halfedge of face `f` to `h`. + void set_halfedge(Face_index f, Halfedge_index h) + { + fconn_[f].halfedge_ = h; } - Halfedge_index h = vconn_[v].halfedge_; - if (h != null_halfedge() && (!has_valid_index(h) || is_removed(h))) { - verr << "Vertex connectivity halfedge error: Vertex " << (size_type) v - << " with " << (size_type) h << std::endl; - return false; - } - return true; - } - - /// performs a validity check on a single halfedge. - bool is_valid(Halfedge_index h, - bool verbose = false) const { - Verbose_ostream verr(verbose); - - if (!has_valid_index(h)) { - verr << "Halfedge has invalid index: " << (size_type) h << std::endl; - return false; + /// returns the opposite halfedge of `h`. Note that there is no function `set_opposite()`. + Halfedge_index opposite(Halfedge_index h) const + { + return Halfedge_index(((size_type)h & 1) ? (size_type)h-1 : (size_type)h+1); } - Face_index f = hconn_[h].face_; - Vertex_index v = hconn_[h].vertex_; - Halfedge_index hn = hconn_[h].next_halfedge_; - Halfedge_index hp = hconn_[h].prev_halfedge_; + ///@} - bool valid = true; - // don't validate the face if this is a border halfedge - if (!is_border(h)) { - if (!has_valid_index(f) || is_removed(f)) { - verr << "Halfedge connectivity error: Face " - << (!has_valid_index(f) ? "invalid" : "removed") - << " in " << (size_type) h << std::endl; - valid = false; - } + /// \name Low-Level Connectivity Convenience Functions + ///@{ + + /// returns the vertex the halfedge `h` emanates from. + Vertex_index source(Halfedge_index h) const + { + return target(opposite(h)); } - if (!has_valid_index(v) || is_removed(v)) { - verr << "Halfedge connectivity error: Vertex " - << (!has_valid_index(v) ? "invalid" : "removed") - << " in " << (size_type) h << std::endl; - valid = false; + /// returns `opposite(next(h))`, that is the next halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the target vertex of `h`. + Halfedge_index next_around_target(Halfedge_index h) const + { + return opposite(next(h)); } - if (!has_valid_index(hn) || is_removed(hn)) { - verr << "Halfedge connectivity error: hnext " - << (!has_valid_index(hn) ? "invalid" : "removed") - << " in " << (size_type) h << std::endl; - valid = false; - } - if (!has_valid_index(hp) || is_removed(hp)) { - verr << "Halfedge connectivity error: hprev " - << (!has_valid_index(hp) ? "invalid" : "removed") - << " in " << (size_type) h << std::endl; - valid = false; - } - return valid; - } - - - /// performs a validity check on a single edge. - bool is_valid(Edge_index e, - bool verbose = false) const { - Verbose_ostream verr(verbose); - - if (!has_valid_index(e)) { - verr << "Edge has invalid index: " << (size_type) e << std::endl; - return false; + /// returns `prev(opposite(h))`, that is the previous halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the target vertex of `h`. + Halfedge_index prev_around_target(Halfedge_index h) const + { + return prev(opposite(h)); } - Halfedge_index h = halfedge(e); - return is_valid(h, verbose) && is_valid(opposite(h), verbose); - } - - - /// performs a validity check on a single face. - bool is_valid(Face_index f, - bool verbose = false) const { - Verbose_ostream verr(verbose); - - if (!has_valid_index(f)) { - verr << "Face has invalid index: " << (size_type) f << std::endl; - return false; + /// returns `next(opposite(h))`, that is the next halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the source vertex of `h`. + Halfedge_index next_around_source(Halfedge_index h) const + { + return next(opposite(h)); } - Halfedge_index h = fconn_[f].halfedge_; - if (!has_valid_index(h) || is_removed(h)) { - verr << "Face connectivity halfedge error: Face " << (size_type) f - << " with " << (size_type) h << std::endl; - return false; + /// returns `opposite(prev(h))`, that is the previous halfedge \ref SurfaceMeshOrientation + /// "clockwise" around the source vertex of `h`. + Halfedge_index prev_around_source(Halfedge_index h) const + { + return opposite(prev(h)); } - return true; - } - ///@} - - - - /// \name Low-Level Connectivity - ///@{ - - /// returns the vertex the halfedge `h` points to. - Vertex_index target(Halfedge_index h) const { - return hconn_[h].vertex_; - } - - /// sets the vertex the halfedge `h` points to to `v`. - void set_target(Halfedge_index h, Vertex_index v) { - hconn_[h].vertex_ = v; - } - - /// returns the face incident to halfedge `h`. - Face_index face(Halfedge_index h) const { - return hconn_[h].face_; - } - - /// sets the incident face to halfedge `h` to `f`. - void set_face(Halfedge_index h, Face_index f) { - hconn_[h].face_ = f; - } - - /// returns the next halfedge within the incident face. - Halfedge_index next(Halfedge_index h) const { - return hconn_[h].next_halfedge_; - } - - /// returns the previous halfedge within the incident face. - Halfedge_index prev(Halfedge_index h) const { - return hconn_[h].prev_halfedge_; - } - - /// @cond CGAL_DOCUMENT_INTERNALS - // sets the next halfedge of `h` within the face to `nh`. - void set_next_only(Halfedge_index h, Halfedge_index nh) { - hconn_[h].next_halfedge_ = nh; - } - - // sets previous halfedge of `h` to `nh`. - void set_prev_only(Halfedge_index h, Halfedge_index nh) { - if (h != null_halfedge()) { - hconn_[h].prev_halfedge_ = nh; + /// returns the i'th vertex of edge `e`, for `i=0` or `1`. + Vertex_index vertex(Edge_index e, unsigned int i) const + { + CGAL_assertion(i<=1); + return target(halfedge(e, i)); } - } - /// @endcond - /// sets the next halfedge of `h` within the face to `nh` and - /// the previous halfedge of `nh` to `h`. - void set_next(Halfedge_index h, Halfedge_index nh) { - set_next_only(h, nh); - set_prev_only(nh, h); - } + /// finds a halfedge between two vertices. Returns a default constructed + /// `Halfedge_index`, if `source` and `target` are not connected. + Halfedge_index halfedge(Vertex_index source, Vertex_index target) const; - /// returns an incoming halfedge of vertex `v`. - /// If `v` is a border vertex this will be a border halfedge. - /// \invariant `target(halfedge(v)) == v` - Halfedge_index halfedge(Vertex_index v) const { - return vconn_[v].halfedge_; - } - - /// sets the incoming halfedge of vertex `v` to `h`. - void set_halfedge(Vertex_index v, Halfedge_index h) { - vconn_[v].halfedge_ = h; - } + ///@} - /// returns a halfedge of face `f`. - Halfedge_index halfedge(Face_index f) const { - return fconn_[f].halfedge_; - } + /// \name Switching between Halfedges and Edges + ///@{ - /// sets the halfedge of face `f` to `h`. - void set_halfedge(Face_index f, Halfedge_index h) { - fconn_[f].halfedge_ = h; - } - - /// returns the opposite halfedge of `h`. Note that there is no function `set_opposite()`. - Halfedge_index opposite(Halfedge_index h) const { - return Halfedge_index(((size_type) h & 1) ? (size_type) h - 1 : (size_type) h + 1); - } - - ///@} - - /// \name Low-Level Connectivity Convenience Functions - ///@{ - - /// returns the vertex the halfedge `h` emanates from. - Vertex_index source(Halfedge_index h) const { - return target(opposite(h)); - } - - /// returns `opposite(next(h))`, that is the next halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the target vertex of `h`. - Halfedge_index next_around_target(Halfedge_index h) const { - return opposite(next(h)); - } - - /// returns `prev(opposite(h))`, that is the previous halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the target vertex of `h`. - Halfedge_index prev_around_target(Halfedge_index h) const { - return prev(opposite(h)); - } - - /// returns `next(opposite(h))`, that is the next halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the source vertex of `h`. - Halfedge_index next_around_source(Halfedge_index h) const { - return next(opposite(h)); - } - - /// returns `opposite(prev(h))`, that is the previous halfedge \ref SurfaceMeshOrientation - /// "clockwise" around the source vertex of `h`. - Halfedge_index prev_around_source(Halfedge_index h) const { - return opposite(prev(h)); - } - - /// returns the i'th vertex of edge `e`, for `i=0` or `1`. - Vertex_index vertex(Edge_index e, unsigned int i) const { - CGAL_assertion(i <= 1); - return target(halfedge(e, i)); - } - - /// finds a halfedge between two vertices. Returns a default constructed - /// `Halfedge_index`, if `source` and `target` are not connected. - Halfedge_index halfedge(Vertex_index source, Vertex_index target) const; - - ///@} - - - /// \name Switching between Halfedges and Edges - ///@{ - - /// returns the edge that contains halfedge `h` as one of its two halfedges. - Edge_index edge(Halfedge_index h) const { - return Edge_index(h); - } - - /// returns the halfedge corresponding to the edge `e`. - Halfedge_index halfedge(Edge_index e) const { - return Halfedge_index(e.halfedge()); - } - - /// returns the i'th halfedge of edge `e`, for `i=0` or `1`. - Halfedge_index halfedge(Edge_index e, unsigned int i) const { - CGAL_assertion(i <= 1); - return Halfedge_index(((size_type) e << 1) + i); - } - - ///@} - - - /// \name Degree Functions - ///@{ - - /// returns the number of incident halfedges of vertex `v`. - size_type degree(Vertex_index v) const; - - /// returns the number of incident halfedges of face `f`. - size_type degree(Face_index f) const; - - ///@} - - - - /// \name Borders - /// - /// A halfedge, or edge is on the border of a surface mesh - /// if it is incident to a `null_face()`. A vertex is on a border - /// if it is isolated or incident to a border halfedge. While for a halfedge and - /// edge this is a constant time operation, for a vertex it means - /// to look at all incident halfedges. If algorithms operating on a - /// surface mesh maintain that the halfedge associated to a border vertex is - /// a border halfedge, this is a constant time operation too. - /// This section provides functions to check if an element is on a - /// border and to change the halfedge associated to a border vertex. - ///@{ - - /// returns whether `v` is a border vertex. - /// \cgalAdvancedBegin - /// With the default value for - /// `check_all_incident_halfedges` the function iteratates over the incident halfedges. - /// With `check_all_incident_halfedges == false` the function returns `true`, if the incident - /// halfedge associated to vertex `v` is a border halfedge, or if the vertex is isolated. - /// \cgalAdvancedEnd - /// \attention If the data contained in the `Surface_mesh` is not a 2-manifold, then - /// this operation is not guaranteed to return the right result. - bool is_border(Vertex_index v, bool check_all_incident_halfedges = true) const { - Halfedge_index h(halfedge(v)); - if (h == null_halfedge()) { - return true; + /// returns the edge that contains halfedge `h` as one of its two halfedges. + Edge_index edge(Halfedge_index h) const + { + return Edge_index(h); } - if (check_all_incident_halfedges) { - Halfedge_around_target_circulator hatc(h, *this), done(hatc); - do { - if (is_border(*hatc)) { + + /// returns the halfedge corresponding to the edge `e`. + Halfedge_index halfedge(Edge_index e) const + { + return Halfedge_index(e.halfedge()); + } + + /// returns the i'th halfedge of edge `e`, for `i=0` or `1`. + Halfedge_index halfedge(Edge_index e, unsigned int i) const + { + CGAL_assertion(i<=1); + return Halfedge_index(((size_type)e << 1) + i); + } + + ///@} + + + /// \name Degree Functions + ///@{ + + /// returns the number of incident halfedges of vertex `v`. + size_type degree(Vertex_index v) const; + + /// returns the number of incident halfedges of face `f`. + size_type degree(Face_index f) const; + + ///@} + + + + /// \name Borders + /// + /// A halfedge, or edge is on the border of a surface mesh + /// if it is incident to a `null_face()`. A vertex is on a border + /// if it is isolated or incident to a border halfedge. While for a halfedge and + /// edge this is a constant time operation, for a vertex it means + /// to look at all incident halfedges. If algorithms operating on a + /// surface mesh maintain that the halfedge associated to a border vertex is + /// a border halfedge, this is a constant time operation too. + /// This section provides functions to check if an element is on a + /// border and to change the halfedge associated to a border vertex. + ///@{ + + /// returns whether `v` is a border vertex. + /// \cgalAdvancedBegin + /// With the default value for + /// `check_all_incident_halfedges` the function iteratates over the incident halfedges. + /// With `check_all_incident_halfedges == false` the function returns `true`, if the incident + /// halfedge associated to vertex `v` is a border halfedge, or if the vertex is isolated. + /// \cgalAdvancedEnd + /// \attention If the data contained in the `Surface_mesh` is not a 2-manifold, then + /// this operation is not guaranteed to return the right result. + bool is_border(Vertex_index v, bool check_all_incident_halfedges = true) const + { + Halfedge_index h(halfedge(v)); + if (h == null_halfedge()){ return true; } - } while (++hatc != done); - return false; + if(check_all_incident_halfedges){ + Halfedge_around_target_circulator hatc(h,*this), done(hatc); + do { + if(is_border(*hatc)){ + return true; + } + }while(++hatc != done); + return false; + } + return is_border(h); } - return is_border(h); - } - /// returns whether `h` is a border halfege, that is if its incident face is `sm.null_face()`. - bool is_border(Halfedge_index h) const { - return !face(h).is_valid(); - } + /// returns whether `h` is a border halfege, that is if its incident face is `sm.null_face()`. + bool is_border(Halfedge_index h) const + { + return !face(h).is_valid(); + } - /// returns whether `e` is a border edge, i.e., if any - /// of its two halfedges is a border halfedge. - bool is_border(Edge_index e) const { - return is_border(e.halfedge()) || is_border(opposite(e.halfedge())); - } + /// returns whether `e` is a border edge, i.e., if any + /// of its two halfedges is a border halfedge. + bool is_border(Edge_index e) const + { + return is_border(e.halfedge()) || is_border(opposite(e.halfedge())); + } /// iterates over the incident halfedges and sets the incident halfedge /// associated to vertex `v` to a border halfedge and returns `true` if it exists. - bool set_vertex_halfedge_to_border_halfedge(Vertex_index v) { - if (halfedge(v) == null_halfedge()) { + bool set_vertex_halfedge_to_border_halfedge(Vertex_index v) + { + if(halfedge(v) == null_halfedge()){ return false; } - Halfedge_around_target_circulator hatc(halfedge(v), *this), done(hatc); + Halfedge_around_target_circulator hatc(halfedge(v),*this), done(hatc); do { - if (is_border(*hatc)) { - set_halfedge(v, *hatc); + if(is_border(*hatc)){ + set_halfedge(v,*hatc); return true; } - } while (++hatc != done); + }while(++hatc != done); return false; } /// applies `set_vertex_halfedge_to_border_halfedge(Vertex_index)` on all vertices /// around the face associated to `h`. - void set_vertex_halfedge_to_border_halfedge(Halfedge_index h) { - if (is_border(h)) { - Halfedge_around_face_circulator hafc(h, *this), done(hafc); + void set_vertex_halfedge_to_border_halfedge(Halfedge_index h) + { + if(is_border(h)){ + Halfedge_around_face_circulator hafc(h,*this),done(hafc); do { - set_halfedge(target(*hafc), *hafc); - } while (++hafc != done); + set_halfedge(target(*hafc),*hafc); + }while(++hafc != done); } else { - Vertex_around_face_circulator vafc(h, *this), done(vafc); + Vertex_around_face_circulator vafc(h,*this),done(vafc); do { set_vertex_halfedge_to_border_halfedge(*vafc); - } while (++vafc != done); + }while(++vafc != done); } } /// applies `set_vertex_halfedge_to_border_halfedge(Vertex_index)` on all vertices /// of the surface mesh. - void set_vertex_halfedge_to_border_halfedge() { - for (Halfedge_index h: halfedges()) { - if (is_border(h)) { - set_halfedge(target(h), h); - } + void set_vertex_halfedge_to_border_halfedge() + { + for(Halfedge_index h : halfedges()){ + if(is_border(h)){ + set_halfedge(target(h),h); + } } } - /// returns whether `v` is isolated, i.e., incident to `Surface_mesh::null_halfedge()`. - bool is_isolated(Vertex_index v) const { - return !halfedge(v).is_valid(); - } + /// returns whether `v` is isolated, i.e., incident to `Surface_mesh::null_halfedge()`. + bool is_isolated(Vertex_index v) const + { + return !halfedge(v).is_valid(); + } - ///@} + ///@} -public: //--------------------------------------------------- property handling +private: //--------------------------------------------------- property handling template Property_container& get_property_container() { @@ -1829,17 +2029,17 @@ public: //--------------------------------------------------- property handling } -public: + public: - /*! \name Property Handling + /*! \name Property Handling - A `Properties::Property_map` allows to associate properties of type `T` to a vertex, halfdge, edge, or face index type I. - Properties can be added, and looked up with a string, and they can be removed at runtime. - The \em point property of type `P` is associated to the string "v:point". + A `Properties::Property_map` allows to associate properties of type `T` to a vertex, halfdge, edge, or face index type I. + Properties can be added, and looked up with a string, and they can be removed at runtime. + The \em point property of type `P` is associated to the string "v:point". - */ - ///@{ + */ + ///@{ /// Model of `LvaluePropertyMap` with `I` as key type and `T` as value type, where `I` /// is either a vertex, halfedge, edge, or face index type. @@ -1852,247 +2052,262 @@ public: #endif - // todo: I can't see a good reason for these two functions to exist separately, but do almost the same thing - - /// adds a property map named `name` with value type `T` and default `t` - /// for index type `I`. Returns the property map together with a Boolean - /// that is `true` if a new map was created. In case it already exists - /// the existing map together with `false` is returned. - template - std::pair, bool> - add_property_map(std::string name = std::string(), const T t = T()) { - if (name.empty()) { - // todo: maybe this should be done by the property container itself? - std::ostringstream oss; - oss << "anonymous-property-" << anonymous_property_++; - name = std::string(oss.str()); + /// adds a property map named `name` with value type `T` and default `t` + /// for index type `I`. Returns the property map together with a Boolean + /// that is `true` if a new map was created. In case it already exists + /// the existing map together with `false` is returned. + template + std::pair, bool> + add_property_map(std::string name=std::string(), const T t=T()) { + if(name.empty()){ + // todo: maybe this should be done by the property container itself? + std::ostringstream oss; + oss << "anonymous-property-" << anonymous_property_++; + name = std::string(oss.str()); + } + auto [array, created] = + const_cast*>(this)->get_property_container().template get_or_add_property(name, t); + return {{array.get()}, created}; } - // todo: double check this is working - auto [array, created] = - const_cast*>(this)->get_property_container().template get_or_add_property(name, t); - return {{array.get()}, created}; - } - /// returns a property map named `name` with key type `I` and value type `T`, - /// and a Boolean that is `true` if the property was created. - template - std::pair, bool> - property_map(const std::string& name) const { - auto [array, created] = - const_cast*>(this)->get_property_container().template get_or_add_property(name); - return {{array.get()}, created}; - } + /// returns a property map named `name` with key type `I` and value type `T`, + /// and a Boolean that is `true` if the property was created. + template + std::pair, bool> + property_map(const std::string& name) const { + auto [array, created] = + const_cast*>(this)->get_property_container().template get_or_add_property(name); + return {{array.get()}, created}; + } - /// returns a property map named `name` with key type `I` and value type `T`, - /// if such a property map exists - template - std::optional> - get_property_map(const std::string& name) { - auto maybe_property_map = get_property_container().template get_property_if_exists(name); - if (!maybe_property_map) return {}; - else return {{maybe_property_map.value()}}; - } + /// returns a property map named `name` with key type `I` and value type `T`, + /// if such a property map exists + template + std::optional> + get_property_map(const std::string& name) { + auto maybe_property_map = get_property_container().template get_property_if_exists(name); + if (!maybe_property_map) return {}; + else return {{maybe_property_map.value()}}; + } - template - std::optional> - get_property_map(const std::string& name) const { - auto maybe_property_map = const_cast*>(this)->get_property_container().template get_property_if_exists(name); - if (!maybe_property_map) return {}; - else return {{maybe_property_map.value()}}; - } + template + std::optional> + get_property_map(const std::string& name) const { + auto maybe_property_map = const_cast*>(this)->get_property_container().template get_property_if_exists(name); + if (!maybe_property_map) return {}; + else return {{maybe_property_map.value()}}; + } - /// removes property map `p`. The memory allocated for that property map is - /// freed. - template - void remove_property_map(Property_map p) { - // Maybe this could be replaced with removal by name? - const_cast*>(this)->get_property_container().template remove_property(p.array()); - } + /// removes property map `p`. The memory allocated for that property map is + /// freed. + template + void remove_property_map(Property_map p) { + // Maybe this could be replaced with removal by name? + const_cast*>(this)->get_property_container().template remove_property(p.array()); + } - /// @cond CGAL_DOCUMENT_INTERNALS - /// returns the std::type_info of the value type of the - /// property identified by `name`. `typeid(void)` if `name` - /// does not identify any property. - /// - /// @tparam I The key type of the property. + /// @cond CGAL_DOCUMENT_INTERNALS + /// returns the std::type_info of the value type of the + /// property identified by `name`. `typeid(void)` if `name` + /// does not identify any property. + /// + /// @tparam I The key type of the property. - template - const std::type_info& property_type(const std::string& name) { - return get_property_container().property_type(name); - } - /// @endcond + template + const std::type_info& property_type(const std::string& name) + { + return get_property_container().property_type(name); + } + /// @endcond - /// returns a vector with all strings that describe properties with the key type `I`. - /// @tparam I The key type of the properties. - template - std::vector properties() const { - return get_property_container().properties(); - } + /// returns a vector with all strings that describe properties with the key type `I`. + /// @tparam I The key type of the properties. + template + std::vector properties() const + { + return get_property_container().properties(); + } - /// returns the property for the string "v:point". - // todo: shouldn't this return a const pmap? - // In the original version, there was no difference between const & non-const maps - Property_array& - points() const { return vpoint_; } + /// returns the property for the string "v:point". + // todo: shouldn't this return a const pmap? + // In the original version, there was no difference between const & non-const maps + Property_array& + points() const { return vpoint_; } - Property_array& - points() { return vpoint_; } + Property_array& + points() { return vpoint_; } - /// returns the point associated to vertex `v`. - const Point& - point(Vertex_index v) const { return vpoint_[v]; } + /// returns the point associated to vertex `v`. + const Point& + point(Vertex_index v) const { return vpoint_[v]; } - /// returns the point associated to vertex `v`. - Point& - point(Vertex_index v) { return vpoint_[v]; } + /// returns the point associated to vertex `v`. + Point& + point(Vertex_index v) { return vpoint_[v]; } - /// @cond CGAL_DOCUMENT_INTERNALS - /// prints property statistics to the stream `out`. The output is human-readable but - /// not machine-friendly. - /// - void property_stats(std::ostream& out = std::cout) const; - /// @endcond - ///@} + /// @cond CGAL_DOCUMENT_INTERNALS + /// prints property statistics to the stream `out`. The output is human-readable but + /// not machine-friendly. + /// + void property_stats(std::ostream& out = std::cout) const; + /// @endcond + ///@} - /// \name Null Elements - ///@{ + /// \name Null Elements + ///@{ /// returns `Vertex_index(std::numeric_limits::%max())`. - static Vertex_index null_vertex() { + static Vertex_index null_vertex() + { return vertex_index((std::numeric_limits::max)()); } /// returns `Edge_index(std::numeric_limits::%max())`. - static Edge_index null_edge() { + static Edge_index null_edge() + { return edge_index((std::numeric_limits::max)()); } - /// returns `Halfedge_index(std::numeric_limits::%max())`. - static Halfedge_index null_halfedge() { + static Halfedge_index null_halfedge() + { return halfedge_index((std::numeric_limits::max)()); } - /// returns `Face_index(std::numeric_limits::%max())`. - static Face_index null_face() { + static Face_index null_face() + { return face_index((std::numeric_limits::max)()); } /// @} #if defined(CGAL_SURFACE_MESH_TEST_SUITE) - - std::vector vertex_freelist() const { - return vprops_.inactive_list(); + Vertex_index vertex_freelist() const + { + return Vertex_index(vertices_freelist_); } - std::vector face_freelist() const { - return fprops_.inactive_list(); + Face_index face_freelist() const + { + return Face_index(faces_freelist_); } - std::vector edge_freelist() const { - return eprops_.inactive_list(); + Edge_index edge_freelist() const + { + return Edge_index(edges_freelist_>>1); } - #endif private: //--------------------------------------------------- helper functions - /// make sure that the incoming halfedge of vertex v is a border halfedge - /// if `v` is a border vertex. - void adjust_incoming_halfedge(Vertex_index v); + /// make sure that the incoming halfedge of vertex v is a border halfedge + /// if `v` is a border vertex. + void adjust_incoming_halfedge(Vertex_index v); private: //------------------------------------------------------- private data - Property_container vprops_; - Property_container hprops_; - Property_container eprops_; - Property_container fprops_; + Property_container vprops_; + Property_container hprops_; + Property_container eprops_; + Property_container fprops_; - Property_array& vconn_; - Property_array& hconn_; - Property_array& fconn_; + Property_array& vconn_; + Property_array& hconn_; + Property_array& fconn_; - Property_array& vpoint_; + Property_array &vremoved_; + Property_array &eremoved_; + Property_array &fremoved_; - size_type vertices_freelist_; - size_type edges_freelist_; - size_type faces_freelist_; - bool recycle_ = true; + Property_array& vpoint_; - size_type anonymous_property_; + size_type removed_vertices_ = 0; + size_type removed_edges_ = 0; + size_type removed_faces_ = 0; + + size_type vertices_freelist_ = std::numeric_limits::max(); + size_type edges_freelist_ = std::numeric_limits::max(); + size_type faces_freelist_ = std::numeric_limits::max(); + bool garbage_ = false; + bool recycle_ = true; + + size_type anonymous_property_; }; -/*! \addtogroup PkgSurface_mesh - * - * @{ - */ + /*! \addtogroup PkgSurface_mesh + * + * @{ + */ -/// \relates Surface_mesh -/// Inserts `other` into `sm`. -/// Shifts the indices of vertices of `other` by `sm.number_of_vertices() + sm.number_of_removed_vertices()` -/// and analogously for halfedges, edges, and faces. -/// Copies entries of all property maps which have the same name in `sm` and `other`. -/// that is, property maps which are only in `other` are ignored. -/// Also copies elements which are marked as removed, and concatenates the freelists of `sm` and `other`. + /// \relates Surface_mesh + /// Inserts `other` into `sm`. + /// Shifts the indices of vertices of `other` by `sm.number_of_vertices() + sm.number_of_removed_vertices()` + /// and analogously for halfedges, edges, and faces. + /// Copies entries of all property maps which have the same name in `sm` and `other`. + /// that is, property maps which are only in `other` are ignored. + /// Also copies elements which are marked as removed, and concatenates the freelists of `sm` and `other`. -template -Surface_mesh

& operator+=(Surface_mesh

& sm, const Surface_mesh

& other) { - sm.join(other); - return sm; -} + template + Surface_mesh

& operator+=(Surface_mesh

& sm, const Surface_mesh

& other) + { + sm.join(other); + return sm; + } -/// \relates Surface_mesh -/// -/// This operator calls `write_OFF(std::ostream& os, const CGAL::Surface_mesh& sm)`. -template -std::ostream& operator<<(std::ostream& os, const Surface_mesh

& sm) { - IO::write_OFF(os, sm); - return os; -} + /// \relates Surface_mesh + /// + /// This operator calls `write_OFF(std::ostream& os, const CGAL::Surface_mesh& sm)`. + template + std::ostream& operator<<(std::ostream& os, const Surface_mesh

& sm) + { + IO::write_OFF(os, sm); + return os; + } -/// \relates Surface_mesh -/// Extracts the surface mesh from an input stream in OFF -/// and appends it to the surface mesh `sm`. -/// -/// This operator calls `read_OFF(std::istream& is, CGAL::Surface_mesh& sm)`. -template -std::istream& operator>>(std::istream& is, Surface_mesh

& sm) { - IO::read_OFF(is, sm); - return is; -} + /// \relates Surface_mesh + /// Extracts the surface mesh from an input stream in OFF + /// and appends it to the surface mesh `sm`. + /// + /// This operator calls `read_OFF(std::istream& is, CGAL::Surface_mesh& sm)`. + template + std::istream& operator>>(std::istream& is, Surface_mesh

& sm) + { + IO::read_OFF(is, sm); + return is; + } -/*! @} */ + /*! @} */ //----------------------------------------------------------------------------- template Surface_mesh

& Surface_mesh

:: -operator=(const Surface_mesh

& rhs) { - if (this != &rhs) { +operator=(const Surface_mesh

& rhs) +{ + if (this != &rhs) + { + // deep copy of property containers + vprops_ = rhs.vprops_; + hprops_ = rhs.hprops_; + eprops_ = rhs.eprops_; + fprops_ = rhs.fprops_; - // Deep copy of properties - vprops_ = rhs.vprops_; - hprops_ = rhs.hprops_; - eprops_ = rhs.eprops_; - fprops_ = rhs.fprops_; - - // Property array refs don't need to be reassigned, - // because the deep copy updated the values they point to + // Property array refs don't need to be reassigned, + // because the deep copy updated the values they point to - // how many elements are removed? - vertices_freelist_ = rhs.vertices_freelist_; - edges_freelist_ = rhs.edges_freelist_; - faces_freelist_ = rhs.faces_freelist_; - recycle_ = rhs.recycle_; - anonymous_property_ = rhs.anonymous_property_; - } + // how many elements are removed? + vertices_freelist_ = rhs.vertices_freelist_; + edges_freelist_ = rhs.edges_freelist_; + faces_freelist_ = rhs.faces_freelist_; + recycle_ = rhs.recycle_; + anonymous_property_ = rhs.anonymous_property_; + } - return *this; + return *this; } //----------------------------------------------------------------------------- @@ -2100,28 +2315,29 @@ operator=(const Surface_mesh

& rhs) { template void Surface_mesh

:: -property_stats(std::ostream& out) const { - std::vector props; +property_stats(std::ostream& out) const +{ + std::vector props; - out << "vertex properties:\n"; - props = properties(); - for (unsigned int i = 0; i < props.size(); ++i) - out << "\t" << props[i] << std::endl; + out << "vertex properties:\n"; + props = properties(); + for (unsigned int i=0; i(); - for (unsigned int i = 0; i < props.size(); ++i) - out << "\t" << props[i] << std::endl; + out << "halfedge properties:\n"; + props = properties(); + for (unsigned int i=0; i(); - for (unsigned int i = 0; i < props.size(); ++i) - out << "\t" << props[i] << std::endl; + out << "edge properties:\n"; + props = properties(); + for (unsigned int i=0; i(); - for (unsigned int i = 0; i < props.size(); ++i) - out << "\t" << props[i] << std::endl; + out << "face properties:\n"; + props = properties(); + for (unsigned int i=0; i typename Surface_mesh

::Halfedge_index Surface_mesh

:: -halfedge(Vertex_index source, Vertex_index target) const { - CGAL_assertion(has_valid_index(source) && has_valid_index(target)); +halfedge(Vertex_index source, Vertex_index target) const +{ + CGAL_assertion(has_valid_index(source) && has_valid_index(target)); - Halfedge_index h = halfedge(target); - const Halfedge_index hh = h; + Halfedge_index h = halfedge(target); + const Halfedge_index hh = h; - if (h.is_valid()) { - do { - if (this->source(h) == source) - return h; - h = next_around_target(h); - } while (h != hh); - } + if (h.is_valid()) + { + do + { + if (this->source(h) == source) + return h; + h = next_around_target(h); + } + while (h != hh); + } - return Halfedge_index(); + return Halfedge_index(); } @@ -2151,116 +2371,291 @@ halfedge(Vertex_index source, Vertex_index target) const { template void Surface_mesh

:: -adjust_incoming_halfedge(Vertex_index v) { - Halfedge_index h = halfedge(v); - Halfedge_index hh = h; +adjust_incoming_halfedge(Vertex_index v) +{ + Halfedge_index h = halfedge(v); + Halfedge_index hh = h; - if (h.is_valid()) { - if (target(h) != v) { - // wrong target, flip - h = opposite(h); - hh = h; - set_halfedge(v, h); + if (h.is_valid()) + { + if (target(h) != v) + { + // wrong target, flip + h = opposite(h); + hh = h; + set_halfedge(v, h); + } + + do + { + if (is_border(h)) + { + set_halfedge(v, h); + return; + } + h = next_around_target(h); + } + while (h != hh); } - - do { - if (is_border(h)) { - set_halfedge(v, h); - return; - } - h = next_around_target(h); - } while (h != hh); - } } //----------------------------------------------------------------------------- -/// @cond CGAL_DOCUMENT_INTERNALS + /// @cond CGAL_DOCUMENT_INTERNALS template template typename Surface_mesh

::Face_index -Surface_mesh

::add_face(const Range& r) { +Surface_mesh

::add_face(const Range& r) +{ return CGAL::Euler::add_face(r, *this); } -/// @endcond + /// @endcond //----------------------------------------------------------------------------- template typename Surface_mesh

::size_type Surface_mesh

:: -degree(Vertex_index v) const { - Halfedge_index h = halfedge(v); +degree(Vertex_index v) const +{ + Halfedge_index h = halfedge(v); - if (h == null_halfedge()) { - return 0; - } - size_type count(0); - Halfedge_index done = h; - do { - ++count; - h = opposite(next(h)); - } while (h != done); - - return count; -} - - -//----------------------------------------------------------------------------- -template -typename Surface_mesh

::size_type -Surface_mesh

:: -degree(Face_index f) const { - size_type count(0); - if (halfedge(f) == null_halfedge()) { - return 0; - } - Vertex_around_face_circulator fvit(halfedge(f), *this); - Vertex_around_face_circulator fvend = fvit; - if (fvit) + if(h == null_halfedge()){ + return 0; + } + size_type count(0); + Halfedge_index done = h; do { ++count; + h = opposite(next(h)); + }while(h != done); + + return count; +} + + +//----------------------------------------------------------------------------- +template +typename Surface_mesh

::size_type +Surface_mesh

:: +degree(Face_index f) const +{ + size_type count(0); + if(halfedge(f) == null_halfedge()){ + return 0; + } + Vertex_around_face_circulator fvit(halfedge(f),*this); + Vertex_around_face_circulator fvend = fvit; + if(fvit) do { + ++count; } while (++fvit != fvend); - return count; + return count; } +template template< typename Visitor> +void +Surface_mesh

:: +collect_garbage(Visitor &visitor) +{ + if (!has_garbage()) + { + return; + } -namespace internal { -namespace handle { -template <> -struct Hash_functor { - std::size_t - operator()(const SM_Vertex_index i) { - return i; - } -}; + std::uint32_t i, i0, i1, + nV(num_vertices()), + nE(num_edges()), + nH(num_halfedges()), + nF(num_faces()); -template <> -struct Hash_functor { - std::size_t - operator()(const SM_Halfedge_index i) { - return i; - } -}; + Vertex_index v; + Halfedge_index h; + Face_index f; -template <> -struct Hash_functor { - std::size_t - operator()(const SM_Edge_index i) { - return i; - } -}; -template <> -struct Hash_functor { - std::size_t - operator()(const SM_Face_index i) { - return i; - } -}; + // setup index mapping% + Property_map vmap = add_property_map("v:garbage-collection").first; + Property_map hmap = add_property_map("h:garbage-collection").first; + Property_map fmap = add_property_map("f:garbage-collection").first; + for (i=0; i 0) + { + i0=0; i1=nV-1; + + while (1) + { + // find first removed and last un-removed + while (!vremoved_[Vertex_index(i0)] && i0 < i1) ++i0; + while ( vremoved_[Vertex_index(i1)] && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + vprops_.swap(i0, i1); + }; + + // remember new size + nV = vremoved_[Vertex_index(i0)] ? i0 : i0+1; + } + + // really remove edges + if (nE > 0) + { + i0=0; i1=nE-1; + + while (1) + { + // find first removed and last un-removed + while (!eremoved_[Edge_index(i0)] && i0 < i1) ++i0; + while ( eremoved_[Edge_index(i1)] && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + eprops_.swap(SM_Edge_index{i0}, SM_Edge_index{i1}); + hprops_.swap(SM_Halfedge_index{2*i0}, SM_Halfedge_index{2*i1}); + hprops_.swap(SM_Halfedge_index{2*i0+1}, SM_Halfedge_index{2*i1+1}); + }; + + // remember new size + nE = eremoved_[Edge_index(i0)] ? i0 : i0+1; + nH = 2*nE; + } + + + // really remove faces + if (nF > 0) + { + i0=0; i1=nF-1; + + while (1) + { + // find 1st removed and last un-removed + while (!fremoved_[Face_index(i0)] && i0 < i1) ++i0; + while ( fremoved_[Face_index(i1)] && i0 < i1) --i1; + if (i0 >= i1) break; + + // swap + fprops_.swap(SM_Face_index{i0}, SM_Face_index{i1}); + }; + + // remember new size + nF = fremoved_[Face_index(i0)] ? i0 : i0+1; + } + + + // update vertex connectivity + for (i=0; i(vmap); + remove_property_map(hmap); + remove_property_map(fmap); + + // finally resize arrays + vprops_.resize(nV); vprops_.shrink_to_fit(); + hprops_.resize(nH); hprops_.shrink_to_fit(); + eprops_.resize(nE); eprops_.shrink_to_fit(); + fprops_.resize(nF); fprops_.shrink_to_fit(); + + removed_vertices_ = removed_edges_ = removed_faces_ = 0; + vertices_freelist_ = edges_freelist_ = faces_freelist_ = -1; + garbage_ = false; } + +#ifndef DOXYGEN_RUNNING +namespace collect_garbage_internal { +struct Dummy_visitor{ + template + void operator()(const A&, const B&, const C&) + {} +}; + +} +#endif + +template +void +Surface_mesh

:: +collect_garbage() +{ + collect_garbage_internal::Dummy_visitor visitor; + collect_garbage(visitor); +} + +namespace internal{ + namespace handle { + template <> + struct Hash_functor{ + std::size_t + operator()(const SM_Vertex_index i) + { + return i; + } + }; + + template <> + struct Hash_functor{ + std::size_t + operator()(const SM_Halfedge_index i) + { + return i; + } + }; + + template <> + struct Hash_functor{ + std::size_t + operator()(const SM_Edge_index i) + { + return i; + } + }; + + template <> + struct Hash_functor{ + std::size_t + operator()(const SM_Face_index i) + { + return i; + } + }; + } } } // namespace CGAL @@ -2276,42 +2671,45 @@ namespace std { #ifndef CGAL_CFG_NO_STD_HASH -template <> -struct hash - : public CGAL::cpp98::unary_function { + template <> + struct hash + : public CGAL::cpp98::unary_function { - std::size_t operator()(const CGAL::SM_Halfedge_index& i) const { - return i; - } -}; + std::size_t operator()(const CGAL::SM_Halfedge_index& i) const + { + return i; + } + }; -template <> -struct hash - : public CGAL::cpp98::unary_function { + template <> + struct hash + : public CGAL::cpp98::unary_function { - std::size_t operator()(const CGAL::SM_Vertex_index& i) const { - return i; - } -}; + std::size_t operator()(const CGAL::SM_Vertex_index& i) const + { + return i; + } + }; -template <> -struct hash - : public CGAL::cpp98::unary_function { + template <> + struct hash + : public CGAL::cpp98::unary_function { - std::size_t operator()(const CGAL::SM_Face_index& i) const { - return i; - } -}; + std::size_t operator()(const CGAL::SM_Face_index& i) const + { + return i; + } + }; -template <> -struct hash - : public CGAL::cpp98::unary_function { - - std::size_t operator()(const CGAL::SM_Edge_index& i) const { - return i; - } -}; + template <> + struct hash + : public CGAL::cpp98::unary_function { + std::size_t operator()(const CGAL::SM_Edge_index& i) const + { + return i; + } + }; #endif // CGAL_CFG_NO_STD_HASH #if defined(BOOST_MSVC) @@ -2321,12 +2719,13 @@ struct hash } // namespace std namespace boost { -template <> -struct hash { - std::size_t operator()(const CGAL::SM_Vertex_index& i) const { - return i; - } -}; + template <> + struct hash { + std::size_t operator()(const CGAL::SM_Vertex_index& i) const + { + return i; + } + }; } // namespace boost diff --git a/Surface_mesh/test/Surface_mesh/sm_circulator_test.cpp b/Surface_mesh/test/Surface_mesh/sm_circulator_test.cpp index 5e932869a44..bf446b30959 100644 --- a/Surface_mesh/test/Surface_mesh/sm_circulator_test.cpp +++ b/Surface_mesh/test/Surface_mesh/sm_circulator_test.cpp @@ -64,20 +64,20 @@ struct test_emptiness : public Surface_fixture assert(m.is_isolated(iv)); Sm::Vertex_around_target_range vr = m.vertices_around_target(m.halfedge(iv)); - assert(is_empty_range(std::begin(vr), std::end(vr))); + assert(is_empty_range(boost::begin(vr), boost::end(vr))); Sm::Face_around_target_range fr = m.faces_around_target(m.halfedge(iv)); - assert(is_empty_range(std::begin(fr), std::end(fr))); + assert(is_empty_range(boost::begin(fr), boost::end(fr))); Sm::Halfedge_around_target_range hr = m.halfedges_around_target(m.halfedge(iv)); - assert(is_empty_range(std::begin(hr), std::end(hr))); + assert(is_empty_range(boost::begin(hr), boost::end(hr))); // not true for everything else m.remove_vertex(iv); assert(m.is_removed(iv)); Sm::Vertex_iterator vb, ve; for(boost::tie(vb, ve) = m.vertices(); vb != ve; ++vb) { Sm::Vertex_around_target_range vr = m.vertices_around_target(m.halfedge(*vb)); - assert(!is_empty_range(std::begin(vr), std::end(vr))); + assert(!is_empty_range(boost::begin(vr), boost::end(vr))); } } }; diff --git a/Surface_mesh/test/Surface_mesh/sm_join_test.cpp b/Surface_mesh/test/Surface_mesh/sm_join_test.cpp index 65b83c9fef6..4a71243b8e4 100644 --- a/Surface_mesh/test/Surface_mesh/sm_join_test.cpp +++ b/Surface_mesh/test/Surface_mesh/sm_join_test.cpp @@ -19,24 +19,35 @@ typedef boost::graph_traits::face_descriptor face_descriptor; void freelist(const Sm& sm, int vc, int fc, int ec) { - // vc should be the number of in-active vertex indices std::cout << "vertex freelist" << std::endl; - auto unused_vertices = sm.vertex_freelist(); - for (auto vd: unused_vertices) + vertex_descriptor vd = sm.vertex_freelist(); + while(vd != sm.null_vertex()){ + --vc; std::cout << vd << std::endl; - assert(vc == unused_vertices.size()); + halfedge_descriptor hd = halfedge(vd,sm); + vd = vertex_descriptor((Sm::size_type)hd); + } + assert(vc == 0); std::cout << "face freelist" << std::endl; - auto unused_faces = sm.face_freelist(); - for (auto fd: unused_faces) + face_descriptor fd = sm.face_freelist(); + while(fd != sm.null_face()){ + --fc; std::cout << fd << std::endl; - assert(fc == unused_faces.size()); + halfedge_descriptor hd = halfedge(fd,sm); + fd = face_descriptor((Sm::size_type)hd); + } + assert(fc == 0); std::cout << "edge freelist" << std::endl; - auto unused_edges = sm.edge_freelist(); - for (auto ed: unused_edges) + edge_descriptor ed = sm.edge_freelist(); + while(ed != sm.null_edge()){ + --ec; std::cout << ed << std::endl; - assert(ec == unused_edges.size()); + halfedge_descriptor hd = next(halfedge(ed,sm),sm); + ed = edge(hd,sm); + } + assert(ec == 0); } diff --git a/Surface_mesh/test/Surface_mesh/sm_remove.cpp b/Surface_mesh/test/Surface_mesh/sm_remove.cpp index 6744fbf77b2..5aadc4a132e 100644 --- a/Surface_mesh/test/Surface_mesh/sm_remove.cpp +++ b/Surface_mesh/test/Surface_mesh/sm_remove.cpp @@ -19,13 +19,13 @@ int main() Sm m; Sm::vertex_index u; - assert(m.number_of_vertices() == 0); + assert(m.num_vertices() == 0); assert(m.number_of_removed_vertices() == 0); for(int i=0; i < 10; i++){ u = m.add_vertex(Point_3(0,0,0)); m.remove_vertex(u); } - assert(m.number_of_vertices() == 0); + assert(m.num_vertices() == 1); assert(m.number_of_removed_vertices() == 1); @@ -34,23 +34,26 @@ int main() assert(! m.does_recycle_garbage()); m.add_vertex(Point_3(0,0,0)); - assert(m.number_of_vertices() == 1); + assert(m.num_vertices() == 2); assert(m.number_of_removed_vertices() == 1); m.set_recycle_garbage(true); m.add_vertex(Point_3(0,0,0)); - assert(m.number_of_vertices() == 2); + assert(m.num_vertices() == 2); assert(m.number_of_removed_vertices() == 0); - std::cout << m.number_of_vertices() << " " << m.number_of_removed_vertices() << std::endl; + std::cout << m.num_vertices() << " " << m.number_of_removed_vertices() << std::endl; // make sure all is OK when clearing the mesh - auto vconn = m.add_property_map("v:connectivity").first; - auto hconn = m.add_property_map("h:connectivity").first; - auto fconn = m.add_property_map("f:connectivity").first; - auto vpoint = m.add_property_map("v:point").first; + auto vconn = m.property_map("v:connectivity").first; + auto hconn = m.property_map("h:connectivity").first; + auto fconn = m.property_map("f:connectivity").first; + auto vpoint = m.property_map("v:point").first; + auto vremoved = m.property_map("v:removed").first; + auto eremoved = m.property_map("e:removed").first; + auto fremoved = m.property_map("f:removed").first; // first call to squat the first available position m.add_property_map("vprop_dummy"); @@ -71,10 +74,13 @@ int main() auto l_fprop = m.add_property_map("fprop").first; auto l_eprop = m.add_property_map("eprop").first; - auto l_vconn = m.add_property_map("v:connectivity").first; - auto l_hconn = m.add_property_map("h:connectivity").first; - auto l_fconn = m.add_property_map("f:connectivity").first; - auto l_vpoint = m.add_property_map("v:point").first; + auto l_vconn = m.property_map("v:connectivity").first; + auto l_hconn = m.property_map("h:connectivity").first; + auto l_fconn = m.property_map("f:connectivity").first; + auto l_vpoint = m.property_map("v:point").first; + auto l_vremoved = m.property_map("v:removed").first; + auto l_eremoved = m.property_map("e:removed").first; + auto l_fremoved = m.property_map("f:removed").first; assert( vconn == l_vconn ); assert( hconn == l_hconn ); @@ -89,10 +95,13 @@ int main() { m.clear(); - auto l_vconn = m.add_property_map("v:connectivity").first; - auto l_hconn = m.add_property_map("h:connectivity").first; - auto l_fconn = m.add_property_map("f:connectivity").first; - auto l_vpoint = m.add_property_map("v:point").first; + auto l_vconn = m.property_map("v:connectivity").first; + auto l_hconn = m.property_map("h:connectivity").first; + auto l_fconn = m.property_map("f:connectivity").first; + auto l_vpoint = m.property_map("v:point").first; + auto l_vremoved = m.property_map("v:removed").first; + auto l_eremoved = m.property_map("e:removed").first; + auto l_fremoved = m.property_map("f:removed").first; assert( vconn == l_vconn ); assert( hconn == l_hconn ); diff --git a/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Tetrahedral_remeshing.txt b/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Tetrahedral_remeshing.txt index 6336998d527..5ae7a827373 100644 --- a/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Tetrahedral_remeshing.txt +++ b/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Tetrahedral_remeshing.txt @@ -15,7 +15,7 @@ namespace CGAL { \section secTetRemeshing Multi-Material Isotropic Tetrahedral Remeshing This package implements an algorithm for quality tetrahedral remeshing, -introduced by N.Faraj et al in \cgalCite{faraj2016mvr}. +introduced by Faraj et al in \cgalCite{faraj2016mvr}. This practical iterative remeshing algorithm is designed to remesh multi-material tetrahedral meshes, by iteratively performing a sequence of elementary operations such as edge splits, edge collapses, edge flips,