diff --git a/.gitignore b/.gitignore index 07f7e4fc0a8..1eb3c5efaad 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ /*/*/*/build /*/*/*/VC* /*/*/*/GCC +.vscode AABB_tree/demo/AABB_tree/AABB_demo AABB_tree/demo/AABB_tree/Makefile AABB_tree/examples/AABB_tree/*.kdev* diff --git a/AABB_tree/include/CGAL/AABB_primitive.h b/AABB_tree/include/CGAL/AABB_primitive.h index faae18e0bf2..b0e9abdaf38 100644 --- a/AABB_tree/include/CGAL/AABB_primitive.h +++ b/AABB_tree/include/CGAL/AABB_primitive.h @@ -53,9 +53,8 @@ public: * The two property maps which are template parameters of the class enable to get the datum and the reference point of * the primitive from the identifier. The last template parameter controls whether the primitive class holds a copy of the datum. * - * \cgalModels `AABBPrimitive` if `ExternalPropertyMaps` is `CGAL::Tag_false`, - * and `AABBPrimitiveWithSharedData` if `ExternalPropertyMaps` is `CGAL::Tag_true`. - * + * \cgalModels `AABBPrimitive` if `ExternalPropertyMaps` is `CGAL::Tag_false`. + * \cgalModels `AABBPrimitiveWithSharedData` if `ExternalPropertyMaps` is `CGAL::Tag_true`. * * \tparam ObjectPropertyMap is a model of `ReadablePropertyMap` with `Id` as * `key_type`. It must be a model of `CopyConstructible`, `DefaultConstructible`, and `CopyAssignable`. @@ -70,7 +69,6 @@ public: * it is constructed on the fly to reduce the memory footprint. * The default is `CGAL::Tag_false` (datum is not stored). * - * \sa `AABBPrimitive` * \sa `AABB_segment_primitive` * \sa `AABB_triangle_primitive` * \sa `AABB_halfedge_graph_segment_primitive` diff --git a/AABB_tree/include/CGAL/AABB_tree.h b/AABB_tree/include/CGAL/AABB_tree.h index 3985cf099db..0016d4ecc09 100644 --- a/AABB_tree/include/CGAL/AABB_tree.h +++ b/AABB_tree/include/CGAL/AABB_tree.h @@ -562,11 +562,14 @@ public: /** * @brief Builds the tree by recursive expansion. + * @param node the root node of the subtree to generate * @param first the first primitive to insert - * @param last the last primitive to insert + * @param beyond the last primitive to insert * @param range the number of primitive of the range + * @param compute_bbox a functor + * @param split_primitives a functor * - * [first,last[ is the range of primitives to be added to the tree. + * [first,beyond[ is the range of primitives to be added to the tree. */ template void expand(Node& node, @@ -574,8 +577,7 @@ public: ConstPrimitiveIterator beyond, const std::size_t range, const ComputeBbox& compute_bbox, - const SplitPrimitives& split_primitives, - const AABBTraits&); + const SplitPrimitives& split_primitives); public: // returns a point which must be on one primitive @@ -791,8 +793,7 @@ public: ConstPrimitiveIterator beyond, const std::size_t range, const ComputeBbox& compute_bbox, - const SplitPrimitives& split_primitives, - const Tr& traits) + const SplitPrimitives& split_primitives) { node.set_bbox(compute_bbox(first, beyond)); @@ -806,13 +807,13 @@ public: break; case 3: node.set_children(*first, new_node()); - expand(node.right_child(), first+1, beyond, 2, compute_bbox, split_primitives, traits); + expand(node.right_child(), first+1, beyond, 2, compute_bbox, split_primitives); break; default: const std::size_t new_range = range/2; node.set_children(new_node(), new_node()); - expand(node.left_child(), first, first + new_range, new_range, compute_bbox, split_primitives, traits); - expand(node.right_child(), first + new_range, beyond, range - new_range, compute_bbox, split_primitives, traits); + expand(node.left_child(), first, first + new_range, new_range, compute_bbox, split_primitives); + expand(node.right_child(), first + new_range, beyond, range - new_range, compute_bbox, split_primitives); } } @@ -844,8 +845,7 @@ public: m_primitives.begin(), m_primitives.end(), m_primitives.size(), compute_bbox, - split_primitives, - m_traits); + split_primitives); } #ifdef CGAL_HAS_THREADS m_atomic_need_build.store(false, std::memory_order_release); // in case build() is triggered by a call to root_node() diff --git a/Alpha_shapes_3/doc/Alpha_shapes_3/Doxyfile.in b/Alpha_shapes_3/doc/Alpha_shapes_3/Doxyfile.in index 6fe61e68211..76909d608fa 100644 --- a/Alpha_shapes_3/doc/Alpha_shapes_3/Doxyfile.in +++ b/Alpha_shapes_3/doc/Alpha_shapes_3/Doxyfile.in @@ -2,5 +2,4 @@ PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 3D Alpha Shapes" -EXAMPLE_PATH = ${CGAL_Alpha_shapes_2_EXAMPLE_DIR} \ - ${CGAL_Alpha_shapes_3_EXAMPLE_DIR} +EXAMPLE_PATH += ${CGAL_Alpha_shapes_2_EXAMPLE_DIR} 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 1ff887f02e4..eca3fa1654e 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 @@ -75,7 +75,7 @@ int main(int argc, char** argv) std::cerr << "Invalid point set input: " << ps_filename << std::endl; return EXIT_FAILURE; } - std::cout << ps_points.size() << " points (Point Set)" << std::endl; + std::cout << ps_points.size() << " points (point set)" << std::endl; const double relative_alpha = (argc > 4) ? std::stod(argv[4]) : 15.; const double relative_offset = (argc > 5) ? std::stod(argv[5]) : 450.; @@ -93,9 +93,9 @@ int main(int argc, char** argv) CGAL::Real_timer t; t.start(); - using TS_Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle; - using SS_Oracle = CGAL::Alpha_wraps_3::internal::Segment_soup_oracle; - using Oracle = CGAL::Alpha_wraps_3::internal::Point_set_oracle; + using TS_Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle; + using SS_Oracle = CGAL::Alpha_wraps_3::internal::Segment_soup_oracle; + using Oracle = CGAL::Alpha_wraps_3::internal::Point_set_oracle; TS_Oracle ts_oracle(K{}); SS_Oracle ss_oracle(ts_oracle); @@ -124,6 +124,7 @@ int main(int argc, char** argv) ps_name = ps_name.substr(0, ps_name.find_last_of(".")); std::string output_name = ts_name + "_" + ss_name + "_" + ps_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, output_mesh, CGAL::parameters::stream_precision(17)); return EXIT_SUCCESS; diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp index 8520713f0d2..feaa9c804af 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/point_set_wrap.cpp @@ -31,6 +31,8 @@ int main(int argc, char** argv) return EXIT_FAILURE; } + std::cout << points.size() << " points" << std::endl; + // Compute the alpha and offset values const double relative_alpha = (argc > 2) ? std::stod(argv[2]) : 10.; const double relative_offset = (argc > 3) ? std::stod(argv[3]) : 300.; @@ -41,6 +43,7 @@ int main(int argc, char** argv) CGAL::square(bbox.zmax() - bbox.zmin())); const double alpha = diag_length / relative_alpha; const double offset = diag_length / relative_offset; + std::cout << "absolute alpha = " << alpha << " absolute offset = " << offset << std::endl; // Construct the wrap CGAL::Real_timer t; @@ -59,6 +62,7 @@ int main(int argc, char** argv) 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)); return EXIT_SUCCESS; diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp index 2f3655eb660..b4b1ec067ff 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/triangle_mesh_wrap.cpp @@ -64,6 +64,7 @@ int main(int argc, char** argv) 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)); return EXIT_SUCCESS; diff --git a/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp b/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp index 0cc59a21d81..91b95584f8c 100644 --- a/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp +++ b/Alpha_wrap_3/examples/Alpha_wrap_3/wrap_from_cavity.cpp @@ -47,7 +47,7 @@ int main(int argc, char** argv) const double offset = diag_length / relative_offset; // Construct the wrap - using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_mesh_oracle; + using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_mesh_oracle; Oracle oracle; oracle.add_triangle_mesh(input); @@ -78,6 +78,7 @@ int main(int argc, char** argv) input_name = input_name.substr(0, input_name.find_last_of(".")); std::string output_name = input_name + "_cavity_" + 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)); 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 51e54a8a4e7..e88e00fafe0 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 @@ -19,6 +19,11 @@ #ifdef CGAL_AW3_DEBUG_PP #ifndef CGAL_AW3_DEBUG #define CGAL_AW3_DEBUG + #define CGAL_AW3_DEBUG_INITIALIZATION + #define CGAL_AW3_DEBUG_STEINER_COMPUTATION + #define CGAL_AW3_DEBUG_QUEUE + #define CGAL_AW3_DEBUG_FACET_STATUS + #define CGAL_AW3_DEBUG_MANIFOLDNESS #endif #endif @@ -94,6 +99,32 @@ public: }; }; +struct Wrapping_default_visitor +{ + Wrapping_default_visitor() { } + + template + void on_alpha_wrapping_begin(const AlphaWrapper&) { } + + template + void on_flood_fill_begin(const AlphaWrapper&) { } + + template + void before_facet_treatment(const AlphaWrapper&, const Gate&) { } + + template + void before_Steiner_point_insertion(const Wrapper&, const Point&) { } + + template + void after_Steiner_point_insertion(const Wrapper&, VertexHandle) { } + + template + void on_flood_fill_end(const AlphaWrapper&) { } + + template + void on_alpha_wrapping_end(const AlphaWrapper&) { }; +}; + template class Alpha_wrap_3 { @@ -167,6 +198,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 Alpha_PQ& queue() const { return m_queue; } double default_alpha() const { @@ -211,6 +245,15 @@ public: OVPM ovpm = choose_parameter(get_parameter(np, internal_np::vertex_point), get_property_map(vertex_point, output_mesh)); + typedef typename internal_np::Lookup_named_param_def < + internal_np::visitor_t, + NamedParameters, + Wrapping_default_visitor // default + >::reference Visitor; + + Wrapping_default_visitor default_visitor; + Visitor visitor = choose_parameter(get_parameter_reference(np, internal_np::visitor), default_visitor); + std::vector no_seeds; using Seeds = typename internal_np::Lookup_named_param_def< internal_np::seed_points_t, NamedParameters, std::vector >::reference; @@ -223,6 +266,8 @@ public: t.start(); #endif + visitor.on_alpha_wrapping_begin(*this); + if(!initialize(alpha, offset, seeds)) return; @@ -232,7 +277,7 @@ public: CGAL::parameters::vertex_point_map(ovpm).stream_precision(17)); #endif - alpha_flood_fill(); + alpha_flood_fill(visitor); #ifdef CGAL_AW3_TIMER t.stop(); @@ -306,10 +351,12 @@ public: std::cout << "Alpha wrap faces: " << faces(output_mesh).size() << std::endl; #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP - IO::write_polygon_mesh("final.off", alpha_wrap, CGAL::parameters::stream_precision(17)); + IO::write_polygon_mesh("final.off", output_mesh, CGAL::parameters::stream_precision(17)); dump_triangulation_faces("final_dt3.off", false /*only_boundary_faces*/); #endif #endif + + visitor.on_alpha_wrapping_end(*this); } // Convenience overloads @@ -602,11 +649,12 @@ private: return true; } +public: // Manifoldness is tolerated while debugging and extracting at intermediate states // Not the preferred way because it uses 3*nv storage template void extract_possibly_non_manifold_surface(OutputMesh& output_mesh, - OVPM ovpm) + OVPM ovpm) const { namespace PMP = Polygon_mesh_processing; @@ -691,7 +739,7 @@ private: template void extract_manifold_surface(OutputMesh& output_mesh, - OVPM ovpm) + OVPM ovpm) const { namespace PMP = Polygon_mesh_processing; @@ -743,7 +791,12 @@ private: if(faces.empty()) return; - CGAL_assertion(PMP::is_polygon_soup_a_polygon_mesh(faces)); + if(!PMP::is_polygon_soup_a_polygon_mesh(faces)) + { + CGAL_warning_msg(false, "Could NOT extract mesh..."); + return; + } + PMP::polygon_soup_to_polygon_mesh(points, faces, output_mesh, CGAL::parameters::default_values(), CGAL::parameters::vertex_point_map(ovpm)); @@ -758,7 +811,7 @@ private: template void extract_surface(OutputMesh& output_mesh, OVPM ovpm, - const bool tolerate_non_manifoldness = false) + const bool tolerate_non_manifoldness = false) const { if(tolerate_non_manifoldness) extract_possibly_non_manifold_surface(output_mesh, ovpm); @@ -788,9 +841,9 @@ private: const bool is_neighbor_cc_in_offset = m_oracle.do_intersect(neighbor_cc_offset_ball); #ifdef CGAL_AW3_DEBUG_STEINER_COMPUTATION - const Point_3& chc = circumcenter(ch); + std::cout << "Compute_steiner_point(" << &*ch << ", " << &*neighbor << ")" << std::endl; - std::cout << "Compute_steiner_point()" << std::endl; + const Point_3& chc = circumcenter(ch); std::cout << "CH" << std::endl; std::cout << "\t" << ch->vertex(0)->point() << std::endl; std::cout << "\t" << ch->vertex(1)->point() << std::endl; @@ -985,12 +1038,15 @@ private: return initialize_with_cavities(seeds); } - void alpha_flood_fill() + template + void alpha_flood_fill(Visitor& visitor) { #ifdef CGAL_AW3_DEBUG std::cout << "> Flood fill..." << std::endl; #endif + visitor.on_flood_fill_begin(*this); + // Explore all finite cells that are reachable from one of the initial outside cells. while(!m_queue.empty()) { @@ -1012,11 +1068,13 @@ private: std::cout << m_dt.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" + << "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; std::cout << "Priority: " << gate.priority() << std::endl; #endif + visitor.before_facet_treatment(*this, gate); + m_queue.pop(); #ifdef CGAL_AW3_DEBUG_DUMP_EVERY_STEP @@ -1077,10 +1135,14 @@ private: m_queue.erase(Gate(mf)); } + 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; + 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)); @@ -1128,6 +1190,8 @@ private: } } // while(!queue.empty()) + 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;) diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_traits.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_traits.h index 8b55605d887..1a3fa7d8183 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_traits.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Alpha_wrap_AABB_traits.h @@ -267,7 +267,11 @@ public: for(int i=0; i<4; ++i) { - if(!q.m_b.test(i) && do_overlap(q.m_tbox[i], bb) && Base::operator()(q.m_triangles[i], bb)) + // this overload of do_intersect() must not filter based on q.m_b because + // it is called from the AABB_tree's traversal with a node's bounding box, + // and the fact that a facet is incident to an outside cell is irrelevant + // for the hierarchy of bounding boxes of the primitives. + if(do_overlap(q.m_tbox[i], bb) && Base::operator()(q.m_triangles[i], bb)) return true; } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Oracle_base.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Oracle_base.h index 5eba09bce0d..c38157a59bf 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Oracle_base.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Oracle_base.h @@ -142,41 +142,85 @@ public: BaseOracle& base() { return static_cast(*this); } const BaseOracle& base() const { return static_cast(*this); } + bool empty() const { return m_tree_ptr->empty(); } + bool do_call() const { return (!empty() || base().do_call()); } + public: typename AABB_tree::Bounding_box bbox() const { - CGAL_precondition(!tree().empty()); + CGAL_precondition(do_call()); - return base().bbox() + tree().bbox(); + typename AABB_tree::Bounding_box bb; + + if(base().do_call()) + bb += base().bbox(); + + if(!empty()) + bb += tree().bbox(); + + return bb; } template bool do_intersect(const T& t) const { - if(base().do_intersect(t)) + CGAL_precondition(do_call()); + + if(base().do_call() && base().do_intersect(t)) return true; - return AABB_helper::do_intersect(t, tree()); + if(!empty()) + return AABB_helper::do_intersect(t, tree()); + + return false; } FT squared_distance(const Point_3& p) const { - const FT base_sqd = base().squared_distance(p); + CGAL_precondition(do_call()); - // @speed could do a smarter traversal, no need to search deeper than the current best - const FT this_sqd = AABB_helper::squared_distance(p, tree()); - - return (std::min)(base_sqd, this_sqd); + if(base().do_call()) + { + if(!empty()) // both non empty + { + const FT base_sqd = base().squared_distance(p); + // @speed could do a smarter traversal, no need to search deeper than the current best + const FT this_sqd = AABB_helper::squared_distance(p, tree()); + return (std::min)(base_sqd, this_sqd); + } + else // this level is empty + { + return base().squared_distance(p); + } + } + else // empty base + { + return AABB_helper::squared_distance(p, tree()); + } } Point_3 closest_point(const Point_3& p) const { - const Point_3 base_c = base().closest_point(p); + CGAL_precondition(do_call()); - // @speed could do a smarter traversal, no need to search deeper than the current best - const Point_3 this_c = AABB_helper::closest_point(p, tree()); - - return (compare_distance_to_point(p, base_c, this_c) == CGAL::SMALLER) ? base_c : this_c; + if(base().do_call()) + { + if(!empty()) // both non empty + { + const Point_3 base_c = base().closest_point(p); + // @speed could do a smarter traversal, no need to search deeper than the current best + const Point_3 this_c = AABB_helper::closest_point(p, tree()); + return (compare_distance_to_point(p, base_c, this_c) == CGAL::SMALLER) ? base_c : this_c; + } + else // this level is empty + { + return base().closest_point(p); + } + } + else // empty base + { + return AABB_helper::closest_point(p, tree()); + } } bool first_intersection(const Point_3& p, const Point_3& q, @@ -184,22 +228,38 @@ public: const FT offset_size, const FT intersection_precision) const { - Point_3 base_o; - bool base_b = base().first_intersection(p, q, base_o, offset_size, intersection_precision); + CGAL_precondition(do_call()); - if(base_b) + if(base().do_call()) { - // @speed could do a smarter traversal, no need to search deeper than the current best - Point_3 this_o; - bool this_b = AABB_helper::first_intersection(p, q, this_o, offset_size, intersection_precision, tree()); - if(this_b) - o = (compare_distance_to_point(p, base_o, this_o) == SMALLER) ? base_o : this_o; - else - o = base_o; + if(!empty()) // both non empty + { + Point_3 base_o; + bool base_b = base().first_intersection(p, q, base_o, offset_size, intersection_precision); - return true; + if(base_b) // intersection found in base + { + // @speed could do a smarter traversal, no need to search deeper than the current best + Point_3 this_o; + bool this_b = AABB_helper::first_intersection(p, q, this_o, offset_size, intersection_precision, tree()); + if(this_b) + o = (compare_distance_to_point(p, base_o, this_o) == SMALLER) ? base_o : this_o; + else + o = base_o; + + return true; + } + else // no intersection found in non-empty base + { + return AABB_helper::first_intersection(p, q, o, offset_size, intersection_precision, tree()); + } + } + else // this level is empty + { + return base().first_intersection(p, q, o, offset_size, intersection_precision); + } } - else + else // empty base { return AABB_helper::first_intersection(p, q, o, offset_size, intersection_precision, tree()); } @@ -250,10 +310,13 @@ public: AABB_tree& tree() { return *m_tree_ptr; } const AABB_tree& tree() const { return *m_tree_ptr; } + bool empty() const { return m_tree_ptr->empty(); } + bool do_call() const { return !empty(); } + public: typename AABB_tree::Bounding_box bbox() const { - CGAL_precondition(!tree().empty()); + CGAL_precondition(!empty()); return tree().bbox(); } @@ -261,27 +324,32 @@ public: template bool do_intersect(const T& t) const { + CGAL_precondition(!empty()); return AABB_helper::do_intersect(t, tree()); } FT squared_distance(const Point_3& p) const { + CGAL_precondition(!empty()); return AABB_helper::squared_distance(p, tree()); } Point_3 closest_point(const Point_3& p) const { + CGAL_precondition(!empty()); return AABB_helper::closest_point(p, tree()); } bool first_intersection(const Point_3& p, const Point_3& q, Point_3& o, const FT offset_size, const FT intersection_precision) const { + CGAL_precondition(!empty()); return AABB_helper::first_intersection(p, q, o, offset_size, intersection_precision, tree()); } bool first_intersection(const Point_3& p, const Point_3& q, Point_3& o, const FT offset_size) const { + CGAL_precondition(!empty()); return AABB_helper::first_intersection(p, q, o, offset_size, 1e-2 * offset_size, tree()); } diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h index 761de1bdb88..b27ffa0525a 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Point_set_oracle.h @@ -24,45 +24,25 @@ #include #include -#include - #include #include +#include #include +#include namespace CGAL { namespace Alpha_wraps_3 { namespace internal { -// No longer used, but might find some purpose again in the future -template -struct Point_from_iterator_map -{ - using key_type = InputIterator; - using value_type = typename boost::property_traits::value_type; - using reference = typename boost::property_traits::reference; - using category = boost::readable_property_map_tag; - - Point_from_iterator_map(const PM& pm = PM()) : pm(pm) { } - - inline friend reference get(const Point_from_iterator_map& map, const key_type it) - { - return get(map.pm, *it); - } - - PM pm; -}; - // Just some typedefs for readability -template +template struct PS_oracle_traits { - using Point = typename boost::range_value::type; - using Default_GT = typename Kernel_traits::Kernel; - using Base_GT = typename Default::Get::type; // = Kernel, usually - using Geom_traits = Alpha_wrap_AABB_traits; // Wrap the kernel to add Ball_3 + custom Do_intersect_3 + using Geom_traits = Alpha_wrap_AABB_traits; // Wrap the kernel to add Ball_3 + custom Do_intersect_3 + + using Points = std::vector; + using PR_iterator = typename Points::const_iterator; - using PR_iterator = typename PointRange::const_iterator; using Primitive = AABB_primitive /*DPM*/, Input_iterator_property_map /*RPM*/, @@ -73,25 +53,28 @@ struct PS_oracle_traits using AABB_tree = CGAL::AABB_tree; }; -template class Point_set_oracle - : public AABB_tree_oracle::Geom_traits, - typename PS_oracle_traits::AABB_tree, + : public AABB_tree_oracle::Geom_traits, + typename PS_oracle_traits::AABB_tree, CGAL::Default, // Default_traversal_traits BaseOracle> { - using PSOT = PS_oracle_traits; - using Base_GT = typename PSOT::Base_GT; + using PSOT = PS_oracle_traits; + using Base_GT = GT_; public: using Geom_traits = typename PSOT::Geom_traits; private: + using Points = typename PSOT::Points; using AABB_tree = typename PSOT::AABB_tree; using Oracle_base = AABB_tree_oracle; +private: + Points m_points; + public: // Constructors Point_set_oracle() @@ -110,9 +93,10 @@ public: public: // adds a range of points to the oracle - template + template void add_point_set(const PointRange& points, - const NamedParameters& /*np*/ = CGAL::parameters::default_values()) + const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values()) { if(points.empty()) { @@ -122,11 +106,16 @@ public: return; } + const std::size_t old_size = m_points.size(); + m_points.insert(std::cend(m_points), std::cbegin(points), std::cend(points)); + #ifdef CGAL_AW3_DEBUG std::cout << "Insert into AABB tree (points)..." << std::endl; #endif - this->tree().insert(points.begin(), points.end()); + this->tree().insert(std::next(std::cbegin(m_points), old_size), std::cend(m_points)); + + CGAL_postcondition(this->tree().size() == m_points.size()); } }; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h index b8759e67b51..a6a87f000ab 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Segment_soup_oracle.h @@ -24,26 +24,25 @@ #include #include -#include - #include #include +#include #include +#include namespace CGAL { namespace Alpha_wraps_3 { namespace internal { // Just some typedefs for readability -template +template struct SS_oracle_traits { - using Segment = typename boost::range_value::type; - using Default_GT = typename Kernel_traits::Kernel; - using Base_GT = typename Default::Get::type; // = Kernel, usually - using Geom_traits = Alpha_wrap_AABB_traits; // Wrap the kernel to add Ball_3 + custom Do_intersect_3 + using Geom_traits = Alpha_wrap_AABB_traits; // Wrap the kernel to add Ball_3 + custom Do_intersect_3 + + using Segments = std::vector; + using SR_iterator = typename Segments::const_iterator; - using SR_iterator = typename SegmentRange::const_iterator; using Primitive = AABB_primitive, // DPM CGAL::internal::Source_of_segment_3_iterator_property_map, // RPM @@ -54,25 +53,28 @@ struct SS_oracle_traits using AABB_tree = CGAL::AABB_tree; }; -template class Segment_soup_oracle - : public AABB_tree_oracle::Geom_traits, - typename SS_oracle_traits::AABB_tree, + : public AABB_tree_oracle::Geom_traits, + typename SS_oracle_traits::AABB_tree, CGAL::Default, // Default_traversal_traits BaseOracle> { - using SSOT = SS_oracle_traits; - using Base_GT = typename SSOT::Base_GT; + using SSOT = SS_oracle_traits; + using Base_GT = GT_; public: using Geom_traits = typename SSOT::Geom_traits; private: + using Segments = typename SSOT::Segments; using AABB_tree = typename SSOT::AABB_tree; using Oracle_base = AABB_tree_oracle; +private: + Segments m_segments; + public: // Constructors Segment_soup_oracle() @@ -90,9 +92,10 @@ public: { } public: - template + template void add_segment_soup(const SegmentRange& segments, - const NamedParameters& /*np*/ = CGAL::parameters::default_values()) + const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values()) { if(segments.empty()) { @@ -102,12 +105,15 @@ public: return; } + const std::size_t old_size = m_segments.size(); + m_segments.insert(std::cend(m_segments), std::cbegin(segments), std::cend(segments)); + #ifdef CGAL_AW3_DEBUG std::cout << "Insert into AABB tree (segments)..." << std::endl; #endif - this->tree().insert(segments.begin(), segments.end()); + this->tree().insert(std::next(std::cbegin(m_segments), old_size), std::cend(m_segments)); - CGAL_postcondition(this->tree().size() == segments.size()); + CGAL_postcondition(this->tree().size() == m_segments.size()); } }; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h index 3d90fd869a3..f4e74da51e9 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_mesh_oracle.h @@ -34,41 +34,36 @@ namespace Alpha_wraps_3 { namespace internal { // Just some typedefs for readability in the main oracle class -template +template struct TM_oracle_traits { - using Default_GT = typename GetGeomTraits::type; + using Geom_traits = Alpha_wrap_AABB_traits; // Wrap the kernel to add Ball_3 + custom Do_intersect_3 - using Base_GT = typename Default::Get::type; // = Kernel, usually - using Geom_traits = Alpha_wrap_AABB_traits; // Wrap the kernel to add Ball_3 + custom Do_intersect_3 using Point_3 = typename Geom_traits::Point_3; using AABB_traits = typename AABB_tree_splitter_traits::AABB_traits; using AABB_tree = typename AABB_tree_splitter_traits::AABB_tree; }; // @speed could do a partial specialization 'subdivide = false' with simpler code for speed? -template class Triangle_mesh_oracle : // this is the base that handles calls to the AABB tree - public AABB_tree_oracle::Geom_traits, - typename TM_oracle_traits::AABB_tree, + public AABB_tree_oracle::Geom_traits, + typename TM_oracle_traits::AABB_tree, typename std::conditional< /*condition*/subdivide, - /*true*/Splitter_traversal_traits::AABB_traits>, - /*false*/Default_traversal_traits::AABB_traits> >::type, + /*true*/Splitter_traversal_traits::AABB_traits>, + /*false*/Default_traversal_traits::AABB_traits> >::type, BaseOracle>, // this is the base that handles splitting input faces and inserting them into the AABB tree public AABB_tree_oracle_splitter::Point_3, - typename TM_oracle_traits::Geom_traits> + typename TM_oracle_traits::Point_3, + typename TM_oracle_traits::Geom_traits> { - using face_descriptor = typename boost::graph_traits::face_descriptor; - - using TMOT = TM_oracle_traits; - using Base_GT = typename TMOT::Base_GT; + using TMOT = TM_oracle_traits; + using Base_GT = GT_; public: using Geom_traits = typename TMOT::Geom_traits; @@ -122,13 +117,16 @@ public: { } public: - template + template void add_triangle_mesh(const TriangleMesh& tmesh, - const NamedParameters& np = CGAL::parameters::default_values()) + const CGAL_NP_CLASS& np = CGAL::parameters::default_values()) { using parameters::get_parameter; using parameters::choose_parameter; + using face_descriptor = typename boost::graph_traits::face_descriptor; + using VPM = typename GetVertexPointMap::const_type; using Point_ref = typename boost::property_traits::reference; diff --git a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h index f2cb2b1772f..81fed3d58df 100644 --- a/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h +++ b/Alpha_wrap_3/include/CGAL/Alpha_wrap_3/internal/Triangle_soup_oracle.h @@ -35,42 +35,34 @@ namespace Alpha_wraps_3 { namespace internal { // Just some typedefs for readability -template +template struct TS_oracle_traits { - using Default_NP = parameters::Default_named_parameters; - using Default_NP_helper = Point_set_processing_3_np_helper; - using Default_GT = typename Default_NP_helper::Geom_traits; - - using Base_GT = typename Default::Get::type; // = Kernel, usually - using Geom_traits = Alpha_wrap_AABB_traits; // Wrap the kernel to add Ball_3 + custom Do_intersect_3 + using Geom_traits = Alpha_wrap_AABB_traits; // Wrap the kernel to add Ball_3 + custom Do_intersect_3 using Point_3 = typename Geom_traits::Point_3; using AABB_traits = typename AABB_tree_splitter_traits::AABB_traits; using AABB_tree = typename AABB_tree_splitter_traits::AABB_tree; }; -template class Triangle_soup_oracle : // this is the base that handles calls to the AABB tree - public AABB_tree_oracle::Geom_traits, - typename TS_oracle_traits::AABB_tree, + public AABB_tree_oracle::Geom_traits, + typename TS_oracle_traits::AABB_tree, typename std::conditional< /*condition*/subdivide, - /*true*/Splitter_traversal_traits::AABB_traits>, - /*false*/Default_traversal_traits::AABB_traits> >::type, + /*true*/Splitter_traversal_traits::AABB_traits>, + /*false*/Default_traversal_traits::AABB_traits> >::type, BaseOracle>, // this is the base that handles splitting input faces and inserting them into the AABB tree public AABB_tree_oracle_splitter::Point_3, - typename TS_oracle_traits::Geom_traits> + typename TS_oracle_traits::Point_3, + typename TS_oracle_traits::Geom_traits> { - using Face = typename boost::range_value::type; - - using TSOT = TS_oracle_traits; - using Base_GT = typename TSOT::Base_GT; + using TSOT = TS_oracle_traits; + using Base_GT = GT_; public: using Geom_traits = typename TSOT::Geom_traits; @@ -124,17 +116,20 @@ public: { } public: - template + template void add_triangle_soup(const PointRange& points, const FaceRange& faces, - const NamedParameters& np = CGAL::parameters::default_values()) + const CGAL_NP_CLASS& np = CGAL::parameters::default_values()) { using parameters::choose_parameter; using parameters::get_parameter; - using PPM = typename GetPointMap::const_type; + using PPM = typename GetPointMap::const_type; using Point_ref = typename boost::property_traits::reference; + using Face = typename boost::range_value::type; + if(points.empty() || faces.empty()) { #ifdef CGAL_AW3_DEBUG @@ -178,6 +173,22 @@ public: std::cout << "Tree: " << this->tree().size() << " primitives (" << faces.size() << " faces in input)" << std::endl; #endif } + + template + void add_triangle_soup(const TriangleRange& triangles, + const CGAL_NP_CLASS& /*np*/ = CGAL::parameters::default_values()) + { + typename Geom_traits::Is_degenerate_3 is_degenerate = this->geom_traits().is_degenerate_3_object(); + + for(const Triangle_3& tr : triangles) + { + if(is_degenerate(tr)) + continue; + + Splitter_base::split_and_insert_datum(tr, this->tree(), this->geom_traits()); + } + } }; } // namespace internal diff --git a/Alpha_wrap_3/include/CGAL/alpha_wrap_3.h b/Alpha_wrap_3/include/CGAL/alpha_wrap_3.h index ddeb40119ed..b22bf878458 100644 --- a/Alpha_wrap_3/include/CGAL/alpha_wrap_3.h +++ b/Alpha_wrap_3/include/CGAL/alpha_wrap_3.h @@ -104,7 +104,7 @@ void alpha_wrap_3(const PointRange& points, using NP_helper = Point_set_processing_3_np_helper; using Geom_traits = typename NP_helper::Geom_traits; - using Oracle = Alpha_wraps_3::internal::Triangle_soup_oracle; + using Oracle = Alpha_wraps_3::internal::Triangle_soup_oracle; using AW3 = Alpha_wraps_3::internal::Alpha_wrap_3; Geom_traits gt = choose_parameter(get_parameter(in_np, internal_np::geom_traits)); @@ -253,7 +253,7 @@ void alpha_wrap_3(const TriangleMesh& tmesh, using parameters::choose_parameter; using Geom_traits = typename GetGeomTraits::type; - using Oracle = Alpha_wraps_3::internal::Triangle_mesh_oracle; + using Oracle = Alpha_wraps_3::internal::Triangle_mesh_oracle; using AW3 = Alpha_wraps_3::internal::Alpha_wrap_3; Geom_traits gt = choose_parameter(get_parameter(in_np, internal_np::geom_traits)); @@ -349,7 +349,7 @@ void alpha_wrap_3(const PointRange& points, using NP_helper = Point_set_processing_3_np_helper; using Geom_traits = typename NP_helper::Geom_traits; - using Oracle = Alpha_wraps_3::internal::Point_set_oracle; + using Oracle = Alpha_wraps_3::internal::Point_set_oracle; using AW3 = Alpha_wraps_3::internal::Alpha_wrap_3; Geom_traits gt = choose_parameter(get_parameter(in_np, internal_np::geom_traits)); diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp index 5d34bebcbe2..d7567bab205 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_cavity_initializations.cpp @@ -55,7 +55,8 @@ void alpha_wrap_triangle_mesh(Mesh& input_mesh, namespace AW3 = CGAL::Alpha_wraps_3; namespace PMP = CGAL::Polygon_mesh_processing; - using Oracle = AW3::internal::Triangle_mesh_oracle; + using Geom_traits = typename CGAL::GetGeomTraits::type; + using Oracle = AW3::internal::Triangle_mesh_oracle; std::cout << "Input: " << num_vertices(input_mesh) << " vertices, " << num_faces(input_mesh) << " faces" << std::endl; diff --git a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp index a6ee7cef5f8..e2abc6f1f12 100644 --- a/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp +++ b/Alpha_wrap_3/test/Alpha_wrap_3/test_AW3_multiple_calls.cpp @@ -36,7 +36,7 @@ void alpha_wrap_triangle_soup(Points& pr, namespace AW3 = CGAL::Alpha_wraps_3; namespace PMP = CGAL::Polygon_mesh_processing; - using Oracle = AW3::internal::Triangle_soup_oracle; + using Oracle = AW3::internal::Triangle_soup_oracle; std::cout << "Input: " << pr.size() << " points, " << fr.size() << " faces" << std::endl; diff --git a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt index 903dcb16903..029b95fa637 100644 --- a/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt +++ b/Arrangement_on_surface_2/doc/Arrangement_on_surface_2/Arrangement_on_surface_2.txt @@ -6241,7 +6241,7 @@ face, respectively, \f$v_b\f$, \f$e_b\f$, and \f$f_b\f$ denote input blue features, and \f$v\f$, \f$e\f$, and \f$f\f$ denote output features. -
    +
    1. A new vertex \f$v\f$ is induced by coinciding vertices \f$v_r\f$ and \f$v_b\f$.
    2. diff --git a/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h b/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h index dccda40981b..39a618a754d 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h +++ b/Arrangement_on_surface_2/include/CGAL/Arr_dcel_base.h @@ -34,8 +34,6 @@ #include #include -#include - namespace CGAL { inline void* _clean_pointer(const void* p) @@ -964,7 +962,7 @@ public: * The arrangement DCEL class. */ template > + class Allocator = CGAL_ALLOCATOR(int) > class Arr_dcel_base { public: // Define the vertex, halfedge and face types. diff --git a/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h b/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h index 505dc543431..6c038ae6935 100644 --- a/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h +++ b/Arrangement_on_surface_2/include/CGAL/Arrangement_on_surface_2.h @@ -48,8 +48,6 @@ #include #include -#include - namespace CGAL { /*! \class Arrangement_on_surface_2 @@ -68,7 +66,7 @@ class Arrangement_on_surface_2 { public: typedef GeomTraits_ Geometry_traits_2; typedef TopTraits_ Topology_traits; - typedef boost::fast_pool_allocator Allocator; + typedef CGAL_ALLOCATOR(int) Allocator; // first define adaptor ... typedef Arr_traits_basic_adaptor_2 Traits_adaptor_2; diff --git a/BGL/doc/BGL/Doxyfile.in b/BGL/doc/BGL/Doxyfile.in index 970bf3ffa8b..4e5d35a91d2 100644 --- a/BGL/doc/BGL/Doxyfile.in +++ b/BGL/doc/BGL/Doxyfile.in @@ -21,13 +21,12 @@ INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/Euler_operations.h \ ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/boost/graph/graph_traits_inheritance_macros.h -EXAMPLE_PATH = ${CGAL_Surface_mesh_skeletonization_EXAMPLE_DIR} \ - ${CGAL_Surface_mesh_segmentation_EXAMPLE_DIR} \ - ${CGAL_Polygon_mesh_processing_EXAMPLE_DIR} \ - ${CGAL_Surface_mesh_EXAMPLE_DIR} \ - ${CGAL_Property_map_EXAMPLE_DIR} \ - ${CGAL_Polyhedron_EXAMPLE_DIR} \ - ${CGAL_BGL_EXAMPLE_DIR} +EXAMPLE_PATH += ${CGAL_Surface_mesh_skeletonization_EXAMPLE_DIR} \ + ${CGAL_Surface_mesh_segmentation_EXAMPLE_DIR} \ + ${CGAL_Polygon_mesh_processing_EXAMPLE_DIR} \ + ${CGAL_Surface_mesh_EXAMPLE_DIR} \ + ${CGAL_Property_map_EXAMPLE_DIR} \ + ${CGAL_Polyhedron_EXAMPLE_DIR} ALIASES += "bgllink{1}=\1" diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/do_intersect.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/do_intersect.h index 86a3caa571b..820596d5fb7 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/do_intersect.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/do_intersect.h @@ -237,7 +237,8 @@ inline bool do_intersect(const General_polygon_with_holes_2& pgn1, // With Traits template inline bool do_intersect(InputIterator begin, InputIterator end, Traits& traits, - unsigned int k=5) + unsigned int k=5, + std::enable_if_t::value>* = 0) { return r_do_intersect(begin, end, traits, k); } // Without Traits @@ -245,6 +246,7 @@ inline bool do_intersect(InputIterator begin, InputIterator end, Traits& traits, template inline bool do_intersect(InputIterator begin, InputIterator end, Tag_true = Tag_true(), unsigned int k=5, + std::enable_if_t::value>* = 0, Enable_if_Polygon_2_iterator* = 0) { return r_do_intersect(begin, end, k); } @@ -252,6 +254,7 @@ inline bool do_intersect(InputIterator begin, InputIterator end, template inline bool do_intersect(InputIterator begin, InputIterator end, Tag_false, unsigned int k=5, + std::enable_if_t::value>* = 0, Enable_if_Polygon_2_iterator* = 0) { typename Iterator_to_gps_traits::Traits traits; @@ -262,6 +265,7 @@ inline bool do_intersect(InputIterator begin, InputIterator end, template inline bool do_intersect(InputIterator begin, InputIterator end, unsigned int k=5, + std::enable_if_t::value>* = 0, Disable_if_Polygon_2_iterator* = 0) { typename Iterator_to_gps_traits::Traits traits; diff --git a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/intersection.h b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/intersection.h index 7599c835c5c..f961e507a0e 100644 --- a/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/intersection.h +++ b/Boolean_set_operations_2/include/CGAL/Boolean_set_operations_2/intersection.h @@ -288,8 +288,7 @@ inline OutputIterator intersection(InputIterator begin, InputIterator end, OutputIterator oi, unsigned int k=5, // workaround to avoid ambiguous calls with kernel functions - typename boost::enable_if - >::type* = 0, + std::enable_if_t::value>* = 0, Disable_if_Polygon_2_iterator* = 0) { typename Iterator_to_gps_traits::Traits traits; diff --git a/Documentation/doc/Documentation/Developer_manual/Chapter_code_format.txt b/Documentation/doc/Documentation/Developer_manual/Chapter_code_format.txt index 92c62a16600..9a8b72e765c 100644 --- a/Documentation/doc/Documentation/Developer_manual/Chapter_code_format.txt +++ b/Documentation/doc/Documentation/Developer_manual/Chapter_code_format.txt @@ -257,29 +257,6 @@ The first list of items are meant as rules, i.e., you should follow them. ... #endif // CGAL_THIS_IS_AN_EXAMPLE_H \endcode -- Support the - result_of - protocol whenever your functors have more than one return type - otherwise provide a `result_type` member typedef. - An example for this is a C++03 style `identity` functor: - \code{.cpp} - struct Identity { - template - T& operator()(T& t) { return t; } - template - const T& operator()(const T& t) { return t; } - template - struct result; - template - struct result { - typedef T& type; - }; - template - struct result { - typedef const T& type; - }; - }; - \endcode The following items can be seen as recommendations in contrast to the rules of previous paragraph. diff --git a/Documentation/doc/Documentation/Developer_manual/Chapter_namespaces.txt b/Documentation/doc/Documentation/Developer_manual/Chapter_namespaces.txt index 17f8a076b34..f2241888167 100644 --- a/Documentation/doc/Documentation/Developer_manual/Chapter_namespaces.txt +++ b/Documentation/doc/Documentation/Developer_manual/Chapter_namespaces.txt @@ -63,14 +63,14 @@ class Some_further_class_local_to_Package; According to the resolutions of the following issues in the forthcoming \cpp-standard ( - 225, - 226 - 229. + 225, + 226 and + 229 ): -Unless otherwise specified, no global or non-member function in the standard library +
      Unless otherwise specified, no global or non-member function in the standard library shall use a function from another namespace which is found through argument-dependent -name lookup -, the namespace `CGAL::NTS` does not need to be used anymore +name lookup
      +the namespace `CGAL::NTS` does not need to be used anymore (currently `CGAL_NTS` macro boils down to `CGAL::`). \section Developer_manualRequirementsandrecommendations_1 Requirements and recommendations diff --git a/Documentation/doc/Documentation/General.txt b/Documentation/doc/Documentation/General.txt index a14d99dd4fe..f1de55dcdc2 100644 --- a/Documentation/doc/Documentation/General.txt +++ b/Documentation/doc/Documentation/General.txt @@ -1,8 +1,3 @@ -///This concept refines both -/// CopyAssignable -///and CopyConstructible. -class Assignable {}; - /// \cgalConcept /// Concept from the \cpp standard. /// See https://en.cppreference.com/w/cpp/named_req/DefaultConstructible @@ -13,6 +8,14 @@ class DefaultConstructible {}; /// See https://en.cppreference.com/w/cpp/named_req/CopyConstructible class CopyConstructible {}; +/// \cgalConcept +/// Concept from the \cpp standard. +/// See https://en.cppreference.com/w/cpp/named_req/CopyAssignable +class CopyAssignable {}; + +///This concept refines both `CopyAssignable` and `CopyConstructible`. +class Assignable {}; + /// \cgalConcept /// Concept from the \cpp standard. /// See https://en.cppreference.com/w/cpp/named_req/Callable diff --git a/Documentation/doc/Documentation/Preliminaries.txt b/Documentation/doc/Documentation/Preliminaries.txt index e07d90e9e37..a2ed83f6740 100644 --- a/Documentation/doc/Documentation/Preliminaries.txt +++ b/Documentation/doc/Documentation/Preliminaries.txt @@ -44,16 +44,6 @@ also avoid CMake to link with the native threads support library on your system. After being based on the \CC standard released in 1998 (and later refined in 2003) for a long time, \cgal is now based on a newer major version of the standard, C++14. -\section Preliminaries_functor Functor Return Types - -\cgal functors support the -result_of -protocol. If a functor `F` has the same return type across all -overloads of `operator()`, the nested type -`F::result_type` is defined to be that type. Otherwise the -return type of calling the functor with an argument of type -`Arg` can be accessed through \link CGAL::cpp11::result_of::type `CGAL::cpp11::result_of::type` \endlink. - \section preliminaries_secchecks Checks Much of the \cgal code contains assert statements for preconditions, and postconditions of functions diff --git a/Documentation/doc/Documentation/Third_party.txt b/Documentation/doc/Documentation/Third_party.txt index 6e25f350ae0..3131ae3caaa 100644 --- a/Documentation/doc/Documentation/Third_party.txt +++ b/Documentation/doc/Documentation/Third_party.txt @@ -12,7 +12,7 @@ supporting C++14 or later. | Operating System | Compiler | | :---------- | :--------------- | | Linux | \gnu `g++` 10.2.1 or later\cgalFootnote{\cgalFootnoteCode{http://gcc.gnu.org/}} | -| | `Clang` \cgalFootnote{\cgalFootnoteCode{http://clang.llvm.org/}} compiler version 13.0.0 | +| | `Clang` \cgalFootnote{\cgalFootnoteCode{http://clang.llvm.org/}} compiler version 13.0.1 | | \ms Windows | \gnu `g++` 10.2.1 or later\cgalFootnote{\cgalFootnoteCode{http://gcc.gnu.org/}} | | | \ms Visual `C++` 14.0, 15.9, 16.10, 17.0 (\visualstudio 2015, 2017, 2019, and 2022)\cgalFootnote{\cgalFootnoteCode{https://visualstudio.microsoft.com/}} | | MacOS X | \gnu `g++` 10.2.1 or later\cgalFootnote{\cgalFootnoteCode{http://gcc.gnu.org/}} | @@ -117,7 +117,7 @@ The exhaustive list of \qt5 components used in demos is: `qcollectiongenerator` (with `sqlite` driver plugin), and `Xml`. \subsection thirdpartyEigen Eigen -Version 3.1 or later +Version 3.3.4 or later \eigen is a `C++` template library for linear algebra. \eigen supports all matrix sizes, various matrix decomposition methods and sparse linear solvers. diff --git a/Documentation/doc/resources/1.8.13/menu_version.js b/Documentation/doc/resources/1.8.13/menu_version.js index e8a424f40cd..903056a6cac 100644 --- a/Documentation/doc/resources/1.8.13/menu_version.js +++ b/Documentation/doc/resources/1.8.13/menu_version.js @@ -6,9 +6,10 @@ var current_version_local = 'master' var all_versions = [ 'master', + '5.5-beta1', 'latest', - '5.4', - '5.3.1', + '5.4.1', + '5.3.2', '5.2.4', '5.1.5', '5.0.4', diff --git a/Documentation/doc/resources/1.8.14/menu_version.js b/Documentation/doc/resources/1.8.14/menu_version.js index e8a424f40cd..903056a6cac 100644 --- a/Documentation/doc/resources/1.8.14/menu_version.js +++ b/Documentation/doc/resources/1.8.14/menu_version.js @@ -6,9 +6,10 @@ var current_version_local = 'master' var all_versions = [ 'master', + '5.5-beta1', 'latest', - '5.4', - '5.3.1', + '5.4.1', + '5.3.2', '5.2.4', '5.1.5', '5.0.4', diff --git a/Documentation/doc/resources/1.8.20/menu_version.js b/Documentation/doc/resources/1.8.20/menu_version.js index e8a424f40cd..903056a6cac 100644 --- a/Documentation/doc/resources/1.8.20/menu_version.js +++ b/Documentation/doc/resources/1.8.20/menu_version.js @@ -6,9 +6,10 @@ var current_version_local = 'master' var all_versions = [ 'master', + '5.5-beta1', 'latest', - '5.4', - '5.3.1', + '5.4.1', + '5.3.2', '5.2.4', '5.1.5', '5.0.4', diff --git a/Documentation/doc/resources/1.8.4/menu_version.js b/Documentation/doc/resources/1.8.4/menu_version.js index e8a424f40cd..903056a6cac 100644 --- a/Documentation/doc/resources/1.8.4/menu_version.js +++ b/Documentation/doc/resources/1.8.4/menu_version.js @@ -6,9 +6,10 @@ var current_version_local = 'master' var all_versions = [ 'master', + '5.5-beta1', 'latest', - '5.4', - '5.3.1', + '5.4.1', + '5.3.2', '5.2.4', '5.1.5', '5.0.4', diff --git a/Documentation/doc/scripts/html_output_post_processing.py b/Documentation/doc/scripts/html_output_post_processing.py index f01a02f1eef..44d15aa6d70 100755 --- a/Documentation/doc/scripts/html_output_post_processing.py +++ b/Documentation/doc/scripts/html_output_post_processing.py @@ -254,6 +254,11 @@ removes some unneeded files, and performs minor repair on some glitches.''') resources_absdir=args.resources os.chdir(args.output) + #workaround issue with operator<< in pyquery + all_pages=glob.glob('*/*.html') + for f in all_pages: + re_replace_in_file("operator<<\(\)", "operator<<()", f) + # number figure automagically_number_figures() diff --git a/GraphicsView/include/CGAL/Qt/camera.h b/GraphicsView/include/CGAL/Qt/camera.h index bda76bafb05..08f76d4eb0b 100644 --- a/GraphicsView/include/CGAL/Qt/camera.h +++ b/GraphicsView/include/CGAL/Qt/camera.h @@ -18,6 +18,7 @@ #include #include #include +#include namespace CGAL{ class QGLViewer; @@ -199,6 +200,7 @@ public: CGAL::QGLViewer's window dimensions when the Camera is attached to a CGAL::QGLViewer. See also QOpenGLWidget::height() */ int screenHeight() const { return screenHeight_; } + qreal devicePixelRatio() const { return devicePixelRatio_; } void getViewport(GLint viewport[4]) const; qreal pixelGLRatio(const Vec &position) const; @@ -279,7 +281,7 @@ public Q_SLOTS: setScreenWidthAndHeight(int(100.0 * aspect), 100); } - void setScreenWidthAndHeight(int width, int height); + void setScreenWidthAndHeight(int width, int height, qreal devicePixelRatio = 1.0); /*! Sets the zNearCoefficient() value. */ void setZNearCoefficient(qreal coef) { zNearCoef_ = coef; @@ -444,6 +446,7 @@ private: // C a m e r a p a r a m e t e r s int screenWidth_, screenHeight_; // size of the window, in pixels + qreal devicePixelRatio_; qreal fieldOfView_; // in radians Vec sceneCenter_; qreal sceneRadius_; // OpenGL units @@ -467,6 +470,36 @@ private: KeyFrameInterpolator *interpolationKfi_; }; +inline void read_pixel(const QPoint &pixel, QOpenGLFunctions *p, + const Camera *camera, GLenum format, GLenum type, + GLvoid *pixel_data) { + const auto pixel_ratio = camera->devicePixelRatio(); + p->glReadPixels(pixel.x() * pixel_ratio, + (camera->screenHeight() - pixel.y()) * pixel_ratio - 1, 1, 1, + format, type, pixel_data); +} + +inline auto read_pixel_as_float_rgb(const QPoint &pixel, QOpenGLFunctions *p, + const Camera *camera) { + std::array res; + read_pixel(pixel, p, camera, GL_RGB, GL_FLOAT, res.data()); + return res; +} + +inline auto read_pixel_as_ubyte_rgba(const QPoint &pixel, QOpenGLFunctions *p, + const Camera *camera) { + std::array res; + read_pixel(pixel, p, camera, GL_RGBA, GL_UNSIGNED_BYTE, res.data()); + return res; +} + +inline float read_depth_under_pixel(const QPoint &pixel, QOpenGLFunctions *p, + const Camera *camera) { + float depth = 2.0f; + read_pixel(pixel, p, camera, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); + return depth; +} + } // namespace qglviewer } //CGAL #endif // QGLVIEWER_CAMERA_H diff --git a/GraphicsView/include/CGAL/Qt/camera_impl.h b/GraphicsView/include/CGAL/Qt/camera_impl.h index 672e5d91c23..6005f48e5e4 100644 --- a/GraphicsView/include/CGAL/Qt/camera_impl.h +++ b/GraphicsView/include/CGAL/Qt/camera_impl.h @@ -160,10 +160,11 @@ frustrum coherence. If your Camera is used without a CGAL::QGLViewer (offscreen rendering, shadow maps), use setAspectRatio() instead to define the projection matrix. */ CGAL_INLINE_FUNCTION -void Camera::setScreenWidthAndHeight(int width, int height) { +void Camera::setScreenWidthAndHeight(int width, int height, qreal devicePixelRatio) { // Prevent negative and zero dimensions that would cause divisions by zero. screenWidth_ = width > 0 ? width : 1; screenHeight_ = height > 0 ? height : 1; + devicePixelRatio_ = devicePixelRatio; projectionMatrixIsUpToDate_ = false; } @@ -884,8 +885,7 @@ Vec Camera::pointUnderPixel(const QPoint &pixel, bool &found) const { // Qt uses upper corner for its origin while GL uses the lower corner. if(auto p = dynamic_cast(parent())) { - p->glReadPixels(pixel.x(), screenHeight() - 1 - pixel.y(), 1, 1, - GL_DEPTH_COMPONENT, GL_FLOAT, &depth); + depth = read_depth_under_pixel(pixel, p, this); } found = depth < 1.0; Vec point(pixel.x(), pixel.y(), depth); diff --git a/GraphicsView/include/CGAL/Qt/qglviewer.h b/GraphicsView/include/CGAL/Qt/qglviewer.h index da0dbace517..e353c8de66e 100644 --- a/GraphicsView/include/CGAL/Qt/qglviewer.h +++ b/GraphicsView/include/CGAL/Qt/qglviewer.h @@ -563,6 +563,21 @@ public: */ void saveSnapshot(); + /*! + * Takes a snapshot without any dialog + */ + void saveSnapshot(const QString& fileName, + const qreal finalWidth, + const qreal finalHeight, + const bool expand = false, + const double oversampling = 1., + qglviewer::SnapShotBackground background_color = qglviewer::CURRENT_BACKGROUND); + + void saveSnapshot(const QString& fileName) + { + return saveSnapshot(fileName, this->width(), this->height()); + } + public: Q_SIGNALS: /*! Signal emitted by the default init() method. diff --git a/GraphicsView/include/CGAL/Qt/qglviewer_impl.h b/GraphicsView/include/CGAL/Qt/qglviewer_impl.h index 70fdfdd9a15..1e10b72d0b0 100644 --- a/GraphicsView/include/CGAL/Qt/qglviewer_impl.h +++ b/GraphicsView/include/CGAL/Qt/qglviewer_impl.h @@ -807,7 +807,7 @@ void CGAL::QGLViewer::setCamera(qglviewer::Camera *const camera) { camera->setSceneRadius(sceneRadius()); camera->setSceneCenter(sceneCenter()); - camera->setScreenWidthAndHeight(width(), height()); + camera->setScreenWidthAndHeight(width(), height(), devicePixelRatio()); // Disconnect current camera from this viewer. disconnect(this->camera()->frame(), SIGNAL(manipulated()), this, @@ -1147,7 +1147,9 @@ void CGAL::QGLViewer::beginSelection(const QPoint &point) { makeCurrent(); glEnable(GL_SCISSOR_TEST); - glScissor(point.x(), camera()->screenHeight()-1-point.y(), 1, 1); + glScissor(point.x() * devicePixelRatio(), + (camera()->screenHeight() - point.y()) * devicePixelRatio() - 1, 1, + 1); } /*! This method is called by select() after scene elements were drawn by @@ -2369,7 +2371,7 @@ CGAL_INLINE_FUNCTION void CGAL::QGLViewer::resizeGL(int width, int height) { QOpenGLWidget::resizeGL(width, height); glViewport(0, 0, GLint(width), GLint(height)); - camera()->setScreenWidthAndHeight(this->width(), this->height()); + camera()->setScreenWidthAndHeight(this->width(), this->height(), this->devicePixelRatio()); } ////////////////////////////////////////////////////////////////////////// @@ -3187,10 +3189,11 @@ void CGAL::QGLViewer::drawVisualHints() { mvpMatrix.ortho(-1,1,-1,1,-1,1); size=30*devicePixelRatio(); rendering_program.setUniformValue("mvp_matrix", mvpMatrix); - glViewport(GLint((camera()->projectedCoordinatesOf(camera()->pivotPoint()).x-size/2)*devicePixelRatio()), - GLint((height() - camera()->projectedCoordinatesOf(camera()->pivotPoint()).y-size/2)*devicePixelRatio()), size, size); - glScissor (GLint((camera()->projectedCoordinatesOf(camera()->pivotPoint()).x-size/2)*devicePixelRatio()), - GLint((height() - camera()->projectedCoordinatesOf(camera()->pivotPoint()).y-size/2)*devicePixelRatio()), size, size); + const auto point_2d = camera()->projectedCoordinatesOf(camera()->pivotPoint()); + glViewport(GLint(point_2d.x*devicePixelRatio()-size/2), + GLint((height() - point_2d.y)*devicePixelRatio()-size/2), size, size); + glScissor (GLint(point_2d.x*devicePixelRatio()-size/2), + GLint((height() - point_2d.y)*devicePixelRatio()-size/2), size, size); rendering_program.setUniformValue("color", QColor(::Qt::black)); glDisable(GL_DEPTH_TEST); glDrawArrays(GL_LINES, 0, static_cast(4)); @@ -3758,8 +3761,29 @@ void CGAL::QGLViewer::saveSnapshot() } } +CGAL_INLINE_FUNCTION +void CGAL::QGLViewer::saveSnapshot(const QString& fileName, + const qreal finalWidth, const qreal finalHeight, + const bool expand, + const double oversampling, + qglviewer::SnapShotBackground background_color) +{ + if(fileName.isEmpty()) + return; + + QSize finalSize(finalWidth, finalHeight); + + QImage* image = takeSnapshot(qglviewer::SnapShotBackground(background_color), + finalSize, oversampling, expand); + if(image) + { + image->save(fileName); + delete image; + } } +} // namespace CGAL + CGAL_INLINE_FUNCTION bool CGAL::QGLViewer::isSharing() const { diff --git a/HalfedgeDS/test/HalfedgeDS/test_hds_range_based_loops.cpp b/HalfedgeDS/test/HalfedgeDS/test_hds_range_based_loops.cpp index 893d5e40b0e..a58aac2c880 100644 --- a/HalfedgeDS/test/HalfedgeDS/test_hds_range_based_loops.cpp +++ b/HalfedgeDS/test/HalfedgeDS/test_hds_range_based_loops.cpp @@ -24,7 +24,6 @@ void test_vertex_handles( assert(hds_list.vertex_handles().size() == 1); for (auto vh : hds_list.vertex_handles()) { assert(vh == lit); - assert(vh->point() == lit->point()); assert(vh->halfedge() == lit->halfedge()); ++lit; } @@ -34,7 +33,6 @@ void test_vertex_handles( assert(hds_vector.vertex_handles().size() == 1); for (auto vh : hds_vector.vertex_handles()) { assert(vh == vit); - assert(vh->point() == vit->point()); assert(vh->halfedge() == vit->halfedge()); ++vit; } @@ -49,7 +47,6 @@ void test_const_vertex_handles( assert(hds_list.vertex_handles().size() == 1); for (const auto& vh : hds_list.vertex_handles()) { assert(vh == lit); - assert(vh->point() == lit->point()); assert(vh->halfedge() == lit->halfedge()); ++lit; } @@ -59,7 +56,6 @@ void test_const_vertex_handles( assert(hds_vector.vertex_handles().size() == 1); for (const auto& vh : hds_vector.vertex_handles()) { assert(vh == vit); - assert(vh->point() == vit->point()); assert(vh->halfedge() == vit->halfedge()); ++vit; } @@ -74,7 +70,6 @@ void test_face_handles( assert(hds_list.face_handles().size() == 2); for (auto fh : hds_list.face_handles()) { assert(fh == lit); - assert(fh->plane() == lit->plane()); assert(fh->halfedge() == lit->halfedge()); ++lit; } @@ -84,7 +79,6 @@ void test_face_handles( assert(hds_vector.face_handles().size() == 2); for (auto fh : hds_vector.face_handles()) { assert(fh == vit); - assert(fh->plane() == vit->plane()); assert(fh->halfedge() == vit->halfedge()); ++vit; } @@ -99,7 +93,6 @@ void test_const_face_handles( assert(hds_list.face_handles().size() == 2); for (const auto& fh : hds_list.face_handles()) { assert(fh == lit); - assert(fh->plane() == lit->plane()); assert(fh->halfedge() == lit->halfedge()); ++lit; } @@ -109,7 +102,6 @@ void test_const_face_handles( assert(hds_vector.face_handles().size() == 2); for (const auto& fh : hds_vector.face_handles()) { assert(fh == vit); - assert(fh->plane() == vit->plane()); assert(fh->halfedge() == vit->halfedge()); ++vit; } diff --git a/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Doxyfile.in b/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Doxyfile.in index 8d17ef5c0b8..c97e9fc5008 100644 --- a/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Doxyfile.in +++ b/Hyperbolic_triangulation_2/doc/Hyperbolic_triangulation_2/Doxyfile.in @@ -2,8 +2,6 @@ EXTRACT_PRIVATE = NO -EXAMPLE_PATH = ${CGAL_PACKAGE_DIR}/examples - PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Hyperbolic Delaunay Triangulations" HTML_EXTRA_STYLESHEET = ${CGAL_PACKAGE_DOC_DIR}/css/customstyle.css diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 7901e3c0e07..00e7bddb5cd 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -7,7 +7,7 @@ Release History Release date: June 2022 -### 3D Alpha Wrapping (new package) +### [3D Alpha Wrapping (new package)](https://doc.cgal.org/5.5/Manual/packages.html#PkgAlphaWrap3) - This component takes a 3D triangle mesh, soup, or point set as input, and generates a valid (watertight, intersection-free, and combinatorially 2-manifold) surface triangle mesh @@ -19,29 +19,26 @@ Release date: June 2022 to the input, respectively. Once combined, these parameters provide a means to trade fidelity to the input for complexity of the output. -### [Point Set Processing](https://doc.cgal.org/5.5/Manual/packages.html#PkgPointSetProcessing3) - -- A new optional named parameter, `min_points_per_cell` has been added to [`grid_simplify_point_set()`](https://doc.cgal.org/5.5/Point_set_processing_3/group__PkgPointSetProcessing3Algorithms.html#ga7757ef9b3900e42fde26f5a0ac56e20f). By adding a minimal number of points in a cell such that a point is retained, one can also filter out low density areas and outliers: in the case of densely sampled point clouds, this yields better results than using grid simplification and then outlier removal, while being very vast. The default value is `1` to keep the previous behavior as default. - -### [dD Spatial Searching](https://doc.cgal.org/5.5/Manual/packages.html#PkgSpatialSearchingD) - -- Added the member function `write_graphviz()` to the class `Kd_tree` that writes the tree in a stream in the [Graphviz](https://graphviz.org/) format. + See also the [announcement page](https://www.cgal.org/2022/05/18/alpha_wrap/). ### [3D Convex Hulls](https://doc.cgal.org/5.5/Manual/packages.html#PkgConvexHull3) -- Added an overload of the function `CGAL::convex_hull_3()`, which writes the result in an indexed triangle set. +- Added an [overload of the function `CGAL::convex_hull_3()`](https://doc.cgal.org/5.5/Convex_hull_3/group__PkgConvexHull3Functions.html#ga52fca4745c2ef0351063fbe66b035fd1), which writes the result in an indexed triangle set. -### Surface Mesh Simplification -- Introduced four variations of the Garland-Heckbert simplification algorithm based on the probabilistic approach of Trettner and Kobbelt (Fast and Robust QEF Minimization using Probabilistic Quadrics): `GarlandHeckbert_plane_policies`, `GarlandHeckbert_probabilistic_plane_policies`, `GarlandHeckbert_triangle_policies`, and `GarlandHeckbert_probabilistic_triangle_policies` -- The class `GarlandHeckbert_policies` has been deprecated, `GarlandHeckbert_plane_policies` replaces it. +### [2D Polygons](https://doc.cgal.org/5.5/Manual/packages.html#PkgPolygon2) -### [CGAL and the Boost Graph Library (BGL)](https://doc.cgal.org/5.5/Manual/packages.html#PkgBGL) +- Add vertex, edge, and hole ranges. +- The concept [`GeneralPolygonWithHoles_2`](https://doc.cgal.org/5.5/Polygon/classGeneralPolygonWithHoles__2.html) now requires the nested type `Polygon_2` instead of `General_polygon_2`. -- Added the function [`invert_selection()`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html#aa428541ebbdd35f9a6e9a3ffd60178df) in the class [`Face_filtered_graph`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html), which toggles the selected status of a graph: selected faces are deselected, and unselected faces are selected. +### [2D Regularized Boolean Set-Operations](https://doc.cgal.org/5.5/Manual/packages.html#PkgBooleanSetOperations2) +- The concept [`GeneralPolygonSetTraits_2`](https://doc.cgal.org/5.5/Boolean_set_operations_2/classGeneralPolygonSetTraits__2.html) now requires the nested type `Construct_polygon_with_holes_2` instead of `Construct_general_polygon_with_holes_2`. -### Combinatorial Maps +### [Combinatorial Maps](https://doc.cgal.org/5.5/Manual/packages.html#PkgCombinatorialMaps) -- Removed old code deprecated in CGAL 4.9 and 4.10 (global fonctions, and information associated with darts). +- Removed old code deprecated in CGAL 4.9 and 4.10 (global functions, and information associated with darts). + +### [2D Arrangements](https://doc.cgal.org/5.5/Manual/packages.html#PkgArrangementOnSurface2) +- Fixed the `intersect_2`, `compare_y_at_x_right`, and `compare_y_at_x_left` function objects of the traits class template [`Arr_geodesic_arc_on_sphere_traits_2`](https://doc.cgal.org/5.5/Arrangement_on_surface_2/classCGAL_1_1Arr__geodesic__arc__on__sphere__traits__2.html) that handles geodesic arcs on sphere and applied a small syntactical fix to the tracing traits. ### [Tetrahedral Mesh Generation](https://doc.cgal.org/5.5/Manual/packages.html#PkgMesh3) @@ -50,22 +47,27 @@ Release date: June 2022 as a post-processing step for the tetrahedral mesh generation. ### [Polygon Mesh Processing](https://doc.cgal.org/5.5/Manual/packages.html#PkgPolygonMeshProcessing) -- Added the function `CGAL::Polygon_mesh_processing::orient_triangle_soup_with_reference_triangle_soup()`, which enables re-orienting the faces of a triangle soup based on the orientation of the nearest face in a reference triangle soup. -- Added the function `CGAL::Polygon_mesh_processing::compatible_orientations()`, which enables to retrieve the (in)compatibility of orientations of faces from different connected components. -- Added the function `CGAL::Polygon_mesh_processing::tangential_relaxation()`, which applies an area-based tangential mesh smoothing to the vertices of a surface triangle mesh. -- Added the named parameter `visitor`to the function `triangulate_hole()`, which enables to track progress with callbacks. +- Added the function [`CGAL::Polygon_mesh_processing::orient_triangle_soup_with_reference_triangle_soup()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__orientation__grp.html#ga855b1c55c201b91ab04eebd2811a87fd), which enables re-orienting the faces of a triangle soup based on the orientation of the nearest face in a reference triangle soup. +- Added the function [`CGAL::Polygon_mesh_processing::compatible_orientations()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__orientation__grp.html#ga9ac9b9434084b64f3304df636c3178a3), which enables to retrieve the (in)compatibility of orientations of faces from different connected components. +- Added the function [`CGAL::Polygon_mesh_processing::tangential_relaxation()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga136c659162e5360354db5879db7431b4), which applies an area-based tangential mesh smoothing to the vertices of a surface triangle mesh. +- Added the named parameter `visitor` to the function [`triangulate_hole()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__hole__filling__grp.html#gad2d3c43bce0ef90a16530478196d7f42), which enables to track progress with callbacks. - Added more functions in the [visitor of the corefinement based methods](https://doc.cgal.org/5.5/Polygon_mesh_processing/classPMPCorefinementVisitor.html) to track progress. -### [2D Polygons](https://doc.cgal.org/5.5/Manual/packages.html#PkgPolygon2) +### [Surface Mesh Simplification](https://doc.cgal.org/5.5/Manual/packages.html#PkgSurfaceMeshSimplification) +- Introduced four variations of the Garland-Heckbert simplification algorithm based on the probabilistic approach of Trettner and Kobbelt (Fast and Robust QEF Minimization using Probabilistic Quadrics): [`GarlandHeckbert_plane_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__plane__policies.html), [`GarlandHeckbert_probabilistic_plane_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__probabilistic__plane__policies.html), [`GarlandHeckbert_triangle_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__triangle__policies.html), and [`GarlandHeckbert_probabilistic_triangle_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__probabilistic__triangle__policies.html). +- The class `GarlandHeckbert_policies` has been deprecated, `GarlandHeckbert_plane_policies` replaces it. -- Add vertex, edge, and hole ranges. -- The concept `GeneralPolygonWithHoles_2` now requires the nested type `Polygon_2` instead of `General_polygon_2`. +### [Point Set Processing](https://doc.cgal.org/5.5/Manual/packages.html#PkgPointSetProcessing3) -### [2D Regularized Boolean Set-Operations](https://doc.cgal.org/5.5/Manual/packages.html#PkgBooleanSetOperations2) -- The concept `GeneralPolygonSetTraits_2` now requires the nested type `Construct_polygon_with_holes_2` instead of `Construct_general_polygon_with_holes_2`. +- A new optional named parameter, `min_points_per_cell` has been added to [`grid_simplify_point_set()`](https://doc.cgal.org/5.5/Point_set_processing_3/group__PkgPointSetProcessing3Algorithms.html#ga7757ef9b3900e42fde26f5a0ac56e20f). By adding a minimal number of points in a cell such that a point is retained, one can also filter out low density areas and outliers: in the case of densely sampled point clouds, this yields better results than using grid simplification and then outlier removal, while being very vast. The default value is `1` to keep the previous behavior as default. -### [2D Arrangements](https://doc.cgal.org/5.5/Manual/packages.html#PkgArrangementOnSurface2) -- Fixed the intersect_2, compare_y_at_x_right, and compare_y_at_x_left function objects of the traits class template that handles geodesic arcs on sphere and applied a small syntactical fix to the tracing traits. +### [dD Spatial Searching](https://doc.cgal.org/5.5/Manual/packages.html#PkgSpatialSearchingD) + +- Added the member function [`write_graphviz()`](https://doc.cgal.org/5.5/Spatial_searching/classCGAL_1_1Kd__tree.html#ac2851b5cafb8d5cce0dc5fb107c8f13f) to the class `Kd_tree` that writes the tree in a stream in the [Graphviz](https://graphviz.org/) format. + +### [CGAL and the Boost Graph Library (BGL)](https://doc.cgal.org/5.5/Manual/packages.html#PkgBGL) + +- Added the function [`invert_selection()`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html#aa428541ebbdd35f9a6e9a3ffd60178df) in the class [`Face_filtered_graph`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html), which toggles the selected status of a graph: selected faces are deselected, and unselected faces are selected. [Release 5.4](https://github.com/CGAL/cgal/releases/tag/v5.4) diff --git a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake index 59e846b89d2..ffddd0917c0 100644 --- a/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake +++ b/Installation/cmake/modules/CGAL_SetupCGALDependencies.cmake @@ -75,6 +75,13 @@ endif() # keyword. # function(CGAL_setup_CGAL_dependencies target) + foreach(dir ${CGAL_INCLUDE_DIRS}) + target_include_directories(${target} INTERFACE + $) + endforeach() + target_include_directories(${target} INTERFACE + $) + if(CGAL_DISABLE_GMP) target_compile_definitions(${target} INTERFACE CGAL_DISABLE_GMP=1) else() @@ -96,13 +103,6 @@ function(CGAL_setup_CGAL_dependencies target) use_CGAL_Boost_support(${target} INTERFACE) - foreach(dir ${CGAL_INCLUDE_DIRS}) - target_include_directories(${target} INTERFACE - $) - endforeach() - target_include_directories(${target} INTERFACE - $) - # Make CGAL depend on threads-support (for Epeck and Epeck_d) if(CGAL_HAS_NO_THREADS) target_compile_definitions(${target} INTERFACE CGAL_HAS_NO_THREADS) diff --git a/Installation/include/CGAL/version.h b/Installation/include/CGAL/version.h index 5283590d252..f655dc58ff5 100644 --- a/Installation/include/CGAL/version.h +++ b/Installation/include/CGAL/version.h @@ -17,12 +17,12 @@ #define CGAL_VERSION_H #ifndef SWIG -#define CGAL_VERSION 5.5-dev +#define CGAL_VERSION 5.6-dev #define CGAL_GIT_HASH abcdef #endif -#define CGAL_VERSION_NR 1050500900 +#define CGAL_VERSION_NR 1050600900 #define CGAL_SVN_REVISION 99999 -#define CGAL_RELEASE_DATE 20220531 +#define CGAL_RELEASE_DATE 20221131 #include diff --git a/Installation/lib/cmake/CGAL/CGALConfig.cmake b/Installation/lib/cmake/CGAL/CGALConfig.cmake index 4f3a16b5026..6edefb1810f 100644 --- a/Installation/lib/cmake/CGAL/CGALConfig.cmake +++ b/Installation/lib/cmake/CGAL/CGALConfig.cmake @@ -89,7 +89,9 @@ if (NOT CGAL_DATA_DIR) if (EXISTS "${CMAKE_SOURCE_DIR}/../../data") set(CGAL_DATA_DIR "${CMAKE_SOURCE_DIR}/../../data") else() - message(WARNING "CGAL_DATA_DIR cannot be deduced, set the variable CGAL_DATA_DIR to set the default value of CGAL::data_file_path()") + if(CGAL_TEST_SUITE) + message(WARNING "CGAL_DATA_DIR cannot be deduced, set the variable CGAL_DATA_DIR to set the default value of CGAL::data_file_path()") + endif() endif() endif() endif() diff --git a/Installation/lib/cmake/CGAL/CGALConfigVersion.cmake b/Installation/lib/cmake/CGAL/CGALConfigVersion.cmake index 315ff61ca1a..87fa9944e4d 100644 --- a/Installation/lib/cmake/CGAL/CGALConfigVersion.cmake +++ b/Installation/lib/cmake/CGAL/CGALConfigVersion.cmake @@ -1,5 +1,5 @@ set(CGAL_MAJOR_VERSION 5) -set(CGAL_MINOR_VERSION 5) +set(CGAL_MINOR_VERSION 6) set(CGAL_BUGFIX_VERSION 0) include(${CMAKE_CURRENT_LIST_DIR}/CGALConfigBuildVersion.cmake) set(CGAL_VERSION_PUBLIC_RELEASE_VERSION "5.5-dev") diff --git a/Intersections_2/include/CGAL/Intersections_2/Segment_2_Segment_2.h b/Intersections_2/include/CGAL/Intersections_2/Segment_2_Segment_2.h index 19d1b300232..5fd1545cc38 100644 --- a/Intersections_2/include/CGAL/Intersections_2/Segment_2_Segment_2.h +++ b/Intersections_2/include/CGAL/Intersections_2/Segment_2_Segment_2.h @@ -353,6 +353,42 @@ protected: mutable typename K::Point_2 _intersection_point, _other_point; }; + +inline +double s2s2_alpha(double x0, double y0, + double x1, double y1, + double x2, double y2, + double x3, double y3) +{ + const double s1_dx = x0 - x1, + s1_dy = y0 - y1, + s2_dx = x3 - x2, + s2_dy = y3 - y2, + lx = x3 - x1, + ly = y3 - y1; + double val = std::fma(lx,s2_dy,-ly*s2_dx)/std::fma(s1_dx,s2_dy,-s1_dy*s2_dx); + if (val!=val) return 0.5; + if (val<0) return 0; + if (val>1) return 1; + return val; +} + +template +FT s2s2_alpha(const FT& x0, const FT& y0, + const FT& x1, const FT& y1, + const FT& x2, const FT& y2, + const FT& x3, const FT& y3) +{ + FT s1_dx = x0 - x1, + s1_dy = y0 - y1, + s2_dx = x3 - x2, + s2_dy = y3 - y2, + lx = x3 - x1, + ly = y3 - y1; + return (lx*s2_dy-ly*s2_dx)/(s1_dx*s2_dy-s1_dy*s2_dx); +} + + template typename Segment_2_Segment_2_pair::Intersection_results Segment_2_Segment_2_pair::intersection_type() const @@ -400,14 +436,8 @@ Segment_2_Segment_2_pair::intersection_type() const : CGAL::make_array( _seg2->point(s2s2_id[c][2]), _seg2->point(s2s2_id[c][3]), _seg1->point(s2s2_id[c][0]), _seg1->point(s2s2_id[c][1]) ); - typename K::FT s1_dx = pts[0].x() - pts[1].x(), - s1_dy = pts[0].y() - pts[1].y(), - s2_dx = pts[3].x() - pts[2].x(), - s2_dy = pts[3].y() - pts[2].y(), - lx = pts[3].x() - pts[1].x(), - ly = pts[3].y() - pts[1].y(); + typename K::FT alpha = s2s2_alpha(pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y(), pts[2].x(), pts[2].y(), pts[3].x(), pts[3].y()); - typename K::FT alpha = (lx*s2_dy-ly*s2_dx)/(s1_dx*s2_dy-s1_dy*s2_dx); _intersection_point = K().construct_barycenter_2_object()(pts[0], alpha, pts[1]); return _result; diff --git a/Intersections_2/test/Intersections_2/issue6600.cpp b/Intersections_2/test/Intersections_2/issue6600.cpp new file mode 100644 index 00000000000..4c94455fd31 --- /dev/null +++ b/Intersections_2/test/Intersections_2/issue6600.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include + +int main() +{ + typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel; + typedef Kernel::Point_3 Point; + typedef CGAL::Surface_mesh Surface_mesh; + Surface_mesh mesh; + CGAL::Polygon_mesh_processing::experimental::autorefine_and_remove_self_intersections(mesh); + + return 0; +} diff --git a/Intersections_3/include/CGAL/Intersections_3/internal/Segment_3_Segment_3_do_intersect.h b/Intersections_3/include/CGAL/Intersections_3/internal/Segment_3_Segment_3_do_intersect.h index 317e531eda0..5943325975b 100644 --- a/Intersections_3/include/CGAL/Intersections_3/internal/Segment_3_Segment_3_do_intersect.h +++ b/Intersections_3/include/CGAL/Intersections_3/internal/Segment_3_Segment_3_do_intersect.h @@ -30,7 +30,7 @@ do_intersect(const typename K::Segment_3& s1, { CGAL_precondition(!s1.is_degenerate() && !s2.is_degenerate()); - bool b = do_intersect(s1.supporting_line(), s2.supporting_line(), k); + bool b = internal::do_intersect(s1.supporting_line(), s2.supporting_line(), k); if(b) { // supporting_line intersects: points are coplanar diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index 2bc9704ed04..ead2582c6bc 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -3548,7 +3548,7 @@ namespace CommonKernelFunctors { // 25 possibilities, so I keep the template. template - decltype(auto) + typename CGAL::Intersection_traits::result_type operator()(const T1& t1, const T2& t2) const { return Intersections::internal::intersection(t1, t2, K()); } }; @@ -3561,11 +3561,11 @@ namespace CommonKernelFunctors { // n possibilities, so I keep the template. template - decltype(auto) + typename CGAL::Intersection_traits::result_type operator()(const T1& t1, const T2& t2) const { return Intersections::internal::intersection(t1, t2, K() ); } - decltype(auto) + boost::optional > operator()(const Plane_3& pl1, const Plane_3& pl2, const Plane_3& pl3)const { return Intersections::internal::intersection(pl1, pl2, pl3, K() ); } }; diff --git a/Maintenance/infrastructure/cgal.geometryfactory.com/crontab b/Maintenance/infrastructure/cgal.geometryfactory.com/crontab index 27a916856a1..27a85b47672 100644 --- a/Maintenance/infrastructure/cgal.geometryfactory.com/crontab +++ b/Maintenance/infrastructure/cgal.geometryfactory.com/crontab @@ -19,16 +19,18 @@ LC_CTYPE=en_US.UTF-8 # The script also updates the manual tools. # "master" alone -0 21 * * Sun cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/master.git --do-it || echo ERROR +0 21 * * Sun cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/master.git --do-it --beta 2 --public || echo ERROR # "integration" 0 21 * * Mon,Tue,Wed,Thu cd $HOME/CGAL/create_internal_release && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/integration.git $HOME/CGAL/branches/empty-dir --do-it || echo ERROR +# from branch 5.5 +0 21 * * Fri cd $HOME/CGAL/create_internal_release-5.5-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.5-branch.git --public --do-it || echo ERROR # from branch 5.4 -0 21 * * Fri cd $HOME/CGAL/create_internal_release-5.4-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.4-branch.git --public --do-it || echo ERROR -# from branch 5.3 -0 21 * * Sat cd $HOME/CGAL/create_internal_release-5.3-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.3-branch.git --public --do-it || echo ERROR +0 21 * * Sat cd $HOME/CGAL/create_internal_release-5.4-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.4-branch.git --public --do-it || echo ERROR ## Older stuff +# from branch 5.3 +0 21 * * Sat cd $HOME/CGAL/create_internal_release-5.3-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.3-branch.git --public --do-it || echo ERROR # from branch 5.2 #0 21 * * Fri cd $HOME/CGAL/create_internal_release-5.2-branch && /usr/bin/time scl enable rh-git29 -- $HOME/bin/create_release $HOME/CGAL/branches/CGAL-5.2-branch.git --public --do-it || echo ERROR # from branch 5.1 diff --git a/Maintenance/public_release/announcement/announcement-beta.md b/Maintenance/public_release/announcement/announcement-beta.md index ad13992963f..744bd37df84 100644 --- a/Maintenance/public_release/announcement/announcement-beta.md +++ b/Maintenance/public_release/announcement/announcement-beta.md @@ -1,88 +1,62 @@ -%The CGAL Open Source Project is pleased to announce the release 5.3 Beta 1 of CGAL, the Computational Geometry Algorithms Library. +The CGAL Open Source Project is pleased to announce the release 5.5 Beta 1 of CGAL, the Computational Geometry Algorithms Library. -CGAL version 5.3 Beta 1 is a public testing release. It should provide a solid ground to report bugs that need to be tackled before the release of the final version of CGAL 5.3 in July 2021. +CGAL version 5.5 Beta 1 is a public testing release. It should provide a solid ground to report bugs that need to be tackled before the release of the final version of CGAL 5.5 in July 2022. + +Besides fixes and general enhancement to existing packages, the following has changed since CGAL 5.4: + +### [3D Alpha Wrapping (new package)](https://doc.cgal.org/5.5/Manual/packages.html#PkgAlphaWrap3) + +- This component takes a 3D triangle mesh, soup, or point set as input, and generates a valid (watertight, intersection-free, and combinatorially 2-manifold) surface triangle mesh that contains the input. + The algorithm proceeds by shrink-wrapping and refining a 3D Delaunay triangulation, starting from a loose bounding box of the input. + Two user-defined parameters, alpha and offset, offer control over the maximum size of cavities where the shrink-wrapping process can enter, and the tightness of the final surface mesh to the input, respectively. Once combined, these parameters provide a means to trade fidelity + to the input for complexity of the output. + + See also the [announcement page](https://www.cgal.org/2022/05/18/alpha_wrap/). + +### [3D Convex Hulls](https://doc.cgal.org/5.5/Manual/packages.html#PkgConvexHull3) + +- Added an [overload of the function `CGAL::convex_hull_3()`](https://doc.cgal.org/5.5/Convex_hull_3/group__PkgConvexHull3Functions.html#ga52fca4745c2ef0351063fbe66b035fd1), which writes the result in an indexed triangle set. + +### [2D Polygons](https://doc.cgal.org/5.5/Manual/packages.html#PkgPolygon2) + +- Add vertex, edge, and hole ranges. +- The concept [`GeneralPolygonWithHoles_2`](https://doc.cgal.org/5.5/Polygon/classGeneralPolygonWithHoles__2.html) now requires the nested type `Polygon_2` instead of `General_polygon_2`. + +### [2D Regularized Boolean Set-Operations](https://doc.cgal.org/5.5/Manual/packages.html#PkgBooleanSetOperations2) +- The concept [`GeneralPolygonSetTraits_2`](https://doc.cgal.org/5.5/Boolean_set_operations_2/classGeneralPolygonSetTraits__2.html) now requires the nested type `Construct_polygon_with_holes_2` instead of `Construct_general_polygon_with_holes_2`. + +### [Combinatorial Maps](https://doc.cgal.org/5.5/Manual/packages.html#PkgCombinatorialMaps) + +- Removed old code deprecated in CGAL 4.9 and 4.10 (global functions, and information associated with darts). + +### [2D Arrangements](https://doc.cgal.org/5.5/Manual/packages.html#PkgArrangementOnSurface2) +- Fixed the `intersect_2`, `compare_y_at_x_right`, and `compare_y_at_x_left` function objects of the traits class template [`Arr_geodesic_arc_on_sphere_traits_2`](https://doc.cgal.org/5.5/Arrangement_on_surface_2/classCGAL_1_1Arr__geodesic__arc__on__sphere__traits__2.html) that handles geodesic arcs on sphere and applied a small syntactical fix to the tracing traits. + +### [Tetrahedral Mesh Generation](https://doc.cgal.org/5.5/Manual/packages.html#PkgMesh3) + +- Added the function [`remove_isolated_vertices()`](https://doc.cgal.org/5.5/Mesh_3/classCGAL_1_1Mesh__complex__3__in__triangulation__3.html#ace57c4e777da457c6e33b4f6e89949ce) as a post-processing step for the tetrahedral mesh generation. + +### [Polygon Mesh Processing](https://doc.cgal.org/5.5/Manual/packages.html#PkgPolygonMeshProcessing) +- Added the function [`CGAL::Polygon_mesh_processing::orient_triangle_soup_with_reference_triangle_soup()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__orientation__grp.html#ga855b1c55c201b91ab04eebd2811a87fd), which enables re-orienting the faces of a triangle soup based on the orientation of the nearest face in a reference triangle soup. +- Added the function [`CGAL::Polygon_mesh_processing::compatible_orientations()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__orientation__grp.html#ga9ac9b9434084b64f3304df636c3178a3), which enables to retrieve the (in)compatibility of orientations of faces from different connected components. +- Added the function [`CGAL::Polygon_mesh_processing::tangential_relaxation()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__meshing__grp.html#ga136c659162e5360354db5879db7431b4), which applies an area-based tangential mesh smoothing to the vertices of a surface triangle mesh. +- Added the named parameter `visitor` to the function [`triangulate_hole()`](https://doc.cgal.org/5.5/Polygon_mesh_processing/group__PMP__hole__filling__grp.html#gad2d3c43bce0ef90a16530478196d7f42), which enables to track progress with callbacks. +- Added more functions in the [visitor of the corefinement based methods](https://doc.cgal.org/5.5/Polygon_mesh_processing/classPMPCorefinementVisitor.html) to track progress. + +### [Surface Mesh Simplification](https://doc.cgal.org/5.5/Manual/packages.html#PkgSurfaceMeshSimplification) +- Introduced four variations of the Garland-Heckbert simplification algorithm based on the probabilistic approach of Trettner and Kobbelt (Fast and Robust QEF Minimization using Probabilistic Quadrics): [`GarlandHeckbert_plane_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__plane__policies.html), [`GarlandHeckbert_probabilistic_plane_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__probabilistic__plane__policies.html), [`GarlandHeckbert_triangle_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__triangle__policies.html), and [`GarlandHeckbert_probabilistic_triangle_policies`](https://doc.cgal.org/5.5/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1GarlandHeckbert__probabilistic__triangle__policies.html). +- The class `GarlandHeckbert_policies` has been deprecated, `GarlandHeckbert_plane_policies` replaces it. + +### [Point Set Processing](https://doc.cgal.org/5.5/Manual/packages.html#PkgPointSetProcessing3) + +- A new optional named parameter, `min_points_per_cell` has been added to [`grid_simplify_point_set()`](https://doc.cgal.org/5.5/Point_set_processing_3/group__PkgPointSetProcessing3Algorithms.html#ga7757ef9b3900e42fde26f5a0ac56e20f). By adding a minimal number of points in a cell such that a point is retained, one can also filter out low density areas and outliers: in the case of densely sampled point clouds, this yields better results than using grid simplification and then outlier removal, while being very vast. The default value is `1` to keep the previous behavior as default. + +### [dD Spatial Searching](https://doc.cgal.org/5.5/Manual/packages.html#PkgSpatialSearchingD) + +- Added the member function [`write_graphviz()`](https://doc.cgal.org/5.5/Spatial_searching/classCGAL_1_1Kd__tree.html#ac2851b5cafb8d5cce0dc5fb107c8f13f) to the class `Kd_tree` that writes the tree in a stream in the [Graphviz](https://graphviz.org/) format. + +### [CGAL and the Boost Graph Library (BGL)](https://doc.cgal.org/5.5/Manual/packages.html#PkgBGL) + +- Added the function [`invert_selection()`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html#aa428541ebbdd35f9a6e9a3ffd60178df) in the class [`Face_filtered_graph`](https://doc.cgal.org/5.5/BGL/structCGAL_1_1Face__filtered__graph.html), which toggles the selected status of a graph: selected faces are deselected, and unselected faces are selected. -Besides fixes and general enhancement to existing packages, the following has changed since CGAL 5.2: - -### [Quadtrees, Octrees, and Orthtrees](https://doc.cgal.org/5.3/Manual/packages.html#PkgOrthtree) (new package) - -- This package implements a tree data structure in which each node encloses a hypercubic section - of space and each non-leave node has hypercubic children whose edge lengths are half its edge length. - Such a data structure is known as a quadtree in 2D, an octree in 3D, and is generalized - as an "orthtree" in higher dimensions. - -### [Triangulations on the Sphere](https://doc.cgal.org/5.3/Manual/packages.html#PkgTriangulationOnSphere2) (new package) - -- This package enables the construction and manipulation of Delaunay triangulations on the 2-sphere. - Triangulations are built incrementally and can be modified by insertion or removal of vertices. - Point location querying and primitives to build the dual Voronoi diagram are provided. - -### File Input / Output - -- Point set, polygon soup, and polygon mesh file I/O functions have been harmonized and documented: - - Point set I/O functions can be found in the packages [Point_set_processing_3](https://doc.cgal.org/5.3/Manual/packages.html#PkgPolygonMeshProcessing), and [Point_set_3](https://doc.cgal.org/5.3/Manual/packages.html#PkgPointSet3). - - Polygon mesh I/O functions can be found in the package [BGL](https://doc.cgal.org/5.3/Manual/packages.html#PkgBGL). - - Polygon soup I/O can be found in the package [Stream_support](https://doc.cgal.org/5.3/Manual/packages.html#PkgStreamSupport). - -A comprehensive list of the supported file formats is available in the Stream_support package -[here](https://doc.cgal.org/5.3/Stream_support/index.html#IOstreamSupportedFormats); -inversely, the following [page](https://doc.cgal.org/5.3/Stream_support/IOStreamSupportedFileFormats.html) -can be used to find out which CGAL data structures can be used given a specific file format. - -### [Requirements](https://doc.cgal.org/5.3/Manual/thirdparty.html) - -- The CMake minimal version is now `3.14`. -- The GNU compiler g++ versions 6 and 7 are no longer tested. Only version 8.3 or later are supported - -### [2D and 3D Linear Geometry Kernel](https://doc.cgal.org/5.3/Manual/packages.html#PkgKernel23) - -- Added `is_translation()`, `is_scaling()`, `is_reflection()`, and `is_rotation()` to the classes - [`Aff_transformation_2`](https://doc.cgal.org/5.3/Kernel_23/classCGAL_1_1Aff__transformation__2.html) - and [`Aff_transformation_3`](https://doc.cgal.org/5.3/Kernel_23/classCGAL_1_1Aff__transformation__3.html), - which enable determining if the transformations use a specialized representation internally. - -### [2D Regularized Boolean Set-Operations](https://doc.cgal.org/5.3/Manual/packages.html#PkgBooleanSetOperations2) -- Added documentation for the free functions [`oriented_side(const Point_2& p, ....)`](https://doc.cgal.org/5.3/Boolean_set_operations_2/group__boolean__oriented__side.html) - that accept a point and a polygon. -- Documentation has been improved across the whole package. - -### [Polygon Mesh Processing](https://doc.cgal.org/5.3/Manual/packages.html#PkgPolygonMeshProcessing) - -- Added the class [`CGAL::Polyhedral_envelope`](https://doc.cgal.org/5.3/Polygon_mesh_processing/structCGAL_1_1Polyhedral__envelope.html), - providing a way to quickly check if a primitive (point, segment, or triangle) - is within a polyhedral envelope around a set of triangles. It is based on the work of - Bolun Wang, Teseo Schneider, Yixin Hu, Marco Attene, and Daniele Panozzo. - "Exact and efficient polyhedral envelope containment check." (ACM Trans. Graph., 39-4, July 2020). -- Added more functions in the [visitor of the corefinement based methods](https://doc.cgal.org/5.3/Polygon_mesh_processing/classPMPCorefinementVisitor.html) - to track all edge creations. - -### [Surface Mesh Topology](https://doc.cgal.org/5.3/Manual/packages.html#PkgSurfaceMeshTopologySummary) -- Added the function [`CGAL::Surface_mesh_topology::Curves_on_surface_topology::is_homotopic_to_simple_cycle()`](https://doc.cgal.org/5.3/Surface_mesh_topology/classCGAL_1_1Surface__mesh__topology_1_1Curves__on__surface__topology.html#a8d7c4cba2cf2cff542f5cd93117233db), - which can be used to determine whehter a closed path on a surface mesh can be continously - transformed to a cycle without self intersection. - -### [Surface Mesh Simplification](https://doc.cgal.org/5.3/Manual/packages.html#PkgSurfaceMeshSimplification) -- Added a filtering mechanism so that costly tests get only applied to the next candidate for the edge collapse. -- Added the class [`Polyhedral_envelope_filter`](https://doc.cgal.org/5.3/Surface_mesh_simplification/classCGAL_1_1Surface__mesh__simplification_1_1Polyhedral__envelope__filter.html), - which enables to perform mesh simplification inside a polyhedral envelope of the input mesh. - -### [2D Polyline Simplification](https://doc.cgal.org/5.3/Manual/packages.html#PkgPolylineSimplification2) -- When polylines have common subsequences of vertices, these subsequences may now be simplifified simultaneously. - -### [dD Triangulations](https://doc.cgal.org/5.3/Manual/packages.html#PkgTriangulations) -- Added the function [`insert_if_in_star()`](https://doc.cgal.org/5.3/Triangulation/classCGAL_1_1Regular__triangulation.html#aa8df2d138f341939e834bcdd7cb6c71a) - to the class [`CGAL::Regular_triangulation`](https://doc.cgal.org/5.3/Triangulation/classCGAL_1_1Regular__triangulation.html), - which enables users to insert a point `p` in a regular triangulation on the condition that `p` - appears post-insertion in the star of a user-specified, existing vertex. - -### [2D and 3D Alpha Shapes](https://doc.cgal.org/5.3/Manual/packages.html#PkgAlphaShapes2) -- **Breaking change**: The following deprecated classes have been removed: `Alpha_shape_euclidean_traits_2`, - `Weighted_alpha_shape_euclidean_traits_2`, `Alpha_shape_euclidean_traits_3`, and - `Weighted_alpha_shape_euclidean_traits_3`. All CGAL kernel can be used directly as models - of the concepts of the 2D and 3D Alpha Shape packages. - -### [Classification](https://doc.cgal.org/5.3/Manual/packages.html#PkgClassification) -- **Breaking change**: the support for TensorFlow has been dropped; the - classifier `CGAL::TensorFlow::Neural_network_classifier` has been removed. - diff --git a/Maintenance/public_release/announcement/mailing-beta.eml b/Maintenance/public_release/announcement/mailing-beta.eml index 7fea9721de1..e6de484eb6d 100644 --- a/Maintenance/public_release/announcement/mailing-beta.eml +++ b/Maintenance/public_release/announcement/mailing-beta.eml @@ -1,97 +1,133 @@ -Subject: CGAL 5.4 Beta 1 Released, Computational Geometry Algorithms Library +Subject: CGAL 5.3.2, 5.4.1, and 5.5 Beta 1 Released, Computational Geometry Algorithms Library Content-Type: text/plain; charset="utf-8" Body: -The CGAL Open Source Project is pleased to announce the release 5.4 Beta 1 -of CGAL, the Computational Geometry Algorithms Library. +The CGAL Open Source Project is pleased to announce today three new +releases: +- CGAL-5.3.2 is the second and last bug-fix release for CGAL-5.3, +- CGAL-5.4.1 is the first bug-fix release for CGAL-5.4, and +- CGAL-5.5-beta1 is the first beta release for CGAL-5.5. -CGAL version 5.4 Beta 1 is a public testing release. It should provide a +CGAL version 5.5 Beta 1 is a public testing release. It should provide a solid ground to report bugs that need to be tackled before the release -of the final version of CGAL 5.4 in January 2022. +of the final version of CGAL 5.5 in July 2022. + +Besides fixes and general enhancement to existing packages, the +following has changed since CGAL 5.4: + +3D Alpha Wrapping (new package) + +- This component takes a 3D triangle mesh, soup, or point set as + input, and generates a valid (watertight, intersection-free, and + combinatorially 2-manifold) surface triangle mesh that contains the + input. The algorithm proceeds by shrink-wrapping and refining a 3D + Delaunay triangulation, starting from a loose bounding box of the + input. Two user-defined parameters, alpha and offset, offer control + over the maximum size of cavities where the shrink-wrapping process + can enter, and the tightness of the final surface mesh to the input, + respectively. Once combined, these parameters provide a means to + trade fidelity to the input for complexity of the output. + + See also https://www.cgal.org/2022/05/18/alpha_wrap/. + +3D Convex Hulls + +- Added an overload of the function CGAL::convex_hull_3(), which + writes the result in an indexed triangle set. + +2D Polygons + +- Add vertex, edge, and hole ranges. +- The concept GeneralPolygonWithHoles_2 now requires the nested type + Polygon_2 instead of General_polygon_2. + +2D Regularized Boolean Set-Operations + +- The concept GeneralPolygonSetTraits_2 now requires the nested type + Construct_polygon_with_holes_2 instead of + Construct_general_polygon_with_holes_2. + +Combinatorial Maps + +- Removed old code deprecated in CGAL 4.9 and 4.10 (global functions, + and information associated with darts). + +2D Arrangements + +- Fixed the intersect_2, compare_y_at_x_right, and compare_y_at_x_left + function objects of the traits class template + Arr_geodesic_arc_on_sphere_traits_2 that handles geodesic arcs on + sphere and applied a small syntactical fix to the tracing traits. + +Tetrahedral Mesh Generation + +- Added the function remove_isolated_vertices() as a post-processing + step for the tetrahedral mesh generation. + +Polygon Mesh Processing + +- Added the function + CGAL::Polygon_mesh_processing::orient_triangle_soup_with_reference_triangle_soup(), + which enables re-orienting the faces of a triangle soup based on the + orientation of the nearest face in a reference triangle soup. +- Added the function + CGAL::Polygon_mesh_processing::compatible_orientations(), which + enables to retrieve the (in)compatibility of orientations of faces + from different connected components. +- Added the function + CGAL::Polygon_mesh_processing::tangential_relaxation(), which + applies an area-based tangential mesh smoothing to the vertices of a + surface triangle mesh. +- Added the named parameter visitor to the function + triangulate_hole(), which enables to track progress with callbacks. +- Added more functions in the visitor of the corefinement based + methods to track progress. + +Surface Mesh Simplification + +- Introduced four variations of the Garland-Heckbert simplification + algorithm based on the probabilistic approach of Trettner and + Kobbelt (Fast and Robust QEF Minimization using Probabilistic + Quadrics): GarlandHeckbert_plane_policies, + GarlandHeckbert_probabilistic_plane_policies, + GarlandHeckbert_triangle_policies, and + GarlandHeckbert_probabilistic_triangle_policies. +- The class GarlandHeckbert_policies has been deprecated, + GarlandHeckbert_plane_policies replaces it. + +Point Set Processing + +- A new optional named parameter, min_points_per_cell has been added + to grid_simplify_point_set(). By adding a minimal number of points + in a cell such that a point is retained, one can also filter out low + density areas and outliers: in the case of densely sampled point + clouds, this yields better results than using grid simplification + and then outlier removal, while being very vast. The default value + is 1 to keep the previous behavior as default. + +dD Spatial Searching + +- Added the member function write_graphviz() to the class Kd_tree that + writes the tree in a stream in the Graphviz format. + +CGAL and the Boost Graph Library (BGL) + +- Added the function invert_selection() in the class + Face_filtered_graph, which toggles the selected status of a graph: + selected faces are deselected, and unselected faces are selected. -Besides fixes and general enhancement to existing packages, the following -has changed since CGAL 5.3: - - -General changes - -- Added the cmake target CGAL::CGAL_Basic_viewer to ease the - compilation of programs using the basic viewer-based function - CGAL::draw(). This target will define the macro and link with - CGAL_Qt5 target when linked with it. - -- The kernel providing exact constructions and exact predicates - (CGAL::Exact_predicates_exact_constructions_kernel) is now - thread-safe. - more details. - - -Shape Regularization (new package) - -- This package enables to regularize a set of segments and open or - closed contours in 2D and a set of planes in 3D such that all input - objects are rotated and aligned with respect to the user-specified - conditions. In addition, it provides a global regularization - framework that can be adjusted for the user needs and any type of - geometric objects. - - https://www.cgal.org/2021/11/16/shape-regularization/ - - https://doc.cgal.org/5.4/Manual/packages.html#PkgShapeRegularization - - -Weights (new package) - -- This package provides a simple and unified interface to different - types of weights. In particular, it groups all weights into three - category: analytic weights including all basic weights which can be - computed analytically for a query point with respect to its local - neighbors in 2D and 3D; barycentric weights, including all weights - which can be computed for a query point with respect to the vertices - of a planar polygon; and weighting regions, including all weights - which are used to balance other weights. - - https://doc.cgal.org/5.4/Manual/packages.html#PkgWeights - - -2D Generalized Barycentric Coordinates (major changes) - -- Breaking change: The headers Segment_coordinates_2.h and - Triangle_coordinates_2.h are renamed to segment_coordinates_2.h and - triangle_coordinates_2.h. -- The classes Segment_coordinates_2 and Triangle_coordinates_2 are - deprecated. The free functions compute_segment_coordinates_2() and - compute_triangle_coordinates_2() are deprecated as well. Instead, - the free functions segment_coordinates_2() and - triangle_coordinates_2() should be used. -- The enums Query_point_location and Type_of_algorithm are deprecated. - Instead, the enum Computation_policy_2 should be used. -- The classes Wachspress_2, Discrete_harmonic_2, Mean_value_2, and - Generalized_barycentric_coordinates_2 are deprecated. As - consequence, the concept BarycentricCoordinates_2 is deprecated as - well. Instead, the classes Wachspress_coordinates_2, - Discrete_harmonic_coordinates_2, and Mean_value_coordinates_2 should - be used. -- Added the class Harmonic_coordinates_2 to compute approximate - harmonic coordinates in 2D. These coordinates satisfy all properties - of barycentric coordinates inside any simple polygon. -- Added a new concept DiscretizedDomain_2 and a model of this concept - called Delaunay_domain_2, which is based on the Mesh 2 package. A - model of this concept is required to use Harmonic_coordinates_2. -- Added free functions to compute Wachspress, discrete harmonic, and - mean value coordinates. -- All free functions and classes are now using ranges and property - maps. - - https://doc.cgal.org/5.4/Manual/packages.html#PkgBarycentricCoordinates2 - - -See https://www.cgal.org/2021/12/17/cgal54-beta1/ for a +See https://www.cgal.org/2022/06/06/cgal55-beta1/ for a complete list of changes. +The development of CGAL will then now on the future CGAL-5.6 (planned +for December 2022), with bug-fixes regularly backported to the branches +for CGAL-5.4.x and CGAL-5.5.x. + + + The CGAL project is a collaborative effort to develop a robust, easy-to-use, and efficient C++ software library of geometric data structures and algorithms, like diff --git a/Mesh_3/doc/Mesh_3/Doxyfile.in b/Mesh_3/doc/Mesh_3/Doxyfile.in index 62ea73403e6..c5f22c38811 100644 --- a/Mesh_3/doc/Mesh_3/Doxyfile.in +++ b/Mesh_3/doc/Mesh_3/Doxyfile.in @@ -23,4 +23,4 @@ HTML_EXTRA_FILES = ${CGAL_PACKAGE_DOC_DIR}/fig/implicit_domain_3.jpg ${CGAL_PACKAGE_DOC_DIR}/fig/protection-complex.png \ ${CGAL_PACKAGE_DOC_DIR}/fig/no-protection-complex.png -EXAMPLE_PATH += ${CGAL_PACKAGE_INCLUDE_DIR} +EXAMPLE_PATH += ${CGAL_PACKAGE_INCLUDE_DIR} # non-documented headers are advertised diff --git a/Mesh_3/include/CGAL/Mesh_3/generate_label_weights.h b/Mesh_3/include/CGAL/Mesh_3/generate_label_weights.h index 6f3d9d77bab..1f1a8014a13 100644 --- a/Mesh_3/include/CGAL/Mesh_3/generate_label_weights.h +++ b/Mesh_3/include/CGAL/Mesh_3/generate_label_weights.h @@ -227,6 +227,7 @@ CGAL::Image_3 generate_label_weights_with_known_word_type(const CGAL::Image_3& i /// @endcond /*! +* \ingroup PkgMesh3Functions * Free function that generates a `CGAL::Image_3` of weights associated to each * voxel of `image`, to make the output mesh surfaces smoother. * The weights image is generated using the algorithm described by Stalling et al diff --git a/Nef_3/include/CGAL/Nef_3/Binary_operation.h b/Nef_3/include/CGAL/Nef_3/Binary_operation.h index 8de14ea4101..4bfed515639 100644 --- a/Nef_3/include/CGAL/Nef_3/Binary_operation.h +++ b/Nef_3/include/CGAL/Nef_3/Binary_operation.h @@ -180,37 +180,9 @@ class Binary_operation : public CGAL::SNC_decorator { snc0(s0), snc1(s1), bop(_bop), result(r), inverse_order(invert_order), A(Ain) {} - void operator()(Halfedge_handle e0, Object_handle o1, const Point_3& ip) - const { - -#ifdef CGAL_NEF3_DUMP_STATISTICS - ++number_of_intersections; -#endif - - Halfedge_handle e; - Halffacet_handle f; - - Point_3 p(normalized(ip)); -#ifdef CGAL_USE_TRACE - CGAL_NEF_TRACEN("Intersection_call_back: intersection reported on " << p << " (normalized: " << normalized(p) << " )"); - CGAL_NEF_TRACEN("edge 0 has source " << e0->source()->point() << " and direction " << e0->vector()); - if( CGAL::assign( e, o1)) { - CGAL_NEF_TRACEN("edge 1 has source " << e->source()->point() << " and direction " << e->vector()); - } - else if( CGAL::assign( f, o1)) { - CGAL_NEF_TRACEN("face 1 has plane equation " << f->plane()); - } - else - CGAL_error_msg( "wrong handle"); -#endif - -#if defined (CGAL_NEF3_TIMER_OVERLAY) || (CGAL_NEF3_TIMER_INTERSECTION) - timer_overlay.start(); -#endif - - if( CGAL::assign( e, o1)) { - // std::cerr << "inverse order " << inverse_order << std::endl; - + void operator()(Halfedge_handle e0, Halfedge_handle e, const Point_3& ip) const override + { + Point_3 p(normalized(ip)); #ifdef CGAL_NEF_EXPERIMENTAL_CODE typename CGAL::Edge_edge_overlay eeo(result, e0, e); Sphere_map* M0 = eeo.create_edge_edge_overlay(p, bop, inverse_order, A); @@ -228,7 +200,10 @@ class Binary_operation : public CGAL::SNC_decorator { result.delete_vertex(v1); #endif } - else if( CGAL::assign( f, o1)) { + + void operator()(Halfedge_handle e0, Halffacet_handle f, const Point_3& ip) const override + { + Point_3 p(normalized(ip)); #ifdef CGAL_NEF3_OVERLAY_BY_HAND_OFF Binary_operation D(result); Vertex_handle v0, v1; @@ -246,14 +221,7 @@ class Binary_operation : public CGAL::SNC_decorator { O.simplify(A); #endif // CGAL_NEF3_OVERLAY_BY_HAND_OFF } - else - CGAL_error_msg( "wrong handle"); -#if defined (CGAL_NEF3_TIMER_OVERLAY) || (CGAL_NEF3_TIMER_INTERSECTION) - timer_overlay.stop(); -#endif - - } private: const SNC_structure& snc0; const SNC_structure& snc1; diff --git a/Nef_3/include/CGAL/Nef_3/K3_tree.h b/Nef_3/include/CGAL/Nef_3/K3_tree.h index e2bf66a33be..77afbf5e629 100644 --- a/Nef_3/include/CGAL/Nef_3/K3_tree.h +++ b/Nef_3/include/CGAL/Nef_3/K3_tree.h @@ -108,15 +108,8 @@ typedef Smaller_than< public: typedef Node* Node_handle; Node(const Vertex_list& V, const Halfedge_list& E, const Halffacet_list& F) : - left_node(nullptr), right_node(nullptr) + left_node(nullptr), right_node(nullptr), vertex_list(V), edge_list(E), facet_list(F) { - object_list.reserve(V.size()+E.size()+F.size()); - for(Vertex_const_iterator vi=V.begin(); vi!=V.end(); ++vi) - object_list.push_back(make_object(*vi)); - for(Halfedge_const_iterator ei=E.begin(); ei!=E.end(); ++ei) - object_list.push_back(make_object(*ei)); - for(Halffacet_const_iterator fi=F.begin(); fi!=F.end(); ++fi) - object_list.push_back(make_object(*fi)); } Node(Node_handle l, Node_handle r, const Plane_3& pl) : @@ -133,20 +126,27 @@ public: Node_handle left() const { return left_node; } Node_handle right() const { return right_node; } const Plane_3& plane() const { return splitting_plane; } - const Object_list& objects() const { return object_list; } + + bool empty() { return vertex_list.empty() && edge_list.empty() && facet_list.empty(); } + Vertex_const_iterator vertices_begin() { return vertex_list.begin(); } + Vertex_const_iterator vertices_end() { return vertex_list.end(); } + Halfedge_const_iterator edges_begin() { return edge_list.begin(); } + Halfedge_const_iterator edges_end() { return edge_list.end(); } + Halffacet_const_iterator facets_begin() { return facet_list.begin(); } + Halffacet_const_iterator facets_end() { return facet_list.end(); } void transform(const Aff_transformation_3& t) { if(left_node != nullptr) { CGAL_assertion(right_node != nullptr); left_node->transform(t); - right_node->transform(t); - splitting_plane = splitting_plane.transform(t); + right_node->transform(t); + splitting_plane = splitting_plane.transform(t); } } void add_facet(Halffacet_handle f, int depth) { if(left_node == nullptr) { - object_list.push_back(make_object(f)); + facet_list.push_back(f); return; } @@ -160,7 +160,7 @@ public: void add_edge(Halfedge_handle e, int depth) { if(left_node == nullptr) { - object_list.push_back(make_object(e)); + edge_list.push_back(e); return; } @@ -174,7 +174,7 @@ public: void add_vertex(Vertex_handle v, int depth) { if(left_node == nullptr) { - object_list.push_back(make_object(v)); + vertex_list.push_back(v); return; } @@ -187,33 +187,19 @@ public: } -friend std::ostream& operator<< - (std::ostream& os, const Node_handle node) { - CGAL_assertion( node != nullptr); - if( node->is_leaf()) - os << node->objects().size(); - else { - os << " ( "; - if( !node->left()) os << '-'; - else os << node->left(); - os << " , "; - if( !node->right()) os << '-'; - else os << node->right(); - os << " ) "; - } - return os; -} - private: Node_handle left_node; Node_handle right_node; Plane_3 splitting_plane; - Object_list object_list; + Vertex_list vertex_list; + Halfedge_list edge_list; + Halffacet_list facet_list; }; typedef boost::container::deque Node_range; typedef Node* Node_handle; + typedef std::vector Node_list; public: @@ -266,10 +252,6 @@ public: ++(*this); // place the interator in the first intersected cell } Iterator( const Self& i) : S(i.S), node(i.node) {} - const Object_list& operator*() const { - CGAL_assertion( node != nullptr); - return node->objects(); - } Self& operator++() { if( S.empty()) @@ -350,35 +332,6 @@ void divide_segment_by_plane( Segment_3 s, Plane_3 pl, }; }; - class Objects_along_ray : public Objects_around_segment - { - typedef Objects_around_segment Base; - protected: - Traits traits; - public: - Objects_along_ray( const K3_tree& k, const Ray_3& r) { - CGAL_NEF_TRACEN("Objects_along_ray: input ray: "< v_mark(false); - Unique_hash_map< Halfedge_handle, bool> e_mark(false); - Unique_hash_map< Halffacet_handle, bool> f_mark(false); - for( typename Objects_around_segment::Iterator oar = objects.begin(); - oar != objects.end(); ++oar) { - for( typename Object_list::const_iterator o = (*oar).begin(); - o != (*oar).end(); ++o) { // TODO: implement operator->(...) - Vertex_handle v; - Halfedge_handle e; - Halffacet_handle f; - if( CGAL::assign( v, *o)) { - if( !v_mark[v]) { - O.push_back(*o); - v_mark[v] = true; - } - } - else if( CGAL::assign( e, *o)) { - if( !e_mark [e]) { - O.push_back(*o); - e_mark[e] = true; - } - } - else if( CGAL::assign( f, *o)) { - if( !f_mark[f]) { - O.push_back(*o); - f_mark[f] = true; - } - } - else - CGAL_error_msg( "wrong handle"); - } + for(typename Objects_around_segment::Iterator oas = objects.begin(); oas != objects.end(); ++oas) { + result.push_back(oas.get_node()); } - return O; + return result; } - - bool is_point_on_cell( const Point_3& p, const typename Objects_around_segment::Iterator& target) const { - return is_point_on_cell( p, target.get_node(), root); + bool is_point_in_node( const Point_3& p, const Node_handle target) const { + return is_point_in_node( p, target, root); } void add_facet(Halffacet_handle f) { @@ -510,12 +433,8 @@ public: void pre_visit(const Node_handle) {} void post_visit(const Node_handle n) { - typename Object_list::const_iterator o; - for( o = n->objects().begin(); - o != n->objects().end(); ++o) { - Vertex_handle v; - if( CGAL::assign( v, *o)) - b.extend(v->point()); + for(Vertex_const_iterator vi = n->vertex_list.begin(); vi!=n->vertex_list.end(); ++vi) { + b.extend((*vi)->point()); } } @@ -722,7 +641,7 @@ static Node_handle get_child_by_side( const Node_handle node, Oriented_side side return node->right(); } -Node_handle locate_cell_containing( const Point_3& p, const Node_handle node) const { +Node_handle locate_node_containing( const Point_3& p, const Node_handle node) const { CGAL_precondition( node != nullptr); if( node->is_leaf()) return node; @@ -730,26 +649,57 @@ Node_handle locate_cell_containing( const Point_3& p, const Node_handle node) co Oriented_side side = node->plane().oriented_side(p); if(side == ON_ORIENTED_BOUNDARY) side = ON_NEGATIVE_SIDE; - return locate_cell_containing(p, get_child_by_side(node, side)); + return locate_node_containing(p, get_child_by_side(node, side)); } -const Object_list& locate( const Point_3& p, const Node_handle node) const { - CGAL_precondition( node != nullptr); - return locate_cell_containing( p, node)->objects(); -} -bool is_point_on_cell( const Point_3& p, const Node_handle target, const Node_handle current) const { +bool is_point_in_node( const Point_3& p, const Node_handle target, const Node_handle current) const { CGAL_precondition( target != nullptr && current != nullptr); if( current->is_leaf()) return (current == target); Oriented_side side = current->plane().oriented_side(p); if( side == ON_NEGATIVE_SIDE) - return is_point_on_cell( p, target, current->left()); + return is_point_in_node( p, target, current->left()); else if( side == ON_POSITIVE_SIDE) - return is_point_on_cell( p, target, current->right()); + return is_point_in_node( p, target, current->right()); CGAL_assertion( side == ON_ORIENTED_BOUNDARY); - return (is_point_on_cell( p, target, current->left()) || - is_point_on_cell( p, target, current->right())); + return (is_point_in_node( p, target, current->left()) || + is_point_in_node( p, target, current->right())); +} + +Segment_3 ray_to_segment(const Ray_3& r) const +{ + CGAL_NEF_TRACEN("Objects_along_ray: input ray: "<volume() != Volume_handle() ) continue; CGAL_NEF_TRACEN( "Outer shell #" << ShellSf[f] << " volume?"); - Volume_handle c = determine_volume( MinimalSFace[ShellSf[f]], - MinimalSFace, ShellSf ); + Volume_handle c = determine_volume( f, MinimalSFace, ShellSf ); c->mark() = f->mark(); link_as_outer_shell( f, c ); } diff --git a/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h b/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h index 8bda46183c5..9814f10bb6f 100644 --- a/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h +++ b/Nef_3/include/CGAL/Nef_3/SNC_point_locator.h @@ -93,14 +93,15 @@ public: const = 0; virtual void intersect_with_edges_and_facets( Halfedge_handle edge, - const Intersection_call_back& call_back) const = 0; + const Intersection_call_back& call_back) const = 0; class Intersection_call_back { public: - virtual void operator()( Halfedge_handle edge, Object_handle object, + virtual void operator()( Halfedge_handle edge0, Halfedge_handle edge1, + const Point_3& intersection_point) const = 0; + virtual void operator()( Halfedge_handle edge0, Halffacet_handle facet1, const Point_3& intersection_point) const = 0; - virtual ~Intersection_call_back() {} }; @@ -182,8 +183,14 @@ public: typedef typename SNC_candidate_provider::Object_list Object_list; typedef typename Object_list::iterator Object_list_iterator; - typedef typename SNC_candidate_provider::Objects_along_ray Objects_along_ray; - typedef typename Objects_along_ray::Iterator Objects_along_ray_iterator; + + typedef typename SNC_candidate_provider::Node_handle Node_handle; + typedef typename SNC_candidate_provider::Node_list Node_list; + typedef typename SNC_candidate_provider::Vertex_list Vertex_list; + typedef typename SNC_candidate_provider::Halfedge_list Halfedge_list; + typedef typename SNC_candidate_provider::Halffacet_list Halffacet_list; + typedef typename SNC_point_locator::Intersection_call_back Intersection_call_back; + using Base::get_visible_facet; public: @@ -218,454 +225,346 @@ public: delete candidate_provider; } + // We next check if v is a vertex on the face to avoid a geometric test + static inline bool v_vertex_of_f(Vertex_handle v, Halffacet_handle f) { + Halffacet_cycle_iterator fci; + for(fci=f->facet_cycles_begin(); fci!=f->facet_cycles_end(); ++fci) { + if(fci.is_shalfedge()) { + SHalfedge_around_facet_circulator sfc(fci), send(sfc); + CGAL_For_all(sfc,send) { + if(sfc->source()->center_vertex() == v){ + return true; + } + } + } + } + return false; + } + virtual Object_handle shoot(const Ray_3& ray, int mask=255) const { Vertex_handle null_handle; return this->shoot(ray, null_handle, mask); } + enum SOLUTION { is_vertex_, is_edge_, is_facet_ , is_none_}; + virtual Object_handle shoot(const Ray_3& ray, Vertex_handle ray_source_vertex, int mask=255) const { CGAL_NEF_TIMER(rs_t.start()); CGAL_assertion( initialized); _CGAL_NEF_TRACEN( "shooting: "<objects_along_ray(ray); - Objects_along_ray_iterator objects_iterator = objects.begin(); - while( !hit && objects_iterator != objects.end()) { - Object_list candidates = *objects_iterator; - Object_list_iterator o; - CGAL_for_each( o, candidates) { - if( CGAL::assign( v, *o) && ((mask&1) != 0)) { + + Node_list nodes = candidate_provider->nodes_along_ray(ray); + typename Node_list::iterator nodes_iterator = nodes.begin(); + + while( !hit && nodes_iterator != nodes.end()) { + Node_handle n(*nodes_iterator); + if((mask&1)!=0) { + for(typename Vertex_list::const_iterator vi=n->vertices_begin(); vi!=n->vertices_end(); ++vi) { + Vertex_handle v(*vi); _CGAL_NEF_TRACEN("trying vertex on "<point()); if( (ray.source() != v->point()) && ray.has_on(v->point())) { _CGAL_NEF_TRACEN("the ray intersects the vertex"); _CGAL_NEF_TRACEN("prev. intersection? "<point())) continue; eor = v->point(); - result = make_object(v); + v_res = v; + solution = is_vertex_; hit = true; _CGAL_NEF_TRACEN("the vertex becomes the new hit object"); } } - else if( CGAL::assign( e, *o) && ((mask&2) != 0)) { + } + if((mask&2)!=0) { + for(typename Halfedge_list::const_iterator ei=n->edges_begin(); ei!=n->edges_end(); ++ei) { + Halfedge_handle e(*ei); Point_3 q; _CGAL_NEF_TRACEN("trying edge on "<< Segment_3(e->source()->point(),e->twin()->source()->point())); if ( (ray_source_vertex == Vertex_handle()) || ( (ray_source_vertex != e->source()) && (ray_source_vertex != e->twin()->source())) ) { - - if( SNC_intersection::does_intersect_internally( ray, Segment_3(e->source()->point(), - e->twin()->source()->point()), q)) { - _CGAL_NEF_TRACEN("ray intersects edge on " << q); - _CGAL_NEF_TRACEN("prev. intersection? " << hit); - CGAL_assertion_code - (if (hit) _CGAL_NEF_TRACEN("prev. intersection on " << eor)); - if (hit && !has_smaller_distance_to_point(ray.source(), q, eor)) - continue; - _CGAL_NEF_TRACEN("is the intersection point on the current cell? " << - candidate_provider->is_point_on_cell(q, objects_iterator)); - if (!candidate_provider->is_point_on_cell(q, objects_iterator)) - continue; - eor = q; - result = make_object(e); - hit = true; - _CGAL_NEF_TRACEN("the edge becomes the new hit object"); - } + if( SNC_intersection::does_intersect_internally( ray, Segment_3(e->source()->point(), + e->twin()->source()->point()), q)) { + _CGAL_NEF_TRACEN("ray intersects edge on "<is_point_in_node( q, n)); + if( !candidate_provider->is_point_in_node( q, n)) + continue; + eor = q; + e_res = e; + solution = is_edge_; + hit = true; + _CGAL_NEF_TRACEN("the edge becomes the new hit object"); + } } } - else if( CGAL::assign( f, *o) && ((mask&4) != 0)) { + } + if((mask&4)!=0) { + for(typename Halffacet_list::const_iterator fi=n->facets_begin(); fi!=n->facets_end(); ++fi) { + Halffacet_handle f(*fi); Point_3 q; _CGAL_NEF_TRACEN("trying facet with on plane "<plane()<< - " with point on "<plane().point()); - if( SNC_intersection::does_intersect_internally( ray, f, q) ) { - _CGAL_NEF_TRACEN("ray intersects facet on "<is_point_on_cell( q, objects_iterator)); - if( !candidate_provider->is_point_on_cell( q, objects_iterator)) - continue; - eor = q; - result = make_object(f); - hit = true; - _CGAL_NEF_TRACEN("the facet becomes the new hit object"); + " with point on "<plane().point()); + if( (ray_source_vertex == Vertex_handle()) || !v_vertex_of_f(ray_source_vertex,f) ) { + if( SNC_intersection::does_intersect_internally( ray, f, q) ) { + _CGAL_NEF_TRACEN("ray intersects facet on "<is_point_in_node( q, n)); + if( !candidate_provider->is_point_in_node( q, n)) + continue; + eor = q; + f_res = f; + solution = is_facet_; + hit = true; + _CGAL_NEF_TRACEN("the facet becomes the new hit object"); + } } } - else if((mask&15) == 15) - CGAL_error_msg( "wrong handle"); } if(!hit) - ++objects_iterator; + ++nodes_iterator; } + CGAL_NEF_TIMER(rs_t.stop()); - return result; + switch (solution) { + case is_vertex_: return make_object(v_res); + case is_edge_: return make_object(e_res); + case is_facet_: return make_object(f_res); + case is_none_ : break; + } + return Object_handle(); } virtual Object_handle locate( const Point_3& p) const { if(Infi_box::extended_kernel()) { - CGAL_NEF_TIMER(pl_t.start()); - CGAL_assertion( initialized); - _CGAL_NEF_TRACEN( "locate "<objects_around_point(p); - Object_list_iterator o = candidates.begin(); - bool found = false; - while( !found && o != candidates.end()) { - if( CGAL::assign( v, *o)) { + CGAL_NEF_TIMER(pl_t.start()); + CGAL_assertion( initialized); + _CGAL_NEF_TRACEN( "locate "<locate_node_containing(p); + for(typename Vertex_list::const_iterator vi=n->vertices_begin(); vi!=n->vertices_end(); ++vi) { + Vertex_handle v(*vi); if ( p == v->point()) { _CGAL_NEF_TRACEN("found on vertex "<point()); - result = make_object(v); - found = true; + return make_object(v); } } - else if( CGAL::assign( e, *o)) { - if ( SNC_intersection::does_contain_internally(e->source()->point(), e->twin()->source()->point(), p) ) { + for(typename Halfedge_list::const_iterator ei=n->edges_begin(); ei!=n->edges_end(); ++ei) { + Halfedge_handle e(*ei); + if (SNC_intersection::does_contain_internally(e->source()->point(),e->twin()->source()->point(), p) ) { _CGAL_NEF_TRACEN("found on edge "<source()->point(),e->twin()->source()->point())); - result = make_object(e); - found = true; + return make_object(e); } } - else if( CGAL::assign( f, *o)) { + for(typename Halffacet_list::const_iterator fi=n->facets_begin(); fi!=n->facets_end(); ++fi) { + Halffacet_handle f(*fi); if (SNC_intersection::does_contain_internally( f, p) ) { _CGAL_NEF_TRACEN("found on facet..."); - result = make_object(f); - found = true; + return make_object(f); } } - o++; - } - if( !found) { + _CGAL_NEF_TRACEN("point not found in 2-skeleton"); _CGAL_NEF_TRACEN("shooting ray to determine the volume"); Ray_3 r( p, Vector_3( -1, 0, 0)); - result = make_object(determine_volume(r)); - } CGAL_NEF_TIMER(pl_t.start()); - CGAL_NEF_TIMER(pl_t.stop()); - return result; + return make_object(determine_volume(r)); + + } else { // standard kernel - } else { // standard kernel + CGAL_assertion( initialized); + _CGAL_NEF_TRACEN( "locate "<locate_node_containing(p); + typename Vertex_list::const_iterator vi = n->vertices_begin(); - CGAL_assertion( initialized); - _CGAL_NEF_TRACEN( "locate "<objects_around_point(p); - Object_list_iterator o = candidates.begin(); + if(n->empty()) + return make_object(Base(*this).volumes_begin()); - if(candidates.empty()) - return make_object(Base(*this).volumes_begin()); - - CGAL::assign(v,*o); - CGAL_assertion(CGAL::assign(v,*o)); - if(p==v->point()) - return make_object(v); - - closest = v; - ++o; - while(o!=candidates.end() && CGAL::assign(v,*o)) { - if ( p == v->point()) { - _CGAL_NEF_TRACEN("found on vertex "<point()); + Vertex_handle v(*vi),closest; + if(p==v->point()) return make_object(v); - } - if(CGAL::has_smaller_distance_to_point(p, v->point(), closest->point())){ - closest = v; - } - ++o; - } - - v = closest; - result = make_object(v); - - Segment_3 s(p,v->point()); - // bool first = true; - Point_3 ip; - - /* - // TODO: das geht effizienter - Object_list_iterator of(o); - while(of != candidates.end() && assign(e, *of)) ++of; - - typename SNC_structure::SHalfedge_iterator sei; - for(sei=v->shalfedges_begin(); sei!=v->shalfedges_end(); ++sei){ - if(sei->is_twin()) continue; - Halffacet_handle fout = sei->facet(); - if(fout->is_twin()) fout = fout->twin(); - Object_list_iterator ofc(of); - for(;ofc!=candidates.end();++ofc) { - if(CGAL::assign(f,*ofc)) { - if(f == fout->twin()) - std::cerr << "shit" << std::endl; - if(f == fout) { - Object_list_iterator oe(ofc); - --ofc; - candidates.erase(oe); - } + closest = v; + ++vi; + while(vi!=n->vertices_end()) { + v = *vi; + if ( p == v->point()) { + _CGAL_NEF_TRACEN("found on vertex "<point()); + return make_object(v); } + + if(CGAL::has_smaller_distance_to_point(p, v->point(), closest->point())){ + closest = v; + } + ++vi; } - } - */ - for(;o!=candidates.end();++o) { - if( CGAL::assign( e, *o)) { - // if(first && - // (e->source() == v || e->twin()->source() == v)) continue; - Segment_3 ss(e->source()->point(),e->twin()->source()->point()); + + v = closest; + Vertex_handle v_res; + Halfedge_handle e_res; + Halffacet_handle f_res; + v_res = v; + solution = is_vertex_; + + Segment_3 s(p,v->point()); + Point_3 ip; + + Halfedge_handle e; + for(typename Halfedge_list::const_iterator ei=n->edges_begin(); ei!=n->edges_end(); ++ei) { + e = *ei; CGAL_NEF_TRACEN("test edge " << e->source()->point() << "->" << e->twin()->source()->point()); if (SNC_intersection::does_contain_internally(e->source()->point(), e->twin()->source()->point(), p)) { - _CGAL_NEF_TRACEN("found on edge "<< ss); + _CGAL_NEF_TRACEN("found on edge "<< ss); return make_object(e); } - if((e->source() != v) && (e->twin()->source() != v) && SNC_intersection::does_intersect_internally(s, ss, ip)) { - // first = false; + if((e->source() != v) && (e->twin()->source() != v) && + SNC_intersection::does_intersect_internally(s, Segment_3(e->source()->point(),e->twin()->source()->point()), ip)) { s = Segment_3(p, normalized(ip)); - result = make_object(e); + e_res = e; + solution = is_edge_; } + } - } else - if( CGAL::assign( f, *o)) { + Halffacet_handle f; + for(typename Halffacet_list::const_iterator fi=n->facets_begin(); fi!=n->facets_end(); ++fi) { + f = *fi; CGAL_NEF_TRACEN("test facet " << f->plane()); if (SNC_intersection::does_contain_internally(f,p) ) { _CGAL_NEF_TRACEN("found on facet..."); return make_object(f); } - // We next check if v is a vertex on the face to avoid a geometric test - bool v_vertex_of_f = false; - Halffacet_cycle_iterator fci; - for(fci=f->facet_cycles_begin(); (! v_vertex_of_f) && (fci!=f->facet_cycles_end()); ++fci) { - if(fci.is_shalfedge()) { - SHalfedge_around_facet_circulator sfc(fci), send(sfc); - CGAL_For_all(sfc,send) { - if(sfc->source()->center_vertex() == v){ - v_vertex_of_f = true; - break; - } - } - } - } - - - if( (! v_vertex_of_f) && SNC_intersection::does_intersect_internally(s,f,ip) ) { + if( !v_vertex_of_f(v,f) && SNC_intersection::does_intersect_internally(s,f,ip) ) { s = Segment_3(p, normalized(ip)); - result = make_object(f); + f_res = f; + solution = is_facet_; } } - else CGAL_error_msg( "wrong handle type"); - } - //CGAL_warning("altered code in SNC_point_locator"); - /* - Halffacet_iterator fc; - CGAL_forall_facets(fc, *this->sncp()) { - CGAL_assertion(!SNC_intersection::does_intersect_internally(s,f,ip)); + if( solution == is_vertex_) { + _CGAL_NEF_TRACEN("vertex hit, obtaining volume..." << v_res->point()); + + //CGAL_warning("altered code in SNC_point_locator"); + SM_point_locator L(&*v_res); + Object_handle so = L.locate(s.source()-s.target(), true); + SFace_handle sf; + if(CGAL::assign(sf,so)) + return make_object(sf->volume()); + CGAL_error_msg( "wrong handle type"); + return Object_handle(); + + } else if( solution == is_facet_) { + _CGAL_NEF_TRACEN("facet hit, obtaining volume..."); + if(f_res->plane().oriented_side(p) == ON_NEGATIVE_SIDE) + f_res = f_res->twin(); + return make_object(f_res->incident_volume()); + } else if( solution == is_edge_) { + SM_decorator SD(&*e_res->source()); + if( SD.is_isolated(e_res)) + return make_object(e_res->incident_sface()->volume()); + return make_object(get_visible_facet(e_res,Ray_3(s.source(),s.to_vector()))->incident_volume()); } - - Halfedge_iterator ec; - CGAL_forall_edges(ec, *this->sncp()) { - Segment_3 ss(ec->source()->point(), ec->twin()->source()->point()); - CGAL_assertion(!SNC_intersection::does_intersect_internally(s,ss,ip)); - } - - Vertex_iterator vc; - CGAL_forall_vertices(vc, *this->sncp()) { - std::cerr << "test vertex " << vc->point() << std::endl; - CGAL_assertion(vc->point() == s.target() || !s.has_on(vc->point())); - } - */ - - if( CGAL::assign( v, result)) { - _CGAL_NEF_TRACEN("vertex hit, obtaining volume..." << v->point()); - - //CGAL_warning("altered code in SNC_point_locator"); - SM_point_locator L(&*v); - Object_handle so = L.locate(s.source()-s.target(), true); - SFace_handle sf; - if(CGAL::assign(sf,so)) - return make_object(sf->volume()); CGAL_error_msg( "wrong handle type"); return Object_handle(); -/* - SHalfedge_handle se; - CGAL_assertion(CGAL::assign(se,so)); - CGAL_NEF_TRACEN("intersect segment " << s << " with edges"); - for(;ox!=candidates.end();++ox) { - if(!CGAL::assign(e,*ox)) continue; - CGAL_NEF_TRACEN("test edge " << e->source()->point() << "->" << e->twin()->source()->point()); - if(SNC_intersection::does_intersect_internally(s,Segment_3(e->source()->point(),e->twin()->source()->point()),ip)) { - s = Segment_3(p, normalized(ip)); - result = make_object(e); - } - } - CGAL_assertion(CGAL::assign(e,result)); - CGAL::assign(e,result); - f = get_visible_facet(e, Ray_3(p, s.target())); - if( f != Halffacet_handle()) - return f->incident_volume(); - SM_decorator SD(&*v); // now, the vertex has no incident facets - CGAL_assertion( SD.number_of_sfaces() == 1); - return SD.sfaces_begin()->volume(); -*/ - } else if( CGAL::assign( f, result)) { - _CGAL_NEF_TRACEN("facet hit, obtaining volume..."); - if(f->plane().oriented_side(p) == ON_NEGATIVE_SIDE) - f = f->twin(); - return make_object(f->incident_volume()); - } else if( CGAL::assign(e, result)) { - SM_decorator SD(&*e->source()); - if( SD.is_isolated(e)) - return make_object(e->incident_sface()->volume()); - return make_object(get_visible_facet(e,Ray_3(s.source(),s.to_vector()))->incident_volume()); } - CGAL_error_msg( "wrong handle type"); - return Object_handle(); - } } virtual void intersect_with_edges_and_facets( Halfedge_handle e0, - const typename SNC_point_locator::Intersection_call_back& call_back) const { - - CGAL_NEF_TIMER(it_t.start()); - CGAL_assertion( initialized); + const Intersection_call_back& call_back) const { _CGAL_NEF_TRACEN( "intersecting edge: "<<&*e0<<' '<source()->point(), - e0->twin()->source()->point())); - - - Segment_3 s(Segment_3(e0->source()->point(),e0->twin()->source()->point())); - Vertex_handle v; - Halfedge_handle e; - Halffacet_handle f; - Object_list_iterator o; - Object_list objects = candidate_provider->objects_around_segment(s); - CGAL_for_each( o, objects) { - if( CGAL::assign( v, *o)) { - /* do nothing */ - } - else if( CGAL::assign( e, *o)) { - -#ifdef CGAL_NEF3_DUMP_STATISTICS - ++number_of_intersection_candidates; -#endif - - Point_3 q; - if( SNC_intersection::does_intersect_internally( s, Segment_3(e->source()->point(), - e->twin()->source()->point()), q)) { - q = normalized(q); - call_back( e0, make_object(Halfedge_handle(e)), q); - _CGAL_NEF_TRACEN("edge intersects edge "<<' '<<&*e<< Segment_3(e->source()->point(), - e->twin()->source()->point())<<" on "<plane()<<" on "<twin()->source()->point())); + Segment_3 s(e0->source()->point(),e0->twin()->source()->point()); + Node_list nodes = candidate_provider->nodes_around_segment(s); + intersect_with_edges(e0,call_back,s,nodes); + intersect_with_facets(e0,call_back,s,nodes); } virtual void intersect_with_edges( Halfedge_handle e0, - const typename SNC_point_locator::Intersection_call_back& call_back) const { + const Intersection_call_back& call_back) const { CGAL_NEF_TIMER(it_t.start()); - CGAL_assertion( initialized); _CGAL_NEF_TRACEN( "intersecting edge: "<<&*e0<<' '<source()->point(), - e0->twin()->source()->point())); - Segment_3 s(Segment_3(e0->source()->point(),e0->twin()->source()->point())); - Vertex_handle v; - Halfedge_handle e; - Halffacet_handle f; - Object_list_iterator o; - Object_list objects = candidate_provider->objects_around_segment(s); - CGAL_for_each( o, objects) { - if( CGAL::assign( v, *o)) { - /* do nothing */ - } - else if( CGAL::assign( e, *o)) { - -#ifdef CGAL_NEF3_DUMP_STATISTICS - ++number_of_intersection_candidates; -#endif - - Point_3 q; - if( SNC_intersection::does_intersect_internally( s, Segment_3(e->source()->point(), - e->twin()->source()->point()), q)) { - q = normalized(q); - call_back( e0, make_object(Halfedge_handle(e)), q); - _CGAL_NEF_TRACEN("edge intersects edge "<<' '<<&*e<< Segment_3(e->source()->point(), - e->twin()->source()->point())<<" on "<twin()->source()->point())); + Segment_3 s(e0->source()->point(),e0->twin()->source()->point()); + Node_list nodes = candidate_provider->nodes_around_segment(s); + intersect_with_edges(e0,call_back,s,nodes); } virtual void intersect_with_facets( Halfedge_handle e0, - const typename SNC_point_locator::Intersection_call_back& call_back) const { - CGAL_NEF_TIMER(it_t.start()); + const Intersection_call_back& call_back) const { CGAL_assertion( initialized); _CGAL_NEF_TRACEN( "intersecting edge: "<< Segment_3(e0->source()->point(), - e0->twin()->source()->point())); - Segment_3 s(Segment_3(e0->source()->point(),e0->twin()->source()->point())); - Vertex_handle v; - Halfedge_handle e; - Halffacet_handle f; - Object_list_iterator o; - Object_list objects = candidate_provider->objects_around_segment(s); - CGAL_for_each( o, objects) { - if( CGAL::assign( v, *o)) { - /* do nothing */ - } - else if( CGAL::assign( e, *o)) { - /* do nothing */ - } - else if( CGAL::assign( f, *o)) { - -#ifdef CGAL_NEF3_DUMP_STATISTICS - ++number_of_intersection_candidates; -#endif - - Point_3 q; - if( SNC_intersection::does_intersect_internally( s, f, q) ) { - q = normalized(q); - call_back( e0, make_object(Halffacet_handle(f)), q); - _CGAL_NEF_TRACEN("edge intersects facet on plane "<plane()<<" on "<twin()->source()->point())); + Segment_3 s(e0->source()->point(),e0->twin()->source()->point()); + Node_list nodes = candidate_provider->nodes_around_segment(s); + intersect_with_facets(e0,call_back,s,nodes); } private: + + void intersect_with_edges( Halfedge_handle e0, + const Intersection_call_back& call_back, Segment_3& s, Node_list& nodes) const { + Unique_hash_map visited(false); + for(typename Node_list::iterator ni = nodes.begin(); ni!=nodes.end(); ++ni) { + Node_handle n(*ni); + for(typename Halfedge_list::const_iterator e = n->edges_begin(); e!=n->edges_end(); ++e) { + if(!visited[*e]) { +#ifdef CGAL_NEF3_DUMP_STATISTICS + ++number_of_intersection_candidates; +#endif + Point_3 q; + if(SNC_intersection::does_intersect_internally( s, Segment_3((*e)->source()->point(), + (*e)->twin()->source()->point()), q)) { + q = normalized(q); + call_back( e0, *e, q); + _CGAL_NEF_TRACEN("edge intersects edge "<<' '<<&*e<< Segment_3((*e)->source()->point(), + (*e)->twin()->source()->point())<<" on "< visited(false); + for(typename Node_list::iterator ni = nodes.begin(); ni!=nodes.end(); ++ni) { + Node_handle n(*ni); + for(typename Halffacet_list::const_iterator f = n->facets_begin(); f!=n->facets_end(); ++f) { + if(!visited[*f]) { +#ifdef CGAL_NEF3_DUMP_STATISTICS + ++number_of_intersection_candidates; +#endif + Point_3 q; + if(SNC_intersection::does_intersect_internally( s, *f, q) ) { + q = normalized(q); + call_back( e0, *f, q); + _CGAL_NEF_TRACEN("edge intersects facet on plane "<plane()<<" on "<::type, and can be omitted when the default is fine. /// @tparam SurfaceMeshComplex_2InTriangulation_3 model of the SurfaceMeshComplex_2InTriangulation_3 concept. diff --git a/Poisson_surface_reconstruction_3/include/CGAL/Poisson_reconstruction_function.h b/Poisson_surface_reconstruction_3/include/CGAL/Poisson_reconstruction_function.h index f6852710264..cb190bbe135 100644 --- a/Poisson_surface_reconstruction_3/include/CGAL/Poisson_reconstruction_function.h +++ b/Poisson_surface_reconstruction_3/include/CGAL/Poisson_reconstruction_function.h @@ -763,8 +763,7 @@ private: /// Poisson reconstruction. /// Returns false on error. /// - /// @commentheading Template parameters: - /// @param SparseLinearAlgebraTraits_d Symmetric definite positive sparse linear solver. + /// @tparam SparseLinearAlgebraTraits_d Symmetric definite positive sparse linear solver. template bool solve_poisson( SparseLinearAlgebraTraits_d solver, ///< sparse linear solver @@ -1203,8 +1202,7 @@ private: /// Assemble vi's row of the linear system A*X=B /// - /// @commentheading Template parameters: - /// @param SparseLinearAlgebraTraits_d Symmetric definite positive sparse linear solver. + /// @tparam SparseLinearAlgebraTraits_d Symmetric definite positive sparse linear solver. template void assemble_poisson_row(typename SparseLinearAlgebraTraits_d::Matrix& A, Vertex_handle vi, diff --git a/Poisson_surface_reconstruction_3/include/CGAL/Reconstruction_triangulation_3.h b/Poisson_surface_reconstruction_3/include/CGAL/Reconstruction_triangulation_3.h index 9ab7e018b68..7dd6a245aa3 100644 --- a/Poisson_surface_reconstruction_3/include/CGAL/Reconstruction_triangulation_3.h +++ b/Poisson_surface_reconstruction_3/include/CGAL/Reconstruction_triangulation_3.h @@ -348,12 +348,12 @@ public: /// Insert the [first, beyond) range of points in the triangulation using a spatial sort. /// Default type is INPUT. /// - /// @commentheading Template Parameters: - /// @param InputIterator iterator over input points. - /// @param PointPMap is a model of `ReadablePropertyMap` with a value_type = Point_3. + /// *Template Parameters:* + /// @tparam InputIterator iterator over input points. + /// @tparam PointPMap is a model of `ReadablePropertyMap` with a value_type = Point_3. /// It can be omitted if InputIterator value_type is convertible to Point_3. - /// @param NormalPMap is a model of `ReadablePropertyMap` with a value_type = Vector_3. - /// + /// @tparam NormalPMap is a model of `ReadablePropertyMap` with a value_type = Vector_3. + /// @tparam Visitor the visitor type /// @return the number of inserted points. // This variant requires all parameters. diff --git a/Poisson_surface_reconstruction_3/include/CGAL/poisson_refine_triangulation.h b/Poisson_surface_reconstruction_3/include/CGAL/poisson_refine_triangulation.h index 9d5d3a8c031..14d91140b5e 100644 --- a/Poisson_surface_reconstruction_3/include/CGAL/poisson_refine_triangulation.h +++ b/Poisson_surface_reconstruction_3/include/CGAL/poisson_refine_triangulation.h @@ -180,17 +180,17 @@ public: /// bad means badly shaped or too big). /// @return the number of vertices inserted. /// -/// @commentheading Preconditions: +/// \pre /// - Tr must use a geometric traits with robust circumcenter computation. /// - convergence is guaranteed if radius_edge_ratio_bound >= 1.0. /// -/// @commentheading Template Parameters: -/// @param Tr 3D Delaunay triangulation. -/// @param Surface Sphere_3 or Iso_cuboid_3. -/// @param Sizing_field A sizing field functor type -/// @param Second_sizing_field A sizing field functor type +/// *Template Parameters* +/// @tparam Tr 3D Delaunay triangulation. +/// @tparam Surface Sphere_3 or Iso_cuboid_3. +/// @tparam Sizing_field A sizing field functor type +/// @tparam Second_sizing_field A sizing field functor type /// -/// @commentheading Sizing fields +/// *Sizing fields* /// - The first sizing field is the real sizing field that is targeted by /// the refinement process. It may be costly to use. /// - The second sizing field is supposed to be a sizing field that is less diff --git a/Polygon/doc/Polygon/Doxyfile.in b/Polygon/doc/Polygon/Doxyfile.in index 8cfb32b528f..5b7caa6808a 100644 --- a/Polygon/doc/Polygon/Doxyfile.in +++ b/Polygon/doc/Polygon/Doxyfile.in @@ -1,8 +1,7 @@ @INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - 2D Polygons" -EXAMPLE_PATH = ${CGAL_PACKAGE_DIR}/examples \ - ${CGAL_Stream_support_EXAMPLE_DIR} +EXAMPLE_PATH += ${CGAL_Stream_support_EXAMPLE_DIR} EXTRACT_ALL = false HIDE_UNDOC_MEMBERS = true diff --git a/Polygon/include/CGAL/General_polygon_with_holes_2.h b/Polygon/include/CGAL/General_polygon_with_holes_2.h index d7d0be256bb..cf3d666421b 100644 --- a/Polygon/include/CGAL/General_polygon_with_holes_2.h +++ b/Polygon/include/CGAL/General_polygon_with_holes_2.h @@ -63,6 +63,10 @@ public: m_pgn(pgn_boundary) {} + explicit General_polygon_with_holes_2(Polygon_2&& pgn_boundary) : + m_pgn(std::move(pgn_boundary)) + {} + template General_polygon_with_holes_2(const Polygon_2& pgn_boundary, HolesInputIterator h_begin, @@ -71,6 +75,14 @@ public: m_holes(h_begin, h_end) {} + template + General_polygon_with_holes_2(Polygon_2&& pgn_boundary, + HolesInputIterator h_begin, + HolesInputIterator h_end) : + m_pgn(std::move(pgn_boundary)), + m_holes(h_begin, h_end) + {} + Holes_container& holes() { return m_holes; } const Holes_container& holes() const { return m_holes; } @@ -91,6 +103,8 @@ public: void add_hole(const Polygon_2& pgn_hole) { m_holes.push_back(pgn_hole); } + void add_hole(Polygon_2&& pgn_hole) { m_holes.emplace_back(std::move(pgn_hole)); } + void erase_hole(Hole_iterator hit) { m_holes.erase(hit); } bool has_holes() const { return (!m_holes.empty()); } @@ -113,10 +127,10 @@ protected: // operator<< //-----------------------------------------------------------------------// /*! -This operator exports a General_polygon_with_holes_2 to the output stream `out`. +This operator exports a `General_polygon_with_holes_2` to the output stream `os`. An \ascii and a binary format exist. The format can be selected with -the \cgal modifiers for streams, `set_ascii_mode(0` and `set_binary_mode()` +the \cgal modifiers for streams, `set_ascii_mode()` and `set_binary_mode()`, respectively. The modifier `set_pretty_mode()` can be used to allow for (a few) structuring comments in the output. Otherwise, the output would be free of comments. The default for writing is \ascii without comments. @@ -164,9 +178,9 @@ operator<<(std::ostream& os, const General_polygon_with_holes_2& p) { //-----------------------------------------------------------------------// /*! -This operator imports a General_polygon_with_holes_2 from the input stream `in`. +This operator imports a `General_polygon_with_holes_2` from the input stream `is`. -Both ASCII and binary formats are supported, and the format is automatically detected. +Both \ascii and binary formats are supported, and the format is automatically detected. The format consists of the number of curves of the outer boundary followed by the curves themselves, followed @@ -187,7 +201,7 @@ operator>>(std::istream& is, General_polygon_with_holes_2& p) { Polygon_ pgn_hole; for (unsigned int i=0; i> pgn_hole; - p.add_hole(pgn_hole); + p.add_hole(std::move(pgn_hole)); } } diff --git a/Polygon/include/CGAL/Polygon_2.h b/Polygon/include/CGAL/Polygon_2.h index 987215691ac..be5ca8c9ef0 100644 --- a/Polygon/include/CGAL/Polygon_2.h +++ b/Polygon/include/CGAL/Polygon_2.h @@ -42,11 +42,11 @@ namespace CGAL { /// \ingroup PkgPolygon2Ref -/// The class Polygon_2 implements polygons. The Polygon_2 is +/// The class `Polygon_2` implements polygons. The `Polygon_2` is /// parameterized by a traits class and a container class. The latter /// can be any class that fulfills the requirements for an STL -/// container, and has a function `resize()` that takes an std::size_t as argument -/// . It defaults to the std::vector class. +/// container, and has a function `resize()` that takes an `std::size_t` as argument. +/// It defaults to the `std::vector` class. /// /// \cgalHeading{Implementation} /// @@ -154,14 +154,16 @@ class Polygon_2 { /// @{ /// Creates an empty polygon. - Polygon_2() : traits() {} + Polygon_2() = default; /// Creates an empty polygon. Polygon_2(const Traits & p_traits) : traits(p_traits) {} /// Copy constructor. - Polygon_2(const Polygon_2& polygon) - : d_container(polygon.d_container), traits(polygon.traits) {} + Polygon_2(const Polygon_2& polygon) = default; + + /// Move constructor + Polygon_2(Polygon_2&& polygon) = default; /// Creates a polygon with vertices from the sequence /// defined by the range \c [first,last). @@ -173,7 +175,8 @@ class Polygon_2 { {} #ifndef DOXYGEN_RUNNING - Polygon_2& operator=(const Polygon_2&)=default; + Polygon_2& operator=(const Polygon_2&) = default; + Polygon_2& operator=(Polygon_2&& p) = default; #endif /// @} @@ -570,7 +573,7 @@ operator!=(const Polygon_2 &p1, const Polygon_2 &p2); /// Returns the image of the polygon \c p under the transformation \c t. -/// \memberof Polygon_2 +/// \relates Polygon_2 template Polygon_2 transform(const Transformation& t, const Polygon_2& p); @@ -584,13 +587,13 @@ transform(const Transformation& t, const Polygon_2& p); /// Reads a polygon from stream `is` and assigns it to `p`. /// \pre The extract operator must be defined for `Point_2`. -/// \memberof Polygon_2 +/// \relates Polygon_2 template std::istream &operator>>(std::istream &is, Polygon_2& p); /// Inserts the polygon `p` into the stream `os`. /// \pre The insert operator must be defined for `Point_2`. -/// \memberof Polygon_2 +/// \relates Polygon_2 template std::ostream &operator<<(std::ostream &os, const Polygon_2& p); diff --git a/Polygon/include/CGAL/Polygon_with_holes_2.h b/Polygon/include/CGAL/Polygon_with_holes_2.h index 91d35a36560..2c0c87960e5 100644 --- a/Polygon/include/CGAL/Polygon_with_holes_2.h +++ b/Polygon/include/CGAL/Polygon_with_holes_2.h @@ -63,6 +63,11 @@ public: Base (pgn_boundary) {} + /*! Move constructor */ + explicit Polygon_with_holes_2 (Polygon_2&& pgn_boundary) : + Base (std::move(pgn_boundary)) + {} + /*! Constructor from a polygon (outer boundary) and hole polygons. */ template Polygon_with_holes_2 (const Polygon_2& pgn_boundary, @@ -71,6 +76,17 @@ public: Base (pgn_boundary, h_begin, h_end) {} + /*! Move constructor. + * \note In order to move the hole polygons a + * `std::move_iterator` may be used. + */ + template + Polygon_with_holes_2 (Polygon_2&& pgn_boundary, + HolesInputIterator h_begin, + HolesInputIterator h_end) : + Base (std::move(pgn_boundary), h_begin, h_end) + {} + /*! Obtain the bounding box of the polygon with holes */ Bbox_2 bbox() const { return this->outer_boundary().bbox(); } }; @@ -80,10 +96,10 @@ public: //-----------------------------------------------------------------------// /*! -This operator exports a polygon with holes to the output stream `out`. +This operator exports a polygon with holes to the output stream `os`. An \ascii and a binary format exist. The format can be selected with -the \cgal modifiers for streams, `set_ascii_mode()` and `set_binary_mode()` +the \cgal modifiers for streams, `set_ascii_mode()` and `set_binary_mode()`, respectively. The modifier `set_pretty_mode()` can be used to allow for (a few) structuring comments in the output. Otherwise, the output would be free of comments. The default for writing is \ascii without comments. @@ -143,9 +159,9 @@ std::ostream& operator<<(std::ostream &os, //-----------------------------------------------------------------------// /*! -This operator imports a polygon with holes from the input stream `in`. +This operator imports a polygon with holes from the input stream `is`. -Both ASCII and binary formats are supported, and the format is automatically detected. +Both \ascii and binary formats are supported, and the format is automatically detected. The format consists of the number of points of the outer boundary followed by the points themselves in counterclockwise order, followed by the number of holes, @@ -170,7 +186,7 @@ std::istream &operator>>(std::istream &is, { Polygon_2 hole; is >> hole; - p.add_hole(hole); + p.add_hole(std::move(hole)); } } diff --git a/Polygon/test/Polygon/PolygonTest.cpp b/Polygon/test/Polygon/PolygonTest.cpp index 8b1cebe50ab..a36aeb86c26 100644 --- a/Polygon/test/Polygon/PolygonTest.cpp +++ b/Polygon/test/Polygon/PolygonTest.cpp @@ -51,6 +51,18 @@ void test_default_methods( vector& pvec0, x=p0; assert(x == p0); + + // move assignement and constructor + x.clear(); + assert(x.is_empty()); + x = std::move(p0); + assert(p0.is_empty()); + assert(x == p0_copy); + + CGAL::Polygon_2 > xm(std::move(x)); + assert(x.is_empty()); + assert(xm == p0_copy); + } { @@ -336,4 +348,3 @@ int main() return 0; } - diff --git a/Polygon/test/Polygon/Polygon_with_holes_test.cpp b/Polygon/test/Polygon/Polygon_with_holes_test.cpp new file mode 100644 index 00000000000..97a3fc80fd1 --- /dev/null +++ b/Polygon/test/Polygon/Polygon_with_holes_test.cpp @@ -0,0 +1,45 @@ +#include +#include +#include + +#include +#include +#include +#include + + +typedef CGAL::Simple_cartesian K; +typedef K::Point_2 Point; + + +typedef CGAL::Polygon_2 Polygon_2; +typedef CGAL::Polygon_with_holes_2 Polygon_with_holes_2; + +int main() +{ + std::array outer = { Point(0, 0), Point(10, 0), Point(10, 10), Point(0, 10) }; + std::array hole1 = { Point(1, 1), Point(1, 2), Point(2, 2), Point(2, 1) }; + std::array hole2 = { Point(3, 3), Point(3, 4), Point(4, 4), Point(4, 3) }; + + std::vector holes; + holes.reserve(2); + holes.emplace_back(hole1.begin(), hole1.end()); + holes.emplace_back(hole2.begin(), hole2.end()); + + Polygon_2 pouter(outer.begin(), outer.end()); + + Polygon_with_holes_2 pwh(std::move(pouter), std::move_iterator::iterator>(holes.begin()), std::move_iterator::iterator>(holes.end())); + + assert(pouter.is_empty()); + assert(holes[0].is_empty()); + assert(holes[1].is_empty()); + + Polygon_with_holes_2 pwh_copy(pwh); + assert(pwh_copy == pwh); + Polygon_with_holes_2 pwh_move_cstructed(std::move(pwh)); + assert(pwh.holes().empty()); + assert(pwh.outer_boundary().is_empty()); + Polygon_with_holes_2 pwh_move_assigned; + pwh_move_assigned = std::move(pwh_copy); + return 0; +} diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h index 12d0a273651..10ecbf6fdd3 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Isotropic_remeshing/remesh_impl.h @@ -441,18 +441,24 @@ namespace internal { //insert new edges to keep triangular faces, and update long_edges if (!is_border(hnew, mesh_)) { + Patch_id patch_id = get_patch_id(face(hnew, mesh_)); halfedge_descriptor hnew2 = CGAL::Euler::split_face(hnew, next(next(hnew, mesh_), mesh_), mesh_); put(ecmap_, edge(hnew2, mesh_), false); + set_patch_id(face(hnew2, mesh_), patch_id); + set_patch_id(face(opposite(hnew2, mesh_), mesh_), patch_id); } //do it again on the other side if we're not on boundary halfedge_descriptor hnew_opp = opposite(hnew, mesh_); if (!is_border(hnew_opp, mesh_)) { + Patch_id patch_id = get_patch_id(face(hnew_opp, mesh_)); halfedge_descriptor hnew2 = CGAL::Euler::split_face(prev(hnew_opp, mesh_), next(hnew_opp, mesh_), mesh_); put(ecmap_, edge(hnew2, mesh_), false); + set_patch_id(face(hnew2, mesh_), patch_id); + set_patch_id(face(opposite(hnew2, mesh_), mesh_), patch_id); } } #ifdef CGAL_PMP_REMESHING_VERBOSE @@ -853,11 +859,12 @@ namespace internal { mesh_, vpmap_, vcmap_, ecmap_, gt_, cap_threshold, // bound on the angle: above 160 deg => cap 4, // bound on shortest/longest edge above 4 => needle - 0);// collapse length threshold : not needed here + 0,// collapse length threshold : not needed here + 0); // flip triangle height threshold std::array r2 = internal::is_badly_shaped( face(opposite(he, mesh_), mesh_), - mesh_, vpmap_, vcmap_, ecmap_, gt_, cap_threshold, 4, 0); + mesh_, vpmap_, vcmap_, ecmap_, gt_, cap_threshold, 4, 0, 0); const bool badly_shaped = (r1[0] != boost::graph_traits::null_halfedge()//needle || r1[1] != boost::graph_traits::null_halfedge()//cap diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h index e127b84e8e5..4520e825de5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/internal/Snapping/snap.h @@ -151,13 +151,19 @@ void simplify_range(HalfedgeRange& halfedge_range, new_tolerance += CGAL::approximate_sqrt(CGAL::squared_distance(new_p, pt)); } + if (!CGAL::Euler::does_satisfy_link_condition(edge(h, tm), tm)) + continue; + const halfedge_descriptor opoh = opposite(prev(opposite(h, tm), tm), tm); + if (is_border(opoh, tm)) + edges_to_test.erase( opoh ); vertex_descriptor v = Euler::collapse_edge(edge(h, tm), tm); + put(vpm, v, new_p); put(tolerance_map, v, new_tolerance); if(get(range_halfedges, prev_h)) edges_to_test.insert(prev_h); - if(get(range_halfedges, next_h)) + if(next_h!=opoh && get(range_halfedges, next_h)) edges_to_test.insert(next_h); ++collapsed_n; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h index 135d80edbcc..2246b28b045 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/orientation.h @@ -364,8 +364,9 @@ void reverse_face_orientations(const FaceRange& face_range, PolygonMesh& pmesh) /** * \ingroup PMP_orientation_grp -* -* makes each connected component of a closed triangulated surface mesh inward or outward oriented. +* makes each closed connected component of a triangulated surface mesh +* inward or outward oriented. If a connected component is not closed, +* the orientation may or may not be changed or not is not guaranteed. * * @tparam TriangleMesh a model of `FaceListGraph` and `MutableFaceGraph` * @tparam NamedParameters a sequence of \ref bgl_namedparameters @@ -418,7 +419,6 @@ void orient(TriangleMesh& tm, CGAL_precondition(is_triangle_mesh(tm)); CGAL_precondition(is_valid_polygon_mesh(tm)); - CGAL_precondition(is_closed(tm)); using parameters::choose_parameter; using parameters::get_parameter; @@ -464,8 +464,17 @@ void orient(TriangleMesh& tm, //orient ccs outward for(std::size_t id=0; id::%face_descriptor` +* as key type and the desired property, model of `CopyConstructible` and `LessThanComparable` as value type.} +* \cgalParamDefault{a default property map where each face is associated with the ID of +* the connected component it belongs to. Connected components are +* computed with respect to the constrained edges listed in the property map +* `edge_is_constrained_map`} +* \cgalParamExtra{The map is updated during the remeshing process while new faces are created.} +* \cgalParamNEnd +* * \cgalParamNBegin{edge_is_constrained_map} * \cgalParamDescription{a property map containing the constrained-or-not status of each edge of `pmesh`} * \cgalParamType{a class model of `ReadWritePropertyMap` with `boost::graph_traits::%edge_descriptor` @@ -421,14 +432,22 @@ void split_long_edges(const EdgeRange& edges ECMap ecmap = choose_parameter(get_parameter(np, internal_np::edge_is_constrained), Static_boolean_property_map()); + typedef typename internal_np::Lookup_named_param_def < + internal_np::face_patch_t, + NamedParameters, + internal::Connected_components_pmap//default + > ::type FPMap; + FPMap fpmap = choose_parameter( + get_parameter(np, internal_np::face_patch), + internal::Connected_components_pmap(faces(pmesh), pmesh, ecmap, fimap, false)); + typename internal::Incremental_remesher, // no constraint pmap - internal::Connected_components_pmap, - FIMap + FPMap,FIMap > remesher(pmesh, vpmap, gt, false/*protect constraints*/, ecmap, Static_boolean_property_map(), - internal::Connected_components_pmap(faces(pmesh), pmesh, ecmap, fimap, false), + fpmap, fimap, false/*need aabb_tree*/); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h index 31d8d003124..7edb6fca279 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_degeneracies.h @@ -61,7 +61,8 @@ is_badly_shaped(const typename boost::graph_traits::face_descripto const Traits& gt, const double cap_threshold, // angle over 160° ==> cap const double needle_threshold, // longest edge / shortest edge over this ratio ==> needle - const double collapse_length_threshold) // max length of edges allowed to be collapsed + const double collapse_length_threshold, // max length of edges allowed to be collapsed + const double flip_triangle_height_threshold_squared) // max height of triangles allowed to be flipped { namespace PMP = CGAL::Polygon_mesh_processing; @@ -83,8 +84,14 @@ is_badly_shaped(const typename boost::graph_traits::face_descripto } res = PMP::is_cap_triangle_face(f, tmesh, cap_threshold, parameters::vertex_point_map(vpm).geom_traits(gt)); - if(res != null_h && !get(ecm, edge(res, tmesh))) + if( res != null_h && !get(ecm, edge(res, tmesh) ) && + (flip_triangle_height_threshold_squared == 0 || + typename Traits::Compare_squared_distance_3()( get(vpm, target(next(res,tmesh), tmesh)), + typename Traits::Line_3(get(vpm, source(res,tmesh)), get(vpm, target(res,tmesh))), + flip_triangle_height_threshold_squared) != LARGER )) + { return make_array(null_h, res); + } return make_array(null_h, null_h); } @@ -100,13 +107,15 @@ void collect_badly_shaped_triangles(const typename boost::graph_traits cap const double needle_threshold, // longest edge / shortest edge over this ratio ==> needle const double collapse_length_threshold, // max length of edges allowed to be collapsed + const double flip_triangle_height_threshold_squared, // max height squared of triangles that can be flipped HalfedgeContainer& edges_to_collapse, HalfedgeContainer& edges_to_flip) { typedef typename boost::graph_traits::halfedge_descriptor halfedge_descriptor; std::array res = is_badly_shaped(f, tmesh, vpm, vcm, ecm, gt, cap_threshold, - needle_threshold, collapse_length_threshold); + needle_threshold, + collapse_length_threshold, flip_triangle_height_threshold_squared); if(res[0] != boost::graph_traits::null_halfedge()) { @@ -580,6 +589,9 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, typedef typename boost::property_map::type DVCM; DVCM vcm = get(Vertex_property_tag(), tmesh); + const double flip_triangle_height_threshold_squared = + CGAL::square(choose_parameter(get_parameter(np, internal_np::flip_triangle_height_threshold), 0)); + CGAL_precondition(is_valid_polygon_mesh(tmesh)); CGAL_precondition(is_triangle_mesh(tmesh)); @@ -611,7 +623,8 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, for(face_descriptor f : face_range) { internal::collect_badly_shaped_triangles(f, tmesh, vpm, vcm, ecm, gt, - cap_threshold, needle_threshold, collapse_length_threshold, + cap_threshold, needle_threshold, + collapse_length_threshold, flip_triangle_height_threshold_squared, edges_to_collapse, edges_to_flip); } @@ -671,7 +684,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, // Verify that the element is still badly shaped const std::array nc = internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, needle_threshold, collapse_length_threshold); + cap_threshold, needle_threshold, collapse_length_threshold, flip_triangle_height_threshold_squared); if(nc[0] != h) { @@ -757,7 +770,8 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, if(!is_border(hv, tmesh)) { internal::collect_badly_shaped_triangles(face(hv, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, needle_threshold, collapse_length_threshold, + cap_threshold, needle_threshold, + collapse_length_threshold, flip_triangle_height_threshold_squared, edges_to_collapse, edges_to_flip); } } @@ -806,7 +820,7 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, std::array nc = internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, cap_threshold, needle_threshold, - collapse_length_threshold); + collapse_length_threshold, flip_triangle_height_threshold_squared); // Check the triangle is still a cap if(nc[1] != h) { @@ -868,7 +882,8 @@ bool remove_almost_degenerate_faces(const FaceRange& face_range, CGAL_assertion(!is_border(h, tmesh)); std::array nc = internal::is_badly_shaped(face(h, tmesh), tmesh, vpm, vcm, ecm, gt, - cap_threshold, needle_threshold, collapse_length_threshold); + cap_threshold, needle_threshold, + collapse_length_threshold, flip_triangle_height_threshold_squared); if(nc[1] != boost::graph_traits::null_halfedge() && nc[1] != h) next_edges_to_flip.insert(nc[1]); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h index 1c1f145774e..fdc57bf0c05 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/repair_polygon_soup.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h index e0f87a849ee..3eb3fa892e6 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/shape_predicates.h @@ -503,7 +503,7 @@ struct Is_cap_angle_over_threshold /// \ingroup PMP_predicates_grp /// /// checks whether a triangle face is a cap. -/// A triangle is said to be a cap if one of the its angles is close to `180` degrees. +/// A triangle is said to be a cap if one of its angles is close to `180` degrees. /// /// @tparam TriangleMesh a model of `FaceGraph` /// @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_remove_caps_needles.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_remove_caps_needles.cpp index ed99bc0b0b7..b57a3dc8e8d 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_remove_caps_needles.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_remove_caps_needles.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -116,7 +117,49 @@ void test_with_envelope(std::string filename, double eps) std::cout << " Output mesh has self-intersections\n"; } +bool same_meshes(const Mesh& m1, const Mesh& m2) +{ + std::size_t c=0, m1_only=0, m2_only=0; + PMP::match_faces(m1, m2, CGAL::Counting_output_iterator(&c) + , CGAL::Counting_output_iterator(&m1_only) + , CGAL::Counting_output_iterator(&m2_only)); + return m1_only==0 && m2_only==0; +} +void test_parameters_on_pig(std::string filename) +{ + std::ifstream input(filename); + Mesh mesh, bk; + if (!input || !(input >> mesh) || !CGAL::is_triangle_mesh(mesh)) { + std::cerr << "Not a valid input file." << std::endl; + exit(EXIT_FAILURE); + } + + bk=mesh; + + PMP::experimental::remove_almost_degenerate_faces(mesh, + std::cos(160. / 180 * CGAL_PI), + 4, + 9999 /*no_constraints*/); + assert(vertices(mesh).size()!=vertices(bk).size()); + + mesh=bk; + PMP::experimental::remove_almost_degenerate_faces(mesh, + std::cos(160. / 180 * CGAL_PI), + 4, + 0.000000000000001); // no-collapse but flips + assert(vertices(mesh).size()==vertices(bk).size()); + assert(!same_meshes(mesh,bk)); + + mesh=bk; + PMP::experimental::remove_almost_degenerate_faces(mesh, + std::cos(160. / 180 * CGAL_PI), + 4, + 0.000000000000001, + CGAL::parameters::flip_triangle_height_threshold(0.000000000000001)); // no-collapse and no flip + assert(vertices(mesh).size()==vertices(bk).size()); + assert(same_meshes(mesh,bk)); +} int main(int argc, char** argv) { @@ -129,5 +172,9 @@ int main(int argc, char** argv) if (argc==3) test_with_envelope(filename, atof(argv[2])); + // only run that test with pig.off + if (argc==1) + test_parameters_on_pig(filename); + return 0; } 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 82003468880..8a190360c42 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 @@ -5,17 +5,22 @@ #include "Scene_surface_mesh_item.h" #include "Scene_polygon_soup_item.h" +#include "Scene_polyhedron_selection_item.h" +#include "Scene_polylines_item.h" +#include "Scene_points_with_normal_item.h" #include #include -#include #include -#include #include -#include #include +#include +#include #include +#include +#include +#include #include #include @@ -26,6 +31,183 @@ #include "ui_alpha_wrap_3_dialog.h" +struct Iterative_AW3_visualization_visitor +{ +private: + bool m_do_snapshot; + Scene_polygon_soup_item* m_iterative_wrap_item = nullptr; + int sid = 0; + +public: + template + Iterative_AW3_visualization_visitor(Scene* scene, + const bool visualize_iterations, + const bool do_snapshot) + : m_do_snapshot(do_snapshot) + { + if(!visualize_iterations) + return; + + m_iterative_wrap_item = new Scene_polygon_soup_item(); + m_iterative_wrap_item->setName(QString("Iterative wrap")); + scene->addItem(m_iterative_wrap_item); + } + +public: + template + void on_alpha_wrapping_begin(const AlphaWrapper&) { } + + template + void on_flood_fill_begin(const AlphaWrapper&) { } + + template + void before_facet_treatment(const AlphaWrapper&, + const Facet&) { } + + template + void before_Steiner_point_insertion(const AlphaWrapper& wrapper, + const Point& /* p */) + { + if(m_iterative_wrap_item == nullptr) + return; + + // If the next top of the queue has vertices on the bbox, don't draw (as to avoid producing + // spikes in the visualization) +// const auto& gate = wrapper.queue().top(); +// if(wrapper.triangulation().number_of_vertices() > 500 && gate.is_artificial_facet()) +// return; + + // Skip some... + if(wrapper.triangulation().number_of_vertices() % 50 != 0) + return; + + // Extract the wrap as a triangle soup + + using Dt = typename std::decay::type; + using Vertex_handle = typename Dt::Vertex_handle; + using Facet = typename Dt::Facet; + using Cell_handle = typename Dt::Cell_handle; + + std::vector points; + std::vector > faces; + + std::unordered_map vertex_to_id; + std::size_t nv = 0; + + // This is used to compute colors depending on what is old and what is new. + // It is not currently used (a uniform gray color is used), but leaving it as it might be useful. + std::size_t min_time_stamp = -1, max_time_stamp = 0; + for(auto cit=wrapper.triangulation().finite_cells_begin(), cend=wrapper.triangulation().finite_cells_end(); cit!=cend; ++cit) + { + if(cit->time_stamp() > max_time_stamp) + max_time_stamp = cit->time_stamp(); + if(cit->time_stamp() < min_time_stamp) + min_time_stamp = cit->time_stamp(); + } + + std::vector vcolors; + std::vector fcolors; + + 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) + 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) + continue; + + std::array ids; + for(int pos=0; pos<3; ++pos) + { + Vertex_handle vh = c->vertex(Dt::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(wrapper.triangulation().point(vh)); + vcolors.push_back(CGAL::IO::Color(0, 0, 0)); + ++nv; + } + + ids[pos] = insertion_res.first->second; + } + + faces.emplace_back(std::vector{ids[0], ids[1], ids[2]}); + double color_val = double(c->time_stamp() - min_time_stamp) / double(max_time_stamp - min_time_stamp); + color_val = int(256. * color_val); + + // fcolors.push_back(CGAL::IO::Color(color_val, 10, 150)); // young is red, old is blue + // fcolors.push_back(CGAL::IO::Color(256 - color_val, 256 - color_val, 256 - color_val)); // young is light, old is dark + fcolors.push_back(CGAL::IO::Color(100, 100, 100)); // uniform darkish gray + } + + // Update the wrap item's visualization + m_iterative_wrap_item->load(points, faces, fcolors, vcolors); + m_iterative_wrap_item->setName(QString("Iterative wrap #%1").arg(sid)); + m_iterative_wrap_item->setAlpha(255 / 2); + + m_iterative_wrap_item->invalidateOpenGLBuffers(); + m_iterative_wrap_item->redraw(); + m_iterative_wrap_item->itemChanged(); + + // Refresh the view + QApplication::processEvents(); + + if(m_do_snapshot) + { + std::stringstream oss; + oss << "Wrap_iteration-" << sid << ".png" << std::ends; + QString filename = QString::fromStdString(oss.str().c_str()); + + CGAL::Three::Viewer_interface* viewer = CGAL::Three::Three::activeViewer(); + viewer->saveSnapshot(filename, 1920, 1080, true /*expand*/, 2.0 /*oversampling*/); + } + + ++sid; + } + + template + void after_Steiner_point_insertion(const AlphaWrapper&, + const VertexHandle) { } + + template + void on_flood_fill_end(const AlphaWrapper&) { } + + template + void on_alpha_wrapping_end(const AlphaWrapper&) + { + if(m_iterative_wrap_item == nullptr) + return; + + m_iterative_wrap_item->setName(QString("Iterative wrap #%1").arg(sid)); + + m_iterative_wrap_item->setAlpha(255); + m_iterative_wrap_item->invalidateOpenGLBuffers(); + m_iterative_wrap_item->redraw(); + m_iterative_wrap_item->itemChanged(); + + QApplication::processEvents(); + + if(m_do_snapshot) + { + std::stringstream oss; + oss << "Wrap_iteration-" << sid << ".png" << std::ends; + QString filename = QString::fromStdString(oss.str().c_str()); + + CGAL::Three::Viewer_interface* viewer = CGAL::Three::Three::activeViewer(); + viewer->saveSnapshot(filename); + } + + m_iterative_wrap_item->setVisible(false); + + // Refresh the view + QApplication::processEvents(); + } +}; + class Polyhedron_demo_alpha_wrap_3_plugin : public QObject, public CGAL::Three::Polyhedron_demo_plugin_helper @@ -34,6 +216,9 @@ class Polyhedron_demo_alpha_wrap_3_plugin Q_INTERFACES(CGAL::Three::Polyhedron_demo_plugin_interface) Q_PLUGIN_METADATA(IID "com.geometryfactory.PolyhedronDemo.PluginInterface/1.0") +private: + Ui::alpha_wrap_3_dialog ui; + public: void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, @@ -49,12 +234,17 @@ public: bool applicable(QAction*) const { - // Ok if there's at least one mesh Q_FOREACH(int index, scene->selectionIndices()) { + if(qobject_cast(scene->item(index))) + return true; if(qobject_cast(scene->item(index))) return true; - if(qobject_cast(scene->item(index))) + if(qobject_cast(scene->item(index))) + return true; + if(qobject_cast(scene->item(index))) + return true; + if(qobject_cast(scene->item(index))) return true; } @@ -67,10 +257,21 @@ public: } private: + void print_message(QString message) const + { + CGAL::Three::Three::information(message); + } + Ui::alpha_wrap_3_dialog create_dialog(QDialog* dialog) { - Ui::alpha_wrap_3_dialog ui; ui.setupUi(dialog); + + connect(ui.wrapEdges, SIGNAL(clicked(bool)), this, SLOT(toggle_wrap_faces())); + connect(ui.wrapFaces, SIGNAL(clicked(bool)), this, SLOT(toggle_wrap_edges())); + + connect(ui.visualizeIterations, SIGNAL(clicked(bool)), + this, SLOT(update_iteration_snapshot_checkbox())); + connect(ui.buttonBox, SIGNAL(accepted()), dialog, SLOT(accept())); connect(ui.buttonBox, SIGNAL(rejected()), dialog, SLOT(reject())); @@ -78,14 +279,35 @@ private: } public Q_SLOTS: + void toggle_wrap_faces() + { + if(!ui.wrapEdges->isChecked()) // if edges are disabled, so are faces + ui.wrapFaces->setChecked(false); + } + + void toggle_wrap_edges() + { + if(ui.wrapFaces->isChecked()) // if faces are enabled, so are edges + ui.wrapEdges->setChecked(true); + } + + void update_iteration_snapshot_checkbox() + { + ui.snapshotIterations->setCheckable(ui.visualizeIterations->isChecked()); + } + void on_actionAlpha_wrap_3_triggered() { - using Points = typename Scene_polygon_soup_item::Points; - using Polygons = typename Scene_polygon_soup_item::Polygons; - using Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle; + using Triangles = std::vector; + using Segments = std::vector; + using Points = std::vector; + + using TS_Oracle = CGAL::Alpha_wraps_3::internal::Triangle_soup_oracle; + using SS_Oracle = CGAL::Alpha_wraps_3::internal::Segment_soup_oracle; + using Oracle = CGAL::Alpha_wraps_3::internal::Point_set_oracle; QDialog dialog(mw); - Ui::alpha_wrap_3_dialog ui = create_dialog(&dialog); + ui = create_dialog(&dialog); dialog.setWindowFlags(Qt::Dialog|Qt::CustomizeWindowHint|Qt::WindowCloseButtonHint); int i = dialog.exec(); @@ -97,49 +319,187 @@ public Q_SLOTS: const bool enforce_manifoldness = ui.runManifoldness->isChecked(); double alpha = ui.alphaValue->value(); double offset = ui.offsetValue->value(); + const bool visualize_iterations = ui.visualizeIterations->isChecked(); + const bool do_snapshot_iterations = ui.snapshotIterations->isChecked(); if(alpha <= 0. || offset <= 0.) return; QApplication::setOverrideCursor(Qt::WaitCursor); - Oracle oracle; + TS_Oracle ts_oracle; + SS_Oracle ss_oracle(ts_oracle); + Oracle oracle(ss_oracle); + + Triangles triangles; + Segments segments; + Points points; + Q_FOREACH(int index, scene->selectionIndices()) { + // --- Scene_surface_mesh_item* sm_item = qobject_cast(scene->item(index)); if(sm_item != nullptr) { - if(!is_triangle_mesh(*(sm_item->polyhedron()))) - continue; + SMesh* pMesh = sm_item->polyhedron(); + auto vpm = get(CGAL::vertex_point, *pMesh); - Points points; - Polygons polygons; - CGAL::Polygon_mesh_processing::polygon_mesh_to_polygon_soup(*(sm_item->polyhedron()), - points, polygons); - - oracle.add_triangle_soup(points, polygons); - } - else - { - Scene_polygon_soup_item* soup_item = qobject_cast(scene->item(index)); - if(soup_item != nullptr) + triangles.reserve(triangles.size() + num_faces(*pMesh)); + for(boost::graph_traits::face_descriptor f : faces(*pMesh)) { - bool is_triangle_soup = true; - for(auto p : soup_item->polygons()) + boost::graph_traits::halfedge_descriptor h = halfedge(f, *pMesh); + if(!is_triangle(h, *pMesh)) { - if(p.size() != 3) - { - is_triangle_soup = false; - break; - } + print_message("Warning: non-triangular face in input"); + continue; } - if(is_triangle_soup) - oracle.add_triangle_soup(soup_item->points(), soup_item->polygons()); + triangles.emplace_back(get(vpm, target(h, *pMesh)), + get(vpm, target(next(h, *pMesh), *pMesh)), + get(vpm, source(h, *pMesh))); } + + sm_item->setRenderingMode(Flat); + + continue; + } + + // --- + Scene_polygon_soup_item* soup_item = qobject_cast(scene->item(index)); + if(soup_item != nullptr) + { + triangles.reserve(triangles.size() + soup_item->polygons().size()); + + for(const auto& p : soup_item->polygons()) + { + if(p.size() != 3) + { + print_message("Warning: non-triangular face in input"); + continue; + } + + triangles.emplace_back(soup_item->points()[p[0]], + soup_item->points()[p[1]], + soup_item->points()[p[2]]); + } + + soup_item->setRenderingMode(Flat); + + continue; + } + + // --- + Scene_polyhedron_selection_item* selection_item = + qobject_cast(scene->item(index)); + if(selection_item != nullptr) + { + SMesh* pMesh = selection_item->polyhedron(); + auto vpm = get(CGAL::vertex_point, *pMesh); + + triangles.reserve(triangles.size() + selection_item->selected_facets.size()); + for(const auto& f : selection_item->selected_facets) + { + boost::graph_traits::halfedge_descriptor h = halfedge(f, *pMesh); + if(!is_triangle(h, *pMesh)) + { + print_message("Warning: non-triangular face in input"); + continue; + } + + triangles.emplace_back(get(vpm, target(h, *pMesh)), + get(vpm, target(next(h, *pMesh), *pMesh)), + get(vpm, source(h, *pMesh))); + } + + segments.reserve(segments.size() + selection_item->selected_edges.size()); + for(const auto& e : selection_item->selected_edges) + { + segments.emplace_back(get(vpm, target(halfedge(e, *pMesh), *pMesh)), + get(vpm, target(opposite(halfedge(e, *pMesh), *pMesh), *pMesh))); + } + + points.reserve(points.size() + selection_item->selected_vertices.size()); + for(const auto& v : selection_item->selected_vertices) + { + points.push_back(get(vpm, v)); + } + + continue; + } + + // --- + Scene_polylines_item* lines_item = qobject_cast(scene->item(index)); + if(lines_item != nullptr) + { + for(auto& polyline : lines_item->polylines) + { + for(auto it=std::begin(polyline), end=std::end(polyline); it!=end; ++it) + { + auto nit = std::next(it); + if(nit != end) + segments.emplace_back(*it, *nit); + } + } + + continue; + } + + // --- + Scene_points_with_normal_item* pts_item = qobject_cast(scene->item(index)); + if(pts_item != nullptr) + { + points.insert(std::cend(points), + std::cbegin(pts_item->point_set()->points()), + std::cend(pts_item->point_set()->points())); + + continue; } } + const bool wrap_triangles = ui.wrapFaces->isChecked(); + const bool wrap_segments = ui.wrapEdges->isChecked(); + + if(!wrap_triangles) + { + segments.reserve(segments.size() + 3 * triangles.size()); + for(const auto& tr : triangles) + { + segments.emplace_back(tr[0], tr[1]); + segments.emplace_back(tr[1], tr[2]); + segments.emplace_back(tr[2], tr[0]); + } + } + + if(!wrap_segments) + { + points.reserve(points.size() + 2 * segments.size()); + for(const auto& s : segments) + { + points.push_back(s[0]); + points.push_back(s[1]); + } + } + + std::cout << triangles.size() << " triangles" << std::endl; + std::cout << segments.size() << " edges" << std::endl; + std::cout << points.size() << " points" << std::endl; + std::cout << "do wrap edges/faces: " << wrap_segments << " " << wrap_triangles << std::endl; + + if(wrap_triangles) + oracle.add_triangle_soup(triangles); + if(wrap_segments) + oracle.add_segment_soup(segments); + oracle.add_point_set(points); + + if(!oracle.do_call()) + { + print_message("Warning: empty input - nothing to wrap"); + QApplication::restoreOverrideCursor(); + return; + } + + // Oracles set up, time to wrap + CGAL::Bbox_3 bbox = oracle.bbox(); const double diag_length = std::sqrt(CGAL::square(bbox.xmax() - bbox.xmin()) + CGAL::square(bbox.ymax() - bbox.ymin()) + @@ -152,13 +512,18 @@ public Q_SLOTS: CGAL::Alpha_wraps_3::internal::Alpha_wrap_3 aw3(oracle); + Iterative_AW3_visualization_visitor visitor(scene, + visualize_iterations, + do_snapshot_iterations); + SMesh wrap; aw3(alpha, offset, wrap, - CGAL::parameters::do_enforce_manifoldness(enforce_manifoldness)); + CGAL::parameters::do_enforce_manifoldness(enforce_manifoldness) + .visitor(visitor)); Scene_surface_mesh_item* wrap_item = new Scene_surface_mesh_item(wrap); - wrap_item->setName(tr("Wrap alpha %2 offset %3").arg(alpha).arg(offset)); - wrap_item->setColor(Qt::cyan); + wrap_item->setName(tr("Wrap with alpha %2 offset %3").arg(alpha).arg(offset)); + wrap_item->setColor(Qt::gray); scene->addItem(wrap_item); QApplication::restoreOverrideCursor(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/CMakeLists.txt index b38cc7a5dae..89b5b8ea92a 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/CMakeLists.txt @@ -5,4 +5,4 @@ qt5_wrap_ui(alpha_wrap_3UI_FILES alpha_wrap_3_dialog.ui) polyhedron_demo_plugin(alpha_wrap_3_plugin Alpha_wrap_3_plugin ${alpha_wrap_3UI_FILES}) #if the plugin uses external libraries like scene_items -target_link_libraries(alpha_wrap_3_plugin PUBLIC scene_surface_mesh_item scene_polygon_soup_item) +target_link_libraries(alpha_wrap_3_plugin PUBLIC scene_surface_mesh_item scene_polygon_soup_item scene_points_with_normal_item scene_selection_item scene_polylines_item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/alpha_wrap_3_dialog.ui b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/alpha_wrap_3_dialog.ui index eda61ccaf00..bbf25c4b345 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/alpha_wrap_3_dialog.ui +++ b/Polyhedron/demo/Polyhedron/Plugins/Alpha_wrap_3/alpha_wrap_3_dialog.ui @@ -9,58 +9,22 @@ 0 0 - 532 - 280 + 646 + 673 - 2D Mesh Criteria + 3D Alpha Wrapping - + 3D Alpha Wrapping - - - - - - - true - - - - - - - true - - - Enforce 2-manifoldness - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - + + @@ -88,15 +52,21 @@ - - + + + + true + - Use relative-to-bbox offset + <html><head/><body><p>Enforce 2-manifold output</p></body></html> + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - + + Qt::Vertical @@ -108,23 +78,69 @@ - - + + - Use relative-to-bbox alpha + Alpha value: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - + + + + Qt::Vertical - - true + + + 20 + 40 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Visualize iterations + + + + <html><head/><body><p>Use relative-to-bbox offset<br/><span style=" font-size:9pt;">As ratio of the length of the bbox's diagonal<br/>(i.e., value </span><span style=" font-size:9pt; font-style:italic;">x </span><span style=" font-size:9pt;">means </span><span style=" font-size:9pt; font-style:italic;">offset := bbox_diag_l / x)</span></p></body></html> + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -144,25 +160,39 @@ - - - - Alpha value: - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + Qt::Horizontal - - + + - Offset value: + <html><head/><body><p>Wrap faces<br/><span style=" font-size:9pt;">If deactivated, only edges of the faces are taken into account</span></p></body></html> - - + + + + <html><head/><body><p>Wrap edges<br/><span style=" font-size:9pt;">If deactivated, only extremities of the edges are taken into account</span></p></body></html> + + + + + + + + + + true + + + + + Qt::Vertical @@ -174,10 +204,125 @@ + + + + <html><head/><body><p>Use relative-to-bbox alpha<br/><span style=" font-size:9pt;">As ratio of the length of the bbox's diagonal<br/>(i.e., value </span><span style=" font-size:9pt; font-style:italic;">x </span><span style=" font-size:9pt;">means alpha</span><span style=" font-size:9pt; font-style:italic;"> := bbox_diag_l / x)</span></p></body></html> + + + + + + + Qt::Vertical + + + + + + + + + + + + + + + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + true + + + + + + + Qt::Horizontal + + + + + + + Offset value: + + + + + + + Qt::Horizontal + + + + + + + + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <html><head/><body><p>Snapshot iterations<br/><span style=" font-size:9pt;">For each iteration, save a snapshot of the viewer <br/>to a file named </span><span style=" font-size:9pt; font-style:italic;">Wrap-iteration_i.png</span></p></body></html> + + + + + + + + + + false + + + - + Qt::Horizontal diff --git a/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp index a405be72fe9..4063d2107ed 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/IO/Polylines_io_plugin.cpp @@ -62,7 +62,7 @@ public: } QString name() const override{ return "polylines_io_plugin"; } - QString nameFilters() const override{ return "Polylines files (*.polylines.txt *.cgal)"; } + QString nameFilters() const override{ return "Polylines files (*.polylines.txt);; CGAL Polylines files (*.cgal)"; } bool canLoad(QFileInfo fileinfo) const override; QList load(QFileInfo fileinfo, bool& ok, bool add_to_scene=true) override; diff --git a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp index 428a0b2611e..72ef02c7c4c 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/Mesh_3/Io_image_plugin.cpp @@ -116,11 +116,7 @@ private: boost::optional fc; Viewer_interface* viewer; void getPixel(const QPoint& e) { - float data[3]; - int vp[4]; - viewer->glGetIntegerv(GL_VIEWPORT, vp); - viewer->glReadPixels(e.x(), vp[3] - e.y(), 1, 1, GL_RGB, GL_FLOAT, data); - + const auto data = read_pixel_as_float_rgb(e, viewer, viewer->camera()); if(fc) { Q_EMIT x(QString::number((*fc)(data[0]), 'f', 6 )); } else if(ic) { diff --git a/Polyhedron/demo/Polyhedron/Plugins/PCA/Scene_edit_box_item.cpp b/Polyhedron/demo/Polyhedron/Plugins/PCA/Scene_edit_box_item.cpp index f4ceff2c056..0013271d9d6 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PCA/Scene_edit_box_item.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PCA/Scene_edit_box_item.cpp @@ -1049,11 +1049,7 @@ void Scene_edit_box_item_priv::picking(int& type, int& id, Viewer_interface *vie viewer->setBackgroundColor(::Qt::white); draw_picking(viewer); - int rowLength = deviceWidth * 4; // data asked in RGBA,so 4 bytes. - const static int dataLength = rowLength * deviceHeight; - GLubyte* buffer = new GLubyte[dataLength]; - // Qt uses upper corner for its origin while GL uses the lower corner. - viewer->glReadPixels(picked_pixel.x(), deviceHeight-1-picked_pixel.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + const auto buffer = read_pixel_as_ubyte_rgba(picked_pixel, viewer, viewer->camera()); //decode ID and pick (don't forget the case nothing is picked if(!(buffer[0]==buffer[1] && buffer[1]==buffer[2])) { @@ -1080,7 +1076,6 @@ void Scene_edit_box_item_priv::picking(int& type, int& id, Viewer_interface *vie } } } - delete[] buffer; viewer->setBackgroundColor(bgColor); fbo->release(); delete fbo; diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt index 76b60fbd535..53cfdc9b825 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt @@ -123,7 +123,7 @@ target_link_libraries( PUBLIC scene_surface_mesh_item scene_polylines_item scene_points_with_normal_item) -qt5_wrap_ui( repairUI_FILES RemoveNeedlesDialog.ui) +qt5_wrap_ui( repairUI_FILES RemoveNeedlesDialog.ui SelfSnapDialog.ui) polyhedron_demo_plugin(repair_polyhedron_plugin Repair_polyhedron_plugin ${repairUI_FILES} KEYWORDS PMP) target_link_libraries(repair_polyhedron_plugin PUBLIC scene_points_with_normal_item scene_surface_mesh_item) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_stitching_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_stitching_plugin.cpp index 40fed3f5a24..7244edde87e 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_stitching_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Polyhedron_stitching_plugin.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include @@ -26,8 +27,9 @@ class Polyhedron_demo_polyhedron_stitching_plugin : QAction* actionDetectBorders; QAction* actionStitchBorders; QAction* actionStitchByCC; + QAction* actionMergeReversibleCCs; public: - QList actions() const { return QList() << actionDetectBorders << actionStitchBorders << actionStitchByCC; } + QList actions() const { return QList() << actionDetectBorders << actionStitchBorders << actionStitchByCC << actionMergeReversibleCCs; } void init(QMainWindow* mainWindow, CGAL::Three::Scene_interface* scene_interface, Messages_interface* /* m */) { scene = scene_interface; @@ -42,6 +44,10 @@ public: actionStitchByCC->setObjectName("actionStitchByCC"); actionStitchByCC->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); + actionMergeReversibleCCs = new QAction(tr("Merge Reversible Connected Components"), mainWindow); + actionMergeReversibleCCs->setObjectName("actionMergeReversibleCCs"); + actionMergeReversibleCCs->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); + autoConnectActions(); } @@ -63,10 +69,14 @@ public: template void on_actionStitchByCC_triggered(Scene_interface::Item_id index); + template + void on_actionMergeReversibleCCs_triggered(Scene_interface::Item_id index); + public Q_SLOTS: void on_actionDetectBorders_triggered(); void on_actionStitchBorders_triggered(); void on_actionStitchByCC_triggered(); + void on_actionMergeReversibleCCs_triggered(); }; // end Polyhedron_demo_polyhedron_stitching_plugin @@ -151,6 +161,19 @@ void Polyhedron_demo_polyhedron_stitching_plugin::on_actionStitchByCC_triggered( scene->itemChanged(item); } +template +void Polyhedron_demo_polyhedron_stitching_plugin::on_actionMergeReversibleCCs_triggered(Scene_interface::Item_id index) +{ + Item* item = + qobject_cast(scene->item(index)); + + if(!item) + return; + CGAL::Polygon_mesh_processing::merge_reversible_connected_components(*item->polyhedron()); + CGAL::Polygon_mesh_processing::orient(*item->polyhedron()); + item->invalidateOpenGLBuffers(); + scene->itemChanged(item); +} void Polyhedron_demo_polyhedron_stitching_plugin::on_actionStitchByCC_triggered() { @@ -158,4 +181,11 @@ void Polyhedron_demo_polyhedron_stitching_plugin::on_actionStitchByCC_triggered( on_actionStitchByCC_triggered(index); } } + +void Polyhedron_demo_polyhedron_stitching_plugin::on_actionMergeReversibleCCs_triggered() +{ + Q_FOREACH(int index, scene->selectionIndices()){ + on_actionMergeReversibleCCs_triggered(index); + } +} #include "Polyhedron_stitching_plugin.moc" diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp index 0c7e1eba63e..52510d174e9 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp @@ -18,8 +18,10 @@ #include #include #include +#include #include "ui_RemoveNeedlesDialog.h" +#include "ui_SelfSnapDialog.h" #include #include #include @@ -53,6 +55,7 @@ public: actionAutorefine = new QAction(tr("Autorefine Mesh"), mw); actionAutorefineAndRMSelfIntersections = new QAction(tr("Autorefine and Remove Self-Intersections"), mw); actionRemoveNeedlesAndCaps = new QAction(tr("Remove Needles And Caps")); + actionSnapBorders = new QAction(tr("Snap Boundaries")); actionRemoveIsolatedVertices->setObjectName("actionRemoveIsolatedVertices"); actionRemoveDegenerateFaces->setObjectName("actionRemoveDegenerateFaces"); @@ -64,6 +67,7 @@ public: actionAutorefine->setObjectName("actionAutorefine"); actionAutorefineAndRMSelfIntersections->setObjectName("actionAutorefineAndRMSelfIntersections"); actionRemoveNeedlesAndCaps->setObjectName("actionRemoveNeedlesAndCaps"); + actionSnapBorders->setObjectName("actionSnapBorders"); actionRemoveDegenerateFaces->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); actionStitchCloseBorderHalfedges->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); @@ -74,7 +78,7 @@ public: actionMergeDuplicatedVerticesOnBoundaryCycles->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); actionAutorefine->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); actionAutorefineAndRMSelfIntersections->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); - actionRemoveNeedlesAndCaps->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); + actionSnapBorders->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); autoConnectActions(); } @@ -90,7 +94,8 @@ public: << actionMergeDuplicatedVerticesOnBoundaryCycles << actionAutorefine << actionAutorefineAndRMSelfIntersections - << actionRemoveNeedlesAndCaps; + << actionRemoveNeedlesAndCaps + << actionSnapBorders; } bool applicable(QAction*) const @@ -128,6 +133,7 @@ public Q_SLOTS: void on_actionAutorefine_triggered(); void on_actionAutorefineAndRMSelfIntersections_triggered(); void on_actionRemoveNeedlesAndCaps_triggered(); + void on_actionSnapBorders_triggered(); private: QAction* actionRemoveIsolatedVertices; @@ -140,6 +146,7 @@ private: QAction* actionAutorefine; QAction* actionAutorefineAndRMSelfIntersections; QAction* actionRemoveNeedlesAndCaps; + QAction* actionSnapBorders; Messages_interface* messages; }; // end Polyhedron_demo_repair_polyhedron_plugin @@ -196,6 +203,148 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveNeedlesAndCaps_tri sm_item->itemChanged(); } +void Polyhedron_demo_repair_polyhedron_plugin::on_actionSnapBorders_triggered() +{ + const Scene_interface::Item_id index = scene->mainSelectionIndex(); + Scene_surface_mesh_item* sm_item = qobject_cast(scene->item(index)); + if(!sm_item) + { + return; + } + + + QDialog dialog; + Ui::SelfSnapDialog ui; + ui.setupUi(&dialog); + connect(ui.use_local_tolerance, SIGNAL(toggled(bool)), + ui.tolerances, SLOT(setDisabled(bool))); + + if(dialog.exec() != QDialog::Accepted) + return; + + QCursor tmp_cursor(Qt::WaitCursor); + CGAL::Three::Three::CursorScopeGuard guard(tmp_cursor); + + typedef Scene_surface_mesh_item::Face_graph Face_graph; + Face_graph& tm = *sm_item->face_graph(); + typedef boost::graph_traits::halfedge_descriptor halfedge_descriptor; + typedef boost::graph_traits::vertex_descriptor vertex_descriptor; + + CGAL::Polygon_mesh_processing::stitch_borders(tm); +#if 1 +/// detection of non-manifold parts + std::map< std::pair, std::vector > edges; + for(halfedge_descriptor h : halfedges(tm)) + { + if (is_border(h,tm)) + edges[CGAL::make_sorted_pair(tm.point(target(h,tm)), tm.point(source(h,tm)))].push_back(h); + } + + std::vector fccs(num_faces(tm),-1); + int nbcc = CGAL::Polygon_mesh_processing::connected_components(tm, CGAL::make_property_map(fccs)); + //this has to be done per cycle so as to keep 2 patches + // remove the smallest CCs + std::vector cc_sizes(nbcc, 0); + for(int i : fccs) + cc_sizes[i]+=1; + std::set ccs_to_rm; + for (auto p : edges) + if (p.second.size() >= 2) + for(halfedge_descriptor h : p.second) + { + int ccid = fccs[face(opposite(h, tm),tm)]; + if ( cc_sizes[ccid]<=4 ) + ccs_to_rm.insert(ccid); + } + std::cout << "removing " << ccs_to_rm.size() << " ccs\n"; + CGAL::Polygon_mesh_processing::remove_connected_components(tm, ccs_to_rm, CGAL::make_property_map(fccs)); + std::cout << "input is valid after cc removal:"<< CGAL::is_valid_polygon_mesh(tm) << "\n"; +/// +#endif + + if (ui.use_local_tolerance->isChecked()) + { + CGAL::Polygon_mesh_processing::experimental::snap_borders(tm, CGAL::parameters::do_simplify_border(ui.do_simplify_border->isChecked())); + CGAL::Polygon_mesh_processing::stitch_borders(tm); + CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices(tm); + } + else + { + std::vector tolerances/* = 0.005, 0.0125, 0.025, 0.05, 0.07 */; + bool ok; + Q_FOREACH(QString tol_text, ui.tolerances->text().split(",")) + { + double d = tol_text.toDouble(&ok); + if (ok) + tolerances.push_back(d); + else + QMessageBox(QMessageBox::Warning, + QString("Invalid value"), + QString("\""+tol_text+"\" is not a valid double, ignored."), + QMessageBox::Ok, + this->mw).exec(); + } + + for (double tol : tolerances ) + { + std::cout << "using tol = " << tol << "\n"; + CGAL::Constant_property_map tolerance_map(tol); + CGAL::Polygon_mesh_processing::experimental::snap_borders(tm, tolerance_map, CGAL::parameters::do_simplify_border(ui.do_simplify_border->isChecked())); + + CGAL::Polygon_mesh_processing::stitch_borders(tm); + CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices(tm); + + // post processing + std::vector remaining_cycles; + CGAL::Polygon_mesh_processing::extract_boundary_cycles(tm, std::back_inserter(remaining_cycles)); + + int tested=0, done=0; + for (halfedge_descriptor hc : remaining_cycles) + { + if (next(next(hc,tm),tm)==prev(hc,tm)) + { + ++tested; + //get smallest halfedge + halfedge_descriptor hm = hc; + double min_l = CGAL::Polygon_mesh_processing::edge_length(hc, tm); + + double el = CGAL::Polygon_mesh_processing::edge_length(next(hc, tm), tm); + if (eltol) + continue; + if (!CGAL::Euler::does_satisfy_link_condition(edge(hm, tm), tm)) + { + // simply fill the face + std::array vr = { source(hm, tm), target(hm, tm), target(next(hm, tm), tm) }; + CGAL::Euler::add_face(vr, tm); + continue; + } + + std::array vr = { source(hm, tm), target(hm, tm), target(next(hm, tm), tm) }; + CGAL::Euler::add_face(vr, tm); + CGAL::Euler::collapse_edge(edge(hm, tm), tm); + ++done; + } + } + } + } + CGAL::Polygon_mesh_processing::duplicate_non_manifold_vertices(tm); + + sm_item->invalidateOpenGLBuffers(); + sm_item->itemChanged(); +} + template void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveDegenerateFaces_triggered(Scene_interface::Item_id index) { @@ -231,7 +380,7 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionRemoveSelfIntersections_ { bool solved = CGAL::Polygon_mesh_processing::experimental::remove_self_intersections( - *poly_item->polyhedron()); + *poly_item->polyhedron(), CGAL::parameters::preserve_genus(false)); if (!solved) CGAL::Three::Three::information(tr("Some self-intersection could not be fixed")); poly_item->invalidateOpenGLBuffers(); diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/SelfSnapDialog.ui b/Polyhedron/demo/Polyhedron/Plugins/PMP/SelfSnapDialog.ui new file mode 100644 index 00000000000..6df35f1a021 --- /dev/null +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/SelfSnapDialog.ui @@ -0,0 +1,91 @@ + + + SelfSnapDialog + + + + 0 + 0 + 413 + 179 + + + + Dialog + + + + + + Use Local Tolerance + + + + + + + Fixed Snapping (comma separate values for several runs): + + + + + + + + + + Collapse Edges Before Snap + + + true + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + SelfSnapDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + SelfSnapDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/Polyhedron/demo/Polyhedron/Scene.cpp b/Polyhedron/demo/Polyhedron/Scene.cpp index 1e17db5fffc..220168f2351 100644 --- a/Polyhedron/demo/Polyhedron/Scene.cpp +++ b/Polyhedron/demo/Polyhedron/Scene.cpp @@ -564,9 +564,8 @@ void Scene::renderScene(const QList &items, if(with_names) { // read depth buffer at pick location; - float depth = 1.0; - viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth); - if (depth != 1.0) + float depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera()); + if (depth < 2.0) { //add object to list of picked objects; picked_item_IDs[depth] = index; @@ -635,7 +634,7 @@ void Scene::renderWireScene(const QList &items, // read depth buffer at pick location; float depth = 1.0; - viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth); + depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera()); if (depth != 1.0) { //add object to list of picked objects; @@ -677,7 +676,7 @@ void Scene::renderPointScene(const QList &items, if(item.renderingMode() == Points && with_names) { // read depth buffer at pick location; float depth = 1.0; - viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth); + depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera()); if (depth != 1.0) { //add object to list of picked objects; diff --git a/Polyhedron/demo/Polyhedron/Scene_group_item.cpp b/Polyhedron/demo/Polyhedron/Scene_group_item.cpp index 29e0685ec51..b064cf4573f 100644 --- a/Polyhedron/demo/Polyhedron/Scene_group_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_group_item.cpp @@ -211,7 +211,7 @@ void Scene_group_item::renderChildren(Viewer_interface *viewer, if(with_names) { // read depth buffer at pick location; float depth = 1.0; - viewer->glReadPixels(picked_pixel.x(),viewer->camera()->screenHeight()-1-picked_pixel.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth); + depth = read_depth_under_pixel(picked_pixel, viewer, viewer->camera()); if (depth != 1.0) { //add object to list of picked objects; diff --git a/Polyhedron/demo/Polyhedron/Scene_spheres_item.cpp b/Polyhedron/demo/Polyhedron/Scene_spheres_item.cpp index 836b4641636..fac56fbda9b 100644 --- a/Polyhedron/demo/Polyhedron/Scene_spheres_item.cpp +++ b/Polyhedron/demo/Polyhedron/Scene_spheres_item.cpp @@ -187,8 +187,6 @@ void Scene_spheres_item::draw(Viewer_interface *viewer) const setBuffersFilled(true); setBuffersInit(viewer, true); } - int deviceWidth = viewer->camera()->screenWidth(); - int deviceHeight = viewer->camera()->screenHeight(); if(d->has_plane) { QVector4D cp = cgal_plane_to_vector4d(d->plane); @@ -207,12 +205,8 @@ void Scene_spheres_item::draw(Viewer_interface *viewer) const } if(d->pickable && (d->spheres.size() > 1 && viewer->inDrawWithNames())) { - int rowLength = deviceWidth * 4; // data asked in RGBA,so 4 bytes. - const static int dataLength = rowLength * deviceHeight; - GLubyte* buffer = new GLubyte[dataLength]; - // Qt uses upper corner for its origin while GL uses the lower corner. QPoint picking_target = viewer->mapFromGlobal(QCursor::pos()); - viewer->glReadPixels(picking_target.x(), deviceHeight-1-picking_target.y(), 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, buffer); + const auto buffer = read_pixel_as_ubyte_rgba(picking_target, viewer, viewer->camera()); int ID = (buffer[0] + buffer[1] * 256 +buffer[2] * 256*256) ; if(buffer[0]*buffer[1]*buffer[2] < 255*255*255) { diff --git a/Polyhedron/include/CGAL/Polyhedron_3.h b/Polyhedron/include/CGAL/Polyhedron_3.h index b948f2e6dcb..6505e960139 100644 --- a/Polyhedron/include/CGAL/Polyhedron_3.h +++ b/Polyhedron/include/CGAL/Polyhedron_3.h @@ -1448,10 +1448,10 @@ public: /// Erases the small connected components and the isolated vertices. /// - /// @commentheading Preconditions: - /// supports vertices, halfedges, and removal operation. /// - /// @commentheading Template Parameters: + /// \pre supports vertices, halfedges, and removal operation. + /// + /// *Parameters* /// @param nb_components_to_keep the number of large connected components to keep. /// /// @return the number of connected components erased (ignoring isolated vertices). diff --git a/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp b/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp index 987b924dcee..52bc9061b0c 100644 --- a/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp +++ b/Polyline_simplification_2/demo/Polyline_simplification_2/Polyline_simplification_2.cpp @@ -397,7 +397,7 @@ void MainWindow::loadWKT(QString fileName) m_pct.insert_constraint(poly.begin(), poly.end()); } } - for(Polygon_with_holes_2 poly : polygons){ + for(const Polygon_with_holes_2& poly : polygons){ m_pct.insert_constraint(poly.outer_boundary().vertices_begin(), poly.outer_boundary().vertices_end()); for(Polygon_with_holes_2::Hole_const_iterator it = poly.holes_begin(); it != poly.holes_end(); ++it){ const Polygon_2& hole = *it; diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp index 0faecfc1c97..6c9c76bd45a 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/points_and_vertices.cpp @@ -1,7 +1,5 @@ #include #include -#include -#include #include #include @@ -74,5 +72,3 @@ int main(int argc, char* argv[]) print(ct, cid); return 0; } - - diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp index 1e5e4e5afa1..3c95bb05025 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify.cpp @@ -1,6 +1,3 @@ -#include -#include - #include #include #include @@ -56,4 +53,3 @@ int main(int argc, char* argv[]) } return 0; } - diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp index e023c999a8e..2e4e69c7a50 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polygon.cpp @@ -1,5 +1,3 @@ -#include -#include #include #include #include diff --git a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp index 7bca0e97a74..38bd2f4bae7 100644 --- a/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp +++ b/Polyline_simplification_2/examples/Polyline_simplification_2/simplify_polyline.cpp @@ -1,11 +1,8 @@ -#include -#include #include #include #include #include #include -#include #include namespace PS = CGAL::Polyline_simplification_2; diff --git a/STL_Extension/doc/STL_Extension/Concepts/Hashable.h b/STL_Extension/doc/STL_Extension/Concepts/Hashable.h index d07c14cdf83..17fa2304230 100644 --- a/STL_Extension/doc/STL_Extension/Concepts/Hashable.h +++ b/STL_Extension/doc/STL_Extension/Concepts/Hashable.h @@ -14,12 +14,11 @@ They can be disables by defining the macro `CGAL_DISABLE_HASH_OPENMESH`. \sa `CGAL::Unique_hash_map` \sa `std::unordered_set` \sa `std::unordered_map` -\sa `boost::unordered_set` -\sa `boost::unordered_map` +\sa `boost::unordered_set` +\sa `boost::unordered_map` */ class Hashable { }; - diff --git a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h index 976730d7faa..42412cdb842 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -130,6 +130,7 @@ CGAL_add_named_parameter(match_faces_t, match_faces, match_faces) CGAL_add_named_parameter(face_epsilon_map_t, face_epsilon_map, face_epsilon_map) CGAL_add_named_parameter(maximum_number_t, maximum_number, maximum_number) CGAL_add_named_parameter(use_one_sided_hausdorff_t, use_one_sided_hausdorff, use_one_sided_hausdorff) +CGAL_add_named_parameter(flip_triangle_height_threshold_t, flip_triangle_height_threshold, flip_triangle_height_threshold) // List of named parameters that we use in the package 'Surface Mesh Simplification' CGAL_add_named_parameter(get_cost_policy_t, get_cost_policy, get_cost) diff --git a/Solver_interface/include/CGAL/Eigen_svd.h b/Solver_interface/include/CGAL/Eigen_svd.h index 0841976072a..276812001b8 100644 --- a/Solver_interface/include/CGAL/Eigen_svd.h +++ b/Solver_interface/include/CGAL/Eigen_svd.h @@ -51,7 +51,11 @@ public: /// \return the condition number of \f$ M\f$ static FT solve(const Matrix& M, Vector& B) { - Eigen::JacobiSVD jacobiSvd(M.eigen_object(),::Eigen::ComputeThinU | ::Eigen::ComputeThinV); +#if EIGEN_VERSION_AT_LEAST(3,4,90) + Eigen::JacobiSVD jacobiSvd(M.eigen_object()); +#else + Eigen::JacobiSVD jacobiSvd(M.eigen_object(), ::Eigen::ComputeThinU | ::Eigen::ComputeThinV); +#endif B.eigen_object()=jacobiSvd.solve(Vector::EigenType(B.eigen_object())); return jacobiSvd.singularValues().array().abs().maxCoeff() / jacobiSvd.singularValues().array().abs().minCoeff(); diff --git a/Stream_support/doc/Stream_support/Doxyfile.in b/Stream_support/doc/Stream_support/Doxyfile.in index f0c48c2e204..31fdc18aeef 100644 --- a/Stream_support/doc/Stream_support/Doxyfile.in +++ b/Stream_support/doc/Stream_support/Doxyfile.in @@ -1,7 +1,6 @@ @INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - IO Streams" -EXAMPLE_PATH = ${CGAL_PACKAGE_DIR}/examples EXTRACT_ALL = false HIDE_UNDOC_MEMBERS = true diff --git a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h index 580d8b6819c..dc30f94af43 100644 --- a/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h +++ b/Surface_mesh/include/CGAL/Surface_mesh/Surface_mesh.h @@ -914,6 +914,7 @@ public: /// Copy constructor: copies `rhs` to `*this`. Performs a deep copy of all properties. Surface_mesh(const Surface_mesh& rhs) { *this = rhs; } + /// Move constructor. Surface_mesh(Surface_mesh&& sm) : vprops_(std::move(sm.vprops_)) , hprops_(std::move(sm.hprops_)) @@ -940,7 +941,7 @@ public: /// 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_); diff --git a/Surface_mesh_approximation/include/CGAL/Variational_shape_approximation.h b/Surface_mesh_approximation/include/CGAL/Variational_shape_approximation.h index 1a495cf99ce..566aec602d7 100644 --- a/Surface_mesh_approximation/include/CGAL/Variational_shape_approximation.h +++ b/Surface_mesh_approximation/include/CGAL/Variational_shape_approximation.h @@ -1209,7 +1209,8 @@ private: * @param t concurrency tag */ template - void fit(const ProxyWrapperIterator beg, const ProxyWrapperIterator end, const CGAL::Sequential_tag &) { + void fit(const ProxyWrapperIterator beg, const ProxyWrapperIterator end, const CGAL::Sequential_tag & t) { + CGAL_USE(t); std::vector > px_faces(m_proxies.size()); for(face_descriptor f : faces(*m_ptm)) px_faces[get(m_fproxy_map, f)].push_back(f); @@ -1230,7 +1231,8 @@ private: * @param t concurrency tag */ template - void fit(const ProxyWrapperIterator beg, const ProxyWrapperIterator end, const CGAL::Parallel_tag &) { + void fit(const ProxyWrapperIterator beg, const ProxyWrapperIterator end, const CGAL::Parallel_tag & t) { + CGAL_USE(t); std::vector > px_faces(m_proxies.size()); for(face_descriptor f : faces(*m_ptm)) px_faces[get(m_fproxy_map, f)].push_back(f); @@ -1334,7 +1336,7 @@ private: * 3. Update the proxy error. * 4. Update proxy map. * @pre current face proxy map is valid - * @param face_descriptor face + * @param f face * @param px_idx proxy index * @return fitted wrapped proxy */ @@ -1790,7 +1792,7 @@ private: /*! * @brief walks along the region boundary cycle to the first halfedge * pointing to a vertex associated with an anchor. - * @param[in/out] he_start region boundary halfedge + * @param[in,out] he_start region boundary halfedge */ void walk_to_first_anchor(halfedge_descriptor &he_start) { const halfedge_descriptor start_mark = he_start; @@ -1805,7 +1807,7 @@ private: /*! * @brief walks along the region boundary cycle to the next anchor * and records the path as a `Boundary_chord`. - * @param[in/out] he_start starting region boundary halfedge + * @param[in,out] he_start starting region boundary halfedge * pointing to a vertex associated with an anchor * @param[out] chord recorded path chord */ @@ -1818,7 +1820,7 @@ private: /*! * @brief walks to the next boundary cycle halfedge. - * @param[in/out] he_start region boundary halfedge + * @param[in,out] he_start region boundary halfedge */ void walk_to_next_border_halfedge(halfedge_descriptor &he_start) const { const std::size_t px_idx = get(m_fproxy_map, face(he_start, *m_ptm)); diff --git a/Surface_mesh_deformation/benchmark/Surface_mesh_deformation/optimal_rotation/optimal_rotation_polar_eigen.cpp b/Surface_mesh_deformation/benchmark/Surface_mesh_deformation/optimal_rotation/optimal_rotation_polar_eigen.cpp index 6000307464a..562bcb90e3c 100644 --- a/Surface_mesh_deformation/benchmark/Surface_mesh_deformation/optimal_rotation/optimal_rotation_polar_eigen.cpp +++ b/Surface_mesh_deformation/benchmark/Surface_mesh_deformation/optimal_rotation/optimal_rotation_polar_eigen.cpp @@ -55,9 +55,14 @@ void polar_eigen(const Mat& A, Mat& R, bool& SVD) if(fetestexcept(FE_UNDERFLOW) || eig.eigenvalues()(0)/eig.eigenvalues()(2)/100.0 svd; - svd.compute(A, Eigen::ComputeFullU | Eigen::ComputeFullV ); + // Fallback to an accurate SVD based decomposition method. +#if EIGEN_VERSION_AT_LEAST(3,4,90) + Eigen::JacobiSVD svd; + svd.compute(A); +#else + Eigen::JacobiSVD svd; + svd.compute(A, Eigen::ComputeFullU | Eigen::ComputeFullV); +#endif const Mat& u = svd.matrixU(); const Mat& v = svd.matrixV(); const Vec& w = svd.singularValues(); R = u*v.transpose(); SVD = true; diff --git a/Surface_mesh_deformation/benchmark/Surface_mesh_deformation/optimal_rotation/optimal_rotation_svd_eigen.cpp b/Surface_mesh_deformation/benchmark/Surface_mesh_deformation/optimal_rotation/optimal_rotation_svd_eigen.cpp index ba6e332f2bf..573e5e7bea5 100644 --- a/Surface_mesh_deformation/benchmark/Surface_mesh_deformation/optimal_rotation/optimal_rotation_svd_eigen.cpp +++ b/Surface_mesh_deformation/benchmark/Surface_mesh_deformation/optimal_rotation/optimal_rotation_svd_eigen.cpp @@ -20,7 +20,14 @@ int main() { } int ite = 200000; + +#if EIGEN_VERSION_AT_LEAST(3,4,90) + Eigen::JacobiSVD svd; +#else Eigen::JacobiSVD svd; +#endif + + Eigen::JacobiSVD svd; Eigen::Matrix3d u, v, cov, r; Eigen::Vector3d w; @@ -44,7 +51,12 @@ int main() { for (int i = 0; i < ite; i++) { - svd.compute( cov, Eigen::ComputeFullU | Eigen::ComputeFullV ); +#if EIGEN_VERSION_AT_LEAST(3,4,90) + svd.compute(cov); +#else + svd.compute(cov, Eigen::ComputeFullU | Eigen::ComputeFullV); +#endif + u = svd.matrixU(); v = svd.matrixV(); w = svd.singularValues(); r = v*u.transpose(); } diff --git a/Surface_mesh_deformation/include/CGAL/Deformation_Eigen_closest_rotation_traits_3.h b/Surface_mesh_deformation/include/CGAL/Deformation_Eigen_closest_rotation_traits_3.h index 59b2fc45b98..98c938b5fbc 100644 --- a/Surface_mesh_deformation/include/CGAL/Deformation_Eigen_closest_rotation_traits_3.h +++ b/Surface_mesh_deformation/include/CGAL/Deformation_Eigen_closest_rotation_traits_3.h @@ -80,8 +80,13 @@ public: /// Computes the closest rotation to `m` and places it into `R` void compute_close_rotation(const Matrix& m, Matrix& R) { +#if EIGEN_VERSION_AT_LEAST(3,4,90) + Eigen::JacobiSVD solver; + solver.compute(m); +#else Eigen::JacobiSVD solver; - solver.compute( m, Eigen::ComputeFullU | Eigen::ComputeFullV ); + solver.compute(m, Eigen::ComputeFullU | Eigen::ComputeFullV); +#endif const Matrix& u = solver.matrixU(); const Matrix& v = solver.matrixV(); R = v * u.transpose(); diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/CMakeLists.txt b/Surface_mesh_simplification/examples/Surface_mesh_simplification/CMakeLists.txt index b37d4fb613f..2af41a74f0a 100644 --- a/Surface_mesh_simplification/examples/Surface_mesh_simplification/CMakeLists.txt +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/CMakeLists.txt @@ -51,3 +51,16 @@ if(OpenMesh_FOUND) create_single_source_cgal_program("edge_collapse_OpenMesh.cpp") target_link_libraries(edge_collapse_OpenMesh PRIVATE ${OPENMESH_LIBRARIES}) endif() + +find_package(METIS) +include(CGAL_METIS_support) + +find_package(TBB) +include(CGAL_TBB_support) + +if(TARGET CGAL::TBB_support AND TARGET CGAL::METIS_support) + create_single_source_cgal_program("collapse_small_edges_in_parallel.cpp") + target_link_libraries(collapse_small_edges_in_parallel PUBLIC CGAL::TBB_support CGAL::METIS_support) +else() + message(STATUS "collapse_small_edges_in_parallel, which use the METIS and TBB libraries will not be compiled.") +endif() diff --git a/Surface_mesh_simplification/examples/Surface_mesh_simplification/collapse_small_edges_in_parallel.cpp b/Surface_mesh_simplification/examples/Surface_mesh_simplification/collapse_small_edges_in_parallel.cpp new file mode 100644 index 00000000000..17eebbe0314 --- /dev/null +++ b/Surface_mesh_simplification/examples/Surface_mesh_simplification/collapse_small_edges_in_parallel.cpp @@ -0,0 +1,157 @@ +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include + + +typedef CGAL::Simple_cartesian Kernel; + +typedef Kernel::Point_3 Point_3; +typedef CGAL::Surface_mesh Triangle_mesh; + + +namespace SMS = CGAL::Surface_mesh_simplification; +namespace PMP = CGAL::Polygon_mesh_processing; + +struct Border_is_constrained_edge_map{ + const Triangle_mesh& sm; + typedef Triangle_mesh::Edge_index key_type; + typedef bool value_type; + typedef value_type reference; + typedef boost::readable_property_map_tag category; + Border_is_constrained_edge_map(const Triangle_mesh& sm) + : sm(sm) + {} + friend bool get(Border_is_constrained_edge_map m, const key_type& edge) { + return CGAL::is_border(edge, m.sm); + } +}; + +struct Simplify +{ + Triangle_mesh* tm_ptr; + double edge_length; + + Simplify() + :tm_ptr(NULL), edge_length(0) + {} + + Simplify(Triangle_mesh& tm, double edge_length) + : tm_ptr(&tm), edge_length(edge_length) + {} + + void operator()() const + { + + SMS::Edge_length_cost cost; + SMS::Edge_length_stop_predicate stop(edge_length); + Border_is_constrained_edge_map eicm(*tm_ptr); + SMS::Constrained_placement, + Border_is_constrained_edge_map > placement(eicm); + + SMS::edge_collapse(*tm_ptr, stop, + CGAL::parameters::edge_is_constrained_map(eicm) + .get_placement(placement) + .get_cost(cost)); + } +}; + +int main(int argc, char** argv) +{ + typedef boost::graph_traits::face_descriptor face_descriptor; + + std::ifstream in((argc>1) ? std::string(argv[1]) : CGAL::data_file_path("meshes/elephant.off")); + double edge_length = (argc>2) ? std::atof(argv[2]) : 0.02; + int number_of_parts = (argc>3) ? std::atoi(argv[3]) : 8; + + Triangle_mesh tm; + in >> tm; + + std::cerr << "Input: #V = "<< num_vertices(tm) << " #E = "<< num_edges(tm) + << " #F = " << num_faces(tm) << std::endl; + + CGAL::Real_timer t; + t.start(); + + // Partition ID map + Triangle_mesh::Property_map fpmap + = tm.add_property_map("f:partition").first; + + // Set some custom options for METIS + idx_t options[METIS_NOPTIONS]; + METIS_SetDefaultOptions(options); + options[METIS_OPTION_CONTIG] = 1; // need to have contiguous subdomains + options[METIS_OPTION_UFACTOR] = 1; + + CGAL::METIS::partition_dual_graph(tm, number_of_parts, CGAL::parameters::METIS_options(&options) + // .vertex_index_map(get(boost::vertex_index,tm)) + .face_partition_id_map(fpmap)); + + SMS::LindstromTurk_placement placement; + SMS::Edge_length_cost cost; + SMS::Edge_length_stop_predicate stop(edge_length); + + CGAL::Face_filtered_graph fg(tm); + std::vector meshes(number_of_parts); + for (int i=0; i< number_of_parts; ++i) + { + fg.set_selected_faces(i, fpmap); + CGAL::copy_face_graph(fg, meshes[i]); + } + + tbb::task_group tasks; + for(int id=0; id. +/// *Template Parameters:* +/// @tparam SurfaceMeshComplex_2InTriangulation_3 model of the `SurfaceMeshComplex_2InTriangulation_3` concept. +/// @tparam Polyhedron an instance of `CGAL::Polyhedron_3`. /// -/// @return true if the surface is manifold and orientable. +/// @return `true` if the surface is manifold and orientable. template CGAL_DEPRECATED_MSG( diff --git a/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Doxyfile.in b/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Doxyfile.in index 59dccb4ff04..a3841240c16 100644 --- a/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Doxyfile.in +++ b/Tetrahedral_remeshing/doc/Tetrahedral_remeshing/Doxyfile.in @@ -6,6 +6,4 @@ EXTRACT_ALL = false HIDE_UNDOC_CLASSES = true WARN_IF_UNDOCUMENTED = false -EXAMPLE_PATH += ${CGAL_Tetrahedral_remeshing_EXAMPLE_DIR} - EXCLUDE = ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/Tetrahedral_remeshing/internal diff --git a/Triangulation_2/test/Triangulation_2/issue_5055.cpp b/Triangulation_2/test/Triangulation_2/issue_5055.cpp new file mode 100644 index 00000000000..0fc7ef56e9a --- /dev/null +++ b/Triangulation_2/test/Triangulation_2/issue_5055.cpp @@ -0,0 +1,80 @@ +#include +#include +#include +#include +#include + +typedef CGAL::Epick Kernel; +typedef Kernel::Point_3 Point3; + +typedef CGAL::Projection_traits_xy_3 TriangulationTraits; +typedef CGAL::Triangulation_vertex_base_2 VertexBase; +typedef CGAL::Constrained_triangulation_face_base_2 + FaceBase; +typedef CGAL::Triangulation_data_structure_2 + TriangulationData; +typedef CGAL::Constrained_Delaunay_triangulation_2< + TriangulationTraits, TriangulationData, CGAL::Exact_predicates_tag> + ConstrainedTriangulation; +typedef CGAL::Constrained_triangulation_plus_2 CDT; + +int main() { + CDT cdt; + cdt.insert_constraint( + Point3(7.22060172459952354984e+02, 5.46431441157868448499e+02, + 1.09259033203125000000e+02), + Point3(7.21605164369421572701e+02, 5.47286947218267187054e+02, + 1.09231933593750000000e+02)); + cdt.insert_constraint( + Point3(4.89054338074482529919e+02, 7.34795619763430352123e+01, + 1.19170654296875000000e+02), + Point3(4.88992971641138979066e+02, 7.06742393092105203323e+01, + 1.19197509765625000000e+02)); + cdt.insert_constraint( + Point3(6.58294921875000000000e+02, 4.94029296875000000000e+02, + 1.08803459167480468750e+02), + Point3(6.55601638506381050320e+02, 4.92704923416975930195e+02, + 1.08774169921875000000e+02)); + cdt.insert_constraint( + Point3(7.48077080682167661507e+02, 5.16511846264136920581e+02, + 1.09748291015625000000e+02), + Point3(7.46966796875000000000e+02, 5.16371093750000000000e+02, + 1.09758056640625000000e+02)); + cdt.insert_constraint( + Point3(5.59349064841414701732e+02, 4.42600717751872252848e+02, + 1.08587158203125000000e+02), + Point3(5.56660156250000000000e+02, 4.41277343750000000000e+02, + 1.08660644531250000000e+02)); + cdt.insert_constraint( + Point3(6.36340512288503987293e+02, 4.83223199100345823354e+02, + 1.08523681640625000000e+02), + Point3(6.36339843750000000000e+02, 4.83224609375000000000e+02, + 1.08523681640625000000e+02)); + cdt.insert_constraint( + Point3(5.72431981051620141443e+02, 4.62372208487347847949e+02, + 1.08266105651855468750e+02), + Point3(5.71998046875000000000e+02, 4.61550781250000000000e+02, + 1.08266105651855468750e+02)); + cdt.insert_constraint( + Point3(5.54615246238433428516e+02, 3.99093747119970316817e+02, + 1.08986572265625000000e+02), + Point3(5.53910156250000000000e+02, 3.96179687500000000000e+02, + 1.09051513671875000000e+02)); + cdt.insert_constraint( + Point3(6.29072265625000000000e+02, 4.77775390625000000000e+02, + 1.08448486328125000000e+02), + Point3(6.29071750798135099103e+02, 4.77776482510548703431e+02, + 1.08448486328125000000e+02)); + cdt.insert_constraint( + Point3(4.89089689771187522638e+02, 7.46450533344111875067e+01, + 1.19143554687500000000e+02), + Point3(4.89006004028320262478e+02, 7.14945312499999943157e+01, + 1.19197509765625000000e+02)); + cdt.insert_constraint( + Point3(4.89054338074482529919e+02, 7.34795619763430352123e+01, + 1.19170654296875000000e+02), + Point3(4.88992951403166102864e+02, 7.06733141447368495847e+01, + 1.19197509765625000000e+02)); + + return 0; +} diff --git a/Triangulation_3/demo/Triangulation_3/Viewer.cpp b/Triangulation_3/demo/Triangulation_3/Viewer.cpp index 2483ea46879..526dc7a2932 100644 --- a/Triangulation_3/demo/Triangulation_3/Viewer.cpp +++ b/Triangulation_3/demo/Triangulation_3/Viewer.cpp @@ -1696,9 +1696,9 @@ void Viewer::drawWithNames() rendering_program.release(); //read depth and store in map - GLfloat depth = 1.0f; - glReadPixels(picking_pos.x(),camera()->screenHeight()-1-picking_pos.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth); - if (depth != 1.0) + GLfloat depth = 2.0f; + depth = read_depth_under_pixel(picking_pos, this, this->camera()); + if (depth < 2.0f) { picked_IDs[depth] = i; } @@ -1740,9 +1740,9 @@ void Viewer::drawWithNames() rendering_program.release(); //read depth and store in map - GLfloat depth = 1.0f; - glReadPixels(picking_pos.x(),camera()->screenHeight()-1-picking_pos.y(),1,1,GL_DEPTH_COMPONENT, GL_FLOAT, &depth); - if (depth != 1.0) + GLfloat depth = 2.0f; + depth = read_depth_under_pixel(picking_pos, this, this->camera()); + if (depth < 2.0f) { picked_IDs[depth] = -1; } diff --git a/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h b/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h index 642a0910276..a83ac381aea 100644 --- a/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h +++ b/Triangulation_3/include/CGAL/Delaunay_triangulation_3.h @@ -1076,7 +1076,7 @@ Delaunay_triangulation_3:: insert(const Point& p, Cell_handle start, bool *could_lock_zone) { Locate_type lt; - int li, lj; + int li = -1, lj = -1; // Parallel if(could_lock_zone) diff --git a/Triangulation_3/include/CGAL/Triangulation_3.h b/Triangulation_3/include/CGAL/Triangulation_3.h index 6368bf90d30..ad24b31c6d6 100644 --- a/Triangulation_3/include/CGAL/Triangulation_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_3.h @@ -3862,7 +3862,7 @@ Triangulation_3:: insert(const Point& p, Cell_handle start) { Locate_type lt; - int li, lj; + int li = -1, lj = -1; Cell_handle c = locate(p, lt, li, lj, start); return insert(p, lt, c, li, lj); } @@ -5174,6 +5174,7 @@ remove_3D(Vertex_handle v, VertexRemover& remover) } typename Vertex_triple_Facet_map::value_type o_vt_f_pair = *oit; + outer_map.erase(oit); Cell_handle o_ch = o_vt_f_pair.second.first; unsigned int o_i = o_vt_f_pair.second.second; @@ -5219,7 +5220,6 @@ remove_3D(Vertex_handle v, VertexRemover& remover) } } } - outer_map.erase(oit); } tds().delete_vertex(v); tds().delete_cells(hole.begin(), hole.end()); @@ -5371,6 +5371,7 @@ remove_3D(Vertex_handle v, VertexRemover& remover, } typename Vertex_triple_Facet_map::value_type o_vt_f_pair = *oit; + outer_map.erase(oit); Cell_handle o_ch = o_vt_f_pair.second.first; unsigned int o_i = o_vt_f_pair.second.second; @@ -5417,7 +5418,6 @@ remove_3D(Vertex_handle v, VertexRemover& remover, } } } - outer_map.erase(oit); } tds().delete_vertex(v); tds().delete_cells(inc_cells.begin(), inc_cells.end()); @@ -5674,6 +5674,7 @@ remove_3D(Vertex_handle v, VertexRemover& remover, OutputItCells fit) } typename Vertex_triple_Facet_map::value_type o_vt_f_pair = *oit; + outer_map.erase(oit); Cell_handle o_ch = o_vt_f_pair.second.first; unsigned int o_i = o_vt_f_pair.second.second; @@ -5721,7 +5722,6 @@ remove_3D(Vertex_handle v, VertexRemover& remover, OutputItCells fit) } } } - outer_map.erase(oit); } tds().delete_vertex(v); tds().delete_cells(hole.begin(), hole.end()); @@ -6063,6 +6063,7 @@ move_if_no_collision(Vertex_handle v, const Point& p, } typename Vertex_triple_Facet_map::value_type o_vt_f_pair = *oit; + outer_map.erase(oit); Cell_handle o_ch = o_vt_f_pair.second.first; unsigned int o_i = o_vt_f_pair.second.second; @@ -6109,7 +6110,6 @@ move_if_no_collision(Vertex_handle v, const Point& p, } } } - outer_map.erase(oit); } // fixing pointer @@ -6515,6 +6515,7 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point& p, } typename Vertex_triple_Facet_map::value_type o_vt_f_pair = *oit; + outer_map.erase(oit); Cell_handle o_ch = o_vt_f_pair.second.first; unsigned int o_i = o_vt_f_pair.second.second; @@ -6562,7 +6563,6 @@ move_if_no_collision_and_give_new_cells(Vertex_handle v, const Point& p, } } } - outer_map.erase(oit); } // fixing pointer @@ -6855,6 +6855,7 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover& rem } typename Vertex_triple_Facet_map::value_type o_vt_f_pair = *oit; + outer_map.erase(oit); Cell_handle o_ch = o_vt_f_pair.second.first; unsigned int o_i = o_vt_f_pair.second.second; @@ -6904,7 +6905,6 @@ _remove_cluster_3D(InputIterator first, InputIterator beyond, VertexRemover& rem } } - outer_map.erase(oit); } this->tds().delete_cells(hole.begin(), hole.end()); diff --git a/Triangulation_3/include/CGAL/Triangulation_hierarchy_3.h b/Triangulation_3/include/CGAL/Triangulation_hierarchy_3.h index bed4d16cd01..7281a4d316b 100644 --- a/Triangulation_3/include/CGAL/Triangulation_hierarchy_3.h +++ b/Triangulation_3/include/CGAL/Triangulation_hierarchy_3.h @@ -439,7 +439,7 @@ protected: struct locs { Cell_handle pos; - int li, lj; + int li = -1, lj = -1; Locate_type lt; }; @@ -538,7 +538,7 @@ insert(const Point &p, Cell_handle start) { int vertex_level = random_level(); Locate_type lt; - int i, j; + int i = -1, j = -1; // locate using hierarchy locs positions[maxlevel]; locate(p, lt, i, j, positions, start);