From a1ff847b6a4ec05ce40e3e24b7d38d8a87fd868e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 2 Jan 2023 08:17:16 +0100 Subject: [PATCH 01/99] add "brute-force" version of autorefine() --- .../Polygon_mesh_processing/CMakeLists.txt | 1 + .../triangle_mesh_autorefinement.cpp | 29 + .../Polygon_mesh_processing/autorefinement.h | 507 ++++++++++++++++++ .../internal/parameters_interface.h | 1 + 4 files changed, 538 insertions(+) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/triangle_mesh_autorefinement.cpp create mode 100644 Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index 192e7d29b74..e188e01e3eb 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -50,6 +50,7 @@ create_single_source_cgal_program("match_faces.cpp") create_single_source_cgal_program("cc_compatible_orientations.cpp") create_single_source_cgal_program("hausdorff_distance_remeshing_example.cpp") create_single_source_cgal_program("hausdorff_bounded_error_distance_example.cpp") +create_single_source_cgal_program("triangle_mesh_autorefinement.cpp") find_package(Eigen3 3.2.0 QUIET) #(requires 3.2.0 or greater) include(CGAL_Eigen3_support) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangle_mesh_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangle_mesh_autorefinement.cpp new file mode 100644 index 00000000000..65db52fef2c --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/triangle_mesh_autorefinement.cpp @@ -0,0 +1,29 @@ +#include +#include + +#include +#include + +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef Kernel::Point_3 Point; + +typedef CGAL::Surface_mesh Mesh; + +namespace PMP = CGAL::Polygon_mesh_processing; + +int main(int argc, char** argv) +{ + Mesh mesh; + + const std::string filename = argc == 1 ? CGAL::data_file_path("meshes/elephant.off") + : std::string(argv[1]); + CGAL::IO::read_polygon_mesh(filename, mesh); + + PMP::autorefine(mesh); + + CGAL::IO::write_polygon_mesh("autorefined.off", mesh, CGAL::parameters::stream_precision(17)); + + return 0; +} diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h new file mode 100644 index 00000000000..8c34b4041d8 --- /dev/null +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -0,0 +1,507 @@ +// Copyright (c) 2023 GeometryFactory (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org). +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-Commercial +// +// +// Author(s) : Sebastien Loriot +// + +#ifndef CGAL_POLYGON_MESH_PROCESSING_AUTOREFINEMENT_H +#define CGAL_POLYGON_MESH_PROCESSING_AUTOREFINEMENT_H + +#include + +#include +#include +#include +#include + +// output +#include +#include + +#ifndef NDEBUG +// debug +#include +#endif + +#include + +namespace CGAL { +namespace Polygon_mesh_processing { + +#ifndef DOXYGEN_RUNNING +namespace autorefine_impl { + +template +void generate_subtriangles(const typename EK::Triangle_3& t, + const std::vector& segments, + const std::vector& points, + std::vector& new_triangles) +{ + typedef CGAL::Projection_traits_3 P_traits; + // typedef CGAL::Exact_intersections_tag Itag; + typedef CGAL::No_constraint_intersection_requiring_constructions_tag Itag; + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; + + + P_traits cdt_traits(normal(t[0], t[1], t[2])); + CDT cdt(cdt_traits); + + cdt.insert_outside_affine_hull(t[0]); + cdt.insert_outside_affine_hull(t[1]); + typename CDT::Vertex_handle v = cdt.tds().insert_dim_up(cdt.infinite_vertex(), false); + v->set_point(t[2]); + + for (const typename EK::Segment_3& s : segments) + cdt.insert_constraint(s[0], s[1]); + + for (const typename EK::Point_3& p : points) + cdt.insert(p); + + for (typename CDT::Face_handle fh : cdt.finite_face_handles()) + { + new_triangles.emplace_back(fh->vertex(0)->point(), + fh->vertex(cdt.ccw(0))->point(), + fh->vertex(cdt.cw(0))->point()); + } +} + +template +struct Intersection_visitor +{ + std::vector& all_segments_1; + std::vector& all_segments_2; + std::vector& all_points_1; + std::vector& all_points_2; + + Intersection_visitor(std::vector& all_segments_1, + std::vector& all_segments_2, + std::vector& all_points_1, + std::vector& all_points_2) + : all_segments_1(all_segments_1) + , all_segments_2(all_segments_2) + , all_points_1(all_points_1) + , all_points_2(all_points_2) + {} + + typedef void result_type; + void operator()(const typename EK::Point_3& p) + { + all_points_1.push_back(p); + all_points_2.push_back(p); + } + + void operator()(const typename EK::Segment_3& s) + { + all_segments_1.push_back(s); + all_segments_2.push_back(s); + } + + void operator()(const typename EK::Triangle_3& t) + { + for (std::size_t i=1; i<3; ++i) + { + typename EK::Segment_3 s(t[i-1], t[i]); + all_segments_1.push_back(s); + all_segments_2.push_back(s); + } + } + + void operator()(const std::vector& poly) + { + std::size_t nbp = poly.size(); + for (std::size_t i=1; i +bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, const std::vector< std::vector>>& triangles) +{ + typedef typename Kernel_traits::value_type>::type IK; + typedef boost::graph_traits Graph_traits; + typedef typename Graph_traits::face_descriptor face_descriptor; + typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor; + + std::vector soup_points; + std::vector > soup_triangles; + Cartesian_converter to_exact; + std::map point_id_map; + + auto get_point_id = [&](const typename EK::Point_3& pt) + { + auto insert_res = point_id_map.insert(std::make_pair(pt, soup_points.size())); + if (insert_res.second) + soup_points.push_back(pt); + return insert_res.first->second; + }; + + for (face_descriptor f : faces(tm)) + { + int tid = get(tid_map, f); + if (tid == -1) + { + halfedge_descriptor h = halfedge(f, tm); + soup_triangles.emplace_back( + CGAL::make_array(get_point_id(to_exact(get(vpm,source(h, tm)))), + get_point_id(to_exact(get(vpm,target(h, tm)))), + get_point_id(to_exact(get(vpm,target(next(h, tm), tm))))) + ); + } + else + { + for (const typename EK::Triangle_3& t : triangles[tid]) + { + soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); + } + } + } + + typedef Surface_mesh Exact_mesh; + Exact_mesh etm; + orient_polygon_soup(soup_points, soup_triangles); + polygon_soup_to_polygon_mesh(soup_points, soup_triangles, etm); + typename Exact_mesh::Property_map is_border_map = + etm.template add_property_map("v:is_border", false).first; + for(typename Exact_mesh::Halfedge_index h : etm.halfedges()) + { + if (CGAL::is_border(h, etm)) + is_border_map[target(h, etm)] = true; + } + + //TODO: double check me + auto skip_faces = [&](const std::pair& p) + { + typename Exact_mesh::Halfedge_index h1 = etm.halfedge(p.first), h2=etm.halfedge(p.second); + + boost::container::small_vector bv1; + if (is_border_map[source(h1, etm)]) bv1.push_back(prev(h1, etm)); + if (is_border_map[target(h1, etm)]) bv1.push_back(h1); + if (is_border_map[target(next(h1, etm), etm)]) bv1.push_back(next(h1, etm)); + if (bv1.empty()) return false; + + boost::container::small_vector bv2; + if (is_border_map[source(h2, etm)]) bv2.push_back(prev(h2, etm)); + if (is_border_map[target(h2, etm)]) bv2.push_back(h2); + if (is_border_map[target(next(h2, etm), etm)]) bv2.push_back(next(h2, etm)); + if (bv2.empty()) return false; + + //collect identical border vertices + boost::container::small_vector, 3> common; + for(typename Exact_mesh::Halfedge_index h1 : bv1) + for(typename Exact_mesh::Halfedge_index h2 : bv2) + if (etm.point(target(h1, etm))==etm.point(target(h2,etm))) + common.push_back(std::make_pair(h1,h2)); + + if (common.empty()) return false; + + switch (common.size()) + { + case 1: + { + // geometric check if the opposite segments intersect the triangles + const typename EK::Triangle_3 t1(etm.point(source(h1,etm)), + etm.point(target(h1,etm)), + etm.point(target(next(h1,etm),etm))); + const typename EK::Triangle_3 t2(etm.point(source(h2,etm)), + etm.point(target(h2,etm)), + etm.point(target(next(h2,etm),etm))); + + const typename EK::Segment_3 s1(etm.point(source(common[0].first,etm)), etm.point(target(next(common[0].first,etm),etm))); + const typename EK::Segment_3 s2(etm.point(source(common[0].second,etm)), etm.point(target(next(common[0].second,etm),etm))); + + if(do_intersect(t1, s2) || do_intersect(t2, s1)) + return false; + return true; + } + case 2: + { + // shared edge + h1 = next(common[0].first, etm) == common[1].first ? common[1].first : common[0].first; + h2 = next(common[0].second, etm) == common[1].second ? common[1].second : common[0].second; + + if ( is_border(etm.opposite(h1), etm) && + is_border(etm.opposite(h2), etm) ) + { + if( CGAL::coplanar(etm.point(source(h1,etm)), + etm.point(target(h1,etm)), + etm.point(target(etm.next(h1),etm)), + etm.point(source(h1,etm))) && + CGAL::coplanar_orientation(etm.point(source(h1,etm)), + etm.point(target(h1,etm)), + etm.point(target(etm.next(h1),etm)), + etm.point(source(h1,etm))) == CGAL::POSITIVE) + { + return false; + } + return true; + } + else + { + // TODO: 2 identical border vertices, no common edge on the boundary. Not sure what to do + return false; + } + } + default: // size == 3 + return true; + } + }; + + std::vector< std::pair > si_faces; + self_intersections(etm, + CGAL::filter_output_iterator(std::back_inserter(si_faces), + skip_faces)); + + return si_faces.empty(); +} + +} // end of autorefine_impl +#endif + +/** + * \ingroup PMP_corefinement_grp + * \link coref_def_subsec autorefines \endlink `tm`. Refines a triangle mesh + * so that no triangles intersects in their interior. + * Self-intersection edges will be marked as constrained. If an edge that was marked as + * constrained is split, its sub-edges will be marked as constrained as well. + * + * @tparam TriangleMesh a model of `HalfedgeListGraph`, `FaceListGraph`, and `MutableFaceGraph` + * @tparam NamedParameters a sequence of \ref namedparameters + * + * @param tm input triangulated surface mesh + * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below + * + * \cgalParamNBegin{geom_traits} + * \cgalParamDescription{an instance of a geometric traits class} + * \cgalParamType{a class model of `PMPSelfIntersectionTraits`} + * \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`} + * \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.} + * \cgalParamNEnd + * + * \cgalNamedParamsBegin + * \cgalParamNBegin{vertex_point_map} + * \cgalParamDescription{a property map associating points to the vertices of `tm`} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * as key type and `%Point_3` as value type} + * \cgalParamDefault{`boost::get(CGAL::vertex_point, tm)`} + * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` + * must be available in `TriangleMesh`.} + * \cgalParamNEnd + * + * \cgalParamNBegin{edge_is_constrained_map} + * \cgalParamDescription{a property map containing the constrained-or-not status of each edge of `tm`} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%edge_descriptor` + * as key type and `bool` as value type} + * \cgalParamDefault{a constant property map returning `false` for any edge} + * \cgalParamNEnd + * + * \cgalParamNBegin{face_index_map} + * \cgalParamDescription{a property map associating to each face of `tm` a unique index between `0` and `num_faces(tm) - 1`} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%face_descriptor` + * as key type and `std::size_t` as value type} + * \cgalParamDefault{an automatically indexed internal map} + * \cgalParamExtra{If the property map is writable, the indices of the faces of `tm1` and `tm2` + * will be set after the corefinement is done.} + * \cgalParamNEnd + * + * \cgalParamNBegin{visitor} + * \cgalParamDescription{a visitor used to track the creation of new faces} + * \cgalParamType{a class model of `PMPCorefinementVisitor`} + * \cgalParamDefault{`Corefinement::Default_visitor`} + * \cgalParamNEnd + * \cgalNamedParamsEnd + * + */ +template +void +autorefine( TriangleMesh& tm, + const NamedParameters& np = parameters::default_values()) +{ + //TODO: what about degenerate faces? + + using parameters::choose_parameter; + using parameters::get_parameter; + + typedef typename GetGeomTraits::type GT; + GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); + + typedef typename GetVertexPointMap::type VPM; + VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), + get_property_map(vertex_point, tm)); + + typedef typename internal_np::Lookup_named_param_def < + internal_np::concurrency_tag_t, + NamedParameters, + Sequential_tag + > ::type Concurrency_tag; + + typedef boost::graph_traits Graph_traits; + typedef typename Graph_traits::face_descriptor face_descriptor; + typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor; + typedef typename Graph_traits::vertex_descriptor vertex_descriptor; + typedef std::pair Pair_of_faces; + + std::vector si_pairs; + + // collect intersecting pairs of triangles + self_intersections(tm, std::back_inserter(si_pairs), np); + + if (si_pairs.empty()) return; + + // assign an id per triangle involved in an intersection + // + the faces involved in the intersection + typedef CGAL::dynamic_face_property_t Face_property_tag; + typedef typename boost::property_map::type Triangle_id_map; + + Triangle_id_map tid_map = get(Face_property_tag(), tm); + for (face_descriptor f : faces(tm)) + put(tid_map, f, -1); + + std::vector intersected_faces; + int tid=-1; + for (const Pair_of_faces& p : si_pairs) + { + if (get(tid_map, p.first)==-1) + { + put(tid_map, p.first, ++tid); + intersected_faces.push_back(p.first); + } + if (get(tid_map, p.second)==-1) + { + put(tid_map, p.second, ++tid); + intersected_faces.push_back(p.second); + } + } + + // init the vector of triangles used for the autorefinement of triangles + typedef CGAL::Exact_predicates_exact_constructions_kernel EK; + std::vector< std::vector > triangles(tid+1); + Cartesian_converter to_exact; + + for(face_descriptor f : intersected_faces) + { + halfedge_descriptor h = halfedge(f, tm); + triangles[get(tid_map, f)].emplace_back( + to_exact( get(vpm, source(h, tm)) ), + to_exact( get(vpm, target(h, tm)) ), + to_exact( get(vpm, target(next(h, tm), tm)) ) ); + } + + typename EK::Intersect_3 intersection = EK().intersect_3_object(); + for (const Pair_of_faces& p : si_pairs) + { + int i1 = get(tid_map, p.first), + i2 = get(tid_map, p.second); + + + std::size_t nbt_1 = triangles[i1].size(), + nbt_2 = triangles[i2].size(); + + std::vector< std::vector > all_segments_1(nbt_1); + std::vector< std::vector > all_segments_2(nbt_2); + std::vector< std::vector > all_points_1(nbt_1); + std::vector< std::vector > all_points_2(nbt_2); + + std::vector t1_subtriangles, t2_subtriangles; + for (std::size_t it1=0; it1 intersection_visitor(all_segments_1[it1], all_segments_2[it2], + all_points_1[it1], all_points_2[it2]); + + boost::apply_visitor(intersection_visitor, *inter); + } + } + } + + // now refine triangles + std::vector new_triangles; + for(std::size_t it1=0; it1(triangles[i1][it1], all_segments_1[it1], all_points_1[it1], new_triangles); + } + triangles[i1].swap(new_triangles); + new_triangles.clear(); + for(std::size_t it2=0; it2(triangles[i2][it2], all_segments_2[it2], all_points_2[it2], new_triangles); + } + triangles[i2].swap(new_triangles); + } + + CGAL_assertion( autorefine_impl::is_output_valid(tm, vpm, tid_map, triangles) ); + + // brute force output: create a soup, orient and to-mesh + // WARNING: there is no reason when using double that identical exact points are identical in double + std::vector soup_points; + std::vector > soup_triangles; + Cartesian_converter to_input; + std::map point_id_map; + + for (vertex_descriptor v : vertices(tm)) + { + if (point_id_map.insert(std::make_pair(to_exact(get(vpm,v)), soup_points.size())).second) + soup_points.push_back(get(vpm,v)); + } + + auto get_point_id = [&](const typename EK::Point_3& pt) + { + auto insert_res = point_id_map.insert(std::make_pair(pt, soup_points.size())); + if (insert_res.second) + soup_points.push_back(to_input(pt)); + return insert_res.first->second; + }; + + for (face_descriptor f : faces(tm)) + { + int tid = get(tid_map, f); + if (tid == -1) + { + halfedge_descriptor h = halfedge(f, tm); + soup_triangles.emplace_back( + CGAL::make_array(get_point_id(to_exact(get(vpm,source(h, tm)))), + get_point_id(to_exact(get(vpm,target(h, tm)))), + get_point_id(to_exact(get(vpm,target(next(h, tm), tm))))) + ); + } + else + { + for (const typename EK::Triangle_3& t : triangles[tid]) + { + soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); + } + } + } + clear(tm); + orient_polygon_soup(soup_points, soup_triangles); + polygon_soup_to_polygon_mesh(soup_points, soup_triangles, tm); +} + +} } // end of CGAL::Polygon_mesh_processing + +#endif // CGAL_POLYGON_MESH_PROCESSING_AUTOREFINEMENT_H 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 5c649faa56c..7d758abc4ee 100644 --- a/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h +++ b/STL_Extension/include/CGAL/STL_Extension/internal/parameters_interface.h @@ -45,6 +45,7 @@ CGAL_add_named_parameter(implementation_tag_t, implementation_tag, implementatio CGAL_add_named_parameter(prevent_unselection_t, prevent_unselection, prevent_unselection) CGAL_add_named_parameter(verbose_t, verbose, verbose) +CGAL_add_named_parameter(concurrency_tag_t, concurrency_tag, concurrency_tag) // List of named parameters used for IO CGAL_add_named_parameter(vertex_normal_output_iterator_t, vertex_normal_output_iterator, vertex_normal_output_iterator) From b0edd90580ea3044ca3fbfe11086d5413f9338cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 2 Jan 2023 17:21:01 +0100 Subject: [PATCH 02/99] add option to directly dump the soup --- .../Polygon_mesh_processing/autorefinement.h | 149 ++++++++++-------- 1 file changed, 84 insertions(+), 65 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 8c34b4041d8..fd124bce857 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -266,67 +266,12 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, const std::vec } } // end of autorefine_impl -#endif -/** - * \ingroup PMP_corefinement_grp - * \link coref_def_subsec autorefines \endlink `tm`. Refines a triangle mesh - * so that no triangles intersects in their interior. - * Self-intersection edges will be marked as constrained. If an edge that was marked as - * constrained is split, its sub-edges will be marked as constrained as well. - * - * @tparam TriangleMesh a model of `HalfedgeListGraph`, `FaceListGraph`, and `MutableFaceGraph` - * @tparam NamedParameters a sequence of \ref namedparameters - * - * @param tm input triangulated surface mesh - * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below - * - * \cgalParamNBegin{geom_traits} - * \cgalParamDescription{an instance of a geometric traits class} - * \cgalParamType{a class model of `PMPSelfIntersectionTraits`} - * \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`} - * \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.} - * \cgalParamNEnd - * - * \cgalNamedParamsBegin - * \cgalParamNBegin{vertex_point_map} - * \cgalParamDescription{a property map associating points to the vertices of `tm`} - * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` - * as key type and `%Point_3` as value type} - * \cgalParamDefault{`boost::get(CGAL::vertex_point, tm)`} - * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` - * must be available in `TriangleMesh`.} - * \cgalParamNEnd - * - * \cgalParamNBegin{edge_is_constrained_map} - * \cgalParamDescription{a property map containing the constrained-or-not status of each edge of `tm`} - * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%edge_descriptor` - * as key type and `bool` as value type} - * \cgalParamDefault{a constant property map returning `false` for any edge} - * \cgalParamNEnd - * - * \cgalParamNBegin{face_index_map} - * \cgalParamDescription{a property map associating to each face of `tm` a unique index between `0` and `num_faces(tm) - 1`} - * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%face_descriptor` - * as key type and `std::size_t` as value type} - * \cgalParamDefault{an automatically indexed internal map} - * \cgalParamExtra{If the property map is writable, the indices of the faces of `tm1` and `tm2` - * will be set after the corefinement is done.} - * \cgalParamNEnd - * - * \cgalParamNBegin{visitor} - * \cgalParamDescription{a visitor used to track the creation of new faces} - * \cgalParamType{a class model of `PMPCorefinementVisitor`} - * \cgalParamDefault{`Corefinement::Default_visitor`} - * \cgalParamNEnd - * \cgalNamedParamsEnd - * - */ -template -void -autorefine( TriangleMesh& tm, - const NamedParameters& np = parameters::default_values()) +template +void autorefine_soup_output(const TriangleMesh& tm, + std::vector& soup_points, + std::vector >& soup_triangles, + const NamedParameters& np = parameters::default_values()) { //TODO: what about degenerate faces? @@ -336,9 +281,9 @@ autorefine( TriangleMesh& tm, typedef typename GetGeomTraits::type GT; GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); - typedef typename GetVertexPointMap::type VPM; + typedef typename GetVertexPointMap::const_type VPM; VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_property_map(vertex_point, tm)); + get_const_property_map(vertex_point, tm)); typedef typename internal_np::Lookup_named_param_def < internal_np::concurrency_tag_t, @@ -362,7 +307,7 @@ autorefine( TriangleMesh& tm, // assign an id per triangle involved in an intersection // + the faces involved in the intersection typedef CGAL::dynamic_face_property_t Face_property_tag; - typedef typename boost::property_map::type Triangle_id_map; + typedef typename boost::property_map::const_type Triangle_id_map; Triangle_id_map tid_map = get(Face_property_tag(), tm); for (face_descriptor f : faces(tm)) @@ -458,8 +403,6 @@ autorefine( TriangleMesh& tm, // brute force output: create a soup, orient and to-mesh // WARNING: there is no reason when using double that identical exact points are identical in double - std::vector soup_points; - std::vector > soup_triangles; Cartesian_converter to_input; std::map point_id_map; @@ -497,11 +440,87 @@ autorefine( TriangleMesh& tm, } } } + +} +#endif + +/** + * \ingroup PMP_corefinement_grp + * \link coref_def_subsec autorefines \endlink `tm`. Refines a triangle mesh + * so that no triangles intersects in their interior. + * Self-intersection edges will be marked as constrained. If an edge that was marked as + * constrained is split, its sub-edges will be marked as constrained as well. + * + * @tparam TriangleMesh a model of `HalfedgeListGraph`, `FaceListGraph`, and `MutableFaceGraph` + * @tparam NamedParameters a sequence of \ref namedparameters + * + * @param tm input triangulated surface mesh + * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below + * + * \cgalParamNBegin{geom_traits} + * \cgalParamDescription{an instance of a geometric traits class} + * \cgalParamType{a class model of `PMPSelfIntersectionTraits`} + * \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`} + * \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.} + * \cgalParamNEnd + * + * \cgalNamedParamsBegin + * \cgalParamNBegin{vertex_point_map} + * \cgalParamDescription{a property map associating points to the vertices of `tm`} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` + * as key type and `%Point_3` as value type} + * \cgalParamDefault{`boost::get(CGAL::vertex_point, tm)`} + * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` + * must be available in `TriangleMesh`.} + * \cgalParamNEnd + * + * \cgalParamNBegin{edge_is_constrained_map} + * \cgalParamDescription{a property map containing the constrained-or-not status of each edge of `tm`} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%edge_descriptor` + * as key type and `bool` as value type} + * \cgalParamDefault{a constant property map returning `false` for any edge} + * \cgalParamNEnd + * + * \cgalParamNBegin{face_index_map} + * \cgalParamDescription{a property map associating to each face of `tm` a unique index between `0` and `num_faces(tm) - 1`} + * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%face_descriptor` + * as key type and `std::size_t` as value type} + * \cgalParamDefault{an automatically indexed internal map} + * \cgalParamExtra{If the property map is writable, the indices of the faces of `tm1` and `tm2` + * will be set after the corefinement is done.} + * \cgalParamNEnd + * + * \cgalParamNBegin{visitor} + * \cgalParamDescription{a visitor used to track the creation of new faces} + * \cgalParamType{a class model of `PMPCorefinementVisitor`} + * \cgalParamDefault{`Corefinement::Default_visitor`} + * \cgalParamNEnd + * \cgalNamedParamsEnd + * + */ +template +void +autorefine( TriangleMesh& tm, + const NamedParameters& np = parameters::default_values()) +{ + using parameters::choose_parameter; + using parameters::get_parameter; + + typedef typename GetGeomTraits::type GT; + GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); + + std::vector soup_points; + std::vector > soup_triangles; + + autorefine_soup_output(tm, soup_points, soup_triangles, np); + clear(tm); orient_polygon_soup(soup_points, soup_triangles); polygon_soup_to_polygon_mesh(soup_points, soup_triangles, tm); } + } } // end of CGAL::Polygon_mesh_processing #endif // CGAL_POLYGON_MESH_PROCESSING_AUTOREFINEMENT_H From 47ac016af779ab6a987ee16c62bbf723bd4c182f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 2 Jan 2023 17:32:35 +0100 Subject: [PATCH 03/99] skip degenerate faces --- .../Polygon_mesh_processing/autorefinement.h | 32 ++++++++++++------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index fd124bce857..4b7020b5615 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -125,8 +126,8 @@ struct Intersection_visitor } }; -template -bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, const std::vector< std::vector>>& triangles) +template +bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map is_degen, const std::vector< std::vector>>& triangles) { typedef typename Kernel_traits::value_type>::type IK; typedef boost::graph_traits Graph_traits; @@ -148,6 +149,7 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, const std::vec for (face_descriptor f : faces(tm)) { + if (get(is_degen, f)) continue; // skip degenerate faces int tid = get(tid_map, f); if (tid == -1) { @@ -273,8 +275,6 @@ void autorefine_soup_output(const TriangleMesh& tm, std::vector >& soup_triangles, const NamedParameters& np = parameters::default_values()) { - //TODO: what about degenerate faces? - using parameters::choose_parameter; using parameters::get_parameter; @@ -304,12 +304,20 @@ void autorefine_soup_output(const TriangleMesh& tm, if (si_pairs.empty()) return; + // mark degenerate faces so that we can ignore them + typedef CGAL::dynamic_face_property_t Degen_property_tag; + typedef typename boost::property_map::const_type Is_degen_map; + Is_degen_map is_degen = get(Degen_property_tag(), tm); + + for(face_descriptor f : faces(tm)) + put(is_degen, f, is_degenerate_triangle_face(f, tm, np)); + // assign an id per triangle involved in an intersection // + the faces involved in the intersection - typedef CGAL::dynamic_face_property_t Face_property_tag; - typedef typename boost::property_map::const_type Triangle_id_map; + typedef CGAL::dynamic_face_property_t TID_property_tag; + typedef typename boost::property_map::const_type Triangle_id_map; - Triangle_id_map tid_map = get(Face_property_tag(), tm); + Triangle_id_map tid_map = get(TID_property_tag(), tm); for (face_descriptor f : faces(tm)) put(tid_map, f, -1); @@ -317,12 +325,12 @@ void autorefine_soup_output(const TriangleMesh& tm, int tid=-1; for (const Pair_of_faces& p : si_pairs) { - if (get(tid_map, p.first)==-1) + if (get(tid_map, p.first)==-1 && !get(is_degen, p.first)) { put(tid_map, p.first, ++tid); intersected_faces.push_back(p.first); } - if (get(tid_map, p.second)==-1) + if (get(tid_map, p.second)==-1 && !get(is_degen, p.second)) { put(tid_map, p.second, ++tid); intersected_faces.push_back(p.second); @@ -349,6 +357,7 @@ void autorefine_soup_output(const TriangleMesh& tm, int i1 = get(tid_map, p.first), i2 = get(tid_map, p.second); + if (i1==-1 || i2==-1) continue; //skip degenerate faces std::size_t nbt_1 = triangles[i1].size(), nbt_2 = triangles[i2].size(); @@ -399,7 +408,7 @@ void autorefine_soup_output(const TriangleMesh& tm, triangles[i2].swap(new_triangles); } - CGAL_assertion( autorefine_impl::is_output_valid(tm, vpm, tid_map, triangles) ); + CGAL_assertion( autorefine_impl::is_output_valid(tm, vpm, tid_map, is_degen, triangles) ); // brute force output: create a soup, orient and to-mesh // WARNING: there is no reason when using double that identical exact points are identical in double @@ -422,6 +431,8 @@ void autorefine_soup_output(const TriangleMesh& tm, for (face_descriptor f : faces(tm)) { + if (get(is_degen, f)) continue; //skip degenerate faces + int tid = get(tid_map, f); if (tid == -1) { @@ -440,7 +451,6 @@ void autorefine_soup_output(const TriangleMesh& tm, } } } - } #endif From 6df9926f9b6ea6553be1fbcfd1c0996e76b802f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 2 Jan 2023 17:47:04 +0100 Subject: [PATCH 04/99] add another example with soup as input --- .../Polygon_mesh_processing/CMakeLists.txt | 1 + .../soup_autorefinement.cpp | 39 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index e188e01e3eb..d2faeb70cb2 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -51,6 +51,7 @@ create_single_source_cgal_program("cc_compatible_orientations.cpp") create_single_source_cgal_program("hausdorff_distance_remeshing_example.cpp") create_single_source_cgal_program("hausdorff_bounded_error_distance_example.cpp") create_single_source_cgal_program("triangle_mesh_autorefinement.cpp") +create_single_source_cgal_program("soup_autorefinement.cpp") find_package(Eigen3 3.2.0 QUIET) #(requires 3.2.0 or greater) include(CGAL_Eigen3_support) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp new file mode 100644 index 00000000000..fa1f5d68690 --- /dev/null +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -0,0 +1,39 @@ +#include +#include + +#include +#include +#include +#include +#include + +#include + +typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; +typedef Kernel::Point_3 Point; + +typedef CGAL::Surface_mesh Mesh; + +namespace PMP = CGAL::Polygon_mesh_processing; + +int main(int argc, char** argv) +{ + const std::string filename = argc == 1 ? CGAL::data_file_path("meshes/elephant.off") + : std::string(argv[1]); + + std::vector input_points; + std::vector > input_triangles; + + CGAL::IO::read_polygon_soup(filename, input_points, input_triangles); + PMP::repair_polygon_soup(input_points, input_triangles); + + Mesh mesh; + PMP::orient_polygon_soup(input_points, input_triangles); + PMP::polygon_soup_to_polygon_mesh(input_points, input_triangles, mesh); + + PMP::autorefine(mesh); + + CGAL::IO::write_polygon_mesh("autorefined.off", mesh, CGAL::parameters::stream_precision(17)); + + return 0; +} From e1414de8d935cc5da43682c48b5419823b806c77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 2 Jan 2023 18:09:26 +0100 Subject: [PATCH 05/99] add debug --- .../Polygon_mesh_processing/autorefinement.h | 46 +++++++++++++++++-- 1 file changed, 43 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 4b7020b5615..8dd8d28fcfc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -181,6 +181,17 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i is_border_map[target(h, etm)] = true; } +#ifdef CGAL_DEBUG_PMP_AUTOREFINE + std::cerr << std::setprecision(17); + auto verbose_fail_msg = [&](int i, const std::pair& p) + { + typename Exact_mesh::Halfedge_index h1 = halfedge(p.first, etm), h2 = halfedge(p.second, etm); + std::cerr << "DEBUG: failing at check #" << i << "\n"; + std::cerr << "DEBUG: " << etm.point(source(h1, etm)) << " " << etm.point(target(h1, etm)) << " " << etm.point(target(next(h1, etm), etm)) << " " << etm.point(source(h1, etm)) << "\n"; + std::cerr << "DEBUG: " << etm.point(source(h2, etm)) << " " << etm.point(target(h2, etm)) << " " << etm.point(target(next(h2, etm), etm)) << " " << etm.point(source(h2, etm)) << "\n"; + }; +#endif + //TODO: double check me auto skip_faces = [&](const std::pair& p) { @@ -190,13 +201,25 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i if (is_border_map[source(h1, etm)]) bv1.push_back(prev(h1, etm)); if (is_border_map[target(h1, etm)]) bv1.push_back(h1); if (is_border_map[target(next(h1, etm), etm)]) bv1.push_back(next(h1, etm)); - if (bv1.empty()) return false; + if (bv1.empty()) + { +#ifdef CGAL_DEBUG_PMP_AUTOREFINE + verbose_fail_msg(1, p); +#endif + return false; + } boost::container::small_vector bv2; if (is_border_map[source(h2, etm)]) bv2.push_back(prev(h2, etm)); if (is_border_map[target(h2, etm)]) bv2.push_back(h2); if (is_border_map[target(next(h2, etm), etm)]) bv2.push_back(next(h2, etm)); - if (bv2.empty()) return false; + if (bv2.empty()) + { +#ifdef CGAL_DEBUG_PMP_AUTOREFINE + verbose_fail_msg(2, p); +#endif + return false; + } //collect identical border vertices boost::container::small_vector, 3> common; @@ -205,7 +228,13 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i if (etm.point(target(h1, etm))==etm.point(target(h2,etm))) common.push_back(std::make_pair(h1,h2)); - if (common.empty()) return false; + if (common.empty()) + { +#ifdef CGAL_DEBUG_PMP_AUTOREFINE + verbose_fail_msg(3, p); +#endif + return false; + } switch (common.size()) { @@ -223,7 +252,12 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i const typename EK::Segment_3 s2(etm.point(source(common[0].second,etm)), etm.point(target(next(common[0].second,etm),etm))); if(do_intersect(t1, s2) || do_intersect(t2, s1)) + { +#ifdef CGAL_DEBUG_PMP_AUTOREFINE + verbose_fail_msg(4, p); +#endif return false; + } return true; } case 2: @@ -244,6 +278,9 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i etm.point(target(etm.next(h1),etm)), etm.point(source(h1,etm))) == CGAL::POSITIVE) { +#ifdef CGAL_DEBUG_PMP_AUTOREFINE + verbose_fail_msg(5, p); +#endif return false; } return true; @@ -251,6 +288,9 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i else { // TODO: 2 identical border vertices, no common edge on the boundary. Not sure what to do +#ifdef CGAL_DEBUG_PMP_AUTOREFINE + verbose_fail_msg(6, p); +#endif return false; } } From 85368c43c6258e67aca26af6985fb57884642901 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 2 Jan 2023 19:38:10 +0100 Subject: [PATCH 06/99] use all vertices in the check --- .../Polygon_mesh_processing/autorefinement.h | 79 ++++++------------- 1 file changed, 23 insertions(+), 56 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 8dd8d28fcfc..fd5e7312c26 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -173,13 +173,6 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i Exact_mesh etm; orient_polygon_soup(soup_points, soup_triangles); polygon_soup_to_polygon_mesh(soup_points, soup_triangles, etm); - typename Exact_mesh::Property_map is_border_map = - etm.template add_property_map("v:is_border", false).first; - for(typename Exact_mesh::Halfedge_index h : etm.halfedges()) - { - if (CGAL::is_border(h, etm)) - is_border_map[target(h, etm)] = true; - } #ifdef CGAL_DEBUG_PMP_AUTOREFINE std::cerr << std::setprecision(17); @@ -197,41 +190,27 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i { typename Exact_mesh::Halfedge_index h1 = etm.halfedge(p.first), h2=etm.halfedge(p.second); - boost::container::small_vector bv1; - if (is_border_map[source(h1, etm)]) bv1.push_back(prev(h1, etm)); - if (is_border_map[target(h1, etm)]) bv1.push_back(h1); - if (is_border_map[target(next(h1, etm), etm)]) bv1.push_back(next(h1, etm)); - if (bv1.empty()) - { -#ifdef CGAL_DEBUG_PMP_AUTOREFINE - verbose_fail_msg(1, p); -#endif - return false; - } + boost::container::small_vector v1; + v1.push_back(prev(h1, etm)); + v1.push_back(h1); + v1.push_back(next(h1, etm)); - boost::container::small_vector bv2; - if (is_border_map[source(h2, etm)]) bv2.push_back(prev(h2, etm)); - if (is_border_map[target(h2, etm)]) bv2.push_back(h2); - if (is_border_map[target(next(h2, etm), etm)]) bv2.push_back(next(h2, etm)); - if (bv2.empty()) - { -#ifdef CGAL_DEBUG_PMP_AUTOREFINE - verbose_fail_msg(2, p); -#endif - return false; - } + boost::container::small_vector v2; + v2.push_back(prev(h2, etm)); + v2.push_back(h2); + v2.push_back(next(h2, etm)); - //collect identical border vertices + //collect identical vertices boost::container::small_vector, 3> common; - for(typename Exact_mesh::Halfedge_index h1 : bv1) - for(typename Exact_mesh::Halfedge_index h2 : bv2) + for(typename Exact_mesh::Halfedge_index h1 : v1) + for(typename Exact_mesh::Halfedge_index h2 : v2) if (etm.point(target(h1, etm))==etm.point(target(h2,etm))) common.push_back(std::make_pair(h1,h2)); if (common.empty()) { #ifdef CGAL_DEBUG_PMP_AUTOREFINE - verbose_fail_msg(3, p); + verbose_fail_msg(1, p); #endif return false; } @@ -254,7 +233,7 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i if(do_intersect(t1, s2) || do_intersect(t2, s1)) { #ifdef CGAL_DEBUG_PMP_AUTOREFINE - verbose_fail_msg(4, p); + verbose_fail_msg(2, p); #endif return false; } @@ -266,33 +245,21 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i h1 = next(common[0].first, etm) == common[1].first ? common[1].first : common[0].first; h2 = next(common[0].second, etm) == common[1].second ? common[1].second : common[0].second; - if ( is_border(etm.opposite(h1), etm) && - is_border(etm.opposite(h2), etm) ) + if( CGAL::coplanar(etm.point(source(h1,etm)), + etm.point(target(h1,etm)), + etm.point(target(etm.next(h1),etm)), + etm.point(source(h1,etm))) && + CGAL::coplanar_orientation(etm.point(source(h1,etm)), + etm.point(target(h1,etm)), + etm.point(target(etm.next(h1),etm)), + etm.point(source(h1,etm))) == CGAL::POSITIVE) { - if( CGAL::coplanar(etm.point(source(h1,etm)), - etm.point(target(h1,etm)), - etm.point(target(etm.next(h1),etm)), - etm.point(source(h1,etm))) && - CGAL::coplanar_orientation(etm.point(source(h1,etm)), - etm.point(target(h1,etm)), - etm.point(target(etm.next(h1),etm)), - etm.point(source(h1,etm))) == CGAL::POSITIVE) - { #ifdef CGAL_DEBUG_PMP_AUTOREFINE - verbose_fail_msg(5, p); -#endif - return false; - } - return true; - } - else - { - // TODO: 2 identical border vertices, no common edge on the boundary. Not sure what to do -#ifdef CGAL_DEBUG_PMP_AUTOREFINE - verbose_fail_msg(6, p); + verbose_fail_msg(3, p); #endif return false; } + return true; } default: // size == 3 return true; From 944475f169213f38a04637480f0be7aaa080b98c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 2 Jan 2023 19:38:38 +0100 Subject: [PATCH 07/99] triangulate input faces --- .../examples/Polygon_mesh_processing/soup_autorefinement.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index fa1f5d68690..8ca983aa31c 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -30,6 +31,7 @@ int main(int argc, char** argv) Mesh mesh; PMP::orient_polygon_soup(input_points, input_triangles); PMP::polygon_soup_to_polygon_mesh(input_points, input_triangles, mesh); + PMP::triangulate_faces(mesh); PMP::autorefine(mesh); From 2b77fcd094859cd07853b1ae02434b05d5a277a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 3 Jan 2023 18:22:14 +0100 Subject: [PATCH 08/99] faster implementation + fix intersection segments + check --- .../Polygon_mesh_processing/autorefinement.h | 244 ++++++++++-------- 1 file changed, 132 insertions(+), 112 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index fd5e7312c26..01188d4d6b1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -26,7 +27,7 @@ #include #include -#ifndef NDEBUG +#ifdef CGAL_DEBUG_PMP_AUTOREFINE // debug #include #endif @@ -46,12 +47,42 @@ void generate_subtriangles(const typename EK::Triangle_3& t, std::vector& new_triangles) { typedef CGAL::Projection_traits_3 P_traits; - // typedef CGAL::Exact_intersections_tag Itag; - typedef CGAL::No_constraint_intersection_requiring_constructions_tag Itag; - typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; + typedef CGAL::Exact_intersections_tag Itag; + //typedef CGAL::No_constraint_intersection_requiring_constructions_tag Itag; + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_base; + typedef CGAL::Constrained_triangulation_plus_2 CDT; + typename EK::Vector_3 n = normal(t[0], t[1], t[2]); + //~ bool orientation_flipped = false; + //~ if (n.x() < 0) + //~ { + //~ orientation_flipped = true; + //~ n = -n; + //~ } + //~ else + //~ { + //~ if (n.x()==0) + //~ { + //~ if (n.y() < 0) + //~ { + //~ orientation_flipped = true; + //~ n = -n; + //~ } + //~ else + //~ { + //~ if (n.y()==0) + //~ { + //~ if (n.z() < 0) + //~ { + //~ orientation_flipped = true; + //~ n = -n; + //~ } + //~ } + //~ } + //~ } + //~ } - P_traits cdt_traits(normal(t[0], t[1], t[2])); + P_traits cdt_traits(n); CDT cdt(cdt_traits); cdt.insert_outside_affine_hull(t[0]); @@ -65,12 +96,41 @@ void generate_subtriangles(const typename EK::Triangle_3& t, for (const typename EK::Point_3& p : points) cdt.insert(p); - for (typename CDT::Face_handle fh : cdt.finite_face_handles()) - { - new_triangles.emplace_back(fh->vertex(0)->point(), - fh->vertex(cdt.ccw(0))->point(), - fh->vertex(cdt.cw(0))->point()); - } + //~ if (orientation_flipped) + //~ for (typename CDT::Face_handle fh : cdt.finite_face_handles()) + //~ { + //~ new_triangles.emplace_back(fh->vertex(0)->point(), + //~ fh->vertex(cdt.cw(0))->point(), + //~ fh->vertex(cdt.ccw(0))->point()); + //~ } + //~ else +#ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS + static int k = 0; + std::stringstream buffer; + buffer.precision(17); + int nbt=0; +#endif + for (typename CDT::Face_handle fh : cdt.finite_face_handles()) + { + new_triangles.emplace_back(fh->vertex(0)->point(), + fh->vertex(cdt.ccw(0))->point(), + fh->vertex(cdt.cw(0))->point()); +#ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS + ++nbt; + buffer << fh->vertex(0)->point() << "\n"; + buffer << fh->vertex(cdt.ccw(0))->point() << "\n"; + buffer << fh->vertex(cdt.cw(0))->point() << "\n"; +#endif + } + +#ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS + std::ofstream dump("triangulation_"+std::to_string(k)+".off"); + dump << "OFF\n" << 3*nbt << " " << nbt << " 0\n"; + dump << buffer.str(); + for (int i=0; i @@ -106,69 +166,31 @@ struct Intersection_visitor void operator()(const typename EK::Triangle_3& t) { - for (std::size_t i=1; i<3; ++i) + for (std::size_t i=0; i<3; ++i) { - typename EK::Segment_3 s(t[i-1], t[i]); + typename EK::Segment_3 s(t[i], t[(i+1)%3]); all_segments_1.push_back(s); all_segments_2.push_back(s); } + } void operator()(const std::vector& poly) { std::size_t nbp = poly.size(); - for (std::size_t i=1; i -bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map is_degen, const std::vector< std::vector>>& triangles) +template +bool is_output_valid(std::vector> soup_points, + std::vector > soup_triangles) { - typedef typename Kernel_traits::value_type>::type IK; - typedef boost::graph_traits Graph_traits; - typedef typename Graph_traits::face_descriptor face_descriptor; - typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor; - - std::vector soup_points; - std::vector > soup_triangles; - Cartesian_converter to_exact; - std::map point_id_map; - - auto get_point_id = [&](const typename EK::Point_3& pt) - { - auto insert_res = point_id_map.insert(std::make_pair(pt, soup_points.size())); - if (insert_res.second) - soup_points.push_back(pt); - return insert_res.first->second; - }; - - for (face_descriptor f : faces(tm)) - { - if (get(is_degen, f)) continue; // skip degenerate faces - int tid = get(tid_map, f); - if (tid == -1) - { - halfedge_descriptor h = halfedge(f, tm); - soup_triangles.emplace_back( - CGAL::make_array(get_point_id(to_exact(get(vpm,source(h, tm)))), - get_point_id(to_exact(get(vpm,target(h, tm)))), - get_point_id(to_exact(get(vpm,target(next(h, tm), tm))))) - ); - } - else - { - for (const typename EK::Triangle_3& t : triangles[tid]) - { - soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); - } - } - } - typedef Surface_mesh Exact_mesh; Exact_mesh etm; orient_polygon_soup(soup_points, soup_triangles); @@ -248,11 +270,11 @@ bool is_output_valid(TriangleMesh& tm , VPM vpm, TID_Map tid_map, Is_degen_map i if( CGAL::coplanar(etm.point(source(h1,etm)), etm.point(target(h1,etm)), etm.point(target(etm.next(h1),etm)), - etm.point(source(h1,etm))) && + etm.point(target(etm.next(h2),etm))) && CGAL::coplanar_orientation(etm.point(source(h1,etm)), etm.point(target(h1,etm)), etm.point(target(etm.next(h1),etm)), - etm.point(source(h1,etm))) == CGAL::POSITIVE) + etm.point(target(etm.next(h2),etm))) == CGAL::POSITIVE) { #ifdef CGAL_DEBUG_PMP_AUTOREFINE verbose_fail_msg(3, p); @@ -346,18 +368,22 @@ void autorefine_soup_output(const TriangleMesh& tm, // init the vector of triangles used for the autorefinement of triangles typedef CGAL::Exact_predicates_exact_constructions_kernel EK; - std::vector< std::vector > triangles(tid+1); + std::vector< EK::Triangle_3 > triangles(tid+1); Cartesian_converter to_exact; for(face_descriptor f : intersected_faces) { halfedge_descriptor h = halfedge(f, tm); - triangles[get(tid_map, f)].emplace_back( + triangles[get(tid_map, f)]= EK::Triangle_3( to_exact( get(vpm, source(h, tm)) ), to_exact( get(vpm, target(h, tm)) ), to_exact( get(vpm, target(next(h, tm), tm)) ) ); } + std::vector< std::vector > all_segments(triangles.size()); + std::vector< std::vector > all_points(triangles.size()); + + typename EK::Intersect_3 intersection = EK().intersect_3_object(); for (const Pair_of_faces& p : si_pairs) { @@ -366,73 +392,59 @@ void autorefine_soup_output(const TriangleMesh& tm, if (i1==-1 || i2==-1) continue; //skip degenerate faces - std::size_t nbt_1 = triangles[i1].size(), - nbt_2 = triangles[i2].size(); + const EK::Triangle_3& t1 = triangles[i1]; + const EK::Triangle_3& t2 = triangles[i2]; - std::vector< std::vector > all_segments_1(nbt_1); - std::vector< std::vector > all_segments_2(nbt_2); - std::vector< std::vector > all_points_1(nbt_1); - std::vector< std::vector > all_points_2(nbt_2); + auto inter = intersection(t1, t2); - std::vector t1_subtriangles, t2_subtriangles; - for (std::size_t it1=0; it1 intersection_visitor(all_segments[i1], all_segments[i2], + all_points[i1], all_points[i2]); - auto inter = intersection(t1, t2); - - if (inter != boost::none) - { - autorefine_impl::Intersection_visitor intersection_visitor(all_segments_1[it1], all_segments_2[it2], - all_points_1[it1], all_points_2[it2]); - - boost::apply_visitor(intersection_visitor, *inter); - } - } + boost::apply_visitor(intersection_visitor, *inter); } - - // now refine triangles - std::vector new_triangles; - for(std::size_t it1=0; it1(triangles[i1][it1], all_segments_1[it1], all_points_1[it1], new_triangles); - } - triangles[i1].swap(new_triangles); - new_triangles.clear(); - for(std::size_t it2=0; it2(triangles[i2][it2], all_segments_2[it2], all_points_2[it2], new_triangles); - } - triangles[i2].swap(new_triangles); } - CGAL_assertion( autorefine_impl::is_output_valid(tm, vpm, tid_map, is_degen, triangles) ); + // now refine triangles + std::vector new_triangles; + for(std::size_t ti=0; ti(triangles[ti], all_segments[ti], all_points[ti], new_triangles); + } + // brute force output: create a soup, orient and to-mesh - // WARNING: there is no reason when using double that identical exact points are identical in double Cartesian_converter to_input; std::map point_id_map; +#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) + std::vector exact_soup_points; +#endif for (vertex_descriptor v : vertices(tm)) { if (point_id_map.insert(std::make_pair(to_exact(get(vpm,v)), soup_points.size())).second) + { soup_points.push_back(get(vpm,v)); +#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) + exact_soup_points.push_back(to_exact(get(vpm,v))); +#endif + } } auto get_point_id = [&](const typename EK::Point_3& pt) { auto insert_res = point_id_map.insert(std::make_pair(pt, soup_points.size())); if (insert_res.second) + { soup_points.push_back(to_input(pt)); +#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) + exact_soup_points.push_back(pt); +#endif + } return insert_res.first->second; }; @@ -450,14 +462,22 @@ void autorefine_soup_output(const TriangleMesh& tm, get_point_id(to_exact(get(vpm,target(next(h, tm), tm))))) ); } - else - { - for (const typename EK::Triangle_3& t : triangles[tid]) - { - soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); - } - } } + for (const typename EK::Triangle_3& t : new_triangles) + { + soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); + } + + +#ifndef CGAL_NDEBUG + CGAL_assertion( autorefine_impl::is_output_valid(exact_soup_points, soup_triangles) ); +#endif + +#ifdef CGAL_DEBUG_PMP_AUTOREFINE + autorefine_impl::is_output_valid(exact_soup_points, soup_triangles); + throw std::runtime_error("invalid output"); +#endif + } #endif From d92d37c476c40e909db3b8a27b20e3968c4e1f28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 3 Jan 2023 18:44:52 +0100 Subject: [PATCH 09/99] fix condition --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 01188d4d6b1..d18826fc2f1 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -474,7 +474,7 @@ void autorefine_soup_output(const TriangleMesh& tm, #endif #ifdef CGAL_DEBUG_PMP_AUTOREFINE - autorefine_impl::is_output_valid(exact_soup_points, soup_triangles); + if (!autorefine_impl::is_output_valid(exact_soup_points, soup_triangles)) throw std::runtime_error("invalid output"); #endif From 34e8d7ee420489459d88a90a83a277cc9e071caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 4 Jan 2023 16:51:55 +0100 Subject: [PATCH 10/99] disable CDT+ that is slower and add debug --- .../Polygon_mesh_processing/autorefinement.h | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index d18826fc2f1..3ec80745042 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -32,6 +32,10 @@ #include #endif +#ifndef CGAL_PMP_AUTOREFINE_VERBOSE +#define CGAL_PMP_AUTOREFINE_VERBOSE(MSG) +#endif + #include namespace CGAL { @@ -49,8 +53,12 @@ void generate_subtriangles(const typename EK::Triangle_3& t, typedef CGAL::Projection_traits_3 P_traits; typedef CGAL::Exact_intersections_tag Itag; //typedef CGAL::No_constraint_intersection_requiring_constructions_tag Itag; - typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_base; - typedef CGAL::Constrained_triangulation_plus_2 CDT; + + + //typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_base; + //typedef CGAL::Constrained_triangulation_plus_2 CDT; + + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; typename EK::Vector_3 n = normal(t[0], t[1], t[2]); //~ bool orientation_flipped = false; @@ -329,6 +337,7 @@ void autorefine_soup_output(const TriangleMesh& tm, std::vector si_pairs; // collect intersecting pairs of triangles + CGAL_PMP_AUTOREFINE_VERBOSE("collect intersecting pairs"); self_intersections(tm, std::back_inserter(si_pairs), np); if (si_pairs.empty()) return; @@ -384,6 +393,7 @@ void autorefine_soup_output(const TriangleMesh& tm, std::vector< std::vector > all_points(triangles.size()); + CGAL_PMP_AUTOREFINE_VERBOSE("compute intersections"); typename EK::Intersect_3 intersection = EK().intersect_3_object(); for (const Pair_of_faces& p : si_pairs) { @@ -406,6 +416,7 @@ void autorefine_soup_output(const TriangleMesh& tm, } } + CGAL_PMP_AUTOREFINE_VERBOSE("triangulate faces"); // now refine triangles std::vector new_triangles; for(std::size_t ti=0; ti to_input; std::map point_id_map; #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) @@ -468,16 +480,17 @@ void autorefine_soup_output(const TriangleMesh& tm, soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); } - #ifndef CGAL_NDEBUG + CGAL_PMP_AUTOREFINE_VERBOSE("check soup"); CGAL_assertion( autorefine_impl::is_output_valid(exact_soup_points, soup_triangles) ); #endif #ifdef CGAL_DEBUG_PMP_AUTOREFINE + CGAL_PMP_AUTOREFINE_VERBOSE("check soup"); if (!autorefine_impl::is_output_valid(exact_soup_points, soup_triangles)) throw std::runtime_error("invalid output"); #endif - + CGAL_PMP_AUTOREFINE_VERBOSE("done"); } #endif From e94c7be4aa72ca2b481e15265ec30f5bad92abec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 5 Jan 2023 08:44:32 +0100 Subject: [PATCH 11/99] update doc + TODOs --- .../Polygon_mesh_processing/autorefinement.h | 31 +++---------------- 1 file changed, 4 insertions(+), 27 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 3ec80745042..0711ad71e21 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1,3 +1,5 @@ +//TODO: add for soup face the id of the input face. not sure it is easy to report intersection edge as a pair of vertex id + // Copyright (c) 2023 GeometryFactory (France). // All rights reserved. // @@ -347,6 +349,7 @@ void autorefine_soup_output(const TriangleMesh& tm, typedef typename boost::property_map::const_type Is_degen_map; Is_degen_map is_degen = get(Degen_property_tag(), tm); +// TODO: we already have this test in bbox inter when it report (f,f) for(face_descriptor f : faces(tm)) put(is_degen, f, is_degenerate_triangle_face(f, tm, np)); @@ -496,10 +499,7 @@ void autorefine_soup_output(const TriangleMesh& tm, /** * \ingroup PMP_corefinement_grp - * \link coref_def_subsec autorefines \endlink `tm`. Refines a triangle mesh - * so that no triangles intersects in their interior. - * Self-intersection edges will be marked as constrained. If an edge that was marked as - * constrained is split, its sub-edges will be marked as constrained as well. + * refines a triangle mesh so that no triangles intersects in their interior. * * @tparam TriangleMesh a model of `HalfedgeListGraph`, `FaceListGraph`, and `MutableFaceGraph` * @tparam NamedParameters a sequence of \ref namedparameters @@ -524,29 +524,6 @@ void autorefine_soup_output(const TriangleMesh& tm, * must be available in `TriangleMesh`.} * \cgalParamNEnd * - * \cgalParamNBegin{edge_is_constrained_map} - * \cgalParamDescription{a property map containing the constrained-or-not status of each edge of `tm`} - * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%edge_descriptor` - * as key type and `bool` as value type} - * \cgalParamDefault{a constant property map returning `false` for any edge} - * \cgalParamNEnd - * - * \cgalParamNBegin{face_index_map} - * \cgalParamDescription{a property map associating to each face of `tm` a unique index between `0` and `num_faces(tm) - 1`} - * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%face_descriptor` - * as key type and `std::size_t` as value type} - * \cgalParamDefault{an automatically indexed internal map} - * \cgalParamExtra{If the property map is writable, the indices of the faces of `tm1` and `tm2` - * will be set after the corefinement is done.} - * \cgalParamNEnd - * - * \cgalParamNBegin{visitor} - * \cgalParamDescription{a visitor used to track the creation of new faces} - * \cgalParamType{a class model of `PMPCorefinementVisitor`} - * \cgalParamDefault{`Corefinement::Default_visitor`} - * \cgalParamNEnd - * \cgalNamedParamsEnd - * */ template From 370d9134a08db1f422e6038dfa7e94ea695efea2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 9 Jan 2023 17:59:56 +0100 Subject: [PATCH 12/99] use insertion by range --- .../CGAL/Polygon_mesh_processing/autorefinement.h | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 0711ad71e21..b2786386205 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -54,13 +54,10 @@ void generate_subtriangles(const typename EK::Triangle_3& t, { typedef CGAL::Projection_traits_3 P_traits; typedef CGAL::Exact_intersections_tag Itag; - //typedef CGAL::No_constraint_intersection_requiring_constructions_tag Itag; - - //typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_base; + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_2; //typedef CGAL::Constrained_triangulation_plus_2 CDT; - - typedef CGAL::Constrained_Delaunay_triangulation_2 CDT; + typedef CDT_2 CDT; typename EK::Vector_3 n = normal(t[0], t[1], t[2]); //~ bool orientation_flipped = false; @@ -100,11 +97,9 @@ void generate_subtriangles(const typename EK::Triangle_3& t, typename CDT::Vertex_handle v = cdt.tds().insert_dim_up(cdt.infinite_vertex(), false); v->set_point(t[2]); - for (const typename EK::Segment_3& s : segments) - cdt.insert_constraint(s[0], s[1]); + cdt.insert_constraints(segments.begin(), segments.end()); + cdt.insert(points.begin(), points.end()); - for (const typename EK::Point_3& p : points) - cdt.insert(p); //~ if (orientation_flipped) //~ for (typename CDT::Face_handle fh : cdt.finite_face_handles()) From 9ba370a22902afb08d0af7629b7383bba785ac57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 10 Jan 2023 14:40:02 +0100 Subject: [PATCH 13/99] use a canonical orientation --- .../Polygon_mesh_processing/autorefinement.h | 58 ++++++------------- 1 file changed, 17 insertions(+), 41 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index b2786386205..881ffcc8796 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -60,55 +60,26 @@ void generate_subtriangles(const typename EK::Triangle_3& t, typedef CDT_2 CDT; typename EK::Vector_3 n = normal(t[0], t[1], t[2]); - //~ bool orientation_flipped = false; - //~ if (n.x() < 0) - //~ { - //~ orientation_flipped = true; - //~ n = -n; - //~ } - //~ else - //~ { - //~ if (n.x()==0) - //~ { - //~ if (n.y() < 0) - //~ { - //~ orientation_flipped = true; - //~ n = -n; - //~ } - //~ else - //~ { - //~ if (n.y()==0) - //~ { - //~ if (n.z() < 0) - //~ { - //~ orientation_flipped = true; - //~ n = -n; - //~ } - //~ } - //~ } - //~ } - //~ } + typename EK::Point_3 o(0,0,0); + + bool orientation_flipped = false; + if ( typename EK::Less_xyz_3()(o+n,o) ) + { + n=-n; + orientation_flipped = true; + } P_traits cdt_traits(n); CDT cdt(cdt_traits); cdt.insert_outside_affine_hull(t[0]); cdt.insert_outside_affine_hull(t[1]); - typename CDT::Vertex_handle v = cdt.tds().insert_dim_up(cdt.infinite_vertex(), false); + typename CDT::Vertex_handle v = cdt.tds().insert_dim_up(cdt.infinite_vertex(), orientation_flipped); v->set_point(t[2]); cdt.insert_constraints(segments.begin(), segments.end()); cdt.insert(points.begin(), points.end()); - - //~ if (orientation_flipped) - //~ for (typename CDT::Face_handle fh : cdt.finite_face_handles()) - //~ { - //~ new_triangles.emplace_back(fh->vertex(0)->point(), - //~ fh->vertex(cdt.cw(0))->point(), - //~ fh->vertex(cdt.ccw(0))->point()); - //~ } - //~ else #ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS static int k = 0; std::stringstream buffer; @@ -117,9 +88,14 @@ void generate_subtriangles(const typename EK::Triangle_3& t, #endif for (typename CDT::Face_handle fh : cdt.finite_face_handles()) { - new_triangles.emplace_back(fh->vertex(0)->point(), - fh->vertex(cdt.ccw(0))->point(), - fh->vertex(cdt.cw(0))->point()); + if (orientation_flipped) + new_triangles.emplace_back(fh->vertex(0)->point(), + fh->vertex(cdt.cw(0))->point(), + fh->vertex(cdt.ccw(0))->point()); + else + new_triangles.emplace_back(fh->vertex(0)->point(), + fh->vertex(cdt.ccw(0))->point(), + fh->vertex(cdt.cw(0))->point()); #ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS ++nbt; buffer << fh->vertex(0)->point() << "\n"; From f9668e279f5f7f2acb49a735adb9f6c15e110841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 11 Jan 2023 11:14:05 +0100 Subject: [PATCH 14/99] use self-intersection test for soup for checking the validity of the output on some cases it seems twice faster --- .../Polygon_mesh_processing/autorefinement.h | 122 +----------------- 1 file changed, 4 insertions(+), 118 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 881ffcc8796..9393e197a19 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -29,11 +29,6 @@ #include #include -#ifdef CGAL_DEBUG_PMP_AUTOREFINE -// debug -#include -#endif - #ifndef CGAL_PMP_AUTOREFINE_VERBOSE #define CGAL_PMP_AUTOREFINE_VERBOSE(MSG) #endif @@ -168,115 +163,6 @@ struct Intersection_visitor } }; -template -bool is_output_valid(std::vector> soup_points, - std::vector > soup_triangles) -{ - typedef Surface_mesh Exact_mesh; - Exact_mesh etm; - orient_polygon_soup(soup_points, soup_triangles); - polygon_soup_to_polygon_mesh(soup_points, soup_triangles, etm); - -#ifdef CGAL_DEBUG_PMP_AUTOREFINE - std::cerr << std::setprecision(17); - auto verbose_fail_msg = [&](int i, const std::pair& p) - { - typename Exact_mesh::Halfedge_index h1 = halfedge(p.first, etm), h2 = halfedge(p.second, etm); - std::cerr << "DEBUG: failing at check #" << i << "\n"; - std::cerr << "DEBUG: " << etm.point(source(h1, etm)) << " " << etm.point(target(h1, etm)) << " " << etm.point(target(next(h1, etm), etm)) << " " << etm.point(source(h1, etm)) << "\n"; - std::cerr << "DEBUG: " << etm.point(source(h2, etm)) << " " << etm.point(target(h2, etm)) << " " << etm.point(target(next(h2, etm), etm)) << " " << etm.point(source(h2, etm)) << "\n"; - }; -#endif - - //TODO: double check me - auto skip_faces = [&](const std::pair& p) - { - typename Exact_mesh::Halfedge_index h1 = etm.halfedge(p.first), h2=etm.halfedge(p.second); - - boost::container::small_vector v1; - v1.push_back(prev(h1, etm)); - v1.push_back(h1); - v1.push_back(next(h1, etm)); - - boost::container::small_vector v2; - v2.push_back(prev(h2, etm)); - v2.push_back(h2); - v2.push_back(next(h2, etm)); - - //collect identical vertices - boost::container::small_vector, 3> common; - for(typename Exact_mesh::Halfedge_index h1 : v1) - for(typename Exact_mesh::Halfedge_index h2 : v2) - if (etm.point(target(h1, etm))==etm.point(target(h2,etm))) - common.push_back(std::make_pair(h1,h2)); - - if (common.empty()) - { -#ifdef CGAL_DEBUG_PMP_AUTOREFINE - verbose_fail_msg(1, p); -#endif - return false; - } - - switch (common.size()) - { - case 1: - { - // geometric check if the opposite segments intersect the triangles - const typename EK::Triangle_3 t1(etm.point(source(h1,etm)), - etm.point(target(h1,etm)), - etm.point(target(next(h1,etm),etm))); - const typename EK::Triangle_3 t2(etm.point(source(h2,etm)), - etm.point(target(h2,etm)), - etm.point(target(next(h2,etm),etm))); - - const typename EK::Segment_3 s1(etm.point(source(common[0].first,etm)), etm.point(target(next(common[0].first,etm),etm))); - const typename EK::Segment_3 s2(etm.point(source(common[0].second,etm)), etm.point(target(next(common[0].second,etm),etm))); - - if(do_intersect(t1, s2) || do_intersect(t2, s1)) - { -#ifdef CGAL_DEBUG_PMP_AUTOREFINE - verbose_fail_msg(2, p); -#endif - return false; - } - return true; - } - case 2: - { - // shared edge - h1 = next(common[0].first, etm) == common[1].first ? common[1].first : common[0].first; - h2 = next(common[0].second, etm) == common[1].second ? common[1].second : common[0].second; - - if( CGAL::coplanar(etm.point(source(h1,etm)), - etm.point(target(h1,etm)), - etm.point(target(etm.next(h1),etm)), - etm.point(target(etm.next(h2),etm))) && - CGAL::coplanar_orientation(etm.point(source(h1,etm)), - etm.point(target(h1,etm)), - etm.point(target(etm.next(h1),etm)), - etm.point(target(etm.next(h2),etm))) == CGAL::POSITIVE) - { -#ifdef CGAL_DEBUG_PMP_AUTOREFINE - verbose_fail_msg(3, p); -#endif - return false; - } - return true; - } - default: // size == 3 - return true; - } - }; - - std::vector< std::pair > si_faces; - self_intersections(etm, - CGAL::filter_output_iterator(std::back_inserter(si_faces), - skip_faces)); - - return si_faces.empty(); -} - } // end of autorefine_impl template @@ -456,13 +342,13 @@ void autorefine_soup_output(const TriangleMesh& tm, #ifndef CGAL_NDEBUG CGAL_PMP_AUTOREFINE_VERBOSE("check soup"); - CGAL_assertion( autorefine_impl::is_output_valid(exact_soup_points, soup_triangles) ); -#endif - + CGAL_assertion( !does_triangle_soup_self_intersect(exact_soup_points, soup_triangles) ); +#else #ifdef CGAL_DEBUG_PMP_AUTOREFINE CGAL_PMP_AUTOREFINE_VERBOSE("check soup"); - if (!autorefine_impl::is_output_valid(exact_soup_points, soup_triangles)) + if (does_triangle_soup_self_intersect(exact_soup_points, soup_triangles)) throw std::runtime_error("invalid output"); +#endif #endif CGAL_PMP_AUTOREFINE_VERBOSE("done"); } From 7d1582ddbb9ad7bf6e7d8872eb08101254b7e68a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 11 Jan 2023 14:00:32 +0100 Subject: [PATCH 15/99] avoid doing twice the degenerate test --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 9393e197a19..283e139eb1c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -206,9 +206,11 @@ void autorefine_soup_output(const TriangleMesh& tm, typedef typename boost::property_map::const_type Is_degen_map; Is_degen_map is_degen = get(Degen_property_tag(), tm); -// TODO: we already have this test in bbox inter when it report (f,f) for(face_descriptor f : faces(tm)) - put(is_degen, f, is_degenerate_triangle_face(f, tm, np)); + put(is_degen, f, false); + for (const Pair_of_faces& p : si_pairs) + if (p.first==p.second) // bbox inter reports (f,f) for degenerate faces + put(is_degen, p.first, true); // assign an id per triangle involved in an intersection // + the faces involved in the intersection From 822e65b3cf93b51855d14349d96cdbcf09cff85f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 13 Jan 2023 09:35:51 +0100 Subject: [PATCH 16/99] build visitor once for all --- .../Polygon_mesh_processing/autorefinement.h | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 283e139eb1c..ea1c0de07eb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -54,6 +54,7 @@ void generate_subtriangles(const typename EK::Triangle_3& t, //typedef CGAL::Constrained_triangulation_plus_2 CDT; typedef CDT_2 CDT; + // positive triangle normal typename EK::Vector_3 n = normal(t[0], t[1], t[2]); typename EK::Point_3 o(0,0,0); @@ -112,32 +113,32 @@ void generate_subtriangles(const typename EK::Triangle_3& t, template struct Intersection_visitor { - std::vector& all_segments_1; - std::vector& all_segments_2; - std::vector& all_points_1; - std::vector& all_points_2; + std::vector< std::vector >& all_segments; + std::vector< std::vector >& all_points; + std::pair ids; - Intersection_visitor(std::vector& all_segments_1, - std::vector& all_segments_2, - std::vector& all_points_1, - std::vector& all_points_2) - : all_segments_1(all_segments_1) - , all_segments_2(all_segments_2) - , all_points_1(all_points_1) - , all_points_2(all_points_2) + Intersection_visitor(std::vector< std::vector >& all_segments, + std::vector< std::vector >& all_points) + : all_segments (all_segments) + , all_points(all_points) {} + void set_triangle_ids(int i1, int i2) + { + ids = {i1, i2}; + } + typedef void result_type; void operator()(const typename EK::Point_3& p) { - all_points_1.push_back(p); - all_points_2.push_back(p); + all_points[ids.first].push_back(p); + all_points[ids.second].push_back(p); } void operator()(const typename EK::Segment_3& s) { - all_segments_1.push_back(s); - all_segments_2.push_back(s); + all_segments[ids.first].push_back(s); + all_segments[ids.second].push_back(s); } void operator()(const typename EK::Triangle_3& t) @@ -145,8 +146,8 @@ struct Intersection_visitor for (std::size_t i=0; i<3; ++i) { typename EK::Segment_3 s(t[i], t[(i+1)%3]); - all_segments_1.push_back(s); - all_segments_2.push_back(s); + all_segments[ids.first].push_back(s); + all_segments[ids.second].push_back(s); } } @@ -157,8 +158,8 @@ struct Intersection_visitor for (std::size_t i=0; i > all_segments(triangles.size()); std::vector< std::vector > all_points(triangles.size()); - CGAL_PMP_AUTOREFINE_VERBOSE("compute intersections"); typename EK::Intersect_3 intersection = EK().intersect_3_object(); + autorefine_impl::Intersection_visitor intersection_visitor(all_segments, all_points); + for (const Pair_of_faces& p : si_pairs) { int i1 = get(tid_map, p.first), @@ -271,9 +273,7 @@ void autorefine_soup_output(const TriangleMesh& tm, if (inter != boost::none) { - autorefine_impl::Intersection_visitor intersection_visitor(all_segments[i1], all_segments[i2], - all_points[i1], all_points[i2]); - + intersection_visitor.set_triangle_ids(i1, i2); boost::apply_visitor(intersection_visitor, *inter); } } From 9c2de3ee7974a1ccd5e72c73bbf60e03366d5523 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 13 Jan 2023 11:42:14 +0100 Subject: [PATCH 17/99] handle soup as input --- .../Polygon_mesh_processing/autorefinement.h | 125 ++++++++---------- 1 file changed, 54 insertions(+), 71 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index ea1c0de07eb..290dde25332 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -28,6 +28,7 @@ // output #include #include +#include #ifndef CGAL_PMP_AUTOREFINE_VERBOSE #define CGAL_PMP_AUTOREFINE_VERBOSE(MSG) @@ -166,8 +167,9 @@ struct Intersection_visitor } // end of autorefine_impl -template -void autorefine_soup_output(const TriangleMesh& tm, +template +void autorefine_soup_output(const PointRange& input_points, + const TriIdsRange& id_triples, std::vector& soup_points, std::vector >& soup_triangles, const NamedParameters& np = parameters::default_values()) @@ -175,12 +177,9 @@ void autorefine_soup_output(const TriangleMesh& tm, using parameters::choose_parameter; using parameters::get_parameter; - typedef typename GetGeomTraits::type GT; - GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); - - typedef typename GetVertexPointMap::const_type VPM; - VPM vpm = choose_parameter(get_parameter(np, internal_np::vertex_point), - get_const_property_map(vertex_point, tm)); + typedef typename GetPolygonSoupGeomTraits::type GT; + typedef typename GetPointMap::const_type Point_map; + Point_map pm = choose_parameter(get_parameter(np, internal_np::point_map)); typedef typename internal_np::Lookup_named_param_def < internal_np::concurrency_tag_t, @@ -188,68 +187,54 @@ void autorefine_soup_output(const TriangleMesh& tm, Sequential_tag > ::type Concurrency_tag; - typedef boost::graph_traits Graph_traits; - typedef typename Graph_traits::face_descriptor face_descriptor; - typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor; - typedef typename Graph_traits::vertex_descriptor vertex_descriptor; - typedef std::pair Pair_of_faces; + typedef std::size_t Input_TID; + typedef std::pair Pair_of_triangle_ids; - std::vector si_pairs; + std::vector si_pairs; // collect intersecting pairs of triangles CGAL_PMP_AUTOREFINE_VERBOSE("collect intersecting pairs"); - self_intersections(tm, std::back_inserter(si_pairs), np); + triangle_soup_self_intersections(input_points, id_triples, std::back_inserter(si_pairs), np); if (si_pairs.empty()) return; // mark degenerate faces so that we can ignore them - typedef CGAL::dynamic_face_property_t Degen_property_tag; - typedef typename boost::property_map::const_type Is_degen_map; - Is_degen_map is_degen = get(Degen_property_tag(), tm); + std::vector is_degen(id_triples.size(), false); - for(face_descriptor f : faces(tm)) - put(is_degen, f, false); - for (const Pair_of_faces& p : si_pairs) + for (const Pair_of_triangle_ids& p : si_pairs) if (p.first==p.second) // bbox inter reports (f,f) for degenerate faces - put(is_degen, p.first, true); + is_degen[p.first] = true; // assign an id per triangle involved in an intersection // + the faces involved in the intersection - typedef CGAL::dynamic_face_property_t TID_property_tag; - typedef typename boost::property_map::const_type Triangle_id_map; - - Triangle_id_map tid_map = get(TID_property_tag(), tm); - for (face_descriptor f : faces(tm)) - put(tid_map, f, -1); - - std::vector intersected_faces; - int tid=-1; - for (const Pair_of_faces& p : si_pairs) + std::vector tri_inter_ids(id_triples.size(), -1); + std::vector intersected_faces; + int tiid=-1; + for (const Pair_of_triangle_ids& p : si_pairs) { - if (get(tid_map, p.first)==-1 && !get(is_degen, p.first)) + if (tri_inter_ids[p.first]==-1 && !is_degen[p.first]) { - put(tid_map, p.first, ++tid); + tri_inter_ids[p.first]=++tiid; intersected_faces.push_back(p.first); } - if (get(tid_map, p.second)==-1 && !get(is_degen, p.second)) + if (tri_inter_ids[p.second]==-1 && !is_degen[p.second]) { - put(tid_map, p.second, ++tid); + tri_inter_ids[p.second]=++tiid; intersected_faces.push_back(p.second); } } // init the vector of triangles used for the autorefinement of triangles typedef CGAL::Exact_predicates_exact_constructions_kernel EK; - std::vector< EK::Triangle_3 > triangles(tid+1); + std::vector< EK::Triangle_3 > triangles(tiid+1); Cartesian_converter to_exact; - for(face_descriptor f : intersected_faces) + for(Input_TID f : intersected_faces) { - halfedge_descriptor h = halfedge(f, tm); - triangles[get(tid_map, f)]= EK::Triangle_3( - to_exact( get(vpm, source(h, tm)) ), - to_exact( get(vpm, target(h, tm)) ), - to_exact( get(vpm, target(next(h, tm), tm)) ) ); + triangles[tri_inter_ids[f]]= EK::Triangle_3( + to_exact( get(pm, input_points[id_triples[f][0]]) ), + to_exact( get(pm, input_points[id_triples[f][1]]) ), + to_exact( get(pm, input_points[id_triples[f][2]]) ) ); } std::vector< std::vector > all_segments(triangles.size()); @@ -259,10 +244,10 @@ void autorefine_soup_output(const TriangleMesh& tm, typename EK::Intersect_3 intersection = EK().intersect_3_object(); autorefine_impl::Intersection_visitor intersection_visitor(all_segments, all_points); - for (const Pair_of_faces& p : si_pairs) + for (const Pair_of_triangle_ids& p : si_pairs) { - int i1 = get(tid_map, p.first), - i2 = get(tid_map, p.second); + int i1 = tri_inter_ids[p.first], + i2 = tri_inter_ids[p.second]; if (i1==-1 || i2==-1) continue; //skip degenerate faces @@ -298,17 +283,6 @@ void autorefine_soup_output(const TriangleMesh& tm, std::vector exact_soup_points; #endif - for (vertex_descriptor v : vertices(tm)) - { - if (point_id_map.insert(std::make_pair(to_exact(get(vpm,v)), soup_points.size())).second) - { - soup_points.push_back(get(vpm,v)); -#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) - exact_soup_points.push_back(to_exact(get(vpm,v))); -#endif - } - } - auto get_point_id = [&](const typename EK::Point_3& pt) { auto insert_res = point_id_map.insert(std::make_pair(pt, soup_points.size())); @@ -322,18 +296,22 @@ void autorefine_soup_output(const TriangleMesh& tm, return insert_res.first->second; }; - for (face_descriptor f : faces(tm)) - { - if (get(is_degen, f)) continue; //skip degenerate faces + std::vector input_point_ids; + input_point_ids.reserve(input_points.size()); + for (const auto& p : input_points) + input_point_ids.push_back(get_point_id(to_exact(get(pm,p)))); - int tid = get(tid_map, f); - if (tid == -1) + for (Input_TID f=0; f::type GT; GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); - std::vector soup_points; - std::vector > soup_triangles; + std::vector in_soup_points; + std::vector > in_soup_triangles; + std::vector out_soup_points; + std::vector > out_soup_triangles; - autorefine_soup_output(tm, soup_points, soup_triangles, np); + polygon_mesh_to_polygon_soup(tm, in_soup_points, in_soup_triangles); + + autorefine_soup_output(in_soup_points, in_soup_triangles, + out_soup_points, out_soup_triangles); clear(tm); - orient_polygon_soup(soup_points, soup_triangles); - polygon_soup_to_polygon_mesh(soup_points, soup_triangles, tm); + orient_polygon_soup(out_soup_points, out_soup_triangles); + polygon_soup_to_polygon_mesh(out_soup_points, out_soup_triangles, tm); } From b4887272e85bfde8bebf0093a9169cc897bca5ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 13 Jan 2023 11:56:36 +0100 Subject: [PATCH 18/99] use soup as input/output in example --- .../soup_autorefinement.cpp | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index 8ca983aa31c..297875c9ec8 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -23,19 +23,14 @@ int main(int argc, char** argv) : std::string(argv[1]); std::vector input_points; - std::vector > input_triangles; - + std::vector> input_triangles; CGAL::IO::read_polygon_soup(filename, input_points, input_triangles); - PMP::repair_polygon_soup(input_points, input_triangles); - Mesh mesh; - PMP::orient_polygon_soup(input_points, input_triangles); - PMP::polygon_soup_to_polygon_mesh(input_points, input_triangles, mesh); - PMP::triangulate_faces(mesh); + std::vector output_points; + std::vector> output_triangles; + PMP::autorefine_soup_output(input_points, input_triangles, output_points, output_triangles); - PMP::autorefine(mesh); - - CGAL::IO::write_polygon_mesh("autorefined.off", mesh, CGAL::parameters::stream_precision(17)); + CGAL::IO::write_polygon_soup("autorefined.off", output_points, output_triangles, CGAL::parameters::stream_precision(17)); return 0; } From d979121cd29c42c203609ab3bc4956601e9b0512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 13 Jan 2023 15:41:33 +0100 Subject: [PATCH 19/99] repair soup is still recommanded --- .../examples/Polygon_mesh_processing/soup_autorefinement.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index 297875c9ec8..9ade96e3be8 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -3,7 +3,6 @@ #include #include -#include #include #include #include @@ -25,6 +24,7 @@ int main(int argc, char** argv) std::vector input_points; std::vector> input_triangles; CGAL::IO::read_polygon_soup(filename, input_points, input_triangles); + PMP::repair_polygon_soup(input_points, input_triangles); std::vector output_points; std::vector> output_triangles; From 4bc74c399cac5ce0ac84ba894e1b5e996960d605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 16 Jan 2023 22:59:18 +0100 Subject: [PATCH 20/99] WIP: start improving intersect computation --- .../Polygon_mesh_processing/autorefinement.h | 269 ++++++++++++++++-- 1 file changed, 248 insertions(+), 21 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 290dde25332..80b964ad859 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1,5 +1,5 @@ //TODO: add for soup face the id of the input face. not sure it is easy to report intersection edge as a pair of vertex id - +//TODO: only return intersection segments // Copyright (c) 2023 GeometryFactory (France). // All rights reserved. // @@ -43,21 +43,26 @@ namespace Polygon_mesh_processing { namespace autorefine_impl { template -void generate_subtriangles(const typename EK::Triangle_3& t, - const std::vector& segments, +void generate_subtriangles(std::size_t ti, + std::vector& segments, const std::vector& points, + const std::vector& in_triangle_ids, + const std::set >& intersecting_triangles, + const std::vector& triangles, std::vector& new_triangles) { typedef CGAL::Projection_traits_3 P_traits; typedef CGAL::Exact_intersections_tag Itag; - typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_2; + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_2; //typedef CGAL::Constrained_triangulation_plus_2 CDT; typedef CDT_2 CDT; + const typename EK::Triangle_3& t = triangles[ti]; + // positive triangle normal typename EK::Vector_3 n = normal(t[0], t[1], t[2]); - typename EK::Point_3 o(0,0,0); + typename EK::Point_3 o(CGAL::ORIGIN); bool orientation_flipped = false; if ( typename EK::Less_xyz_3()(o+n,o) ) @@ -74,6 +79,184 @@ void generate_subtriangles(const typename EK::Triangle_3& t, typename CDT::Vertex_handle v = cdt.tds().insert_dim_up(cdt.infinite_vertex(), orientation_flipped); v->set_point(t[2]); +#if 1 + //~ static std::ofstream debug("inter_segments.polylines.txt"); + //~ debug.precision(17); + + // pre-compute segment intersections + if (!segments.empty()) + { + std::size_t nbs = segments.size(); + //~ std::cout << "nbs " << nbs << "\n"; + + //~ if (nbs==8) + //~ { + //~ for (std::size_t i = 0; i > points_on_segments(nbs); + for (std::size_t i = 0; i(&(*res))) + { + points_on_segments[i].push_back(*pt_ptr); + points_on_segments[j].push_back(*pt_ptr); + + //~ std::cout << "new inter " << *pt_ptr << "\n"; + + } + else + { + // We can have hard cases if two triangles are coplanar.... + + //~ std::cout << "coplanar inter: " << i << " " << j << "\n"; + + auto inter = CGAL::intersection(segments[i], segments[j]); + if (const typename EK::Point_3* pt_ptr = boost::get(&(*inter))) + { + points_on_segments[i].push_back(*pt_ptr); + points_on_segments[j].push_back(*pt_ptr); + + //~ std::cout << "new inter bis" << *pt_ptr << "\n"; + } + else + { + if (const typename EK::Segment_3* seg_ptr = boost::get(&(*inter))) + { + points_on_segments[i].push_back(seg_ptr->source()); + points_on_segments[j].push_back(seg_ptr->source()); + points_on_segments[i].push_back(seg_ptr->target()); + points_on_segments[j].push_back(seg_ptr->target()); + + } + else + std::cerr <<"ERROR!\n"; + } + + #if 0 + //this code works if triangles are not coplanar + // coplanar intersection that is not a point + int coord = 0; + const typename EK::Segment_3& s = segments[i]; + typename EK::Point_3 src = s.source(), tgt=s.target(); + if (src.x()==tgt.x()) + { + coord=1; + if (src.y()==tgt.y()) + coord==2; + } + + std::vector tmp_pts = { + src, tgt, segments[j][0], segments[j][1] }; + + std::sort(tmp_pts.begin(), tmp_pts.end(), + [coord](const typename EK::Point_3& p, const typename EK::Point_3& q) + {return p[coord] cst_points; + std::vector> csts; + for (std::size_t i = 0; itgt[coord]) + std::swap(src, tgt); + + std::sort(points_on_segments[i].begin(), points_on_segments[i].end(), [coord](const typename EK::Point_3& p, const typename EK::Point_3& q){return p[coord] no_inter_segments; + no_inter_segments.reserve(nbs); + for (std::size_t i = 0; i >& all_segments; std::vector< std::vector >& all_points; + std::vector< std::vector >& all_in_triangle_ids; std::pair ids; Intersection_visitor(std::vector< std::vector >& all_segments, - std::vector< std::vector >& all_points) + std::vector< std::vector >& all_points, + std::vector< std::vector >& all_in_triangle_ids) : all_segments (all_segments) , all_points(all_points) + , all_in_triangle_ids(all_in_triangle_ids) {} void set_triangle_ids(int i1, int i2) @@ -140,6 +326,8 @@ struct Intersection_visitor { all_segments[ids.first].push_back(s); all_segments[ids.second].push_back(s); + all_in_triangle_ids[ids.first].push_back(ids.second); + all_in_triangle_ids[ids.second].push_back(ids.first); } void operator()(const typename EK::Triangle_3& t) @@ -149,6 +337,8 @@ struct Intersection_visitor typename EK::Segment_3 s(t[i], t[(i+1)%3]); all_segments[ids.first].push_back(s); all_segments[ids.second].push_back(s); + all_in_triangle_ids[ids.first].push_back(ids.second); + all_in_triangle_ids[ids.second].push_back(ids.first); } } @@ -161,6 +351,8 @@ struct Intersection_visitor typename EK::Segment_3 s(poly[i], poly[(i+1)%nbp]); all_segments[ids.first].push_back(s); all_segments[ids.second].push_back(s); + all_in_triangle_ids[ids.first].push_back(ids.second); + all_in_triangle_ids[ids.second].push_back(ids.first); } } }; @@ -239,11 +431,13 @@ void autorefine_soup_output(const PointRange& input_points, std::vector< std::vector > all_segments(triangles.size()); std::vector< std::vector > all_points(triangles.size()); + std::vector< std::vector > all_in_triangle_ids(triangles.size()); CGAL_PMP_AUTOREFINE_VERBOSE("compute intersections"); typename EK::Intersect_3 intersection = EK().intersect_3_object(); - autorefine_impl::Intersection_visitor intersection_visitor(all_segments, all_points); + autorefine_impl::Intersection_visitor intersection_visitor(all_segments, all_points, all_in_triangle_ids); + std::set > intersecting_triangles; for (const Pair_of_triangle_ids& p : si_pairs) { int i1 = tri_inter_ids[p.first], @@ -258,25 +452,13 @@ void autorefine_soup_output(const PointRange& input_points, if (inter != boost::none) { + intersecting_triangles.insert(CGAL::make_sorted_pair(i1, i2)); intersection_visitor.set_triangle_ids(i1, i2); boost::apply_visitor(intersection_visitor, *inter); } } - CGAL_PMP_AUTOREFINE_VERBOSE("triangulate faces"); - // now refine triangles - std::vector new_triangles; - for(std::size_t ti=0; ti(triangles[ti], all_segments[ti], all_points[ti], new_triangles); - } - - - // brute force output: create a soup, orient and to-mesh - CGAL_PMP_AUTOREFINE_VERBOSE("create output soup"); + // deduplicate inserted segments Cartesian_converter to_input; std::map point_id_map; #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) @@ -296,6 +478,51 @@ void autorefine_soup_output(const PointRange& input_points, return insert_res.first->second; }; + // filter duplicated segments + for(std::size_t ti=0; ti filtered_segments; + std::vector filtered_in_triangle_ids; + filtered_segments.reserve(nbs); + std::set> segset; + for (std::size_t si=0; si new_triangles; + for(std::size_t ti=0; ti(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + } + + + // brute force output: create a soup, orient and to-mesh + CGAL_PMP_AUTOREFINE_VERBOSE("create output soup"); + std::vector input_point_ids; input_point_ids.reserve(input_points.size()); for (const auto& p : input_points) From 842b6282b5c7a0b9f9c9551dfa443edd4f5319f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 23 Jan 2023 15:39:01 +0100 Subject: [PATCH 21/99] STILL WIP: copy/paste code for coplanar intersection --- .../Polygon_mesh_processing/autorefinement.h | 44 +++++++++++++++++-- 1 file changed, 40 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 80b964ad859..6d97f7521de 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -36,12 +36,43 @@ #include +#define TEST_RESOLVE_INTERSECTION +#define DEDUPLICATE_SEGMENTS + namespace CGAL { namespace Polygon_mesh_processing { #ifndef DOXYGEN_RUNNING namespace autorefine_impl { +template +bool do_coplanar_segments_intersect(const typename K::Segment_3& s1, + const typename K::Segment_3& s2, + const K& k = K()) +{ + // supporting_line intersects: points are coplanar + typename K::Coplanar_orientation_3 cpl_orient=k.coplanar_orientation_3_object(); + ::CGAL::Orientation or1 = cpl_orient(s1[0], s1[1], s2[0]); + ::CGAL::Orientation or2 = cpl_orient(s1[0], s1[1], s2[1]); + + if(or1 == COLLINEAR && or2 == COLLINEAR) + { + // segments are collinear + typename K::Collinear_are_ordered_along_line_3 cln_order = k.collinear_are_ordered_along_line_3_object(); + return (cln_order(s1[0], s2[0], s1[1]) || + cln_order(s1[0], s2[1], s1[1]) || + cln_order(s2[0], s1[0], s2[1])); + } + + if(or1 != or2) + { + or1 = cpl_orient(s2[0], s2[1], s1[0]); + return (or1 == COLLINEAR || or1 != cpl_orient(s2[0], s2[1], s1[1])); + } + + return false; +} + template void generate_subtriangles(std::size_t ti, std::vector& segments, @@ -54,7 +85,11 @@ void generate_subtriangles(std::size_t ti, typedef CGAL::Projection_traits_3 P_traits; typedef CGAL::Exact_intersections_tag Itag; - typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_2; + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_2; //typedef CGAL::Constrained_triangulation_plus_2 CDT; typedef CDT_2 CDT; @@ -79,7 +114,7 @@ void generate_subtriangles(std::size_t ti, typename CDT::Vertex_handle v = cdt.tds().insert_dim_up(cdt.infinite_vertex(), orientation_flipped); v->set_point(t[2]); -#if 1 +#ifdef TEST_RESOLVE_INTERSECTION //~ static std::ofstream debug("inter_segments.polylines.txt"); //~ debug.precision(17); @@ -102,7 +137,7 @@ void generate_subtriangles(std::size_t ti, { if (intersecting_triangles.count(CGAL::make_sorted_pair(in_triangle_ids[i], in_triangle_ids[j]))!=0) { - if (CGAL::do_intersect(segments[i], segments[j])) + if (do_coplanar_segments_intersect(segments[i], segments[j])) { auto res = CGAL::intersection(triangles[in_triangle_ids[i]].supporting_plane(), triangles[in_triangle_ids[j]].supporting_plane(), @@ -479,6 +514,7 @@ void autorefine_soup_output(const PointRange& input_points, }; // filter duplicated segments +#ifdef DEDUPLICATE_SEGMENTS for(std::size_t ti=0; ti(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); } - // brute force output: create a soup, orient and to-mesh CGAL_PMP_AUTOREFINE_VERBOSE("create output soup"); From 39d7bbc57fee319e45f8c51c75794f7828cc21d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 24 Jan 2023 14:54:20 +0100 Subject: [PATCH 22/99] WIP import intersection computation from coref code --- .../Polygon_mesh_processing/autorefinement.h | 363 +++++++++++++----- 1 file changed, 259 insertions(+), 104 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 6d97f7521de..afbe0c3479d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -36,8 +36,8 @@ #include -#define TEST_RESOLVE_INTERSECTION -#define DEDUPLICATE_SEGMENTS +// #define TEST_RESOLVE_INTERSECTION +// #define DEDUPLICATE_SEGMENTS namespace CGAL { namespace Polygon_mesh_processing { @@ -45,10 +45,13 @@ namespace Polygon_mesh_processing { #ifndef DOXYGEN_RUNNING namespace autorefine_impl { +enum Segment_inter_type { NO_INTERSECTION=0, COPLANAR_SEGMENTS, POINT_INTERSECTION }; + template -bool do_coplanar_segments_intersect(const typename K::Segment_3& s1, - const typename K::Segment_3& s2, - const K& k = K()) +Segment_inter_type +do_coplanar_segments_intersect(const typename K::Segment_3& s1, + const typename K::Segment_3& s2, + const K& k = K()) { // supporting_line intersects: points are coplanar typename K::Coplanar_orientation_3 cpl_orient=k.coplanar_orientation_3_object(); @@ -61,26 +64,207 @@ bool do_coplanar_segments_intersect(const typename K::Segment_3& s1, typename K::Collinear_are_ordered_along_line_3 cln_order = k.collinear_are_ordered_along_line_3_object(); return (cln_order(s1[0], s2[0], s1[1]) || cln_order(s1[0], s2[1], s1[1]) || - cln_order(s2[0], s1[0], s2[1])); + cln_order(s2[0], s1[0], s2[1])) ? COPLANAR_SEGMENTS : NO_INTERSECTION; } if(or1 != or2) { or1 = cpl_orient(s2[0], s2[1], s1[0]); - return (or1 == COLLINEAR || or1 != cpl_orient(s2[0], s2[1], s1[1])); + return (or1 == COLLINEAR || or1 != cpl_orient(s2[0], s2[1], s1[1])) ? POINT_INTERSECTION : NO_INTERSECTION; } - return false; + return NO_INTERSECTION; } +////////////////////////////////// +////////////////////////////////// +////////////////////////////////// +////////////////////////////////// +////////////////////////////////// + +// imported from Polygon_mesh_processing/internal/Corefinement/intersect_triangle_segment_3.h + +template +void +find_intersection(const typename K::Point_3& p, const typename K::Point_3& q, //segment + const typename K::Point_3& a, const typename K::Point_3& b, const typename K::Point_3& c, //triangle + std::vector& inter_pts, + bool is_p_coplanar=false, bool is_q_coplanar=false) // note that in coref this was wrt a halfedge not p/q +{ + Orientation ab=orientation(p,q,a,b); + Orientation bc=orientation(p,q,b,c); + Orientation ca=orientation(p,q,c,a); + + if ( ab==POSITIVE || bc==POSITIVE || ca==POSITIVE ) + return; + + int nb_coplanar=(ab==COPLANAR?1:0) + (bc==COPLANAR?1:0) + (ca==COPLANAR?1:0); + +/* + if ( nb_coplanar==0 ) + return result_type(ON_FACE,hd,is_src_coplanar,is_tgt_coplanar); + + if (nb_coplanar==1){ + if (ab==COPLANAR) + // intersection is ab + return result_type(ON_EDGE,next(hd,tm),is_src_coplanar,is_tgt_coplanar); + if (bc==COPLANAR) + // intersection is bc + return result_type(ON_EDGE,prev(hd,tm),is_src_coplanar,is_tgt_coplanar); + CGAL_assertion(ca==COPLANAR); + // intersection is ca + return result_type(ON_EDGE,hd,is_src_coplanar,is_tgt_coplanar); + } +*/ + + if (is_p_coplanar) + { + inter_pts.push_back(p); + return; + } + if (is_q_coplanar) + { + inter_pts.push_back(q); + return; + } + + if (nb_coplanar!=2) + { + inter_pts.push_back( + typename K::Construct_plane_line_intersection_point_3()(a, b, c, p, q) + ); + } + else + { + if (ab!=COPLANAR) + { + // intersection is c + inter_pts.push_back(c); + return; + } + + if (bc!=COPLANAR) + { + // intersection is a + inter_pts.push_back(a); + return; + } + CGAL_assertion(ca!=COPLANAR); + // intersection is b + inter_pts.push_back(b); + } +} + +template +void test_edge(const typename K::Point_3& p, const typename K::Point_3& q, + const typename K::Point_3& a, const typename K::Point_3& b, const typename K::Point_3& c, + const Orientation abcp, + const Orientation abcq, + std::vector& inter_pts) +{ + switch ( abcp ) { + case POSITIVE: + switch ( abcq ) { + case POSITIVE: + // the segment lies in the positive open halfspaces defined by the + // triangle's supporting plane + break; + case NEGATIVE: + // p sees the triangle in counterclockwise order + find_intersection(p,q,a,b,c,inter_pts); + break; + //case COPLANAR: + default: + // q belongs to the triangle's supporting plane + // p sees the triangle in counterclockwise order + find_intersection(p,q,a,b,c,inter_pts,false,true); + } + break; + case NEGATIVE: + switch ( abcq ) { + case POSITIVE: + // q sees the triangle in counterclockwise order + find_intersection(q,p,a,b,c,inter_pts); + break; + case NEGATIVE: + // the segment lies in the negative open halfspaces defined by the + // triangle's supporting plane + break; + // case COPLANAR: + default: + // q belongs to the triangle's supporting plane + // p sees the triangle in clockwise order + find_intersection(q,p,a,b,c,inter_pts,true,false); + } + break; + default: + //case COPLANAR: // p belongs to the triangle's supporting plane + switch ( abcq ) { + case POSITIVE: + // q sees the triangle in counterclockwise order + find_intersection(q,p,a,b,c,inter_pts,false, true); + break; + case NEGATIVE: + // q sees the triangle in clockwise order + find_intersection(p,q,a,b,c,inter_pts,true); + break; + //case COPLANAR: + default: + // the segment is coplanar with the triangle's supporting plane + // we test whether the segment intersects the triangle in the common + // supporting plane + if ( ::CGAL::Intersections::internal::do_intersect_coplanar(a,b,c,p,q,K()) ) + { + //handle coplanar intersection + // TODO: use coref function + throw std::runtime_error("coplanar intersection"); + return; + } + } + } +} + +template +void collect_intersections(const std::array& t1, + const std::array& t2, + std::vector& inter_pts) +{ + // test edges of t1 vs t2 + std::array ori; + for (int i=0; i<3; ++i) + ori[i] = orientation(t2[0],t2[1],t2[2],t1[i]); + for (int i=0; i<3; ++i) + { + int j=(i+1)%3; + test_edge(t1[i], t1[j], t2[0], t2[1], t2[2], ori[i], ori[j], inter_pts); + if (inter_pts.size()>1) return; + } + + // test edges of t2 vs t1 + for (int i=0; i<3; ++i) + ori[i] = orientation(t1[0],t1[1],t1[2],t2[i]); + for (int i=0; i<3; ++i) + { + int j=(i+1)%3; + test_edge(t2[i], t2[j], t1[0], t1[1], t1[2], ori[i], ori[j], inter_pts); + if (inter_pts.size()>1) return; + } +} + +////////////////////////////////// +////////////////////////////////// +////////////////////////////////// +////////////////////////////////// +////////////////////////////////// + template void generate_subtriangles(std::size_t ti, std::vector& segments, const std::vector& points, const std::vector& in_triangle_ids, const std::set >& intersecting_triangles, - const std::vector& triangles, - std::vector& new_triangles) + const std::vector>& triangles, + std::vector>& new_triangles) { typedef CGAL::Projection_traits_3 P_traits; typedef CGAL::Exact_intersections_tag Itag; @@ -93,7 +277,7 @@ void generate_subtriangles(std::size_t ti, //typedef CGAL::Constrained_triangulation_plus_2 CDT; typedef CDT_2 CDT; - const typename EK::Triangle_3& t = triangles[ti]; + const std::array& t = triangles[ti]; // positive triangle normal typename EK::Vector_3 n = normal(t[0], t[1], t[2]); @@ -130,6 +314,11 @@ void generate_subtriangles(std::size_t ti, //~ std::ofstream("cst_"+std::to_string(i)+".polylines.txt") << std::setprecision(17) << "2 " << segments[i] << "\n"; //~ } + auto supporting_plane = [](const std::array& t) + { + return typename EK::Plane_3(t[0], t[1], t[2]); + }; + std::vector< std::vector > points_on_segments(nbs); for (std::size_t i = 0; i(segments[i], segments[j])) + Segment_inter_type seg_inter_type = do_coplanar_segments_intersect(segments[i], segments[j]); + switch(seg_inter_type) { - auto res = CGAL::intersection(triangles[in_triangle_ids[i]].supporting_plane(), - triangles[in_triangle_ids[j]].supporting_plane(), - triangles[ti].supporting_plane()); - - if (const typename EK::Point_3* pt_ptr = boost::get(&(*res))) + case POINT_INTERSECTION: { - points_on_segments[i].push_back(*pt_ptr); - points_on_segments[j].push_back(*pt_ptr); + auto res = CGAL::intersection(supporting_plane(triangles[in_triangle_ids[i]]), + supporting_plane(triangles[in_triangle_ids[j]]), + supporting_plane(triangles[ti])); - //~ std::cout << "new inter " << *pt_ptr << "\n"; + if (const typename EK::Point_3* pt_ptr = boost::get(&(*res))) + { + points_on_segments[i].push_back(*pt_ptr); + points_on_segments[j].push_back(*pt_ptr); + //~ std::cout << "new inter " << *pt_ptr << "\n"; + + } } - else + // break; No break because of the coplanar case + case COPLANAR_SEGMENTS: { // We can have hard cases if two triangles are coplanar.... //~ std::cout << "coplanar inter: " << i << " " << j << "\n"; auto inter = CGAL::intersection(segments[i], segments[j]); + + if (inter == boost::none) throw std::runtime_error("Unexpected case #2"); + if (const typename EK::Point_3* pt_ptr = boost::get(&(*inter))) { points_on_segments[i].push_back(*pt_ptr); @@ -224,6 +421,9 @@ void generate_subtriangles(std::size_t ti, //~ debug << "4 " << triangles[ti] << " " << triangles[ti][0] << "\n"; //~ exit(1); } + break; + default: + break; } } } @@ -304,13 +504,13 @@ void generate_subtriangles(std::size_t ti, for (typename CDT::Face_handle fh : cdt.finite_face_handles()) { if (orientation_flipped) - new_triangles.emplace_back(fh->vertex(0)->point(), - fh->vertex(cdt.cw(0))->point(), - fh->vertex(cdt.ccw(0))->point()); + new_triangles.push_back( CGAL::make_array(fh->vertex(0)->point(), + fh->vertex(cdt.cw(0))->point(), + fh->vertex(cdt.ccw(0))->point()) ); else - new_triangles.emplace_back(fh->vertex(0)->point(), - fh->vertex(cdt.ccw(0))->point(), - fh->vertex(cdt.cw(0))->point()); + new_triangles.push_back( CGAL::make_array(fh->vertex(0)->point(), + fh->vertex(cdt.ccw(0))->point(), + fh->vertex(cdt.cw(0))->point()) ); #ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS ++nbt; buffer << fh->vertex(0)->point() << "\n"; @@ -329,69 +529,6 @@ void generate_subtriangles(std::size_t ti, #endif } -template -struct Intersection_visitor -{ - std::vector< std::vector >& all_segments; - std::vector< std::vector >& all_points; - std::vector< std::vector >& all_in_triangle_ids; - std::pair ids; - - Intersection_visitor(std::vector< std::vector >& all_segments, - std::vector< std::vector >& all_points, - std::vector< std::vector >& all_in_triangle_ids) - : all_segments (all_segments) - , all_points(all_points) - , all_in_triangle_ids(all_in_triangle_ids) - {} - - void set_triangle_ids(int i1, int i2) - { - ids = {i1, i2}; - } - - typedef void result_type; - void operator()(const typename EK::Point_3& p) - { - all_points[ids.first].push_back(p); - all_points[ids.second].push_back(p); - } - - void operator()(const typename EK::Segment_3& s) - { - all_segments[ids.first].push_back(s); - all_segments[ids.second].push_back(s); - all_in_triangle_ids[ids.first].push_back(ids.second); - all_in_triangle_ids[ids.second].push_back(ids.first); - } - - void operator()(const typename EK::Triangle_3& t) - { - for (std::size_t i=0; i<3; ++i) - { - typename EK::Segment_3 s(t[i], t[(i+1)%3]); - all_segments[ids.first].push_back(s); - all_segments[ids.second].push_back(s); - all_in_triangle_ids[ids.first].push_back(ids.second); - all_in_triangle_ids[ids.second].push_back(ids.first); - } - - } - - void operator()(const std::vector& poly) - { - std::size_t nbp = poly.size(); - for (std::size_t i=0; i @@ -453,24 +590,22 @@ void autorefine_soup_output(const PointRange& input_points, // init the vector of triangles used for the autorefinement of triangles typedef CGAL::Exact_predicates_exact_constructions_kernel EK; - std::vector< EK::Triangle_3 > triangles(tiid+1); + std::vector< std::array > triangles(tiid+1); Cartesian_converter to_exact; for(Input_TID f : intersected_faces) { - triangles[tri_inter_ids[f]]= EK::Triangle_3( + triangles[tri_inter_ids[f]]= CGAL::make_array( to_exact( get(pm, input_points[id_triples[f][0]]) ), to_exact( get(pm, input_points[id_triples[f][1]]) ), to_exact( get(pm, input_points[id_triples[f][2]]) ) ); } - std::vector< std::vector > all_segments(triangles.size()); + std::vector< std::vector > all_segments(triangles.size()); // TODO use std::pair std::vector< std::vector > all_points(triangles.size()); std::vector< std::vector > all_in_triangle_ids(triangles.size()); CGAL_PMP_AUTOREFINE_VERBOSE("compute intersections"); - typename EK::Intersect_3 intersection = EK().intersect_3_object(); - autorefine_impl::Intersection_visitor intersection_visitor(all_segments, all_points, all_in_triangle_ids); std::set > intersecting_triangles; for (const Pair_of_triangle_ids& p : si_pairs) @@ -480,16 +615,36 @@ void autorefine_soup_output(const PointRange& input_points, if (i1==-1 || i2==-1) continue; //skip degenerate faces - const EK::Triangle_3& t1 = triangles[i1]; - const EK::Triangle_3& t2 = triangles[i2]; + const std::array& t1 = triangles[i1]; + const std::array& t2 = triangles[i2]; - auto inter = intersection(t1, t2); + std::vector inter_pts; + autorefine_impl::collect_intersections(t1, t2, inter_pts); - if (inter != boost::none) + if (!inter_pts.empty()) { - intersecting_triangles.insert(CGAL::make_sorted_pair(i1, i2)); - intersection_visitor.set_triangle_ids(i1, i2); - boost::apply_visitor(intersection_visitor, *inter); + std::size_t nbi = inter_pts.size(); + switch(nbi) + { + case 1: + all_points[i1].push_back(inter_pts[0]); + all_points[i2].push_back(inter_pts[0]); + break; + case 2: + all_segments[i1].push_back({inter_pts[0], inter_pts[1]}); + all_segments[i2].push_back({inter_pts[0], inter_pts[1]}); + all_in_triangle_ids[i1].push_back(i2); + all_in_triangle_ids[i2].push_back(i1); + break; + default: + for (std::size_t i=0;i new_triangles; + std::vector> new_triangles; for(std::size_t ti=0; ti& t : new_triangles) { soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); } From 10252faf1df2480f21c25959c1980e68819099a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 24 Jan 2023 16:04:43 +0100 Subject: [PATCH 23/99] WIP use segments --- .../Polygon_mesh_processing/autorefinement.h | 46 ++++++++++--------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index afbe0c3479d..c9bb3f3ffa8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -36,8 +36,8 @@ #include -// #define TEST_RESOLVE_INTERSECTION -// #define DEDUPLICATE_SEGMENTS +//#define TEST_RESOLVE_INTERSECTION +//#define DEDUPLICATE_SEGMENTS namespace CGAL { namespace Polygon_mesh_processing { @@ -49,8 +49,8 @@ enum Segment_inter_type { NO_INTERSECTION=0, COPLANAR_SEGMENTS, POINT_INTERSECTI template Segment_inter_type -do_coplanar_segments_intersect(const typename K::Segment_3& s1, - const typename K::Segment_3& s2, +do_coplanar_segments_intersect(const std::array& s1, + const std::array& s2, const K& k = K()) { // supporting_line intersects: points are coplanar @@ -259,7 +259,7 @@ void collect_intersections(const std::array& t1, template void generate_subtriangles(std::size_t ti, - std::vector& segments, + std::vector>& segments, const std::vector& points, const std::vector& in_triangle_ids, const std::set >& intersecting_triangles, @@ -351,7 +351,9 @@ void generate_subtriangles(std::size_t ti, //~ std::cout << "coplanar inter: " << i << " " << j << "\n"; - auto inter = CGAL::intersection(segments[i], segments[j]); + typename EK::Segment_3 s1(segments[i][0], segments[i][1]); + typename EK::Segment_3 s2(segments[j][0], segments[j][1]);// TODO: avoid this construction + auto inter = CGAL::intersection(s1, s2); if (inter == boost::none) throw std::runtime_error("Unexpected case #2"); @@ -381,7 +383,7 @@ void generate_subtriangles(std::size_t ti, // coplanar intersection that is not a point int coord = 0; const typename EK::Segment_3& s = segments[i]; - typename EK::Point_3 src = s.source(), tgt=s.target(); + typename EK::Point_3 src = s[0], tgt=s[1]; if (src.x()==tgt.x()) { coord=1; @@ -401,10 +403,10 @@ void generate_subtriangles(std::size_t ti, points_on_segments[j].push_back(tmp_pts[1]); points_on_segments[j].push_back(tmp_pts[2]); #endif - //~ std::cout << "new inter coli " << segments[j].source() << "\n"; - //~ std::cout << "new inter coli " << segments[j].target() << "\n"; - //~ std::cout << "new inter coli " << segments[i].source() << "\n"; - //~ std::cout << "new inter coli " << segments[i].target() << "\n"; + //~ std::cout << "new inter coli " << segments[j][0] << "\n"; + //~ std::cout << "new inter coli " << segments[j][1] << "\n"; + //~ std::cout << "new inter coli " << segments[i][0] << "\n"; + //~ std::cout << "new inter coli " << segments[i][1] << "\n"; //~ points_on_segments[j].push_back(*pt_ptr); @@ -437,8 +439,8 @@ void generate_subtriangles(std::size_t ti, { // TODO: predicate on input triangles int coord = 0; - const typename EK::Segment_3& s = segments[i]; - typename EK::Point_3 src = s.source(), tgt=s.target(); + const std::array& s = segments[i]; + typename EK::Point_3 src = s[0], tgt=s[1]; if (src.x()==tgt.x()) { coord=1; @@ -482,7 +484,7 @@ void generate_subtriangles(std::size_t ti, cdt.insert_constraints(cst_points.begin(), cst_points.end(), csts.begin(), csts.end()); - std::vector no_inter_segments; + std::vector> no_inter_segments; no_inter_segments.reserve(nbs); for (std::size_t i = 0; i > all_segments(triangles.size()); // TODO use std::pair + std::vector< std::vector > > all_segments(triangles.size()); std::vector< std::vector > all_points(triangles.size()); std::vector< std::vector > all_in_triangle_ids(triangles.size()); @@ -631,16 +633,16 @@ void autorefine_soup_output(const PointRange& input_points, all_points[i2].push_back(inter_pts[0]); break; case 2: - all_segments[i1].push_back({inter_pts[0], inter_pts[1]}); - all_segments[i2].push_back({inter_pts[0], inter_pts[1]}); + all_segments[i1].push_back(CGAL::make_array(inter_pts[0], inter_pts[1])); + all_segments[i2].push_back(CGAL::make_array(inter_pts[0], inter_pts[1])); all_in_triangle_ids[i1].push_back(i2); all_in_triangle_ids[i2].push_back(i1); break; default: for (std::size_t i=0;i filtered_segments; + std::vector> filtered_segments; std::vector filtered_in_triangle_ids; filtered_segments.reserve(nbs); std::set> segset; for (std::size_t si=0; si Date: Tue, 24 Jan 2023 16:04:54 +0100 Subject: [PATCH 24/99] always std::array as cst --- Triangulation_2/include/CGAL/Constrained_triangulation_2.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Triangulation_2/include/CGAL/Constrained_triangulation_2.h b/Triangulation_2/include/CGAL/Constrained_triangulation_2.h index 42867cfbb07..047c8526afc 100644 --- a/Triangulation_2/include/CGAL/Constrained_triangulation_2.h +++ b/Triangulation_2/include/CGAL/Constrained_triangulation_2.h @@ -330,11 +330,11 @@ public: #if 1 template static decltype(auto) get_source(const Segment_2& segment){ - return segment.source(); + return segment[0]; } template static decltype(auto) get_target(const Segment_2& segment){ - return segment.target(); + return segment[1]; } static const Point& get_source(const Constraint& cst){ From 810715778223710a066d3161e2a4ec453475eaf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 24 Jan 2023 18:04:10 +0100 Subject: [PATCH 25/99] WIP handle coplanar --- .../Polygon_mesh_processing/autorefinement.h | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index c9bb3f3ffa8..f412c2ea298 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -82,8 +82,30 @@ do_coplanar_segments_intersect(const std::array& s1, ////////////////////////////////// ////////////////////////////////// -// imported from Polygon_mesh_processing/internal/Corefinement/intersect_triangle_segment_3.h +// imported from Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h +template +void coplanar_intersections(const std::array& t1, + const std::array& t2, + std::vector& inter_pts) +{ + const typename K::Point_3& p = t1[0], q = t1[1], r = t1[2]; + + std::list l_inter_pts; + l_inter_pts.push_back(t2[0]); + l_inter_pts.push_back(t2[1]); + l_inter_pts.push_back(t2[2]); + + //intersect t2 with the three half planes which intersection defines t1 + K k; + Intersections::internal::intersection_coplanar_triangles_cutoff(p,q,r,k,l_inter_pts); //line pq + Intersections::internal::intersection_coplanar_triangles_cutoff(q,r,p,k,l_inter_pts); //line qr + Intersections::internal::intersection_coplanar_triangles_cutoff(r,p,q,k,l_inter_pts); //line rp + + inter_pts.assign(l_inter_pts.begin(), l_inter_pts.end()); +} + +// imported from Polygon_mesh_processing/internal/Corefinement/intersect_triangle_segment_3.h template void find_intersection(const typename K::Point_3& p, const typename K::Point_3& q, //segment @@ -162,7 +184,7 @@ void test_edge(const typename K::Point_3& p, const typename K::Point_3& q, const Orientation abcq, std::vector& inter_pts) { - switch ( abcp ) { + switch ( abcp ) { case POSITIVE: switch ( abcq ) { case POSITIVE: @@ -213,13 +235,13 @@ void test_edge(const typename K::Point_3& p, const typename K::Point_3& q, // the segment is coplanar with the triangle's supporting plane // we test whether the segment intersects the triangle in the common // supporting plane - if ( ::CGAL::Intersections::internal::do_intersect_coplanar(a,b,c,p,q,K()) ) - { + //if ( ::CGAL::Intersections::internal::do_intersect_coplanar(a,b,c,p,q,K()) ) + //{ //handle coplanar intersection - // TODO: use coref function - throw std::runtime_error("coplanar intersection"); - return; - } + // nothing done as coplanar case handle in collect_intersections + // and other intersection points will be collected with non-coplanar edges + //} + break; } } } @@ -233,6 +255,13 @@ void collect_intersections(const std::array& t1, std::array ori; for (int i=0; i<3; ++i) ori[i] = orientation(t2[0],t2[1],t2[2],t1[i]); + + if (ori[0]== COPLANAR && ori[1]==COPLANAR && ori[2]==COPLANAR) + { + coplanar_intersections(t1, t2, inter_pts); + return; + } + for (int i=0; i<3; ++i) { int j=(i+1)%3; @@ -378,7 +407,7 @@ void generate_subtriangles(std::size_t ti, std::cerr <<"ERROR!\n"; } - #if 0 +#if 0 //this code works if triangles are not coplanar // coplanar intersection that is not a point int coord = 0; From fa662e7dea97c5f33c8872c71817c18f51df0894 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 25 Jan 2023 14:45:12 +0100 Subject: [PATCH 26/99] WIP handle duplicated intersections + add in intersection list --- .../Polygon_mesh_processing/autorefinement.h | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index f412c2ea298..ae9858ae77d 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1,5 +1,5 @@ //TODO: add for soup face the id of the input face. not sure it is easy to report intersection edge as a pair of vertex id -//TODO: only return intersection segments +//TODO: only return intersection segments (pay attention to degenerate triangles that are currently ignored) // Copyright (c) 2023 GeometryFactory (France). // All rights reserved. // @@ -36,8 +36,8 @@ #include -//#define TEST_RESOLVE_INTERSECTION -//#define DEDUPLICATE_SEGMENTS +// #define TEST_RESOLVE_INTERSECTION +// #define DEDUPLICATE_SEGMENTS namespace CGAL { namespace Polygon_mesh_processing { @@ -266,7 +266,7 @@ void collect_intersections(const std::array& t1, { int j=(i+1)%3; test_edge(t1[i], t1[j], t2[0], t2[1], t2[2], ori[i], ori[j], inter_pts); - if (inter_pts.size()>1) return; + //~ if (inter_pts.size()>1) return; } // test edges of t2 vs t1 @@ -276,8 +276,13 @@ void collect_intersections(const std::array& t1, { int j=(i+1)%3; test_edge(t2[i], t2[j], t1[0], t1[1], t1[2], ori[i], ori[j], inter_pts); - if (inter_pts.size()>1) return; + //~ if (inter_pts.size()>1) return; } + + // because we don't handle intersection type and can have edge-edge edge-vertex duplicates + std::sort(inter_pts.begin(), inter_pts.end()); + auto last = std::unique(inter_pts.begin(), inter_pts.end()); + inter_pts.erase(last, inter_pts.end()); } ////////////////////////////////// @@ -288,7 +293,7 @@ void collect_intersections(const std::array& t1, template void generate_subtriangles(std::size_t ti, - std::vector>& segments, + std::vector>& segments, const std::vector& points, const std::vector& in_triangle_ids, const std::set >& intersecting_triangles, @@ -331,6 +336,27 @@ void generate_subtriangles(std::size_t ti, //~ static std::ofstream debug("inter_segments.polylines.txt"); //~ debug.precision(17); + //~ std::cout << "points.size() " << points.size() << "\n"; + //~ std::set all_triangles_indices(in_triangle_ids.begin(), in_triangle_ids.end()); + //~ all_triangles_indices.insert(ti); + + //~ std::ofstream debug("triangles.polylines.txt"); + //~ debug << std::setprecision(17); + //~ for (std::size_t i : all_triangles_indices) + //~ debug << "4 " + //~ << triangles[i][0] << " " + //~ << triangles[i][1] << " " + //~ << triangles[i][2] << " " + //~ << triangles[i][0] << "\n"; + //~ debug.close(); + //~ debug.open("triangle.off"); + //~ debug << std::setprecision(17); + //~ debug << "OFF\n3 1 0\n"; + //~ debug << triangles[ti][0] << "\n" + //~ << triangles[ti][1] << "\n" + //~ << triangles[ti][2] << "\n 3 0 1 2\n"; + //~ debug.close(); + // pre-compute segment intersections if (!segments.empty()) { @@ -340,7 +366,7 @@ void generate_subtriangles(std::size_t ti, //~ if (nbs==8) //~ { //~ for (std::size_t i = 0; i& t) @@ -404,7 +430,7 @@ void generate_subtriangles(std::size_t ti, } else - std::cerr <<"ERROR!\n"; + throw std::runtime_error("BOOM\n"); } #if 0 @@ -671,11 +697,12 @@ void autorefine_soup_output(const PointRange& input_points, for (std::size_t i=0;i Date: Thu, 2 Feb 2023 11:14:18 +0100 Subject: [PATCH 27/99] WIP new coplanar intersection --- .../Triangle_3_Triangle_3_intersection.h | 301 +++++++++++++++--- .../Polygon_mesh_processing/autorefinement.h | 36 ++- 2 files changed, 287 insertions(+), 50 deletions(-) diff --git a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h index 424e1fc9361..d4e467a0798 100644 --- a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h +++ b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h @@ -31,54 +31,257 @@ namespace CGAL { namespace Intersections { namespace internal{ -template -void intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3& p, - const typename Kernel::Point_3& q, - const typename Kernel::Point_3& r, - const Kernel& k, - std::list& inter_pts) +template +typename K::FT +coplanar_segment_segment_alpha_intersection(const typename K::Point_3& p1, const typename K::Point_3& p2, // segment 1 + const typename K::Point_3& p3, const typename K::Point_3& p4, // segment 2 + const K& k) { - typedef typename std::list::iterator Iterator; + const typename K::Vector_3 v1 = p2-p1; + const typename K::Vector_3 v2 = p4-p3; + + CGAL_assertion(k.coplanar_3_object()(p1,p2,p3,p4)); + + const typename K::Vector_3 v3 = p3 - p1; + const typename K::Vector_3 v3v2 = cross_product(v3,v2); + const typename K::Vector_3 v1v2 = cross_product(v1,v2); + const typename K::FT sl = v1v2.squared_length(); + CGAL_assertion(!certainly(is_zero(sl))); + + const typename K::FT t = ((v3v2.x()*v1v2.x()) + (v3v2.y()*v1v2.y()) + (v3v2.z()*v1v2.z())) / sl; + return t; // p1 + (p2-p1) * t +} + +template +struct Point_on_triangle +{ + static + inline + const typename Kernel::Point_3& + point_from_id(const typename Kernel::Point_3& p, + const typename Kernel::Point_3& q, + const typename Kernel::Point_3& r, + int id) + { + switch(id) + { + case 0: + return p; + case 1: + return q; + default: + return r; + } + } + + Point_on_triangle(int i1, int i2=-1, int sign=0, typename Kernel::FT alpha = 0.) // TODO add global zero()? + : t1_t2_ids(i1,i2) + , sign(sign) + {} + + // (id, -1) point on t1 + // (-1, id) point on t2 + // (id1, id2) intersection of edges + std::pair t1_t2_ids; + int sign; + typename Kernel::FT alpha; + + Orientation + orientation (const typename Kernel::Point_3& p1, // source of edge edge_ids1 + const typename Kernel::Point_3& q1, // target of edge edge_ids1 + const typename Kernel::Point_3& r1, + int edge_id1, + const typename Kernel::Point_3& p2, + const typename Kernel::Point_3& q2, + const typename Kernel::Point_3& r2, + const Kernel& k) const + { + if (t1_t2_ids.first!=-1) + { + if (t1_t2_ids.second==-1) return ZERO; // it is a point on t1 + // this is an intersection point + if (sign == 0) + return POSITIVE; + if (sign == -1) + return edge_id1==t1_t2_ids.first+1?POSITIVE:NEGATIVE; + else + return edge_id1==t1_t2_ids.first+1?NEGATIVE:POSITIVE; + } + else + { + //this is an input point of t2 + typename Kernel::Coplanar_orientation_3 orient = k.coplanar_orientation_3_object(); + const typename Kernel::Point_3& query = point_from_id(p2,q2,r2,t1_t2_ids.second); + return orient(p1,q1,r1,query); + } + } + + int id1() const { return t1_t2_ids.first; } + int id2() const { return t1_t2_ids.second; } + + typename Kernel::Point_3 + point(const typename Kernel::Point_3& p1, + const typename Kernel::Point_3& q1, + const typename Kernel::Point_3& r1, + const typename Kernel::Point_3& p2, + const typename Kernel::Point_3& q2, + const typename Kernel::Point_3& r2, + const Kernel& k) const + { + if (t1_t2_ids.first==-1) + return point_from_id(p2,q2,r2,t1_t2_ids.second); + if (t1_t2_ids.second==-1) + return point_from_id(p1,q1,r1,t1_t2_ids.first); + + return k.construct_barycenter_3_object()(point_from_id(p2,q2,r2,(t1_t2_ids.second+1)%3), alpha, point_from_id(p2,q2,r2,t1_t2_ids.second)) ; + } +}; + +template +Point_on_triangle +intersection(const Point_on_triangle& p, + const Point_on_triangle& q, + int edge_id_t1, + const typename Kernel::Point_3& p1, + const typename Kernel::Point_3& q1, +// const typename Kernel::Point_3& r1, + const typename Kernel::Point_3& p2, + const typename Kernel::Point_3& q2, + const typename Kernel::Point_3& r2, + const Kernel& k) +{ + typedef Point_on_triangle Pot; + switch(p.id1()) + { + case -1: + { + switch(q.id1()) + { + case -1: // (-1, ip2) - (-1, iq2) + { + typename Kernel::FT alpha = + coplanar_segment_segment_alpha_intersection(p1, q1, + Pot::point_from_id(p2, q2, r2, p.id2()), + Pot::point_from_id(p2, q2, r2, q.id2()), k); + int sgn = sign(alpha); + return Point_on_triangle(edge_id_t1, p.id2(), sgn, alpha); // intersection with an original edge of t2 + } + default: + if (q.id2()!=-1) // (-1, ip2) - (iq1, iq2) + { + // we shorten an already cut edge + CGAL_assertion((p.id2()+1)%3 == q.id2()); + + typename Kernel::FT alpha = + coplanar_segment_segment_alpha_intersection(p1, q1, + Pot::point_from_id(p2, q2, r2, p.id2()), + Pot::point_from_id(p2, q2, r2, q.id2()), k); + int sgn = sign(alpha); + return Point_on_triangle(edge_id_t1, p.id2(), sgn, alpha); + } + // (-1, ip2) - (iq1, -1) + //vertex of t1, special case t1 edge passed thru a vertex of t2 + CGAL_assertion(edge_id_t1 == 2); + return Point_on_triangle(2, -1); // point on t1 has to be created from the intersection of edge 0 and edge 1 + } + } + default: + { + switch(p.id2()) + { + case -1: + { + switch(q.id1()) + { + case -1: // (ip1, -1) - (-1, iq2) + //vertex of t1, special case t1 edge passed thru a vertex of t2 + return Point_on_triangle(0, -1); + default: + { + CGAL_assertion(q.id2()!=-1); // (ip1, -1) - (iq2, -1) + //(ip1,-1), (iq1, iq2) + CGAL_assertion(edge_id_t1==2 && p.id1()==1); + return Point_on_triangle(q.id1()==1?2:0,-1); // vertex of t1 + } + } + } + default: + { + switch(q.id1()) + { + case -1: // (ip1, ip2) - (-1, iq2) + { + // we shorten an already cut edge + CGAL_assertion((q.id2()+1)%3 == p.id2()); + + typename Kernel::FT alpha = + coplanar_segment_segment_alpha_intersection(p1, q1, + Pot::point_from_id(p2, q2, r2, q.id2()), + Pot::point_from_id(p2, q2, r2, p.id2()), k); + int sgn = sign(alpha); + return Point_on_triangle(edge_id_t1, p.id2(), sgn, alpha); + } + default: + { + switch(q.id2()) + { + case -1: // (ip1, ip2) - (iq1, -1) + { + CGAL_assertion(edge_id_t1==2 && q.id1()==1); + return Point_on_triangle(p.id1()==1?2:0); // vertex of t1 + } + default: // (ip1, ip2) - (iq1, iq2) + return Point_on_triangle((p.id1()+1)%3==q.id1()?q.id1():p.id1(), -1); // vertex of t1 + } + } + } + } + } + } + } +} + +template +void intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3& p1, + const typename Kernel::Point_3& q1, + const typename Kernel::Point_3& r1, + int edge_id, + const typename Kernel::Point_3& p2, + const typename Kernel::Point_3& q2, + const typename Kernel::Point_3& r2, + const Kernel& k, + std::list>& inter_pts) +{ + typedef typename std::list>::iterator Iterator; if(inter_pts.empty()) return; - typename Kernel::Coplanar_orientation_3 orient = k.coplanar_orientation_3_object(); - typename Kernel::Construct_line_3 line = k.construct_line_3_object(); + //orient(p1,q1,r1,r1) is POSITIVE + std::map*,Orientation> orientations; // TODO skip map + for (const Point_on_triangle& pot : inter_pts) + orientations[ &pot ]=pot.orientation(p1,q1,r1,edge_id,p2,q2,r2,k); - //orient(p,q,r,r) is POSITIVE - std::map orientations; - for (Iterator it=inter_pts.begin();it!=inter_pts.end();++it) - orientations[ &(*it) ]=orient(p,q,r,*it); + CGAL_kernel_assertion_code(int pt_added = 0); - CGAL_kernel_assertion_code(int pt_added = 0;) - - const typename Kernel::Point_3* prev = &(*boost::prior(inter_pts.end())); - Iterator stop = inter_pts.size() > 2 ? inter_pts.end() : boost::prior(inter_pts.end()); + Iterator prev = std::prev(inter_pts.end()); + Iterator stop = inter_pts.size() > 2 ? inter_pts.end() : std::prev(inter_pts.end()); for(Iterator it=inter_pts.begin(); it!=stop; ++it) { - const typename Kernel::Point_3& curr = *it; - Orientation or_prev = orientations[prev], - or_curr = orientations[&curr]; + Orientation or_prev = orientations[&(*prev)], + or_curr = orientations[&(*it)]; if((or_prev == POSITIVE && or_curr == NEGATIVE) || (or_prev == NEGATIVE && or_curr == POSITIVE)) { - typename Intersection_traits::result_type - obj = intersection(line(p,q), line(*prev,curr), k); + Point_on_triangle new_pt = intersection(*prev, *it, edge_id, p1, q1, p2, q2, r2, k); - // assert "not empty" - CGAL_kernel_assertion(bool(obj)); - - const typename Kernel::Point_3* inter = intersect_get(obj); - CGAL_kernel_assertion(inter != nullptr); - - prev = &(*inter_pts.insert(it,*inter)); - orientations[prev] = COLLINEAR; - CGAL_kernel_assertion_code(++pt_added;) + prev = inter_pts.insert(it,new_pt); + orientations[&(*prev)] = COLLINEAR; + CGAL_assertion_code(++pt_added); } - prev = &(*it); + prev = it; } CGAL_kernel_assertion(pt_added<3); @@ -98,35 +301,41 @@ intersection_coplanar_triangles(const typename K::Triangle_3& t1, const typename K::Triangle_3& t2, const K& k) { - const typename K::Point_3& p = t1.vertex(0), - q = t1.vertex(1), - r = t1.vertex(2); + const typename K::Point_3& p1 = t1.vertex(0), + q1 = t1.vertex(1), + r1 = t1.vertex(2); - std::list inter_pts; - inter_pts.push_back(t2.vertex(0)); - inter_pts.push_back(t2.vertex(1)); - inter_pts.push_back(t2.vertex(2)); + const typename K::Point_3& p2 = t2.vertex(0), + q2 = t2.vertex(1), + r2 = t2.vertex(2); + + std::list> inter_pts; + inter_pts.push_back(Point_on_triangle(-1,0)); + inter_pts.push_back(Point_on_triangle(-1,1)); + inter_pts.push_back(Point_on_triangle(-1,2)); //intersect t2 with the three half planes which intersection defines t1 - intersection_coplanar_triangles_cutoff(p,q,r,k,inter_pts); //line pq - intersection_coplanar_triangles_cutoff(q,r,p,k,inter_pts); //line qr - intersection_coplanar_triangles_cutoff(r,p,q,k,inter_pts); //line rp + intersection_coplanar_triangles_cutoff(p1,q1,r1,0,p2,q2,r2,k,inter_pts); //line pq + intersection_coplanar_triangles_cutoff(q1,r1,p1,1,p2,q2,r2,k,inter_pts); //line qr + intersection_coplanar_triangles_cutoff(r1,p1,q1,2,p2,q2,r2,k,inter_pts); //line rp + auto point = [&](const Point_on_triangle& pot){ return pot.point(p1,q1,r1,p2,q2,r2,k); }; switch(inter_pts.size()) { case 0: return intersection_return(); case 1: - return intersection_return(*inter_pts.begin()); + return intersection_return(point(*inter_pts.begin())); case 2: return intersection_return( - k.construct_segment_3_object()(*inter_pts.begin(), *boost::next(inter_pts.begin())) ); + k.construct_segment_3_object()(point(*inter_pts.begin()), point(*std::next(inter_pts.begin()))) ); case 3: return intersection_return( - k.construct_triangle_3_object()(*inter_pts.begin(), *boost::next(inter_pts.begin()), *boost::prior(inter_pts.end())) ); + k.construct_triangle_3_object()(point(*inter_pts.begin()), point(*std::next(inter_pts.begin())), point(*std::prev(inter_pts.end()))) ); default: return intersection_return( - std::vector(inter_pts.begin(),inter_pts.end())); + std::vector(boost::make_transform_iterator(inter_pts.begin(), point), + boost::make_transform_iterator(inter_pts.end(), point))); } } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index ae9858ae77d..6d0334d9366 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -36,8 +36,8 @@ #include -// #define TEST_RESOLVE_INTERSECTION -// #define DEDUPLICATE_SEGMENTS +//#define TEST_RESOLVE_INTERSECTION +//#define DEDUPLICATE_SEGMENTS namespace CGAL { namespace Polygon_mesh_processing { @@ -259,6 +259,9 @@ void collect_intersections(const std::array& t1, if (ori[0]== COPLANAR && ori[1]==COPLANAR && ori[2]==COPLANAR) { coplanar_intersections(t1, t2, inter_pts); + for (auto p : inter_pts) + if (depth(p)>2) throw std::runtime_error("Depth is not 2: "+std::to_string(depth(p))); + return; } @@ -283,6 +286,11 @@ void collect_intersections(const std::array& t1, std::sort(inter_pts.begin(), inter_pts.end()); auto last = std::unique(inter_pts.begin(), inter_pts.end()); inter_pts.erase(last, inter_pts.end()); + + + for (auto p : inter_pts) + if (depth(p)>2) throw std::runtime_error("Depth is not 2: "+std::to_string(depth(p))); + } ////////////////////////////////// @@ -300,6 +308,10 @@ void generate_subtriangles(std::size_t ti, const std::vector>& triangles, std::vector>& new_triangles) { + //~ std::cout << "generate_subtriangles()\n"; + std::cout << std::setprecision(17); + + typedef CGAL::Projection_traits_3 P_traits; typedef CGAL::Exact_intersections_tag Itag; @@ -395,7 +407,7 @@ void generate_subtriangles(std::size_t ti, points_on_segments[i].push_back(*pt_ptr); points_on_segments[j].push_back(*pt_ptr); - //~ std::cout << "new inter " << *pt_ptr << "\n"; + //~ std::cout << "new inter " << *pt_ptr << " (" << depth(points_on_segments[i].back()) << ")" << "\n"; } } @@ -417,7 +429,7 @@ void generate_subtriangles(std::size_t ti, points_on_segments[i].push_back(*pt_ptr); points_on_segments[j].push_back(*pt_ptr); - //~ std::cout << "new inter bis" << *pt_ptr << "\n"; + //~ std::cout << "new inter bis " << *pt_ptr << " (" << depth(points_on_segments[i].back()) << ")" << "\n"; } else { @@ -428,6 +440,8 @@ void generate_subtriangles(std::size_t ti, points_on_segments[i].push_back(seg_ptr->target()); points_on_segments[j].push_back(seg_ptr->target()); + //~ std::cout << "new inter seg " << *seg_ptr << " (" << depth(*seg_ptr) << ")" << "\n"; + } else throw std::runtime_error("BOOM\n"); @@ -537,6 +551,20 @@ void generate_subtriangles(std::size_t ti, } } + //~ int max_degree = 0; + //~ for (const auto p : cst_points) + //~ max_degree = std::max(max_degree, depth(p)); + //~ std::cout << "max_degree " << max_degree << "\n"; + + //~ if (max_degree > 10){ + //~ for (const auto p : cst_points) + //~ std::cout << " -- " << p << "(" << depth(p) << ")\n"; + //~ std::cout << "segments:\n"; + //~ for (auto s : segments) + //~ std::cout << " " << depth(s[0]) << " " << depth(s[1]) << "\n"; + //~ exit(1); + //~ } + cdt.insert_constraints(cst_points.begin(), cst_points.end(), csts.begin(), csts.end()); std::vector> no_inter_segments; From 8e050bdb49c5268af0e12bb48bcf34edd01db96c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 1 Mar 2023 15:39:28 +0100 Subject: [PATCH 28/99] fix various bug and add debug triangle_3_triangle_3_intersection now passes --- .../Triangle_3_Triangle_3_intersection.h | 129 +++++++++++++----- 1 file changed, 97 insertions(+), 32 deletions(-) diff --git a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h index d4e467a0798..55610e867ff 100644 --- a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h +++ b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h @@ -14,6 +14,8 @@ #ifndef CGAL_INTERNAL_INTERSECTIONS_TRIANGLE_3_TRIANGLE_3_INTERSECTION_H #define CGAL_INTERNAL_INTERSECTIONS_TRIANGLE_3_TRIANGLE_3_INTERSECTION_H +//#define CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + #include #include #include @@ -74,21 +76,20 @@ struct Point_on_triangle } } - Point_on_triangle(int i1, int i2=-1, int sign=0, typename Kernel::FT alpha = 0.) // TODO add global zero()? + Point_on_triangle(int i1, int i2=-1, typename Kernel::FT alpha = 0.) // TODO add global zero()? : t1_t2_ids(i1,i2) - , sign(sign) + , alpha(alpha) {} // (id, -1) point on t1 // (-1, id) point on t2 // (id1, id2) intersection of edges std::pair t1_t2_ids; - int sign; typename Kernel::FT alpha; Orientation - orientation (const typename Kernel::Point_3& p1, // source of edge edge_ids1 - const typename Kernel::Point_3& q1, // target of edge edge_ids1 + orientation (const typename Kernel::Point_3& p1, // source of edge edge_id1 + const typename Kernel::Point_3& q1, // target of edge edge_id1 const typename Kernel::Point_3& r1, int edge_id1, const typename Kernel::Point_3& p2, @@ -98,15 +99,21 @@ struct Point_on_triangle { if (t1_t2_ids.first!=-1) { - if (t1_t2_ids.second==-1) return ZERO; // it is a point on t1 + if (t1_t2_ids.second==-1) + return (edge_id1==t1_t2_ids.first || (edge_id1+1)%3==t1_t2_ids.first) ? ZERO:POSITIVE; // it is a point on t1 // this is an intersection point - if (sign == 0) - return POSITIVE; - if (sign == -1) - return edge_id1==t1_t2_ids.first+1?POSITIVE:NEGATIVE; - else - return edge_id1==t1_t2_ids.first+1?NEGATIVE:POSITIVE; - } + + if (t1_t2_ids.first==edge_id1) + return ZERO; + if (t1_t2_ids.first==(edge_id1+1)%3) + { + if (alpha==0) return ZERO; + return alpha>=0 ? POSITIVE:NEGATIVE; + } + CGAL_assertion((t1_t2_ids.first+1)%3==edge_id1); + if (alpha==1) return ZERO; + return alpha<=1?POSITIVE:NEGATIVE; + } else { //this is an input point of t2 @@ -150,6 +157,11 @@ intersection(const Point_on_triangle& p, const typename Kernel::Point_3& r2, const Kernel& k) { +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " calling intersection: "; + std::cout << " (" << p.id1() << "," << p.id2() << ",[" << p.alpha << "])-"; + std::cout << " (" << q.id1() << "," << q.id2() << ",[" << q.alpha << "]) || e" << edge_id_t1 << "\n"; +#endif typedef Point_on_triangle Pot; switch(p.id1()) { @@ -163,21 +175,23 @@ intersection(const Point_on_triangle& p, coplanar_segment_segment_alpha_intersection(p1, q1, Pot::point_from_id(p2, q2, r2, p.id2()), Pot::point_from_id(p2, q2, r2, q.id2()), k); - int sgn = sign(alpha); - return Point_on_triangle(edge_id_t1, p.id2(), sgn, alpha); // intersection with an original edge of t2 + return Point_on_triangle(edge_id_t1, p.id2(), alpha); // intersection with an original edge of t2 } default: if (q.id2()!=-1) // (-1, ip2) - (iq1, iq2) { - // we shorten an already cut edge - CGAL_assertion((p.id2()+1)%3 == q.id2()); + if (p.id2() == q.id2() || p.id2() == (q.id2()+1)%3) + { + // points are on the same edge of t2 --> we shorten an already cut edge + typename Kernel::FT alpha = + coplanar_segment_segment_alpha_intersection(p1, q1, + Pot::point_from_id(p2, q2, r2, q.id2()), + Pot::point_from_id(p2, q2, r2, (q.id2()+1)%3), k); - typename Kernel::FT alpha = - coplanar_segment_segment_alpha_intersection(p1, q1, - Pot::point_from_id(p2, q2, r2, p.id2()), - Pot::point_from_id(p2, q2, r2, q.id2()), k); - int sgn = sign(alpha); - return Point_on_triangle(edge_id_t1, p.id2(), sgn, alpha); + return Point_on_triangle(edge_id_t1, q.id2(), alpha); + } + // point of t1 + return Point_on_triangle((q.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3 , -1); } // (-1, ip2) - (iq1, -1) //vertex of t1, special case t1 edge passed thru a vertex of t2 @@ -211,15 +225,18 @@ intersection(const Point_on_triangle& p, { case -1: // (ip1, ip2) - (-1, iq2) { - // we shorten an already cut edge - CGAL_assertion((q.id2()+1)%3 == p.id2()); + if (q.id2() == p.id2() || q.id2() == (p.id2()+1)%3) + { + // points are on the same edge of t2 --> we shorten an already cut edge + typename Kernel::FT alpha = + coplanar_segment_segment_alpha_intersection(p1, q1, + Pot::point_from_id(p2, q2, r2, p.id2()), + Pot::point_from_id(p2, q2, r2, (p.id2()+1)%3), k); - typename Kernel::FT alpha = - coplanar_segment_segment_alpha_intersection(p1, q1, - Pot::point_from_id(p2, q2, r2, q.id2()), - Pot::point_from_id(p2, q2, r2, p.id2()), k); - int sgn = sign(alpha); - return Point_on_triangle(edge_id_t1, p.id2(), sgn, alpha); + return Point_on_triangle(edge_id_t1, p.id2(), alpha); + } + // point of t1 + return Point_on_triangle((p.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3 , -1); } default: { @@ -231,7 +248,8 @@ intersection(const Point_on_triangle& p, return Point_on_triangle(p.id1()==1?2:0); // vertex of t1 } default: // (ip1, ip2) - (iq1, iq2) - return Point_on_triangle((p.id1()+1)%3==q.id1()?q.id1():p.id1(), -1); // vertex of t1 + CGAL_assertion(p.id1()==q.id1()); + return Point_on_triangle((p.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3, -1); // vertex of t1 } } } @@ -252,6 +270,11 @@ void intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3& p1, const Kernel& k, std::list>& inter_pts) { +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " cutoff using e" << edge_id << ": " + << to_double(p1.x()) << " " << to_double(p1.y()) << " " << to_double(p1.z()) << " " + << to_double(q1.x()) << " " << to_double(q1.y()) << " " << to_double(q1.z()) << "\n"; +#endif typedef typename std::list>::iterator Iterator; if(inter_pts.empty()) @@ -262,6 +285,12 @@ void intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3& p1, for (const Point_on_triangle& pot : inter_pts) orientations[ &pot ]=pot.orientation(p1,q1,r1,edge_id,p2,q2,r2,k); +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " Orientations:"; + for (const Point_on_triangle& pot : inter_pts) + std::cout << " " << orientations[ &pot ]; + std::cout << "\n"; +#endif CGAL_kernel_assertion_code(int pt_added = 0); Iterator prev = std::prev(inter_pts.end()); @@ -301,6 +330,22 @@ intersection_coplanar_triangles(const typename K::Triangle_3& t1, const typename K::Triangle_3& t2, const K& k) { +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + auto to_string = [](const typename K::Triangle_3& t) + { + std::stringstream sstr; + sstr << "4 " + << to_double(t[0].x()) << " " << to_double(t[0].y()) << " " << to_double(t[0].z()) << " " + << to_double(t[1].x()) << " " << to_double(t[1].y()) << " " << to_double(t[1].z()) << " " + << to_double(t[2].x()) << " " << to_double(t[2].y()) << " " << to_double(t[2].z()) << " " + << to_double(t[0].x()) << " " << to_double(t[0].y()) << " " << to_double(t[0].z()) << "\n"; + return sstr.str(); + }; + + std::cout << "intersection_coplanar_triangles\n"; + std::ofstream("/tmp/t1.polylines.txt") << to_string(t1) << "\n"; + std::ofstream("/tmp/t2.polylines.txt") << to_string(t2) << "\n"; +#endif const typename K::Point_3& p1 = t1.vertex(0), q1 = t1.vertex(1), r1 = t1.vertex(2); @@ -314,10 +359,30 @@ intersection_coplanar_triangles(const typename K::Triangle_3& t1, inter_pts.push_back(Point_on_triangle(-1,1)); inter_pts.push_back(Point_on_triangle(-1,2)); +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + auto print_points = [&]() + { + for(auto p : inter_pts) std::cout << " (" << p.id1() << "," << p.id2() << ",[" << p.alpha << "]) "; std::cout <<"\n"; + }; + std::cout << " ipts size: " << inter_pts.size() << "\n"; + print_points(); +#endif //intersect t2 with the three half planes which intersection defines t1 intersection_coplanar_triangles_cutoff(p1,q1,r1,0,p2,q2,r2,k,inter_pts); //line pq +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " ipts size: " << inter_pts.size() << "\n"; + print_points(); +#endif intersection_coplanar_triangles_cutoff(q1,r1,p1,1,p2,q2,r2,k,inter_pts); //line qr +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " ipts size: " << inter_pts.size() << "\n"; + print_points(); +#endif intersection_coplanar_triangles_cutoff(r1,p1,q1,2,p2,q2,r2,k,inter_pts); //line rp +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " ipts size: " << inter_pts.size() << "\n"; + print_points(); +#endif auto point = [&](const Point_on_triangle& pot){ return pot.point(p1,q1,r1,p2,q2,r2,k); }; switch(inter_pts.size()) From 0bf300d5c51ea71657925aec1a3e6721729cc3c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 1 Mar 2023 17:19:35 +0100 Subject: [PATCH 29/99] plug new coplanar triangle intersection code --- .../Polygon_mesh_processing/autorefinement.h | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 6d0334d9366..b87a04c8a6a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -83,26 +83,44 @@ do_coplanar_segments_intersect(const std::array& s1, ////////////////////////////////// // imported from Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h - template void coplanar_intersections(const std::array& t1, const std::array& t2, std::vector& inter_pts) { - const typename K::Point_3& p = t1[0], q = t1[1], r = t1[2]; + const typename K::Point_3& p1 = t1[0], q1 = t1[1], r1 = t1[2]; + const typename K::Point_3& p2 = t2[0], q2 = t2[1], r2 = t2[2]; - std::list l_inter_pts; - l_inter_pts.push_back(t2[0]); - l_inter_pts.push_back(t2[1]); - l_inter_pts.push_back(t2[2]); + std::list> l_inter_pts; + l_inter_pts.push_back(Intersections::internal::Point_on_triangle(-1,0)); + l_inter_pts.push_back(Intersections::internal::Point_on_triangle(-1,1)); + l_inter_pts.push_back(Intersections::internal::Point_on_triangle(-1,2)); + +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + auto to_string = [](const auto& t) + { + std::stringstream sstr; + sstr << "4 " + << to_double(t[0].x()) << " " << to_double(t[0].y()) << " " << to_double(t[0].z()) << " " + << to_double(t[1].x()) << " " << to_double(t[1].y()) << " " << to_double(t[1].z()) << " " + << to_double(t[2].x()) << " " << to_double(t[2].y()) << " " << to_double(t[2].z()) << " " + << to_double(t[0].x()) << " " << to_double(t[0].y()) << " " << to_double(t[0].z()) << "\n"; + return sstr.str(); + }; + + std::cout << "intersection_coplanar_triangles\n"; + std::ofstream("/tmp/t1.polylines.txt") << to_string(t1) << "\n"; + std::ofstream("/tmp/t2.polylines.txt") << to_string(t2) << "\n"; +#endif //intersect t2 with the three half planes which intersection defines t1 K k; - Intersections::internal::intersection_coplanar_triangles_cutoff(p,q,r,k,l_inter_pts); //line pq - Intersections::internal::intersection_coplanar_triangles_cutoff(q,r,p,k,l_inter_pts); //line qr - Intersections::internal::intersection_coplanar_triangles_cutoff(r,p,q,k,l_inter_pts); //line rp + intersection_coplanar_triangles_cutoff(p1,q1,r1,0,p2,q2,r2,k,l_inter_pts); //line p1q1 + intersection_coplanar_triangles_cutoff(q1,r1,p1,1,p2,q2,r2,k,l_inter_pts); //line q1r1 + intersection_coplanar_triangles_cutoff(r1,p1,q1,2,p2,q2,r2,k,l_inter_pts); //line r1p1 - inter_pts.assign(l_inter_pts.begin(), l_inter_pts.end()); + for (const Intersections::internal::Point_on_triangle& pot : l_inter_pts) + inter_pts.push_back( pot.point(p1,q1,r1,p2,q2,r2,k) ); } // imported from Polygon_mesh_processing/internal/Corefinement/intersect_triangle_segment_3.h From 4fa600bc5fbf357f071817c7e8a775e89d9b2fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 3 Mar 2023 10:33:16 +0100 Subject: [PATCH 30/99] bug fix --- .../internal/Triangle_3_Triangle_3_intersection.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h index 55610e867ff..7c6ad7b95f8 100644 --- a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h +++ b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h @@ -33,6 +33,7 @@ namespace CGAL { namespace Intersections { namespace internal{ +//TODO: move into a functor template typename K::FT coplanar_segment_segment_alpha_intersection(const typename K::Point_3& p1, const typename K::Point_3& p2, // segment 1 @@ -248,8 +249,18 @@ intersection(const Point_on_triangle& p, return Point_on_triangle(p.id1()==1?2:0); // vertex of t1 } default: // (ip1, ip2) - (iq1, iq2) - CGAL_assertion(p.id1()==q.id1()); - return Point_on_triangle((p.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3, -1); // vertex of t1 + { + CGAL_assertion(p.id1()==q.id1() || p.id2()==q.id2() ); + + if (p.id1()==q.id1()) + return Point_on_triangle((p.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3, -1); // vertex of t1 + + typename Kernel::FT alpha = + coplanar_segment_segment_alpha_intersection(p1, q1, + Pot::point_from_id(p2, q2, r2, q.id2()), + Pot::point_from_id(p2, q2, r2, (q.id2()+1)%3), k); + return Point_on_triangle(edge_id_t1, q.id2(), alpha); + } } } } From 2fade292146be00a4d383c8a0356802de81aa708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 3 Mar 2023 10:35:42 +0100 Subject: [PATCH 31/99] add more debug --- .../Polygon_mesh_processing/autorefinement.h | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index b87a04c8a6a..c5f3ebb7890 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -38,6 +38,7 @@ //#define TEST_RESOLVE_INTERSECTION //#define DEDUPLICATE_SEGMENTS +//#define DEBUG_DEPTH namespace CGAL { namespace Polygon_mesh_processing { @@ -111,13 +112,31 @@ void coplanar_intersections(const std::array& t1, std::cout << "intersection_coplanar_triangles\n"; std::ofstream("/tmp/t1.polylines.txt") << to_string(t1) << "\n"; std::ofstream("/tmp/t2.polylines.txt") << to_string(t2) << "\n"; + auto print_points = [&]() + { + for(auto p : l_inter_pts) std::cout << " (" << p.id1() << "," << p.id2() << ",[" << p.alpha << "]) "; std::cout <<"\n"; + }; + std::cout << " ipts size: " << l_inter_pts.size() << "\n"; + print_points(); #endif //intersect t2 with the three half planes which intersection defines t1 K k; intersection_coplanar_triangles_cutoff(p1,q1,r1,0,p2,q2,r2,k,l_inter_pts); //line p1q1 +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " ipts size: " << l_inter_pts.size() << "\n"; + print_points(); +#endif intersection_coplanar_triangles_cutoff(q1,r1,p1,1,p2,q2,r2,k,l_inter_pts); //line q1r1 +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " ipts size: " << l_inter_pts.size() << "\n"; + print_points(); +#endif intersection_coplanar_triangles_cutoff(r1,p1,q1,2,p2,q2,r2,k,l_inter_pts); //line r1p1 +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " ipts size: " << l_inter_pts.size() << "\n"; + print_points(); +#endif for (const Intersections::internal::Point_on_triangle& pot : l_inter_pts) inter_pts.push_back( pot.point(p1,q1,r1,p2,q2,r2,k) ); @@ -277,8 +296,10 @@ void collect_intersections(const std::array& t1, if (ori[0]== COPLANAR && ori[1]==COPLANAR && ori[2]==COPLANAR) { coplanar_intersections(t1, t2, inter_pts); +#ifdef DEBUG_DEPTH for (auto p : inter_pts) - if (depth(p)>2) throw std::runtime_error("Depth is not 2: "+std::to_string(depth(p))); + if (depth(p)>2) throw std::runtime_error("Depth is not 4: "+std::to_string(depth(p))); +#endif return; } @@ -308,7 +329,6 @@ void collect_intersections(const std::array& t1, for (auto p : inter_pts) if (depth(p)>2) throw std::runtime_error("Depth is not 2: "+std::to_string(depth(p))); - } ////////////////////////////////// From f3e4a60f96be4fe94124a8c945a0bd3bd2f5ffb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 6 Mar 2023 14:03:24 +0100 Subject: [PATCH 32/99] fix intersection point computation --- .../internal/Triangle_3_Triangle_3_intersection.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h index 7c6ad7b95f8..ac376f44350 100644 --- a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h +++ b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h @@ -141,7 +141,7 @@ struct Point_on_triangle if (t1_t2_ids.second==-1) return point_from_id(p1,q1,r1,t1_t2_ids.first); - return k.construct_barycenter_3_object()(point_from_id(p2,q2,r2,(t1_t2_ids.second+1)%3), alpha, point_from_id(p2,q2,r2,t1_t2_ids.second)) ; + return k.construct_barycenter_3_object()(point_from_id(p1,q1,r1,(t1_t2_ids.first+1)%3), alpha, point_from_id(p1,q1,r1,t1_t2_ids.first)) ; } }; @@ -160,8 +160,8 @@ intersection(const Point_on_triangle& p, { #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " calling intersection: "; - std::cout << " (" << p.id1() << "," << p.id2() << ",[" << p.alpha << "])-"; - std::cout << " (" << q.id1() << "," << q.id2() << ",[" << q.alpha << "]) || e" << edge_id_t1 << "\n"; + std::cout << " (" << p.id1() << "," << p.id2() << ",[" << p.alpha << "]) -"; + std::cout << " (" << q.id1() << "," << q.id2() << ",[" << q.alpha << "]) || e" << edge_id_t1 << "\n"; #endif typedef Point_on_triangle Pot; switch(p.id1()) @@ -354,8 +354,8 @@ intersection_coplanar_triangles(const typename K::Triangle_3& t1, }; std::cout << "intersection_coplanar_triangles\n"; - std::ofstream("/tmp/t1.polylines.txt") << to_string(t1) << "\n"; - std::ofstream("/tmp/t2.polylines.txt") << to_string(t2) << "\n"; + std::ofstream("/tmp/t1.polylines.txt") << std::setprecision(17) << to_string(t1) << "\n"; + std::ofstream("/tmp/t2.polylines.txt") << std::setprecision(17) << to_string(t2) << "\n"; #endif const typename K::Point_3& p1 = t1.vertex(0), q1 = t1.vertex(1), From f499c392664483298fb4c26bc587cce758671b37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 6 Mar 2023 19:30:07 +0100 Subject: [PATCH 33/99] add a version with fixed dimension for projection --- .../Polygon_mesh_processing/autorefinement.h | 54 +++++++++++++++++-- 1 file changed, 49 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index c5f3ebb7890..7524c9c7f34 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -38,8 +38,13 @@ //#define TEST_RESOLVE_INTERSECTION //#define DEDUPLICATE_SEGMENTS +//#define USE_FIXED_PROJECTION_TRAITS //#define DEBUG_DEPTH +#ifdef USE_FIXED_PROJECTION_TRAITS +#include +#endif + namespace CGAL { namespace Polygon_mesh_processing { @@ -337,7 +342,11 @@ void collect_intersections(const std::array& t1, ////////////////////////////////// ////////////////////////////////// -template +template void generate_subtriangles(std::size_t ti, std::vector>& segments, const std::vector& points, @@ -349,8 +358,11 @@ void generate_subtriangles(std::size_t ti, //~ std::cout << "generate_subtriangles()\n"; std::cout << std::setprecision(17); - +#ifdef USE_FIXED_PROJECTION_TRAITS + typedef ::CGAL::internal::Projection_traits_3 P_traits; +#else typedef CGAL::Projection_traits_3 P_traits; +#endif typedef CGAL::Exact_intersections_tag Itag; typedef CGAL::Constrained_Delaunay_triangulation_2set_point(t[2]); +#endif #ifdef TEST_RESOLVE_INTERSECTION //~ static std::ofstream debug("inter_segments.polylines.txt"); @@ -832,7 +852,31 @@ void autorefine_soup_output(const PointRange& input_points, if (all_segments[ti].empty() && all_points[ti].empty()) new_triangles.push_back(triangles[ti]); else + { + #ifdef USE_FIXED_PROJECTION_TRAITS + const std::array& t = triangles[ti]; + auto is_constant_in_dim = [](const std::array& t, int dim) + { + return t[0][dim]==t[1][dim] && t[0][dim]!=t[2][dim]; + }; + + typename EK::Vector_3 orth = CGAL::normal(t[0], t[1], t[2]); // TODO::avoid construction? + int c = CGAL::abs(orth[0]) > CGAL::abs(orth[1]) ? 0 : 1; + c = CGAL::abs(orth[2]) > CGAL::abs(orth[c]) ? 2 : c; + + if(c == 0) { + autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + } else if(c == 1) { + autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + } else if(c == 2) { + autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + } + #else autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + #endif + } + + } // brute force output: create a soup, orient and to-mesh From 3abf7c401b67eefc2a2408dbac40c11f7e933203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 6 Mar 2023 19:31:26 +0100 Subject: [PATCH 34/99] add debug --- .../CGAL/Polygon_mesh_processing/autorefinement.h | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 7524c9c7f34..e5a7dbbb139 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -145,6 +145,19 @@ void coplanar_intersections(const std::array& t1, for (const Intersections::internal::Point_on_triangle& pot : l_inter_pts) inter_pts.push_back( pot.point(p1,q1,r1,p2,q2,r2,k) ); + +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::ofstream debug("interpts.xyz"); + debug << std::setprecision(17); + debug << l_inter_pts.size() << "\n"; + for (auto pot : l_inter_pts) + debug << pot.point(p1,q1,r1,p2,q2,r2,k) << "\n"; + debug.close(); + std::cout <<"check!\n"; + int i; + std::cin >> i; +#endif + } // imported from Polygon_mesh_processing/internal/Corefinement/intersect_triangle_segment_3.h From 8ff9f17a415524a52aa253b3c148ad45459de656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 13 Mar 2023 15:33:35 +0100 Subject: [PATCH 35/99] restore traits creation --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index e5a7dbbb139..3bb845854ec 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -401,13 +401,14 @@ void generate_subtriangles(std::size_t ti, cdt.insert(t[1]); cdt.insert(t[2]); #else - P_traits cdt_traits(n); bool orientation_flipped = false; if ( typename EK::Less_xyz_3()(o+n,o) ) { n=-n; orientation_flipped = true; } + + P_traits cdt_traits(n); CDT cdt(cdt_traits); cdt.insert_outside_affine_hull(t[0]); cdt.insert_outside_affine_hull(t[1]); From 14105bbdd4319109f83b256b7af86e855870a487 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 14 Mar 2023 13:56:54 +0100 Subject: [PATCH 36/99] always use local indices for range insertion of constraints --- .../Polygon_mesh_processing/autorefinement.h | 253 ++++++++++++------ 1 file changed, 167 insertions(+), 86 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 3bb845854ec..a81b00f65a4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -37,7 +37,8 @@ #include //#define TEST_RESOLVE_INTERSECTION -//#define DEDUPLICATE_SEGMENTS +#define DEDUPLICATE_SEGMENTS +//#define DEBUG_COUNTERS //#define USE_FIXED_PROJECTION_TRAITS //#define DEBUG_DEPTH @@ -45,6 +46,10 @@ #include #endif +#ifdef DEBUG_COUNTERS +#include +#endif + namespace CGAL { namespace Polygon_mesh_processing { @@ -55,28 +60,28 @@ enum Segment_inter_type { NO_INTERSECTION=0, COPLANAR_SEGMENTS, POINT_INTERSECTI template Segment_inter_type -do_coplanar_segments_intersect(const std::array& s1, - const std::array& s2, +do_coplanar_segments_intersect(const typename K::Point_3& s1_0, const typename K::Point_3& s1_1, + const typename K::Point_3& s2_0, const typename K::Point_3& s2_1, const K& k = K()) { // supporting_line intersects: points are coplanar typename K::Coplanar_orientation_3 cpl_orient=k.coplanar_orientation_3_object(); - ::CGAL::Orientation or1 = cpl_orient(s1[0], s1[1], s2[0]); - ::CGAL::Orientation or2 = cpl_orient(s1[0], s1[1], s2[1]); + ::CGAL::Orientation or1 = cpl_orient(s1_0, s1_1, s2_0); + ::CGAL::Orientation or2 = cpl_orient(s1_0, s1_1, s2_1); if(or1 == COLLINEAR && or2 == COLLINEAR) { // segments are collinear typename K::Collinear_are_ordered_along_line_3 cln_order = k.collinear_are_ordered_along_line_3_object(); - return (cln_order(s1[0], s2[0], s1[1]) || - cln_order(s1[0], s2[1], s1[1]) || - cln_order(s2[0], s1[0], s2[1])) ? COPLANAR_SEGMENTS : NO_INTERSECTION; + return (cln_order(s1_0, s2_0, s1_1) || + cln_order(s1_0, s2_1, s1_1) || + cln_order(s2_0, s1_0, s2_1)) ? COPLANAR_SEGMENTS : NO_INTERSECTION; } if(or1 != or2) { - or1 = cpl_orient(s2[0], s2[1], s1[0]); - return (or1 == COLLINEAR || or1 != cpl_orient(s2[0], s2[1], s1[1])) ? POINT_INTERSECTION : NO_INTERSECTION; + or1 = cpl_orient(s2_0, s2_1, s1_0); + return (or1 == COLLINEAR || or1 != cpl_orient(s2_0, s2_1, s1_1)) ? POINT_INTERSECTION : NO_INTERSECTION; } return NO_INTERSECTION; @@ -361,8 +366,8 @@ template void generate_subtriangles(std::size_t ti, - std::vector>& segments, - const std::vector& points, + std::vector>& segments, + std::vector& points, const std::vector& in_triangle_ids, const std::set >& intersecting_triangles, const std::vector>& triangles, @@ -376,13 +381,14 @@ void generate_subtriangles(std::size_t ti, #else typedef CGAL::Projection_traits_3 P_traits; #endif - typedef CGAL::Exact_intersections_tag Itag; - typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_2; + + typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_2; //typedef CGAL::Constrained_triangulation_plus_2 CDT; typedef CDT_2 CDT; @@ -416,6 +422,35 @@ void generate_subtriangles(std::size_t ti, v->set_point(t[2]); #endif +#ifdef DEBUG_COUNTERS + struct Counter + { + int c1=0; + int c2=0; + int c3=0; + int c4=0; + int total=0; + ~Counter() + { + std::cout << "intersection of 3 planes: " << c1 << "\n"; + std::cout << "coplanar segment intersection : " << c2 << "\n"; + std::cout << "coplanar segment overlap: " << c3 << "\n"; + std::cout << "no intersection: " << c4 << "\n"; + std::cout << "# pairs of segments : " << total << "\n"; + std::cout << "time computing segment intersections: " << timer1.time() << "\n"; + std::cout << "time sorting intersection points: " << timer2.time() << "\n"; + std::cout << "time for cdt of constraints: " << timer3.time() << "\n"; + } + CGAL::Real_timer timer1, timer2, timer3; + }; + + static Counter counter; +#define COUNTER_INSTRUCTION(X) X +#else +#define COUNTER_INSTRUCTION(X) +#endif + + #ifdef TEST_RESOLVE_INTERSECTION //~ static std::ofstream debug("inter_segments.polylines.txt"); //~ debug.precision(17); @@ -458,14 +493,33 @@ void generate_subtriangles(std::size_t ti, return typename EK::Plane_3(t[0], t[1], t[2]); }; - std::vector< std::vector > points_on_segments(nbs); + std::vector< std::vector > points_on_segments(nbs); + + COUNTER_INSTRUCTION(counter.timer1.start();) + + std::map point_id_map; + + for (std::size_t pid=0; pidsecond; + }; + + for (std::size_t i = 0; i(segments[i], segments[j]); + Segment_inter_type seg_inter_type = + do_coplanar_segments_intersect(points[segments[i].first], points[segments[i].second], + points[segments[j].first], points[segments[j].second]); switch(seg_inter_type) { case POINT_INTERSECTION: @@ -476,9 +530,11 @@ void generate_subtriangles(std::size_t ti, if (const typename EK::Point_3* pt_ptr = boost::get(&(*res))) { - points_on_segments[i].push_back(*pt_ptr); - points_on_segments[j].push_back(*pt_ptr); - + COUNTER_INSTRUCTION(++counter.c1;) + std::size_t pid = get_point_id(*pt_ptr); + points_on_segments[i].push_back(pid); + points_on_segments[j].push_back(pid); + break; //~ std::cout << "new inter " << *pt_ptr << " (" << depth(points_on_segments[i].back()) << ")" << "\n"; } @@ -490,30 +546,35 @@ void generate_subtriangles(std::size_t ti, //~ std::cout << "coplanar inter: " << i << " " << j << "\n"; - typename EK::Segment_3 s1(segments[i][0], segments[i][1]); - typename EK::Segment_3 s2(segments[j][0], segments[j][1]);// TODO: avoid this construction + typename EK::Segment_3 s1(points[segments[i].first], points[segments[i].second]); + typename EK::Segment_3 s2(points[segments[j].first], points[segments[j].second]);// TODO: avoid this construction auto inter = CGAL::intersection(s1, s2); if (inter == boost::none) throw std::runtime_error("Unexpected case #2"); if (const typename EK::Point_3* pt_ptr = boost::get(&(*inter))) { - points_on_segments[i].push_back(*pt_ptr); - points_on_segments[j].push_back(*pt_ptr); - + COUNTER_INSTRUCTION(++counter.c2;) + std::size_t pid = get_point_id(*pt_ptr); + points_on_segments[i].push_back(pid); + points_on_segments[j].push_back(pid); + break; //~ std::cout << "new inter bis " << *pt_ptr << " (" << depth(points_on_segments[i].back()) << ")" << "\n"; } else { if (const typename EK::Segment_3* seg_ptr = boost::get(&(*inter))) { - points_on_segments[i].push_back(seg_ptr->source()); - points_on_segments[j].push_back(seg_ptr->source()); - points_on_segments[i].push_back(seg_ptr->target()); - points_on_segments[j].push_back(seg_ptr->target()); - + //TODO HERE WE SHOULD IMPROVE TO AVOID RECOMPUTING SEGMENTS ENDPOINTS + COUNTER_INSTRUCTION(++counter.c3;) + std::size_t src_pid = get_point_id(seg_ptr->source()); + std::size_t tgt_pid = get_point_id(seg_ptr->target()); + points_on_segments[i].push_back(src_pid); + points_on_segments[j].push_back(src_pid); + points_on_segments[i].push_back(tgt_pid); + points_on_segments[j].push_back(tgt_pid); + break; //~ std::cout << "new inter seg " << *seg_ptr << " (" << depth(*seg_ptr) << ")" << "\n"; - } else throw std::runtime_error("BOOM\n"); @@ -564,24 +625,26 @@ void generate_subtriangles(std::size_t ti, //~ debug << "4 " << triangles[ti] << " " << triangles[ti][0] << "\n"; //~ exit(1); } - break; +// break; default: + COUNTER_INSTRUCTION(++counter.c4;) break; } } + COUNTER_INSTRUCTION(++counter.total;) } } - - std::vector cst_points; - std::vector> csts; + COUNTER_INSTRUCTION(counter.timer1.stop();) + COUNTER_INSTRUCTION(counter.timer2.start();) + std::size_t nb_new_segments=0; for (std::size_t i = 0; i& s = segments[i]; - typename EK::Point_3 src = s[0], tgt=s[1]; + std::size_t src_id = segments[i].first, tgt_id = segments[i].second; + typename EK::Point_3 src = points[src_id], tgt=points[tgt_id]; if (src.x()==tgt.x()) { coord=1; @@ -589,15 +652,23 @@ void generate_subtriangles(std::size_t ti, coord==2; } if (src[coord]>tgt[coord]) + { + std::swap(src_id, tgt_id); std::swap(src, tgt); + } - std::sort(points_on_segments[i].begin(), points_on_segments[i].end(), [coord](const typename EK::Point_3& p, const typename EK::Point_3& q){return p[coord]> no_inter_segments; - no_inter_segments.reserve(nbs); + // now fill segments with new segments + segments.reserve(segments.size()+nb_new_segments); for (std::size_t i = 0; i to_input; - std::map point_id_map; -#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) - std::vector exact_soup_points; -#endif - - auto get_point_id = [&](const typename EK::Point_3& pt) - { - auto insert_res = point_id_map.insert(std::make_pair(pt, soup_points.size())); - if (insert_res.second) - { - soup_points.push_back(to_input(pt)); -#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) - exact_soup_points.push_back(pt); -#endif - } - return insert_res.first->second; - }; - - // filter duplicated segments #ifdef DEDUPLICATE_SEGMENTS + // deduplicate inserted segments + std::vector>> all_segments_ids(all_segments.size()); for(std::size_t ti=0; ti point_id_map; + auto get_point_id = [&](const typename EK::Point_3& pt) + { + auto insert_res = point_id_map.insert(std::make_pair(pt, all_points[ti].size())); + if (insert_res.second) + all_points[ti].push_back(pt); + return insert_res.first->second; + }; + std::size_t nbs = all_segments[ti].size(); std::vector> filtered_segments; std::vector filtered_in_triangle_ids; @@ -841,19 +904,16 @@ void autorefine_soup_output(const PointRange& input_points, { EK::Point_3 src = all_segments[ti][si][0], tgt = all_segments[ti][si][1]; + std::size_t src_id = get_point_id(src), tgt_id=get_point_id(tgt); if (segset.insert( - CGAL::make_sorted_pair( get_point_id(src), - get_point_id(tgt))).second) + CGAL::make_sorted_pair(src_id, tgt_id)).second) { - filtered_segments.push_back(all_segments[ti][si]); + all_segments_ids[ti].emplace_back(src_id, tgt_id); filtered_in_triangle_ids.push_back(all_in_triangle_ids[ti][si]); } } - if (filtered_segments.size()!=nbs) - { - filtered_segments.swap(all_segments[ti]); + if (all_segments_ids[ti].size()!=nbs) filtered_in_triangle_ids.swap(all_in_triangle_ids[ti]); - } } } #endif @@ -886,7 +946,7 @@ void autorefine_soup_output(const PointRange& input_points, autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); } #else - autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + autorefine_impl::generate_subtriangles(ti, all_segments_ids[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); #endif } @@ -896,11 +956,31 @@ void autorefine_soup_output(const PointRange& input_points, // brute force output: create a soup, orient and to-mesh CGAL_PMP_AUTOREFINE_VERBOSE("create output soup"); + Cartesian_converter to_input; + std::map point_id_map; +#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) + std::vector exact_soup_points; +#endif + + auto get_point_id = [&](const typename EK::Point_3& pt) + { + auto insert_res = point_id_map.insert(std::make_pair(pt, soup_points.size())); + if (insert_res.second) + { + soup_points.push_back(to_input(pt)); +#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) + exact_soup_points.push_back(pt); +#endif + } + return insert_res.first->second; + }; + std::vector input_point_ids; input_point_ids.reserve(input_points.size()); for (const auto& p : input_points) input_point_ids.push_back(get_point_id(to_exact(get(pm,p)))); + // raw copy of input triangles with no intersection for (Input_TID f=0; f& t : new_triangles) { soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); From 003910ee220262b370b31bfe525ecb20bf2e8a27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 14 Mar 2023 18:10:04 +0100 Subject: [PATCH 37/99] fix typo --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index a81b00f65a4..e18cf1982b2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -663,7 +663,7 @@ void generate_subtriangles(std::size_t ti, [&](std::size_t id1, std::size_t id2) { if (id1==id2) return false; - return points[id1][coord] Date: Tue, 14 Mar 2023 18:32:31 +0100 Subject: [PATCH 38/99] dramatic typo --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index e18cf1982b2..d40fce82d2b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -649,7 +649,7 @@ void generate_subtriangles(std::size_t ti, { coord=1; if (src.y()==tgt.y()) - coord==2; + coord=2; } if (src[coord]>tgt[coord]) { From 5defd784cc0dae96083708f8b2454c2249509dad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 15 Mar 2023 14:24:37 +0100 Subject: [PATCH 39/99] better treatment of intersection between segments --- .../Polygon_mesh_processing/autorefinement.h | 447 ++++++++++++++---- 1 file changed, 346 insertions(+), 101 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index d40fce82d2b..711c3d82ce0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -56,13 +56,59 @@ namespace Polygon_mesh_processing { #ifndef DOXYGEN_RUNNING namespace autorefine_impl { -enum Segment_inter_type { NO_INTERSECTION=0, COPLANAR_SEGMENTS, POINT_INTERSECTION }; + +enum Segment_inter_type_old { NO_INTERSECTION_OLD=0, COPLANAR_SEGMENTS, POINT_INTERSECTION_OLD }; +enum Segment_inter_type { NO_INTERSECTION=0, + POINT_INTERSECTION, + POINT_P, + POINT_Q, + POINT_R, + POINT_S, + COPLANAR_SEGMENT_PQ, + COPLANAR_SEGMENT_RS, + COPLANAR_SEGMENT_PS, + COPLANAR_SEGMENT_QS, + COPLANAR_SEGMENT_PR, + COPLANAR_SEGMENT_QR, + }; + + + +std::string print_enum(Segment_inter_type_old s) +{ + switch(s) + { + case NO_INTERSECTION_OLD: return "NO_INTERSECTION_OLD"; + case COPLANAR_SEGMENTS: return "COPLANAR_SEGMENTS"; + case POINT_INTERSECTION_OLD: return "POINT_INTERSECTION_OLD"; + } +} + +std::string print_enum(Segment_inter_type s) +{ + switch(s) + { + case NO_INTERSECTION: return "NO_INTERSECTION"; + case POINT_INTERSECTION: return "POINT_INTERSECTION"; + case POINT_P: return "POINT_P"; + case POINT_Q: return "POINT_Q"; + case POINT_R: return "POINT_R"; + case POINT_S: return "POINT_S"; + case COPLANAR_SEGMENT_PQ: return "COPLANAR_SEGMENT_PQ"; + case COPLANAR_SEGMENT_RS: return "COPLANAR_SEGMENT_RS"; + case COPLANAR_SEGMENT_PS: return "COPLANAR_SEGMENT_PS"; + case COPLANAR_SEGMENT_QS: return "COPLANAR_SEGMENT_QS"; + case COPLANAR_SEGMENT_PR: return "COPLANAR_SEGMENT_PR"; + case COPLANAR_SEGMENT_QR: return "COPLANAR_SEGMENT_QR"; + } +} + template -Segment_inter_type -do_coplanar_segments_intersect(const typename K::Point_3& s1_0, const typename K::Point_3& s1_1, - const typename K::Point_3& s2_0, const typename K::Point_3& s2_1, - const K& k = K()) +Segment_inter_type_old +do_coplanar_segments_intersect_old(const typename K::Point_3& s1_0, const typename K::Point_3& s1_1, + const typename K::Point_3& s2_0, const typename K::Point_3& s2_1, + const K& k = K()) { // supporting_line intersects: points are coplanar typename K::Coplanar_orientation_3 cpl_orient=k.coplanar_orientation_3_object(); @@ -75,13 +121,155 @@ do_coplanar_segments_intersect(const typename K::Point_3& s1_0, const typename K typename K::Collinear_are_ordered_along_line_3 cln_order = k.collinear_are_ordered_along_line_3_object(); return (cln_order(s1_0, s2_0, s1_1) || cln_order(s1_0, s2_1, s1_1) || - cln_order(s2_0, s1_0, s2_1)) ? COPLANAR_SEGMENTS : NO_INTERSECTION; + cln_order(s2_0, s1_0, s2_1)) ? COPLANAR_SEGMENTS : NO_INTERSECTION_OLD; } if(or1 != or2) { or1 = cpl_orient(s2_0, s2_1, s1_0); - return (or1 == COLLINEAR || or1 != cpl_orient(s2_0, s2_1, s1_1)) ? POINT_INTERSECTION : NO_INTERSECTION; + return (or1 == COLLINEAR || or1 != cpl_orient(s2_0, s2_1, s1_1)) ? POINT_INTERSECTION_OLD : NO_INTERSECTION_OLD; + } + + return NO_INTERSECTION_OLD; +} + + +// test intersection in the interior of segment pq and rs with pq and rs being coplanar segments +// note that for coplanar cases, we might report identical endpoints +template +Segment_inter_type +do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, + std::size_t ri, std::size_t si, + const std::vector& points, + const K& k = K()) +{ + typename K::Collinear_are_ordered_along_line_3 cln_order = k.collinear_are_ordered_along_line_3_object(); + typename K::Coplanar_orientation_3 cpl_orient=k.coplanar_orientation_3_object(); + + const typename K::Point_3& p=points[pi]; + const typename K::Point_3& q=points[qi]; + const typename K::Point_3& r=points[ri]; + const typename K::Point_3& s=points[si]; + + // first handle case of shared endpoints + if (pi==ri) + { + if (si==qi || cpl_orient(p, q, s)!=COPLANAR) return NO_INTERSECTION; + // can be s, q or nothing + if (cln_order(p,s,q)) + return POINT_S; + if (cln_order(p,q,s)) + return POINT_Q; + return NO_INTERSECTION; + } + else + { + if(pi==si) + { + if (qi==ri || cpl_orient(p, q, r)!=COPLANAR) return NO_INTERSECTION; + // can be r, q or nothing + if (cln_order(p,r,q)) + return POINT_R; + if (cln_order(p,q,r)) + return POINT_Q; + return NO_INTERSECTION; + } + else + { + if (qi==ri) + { + if (pi==si || cpl_orient(p, q, s)!=COPLANAR) return NO_INTERSECTION; + // can be p, s or nothing + if (cln_order(p,s,q)) + return POINT_S; + if (cln_order(q,p,s)) + return POINT_P; + return NO_INTERSECTION; + } + else + { + if (qi==si) + { + if (pi==ri || cpl_orient(p, q, r)!=COPLANAR) return NO_INTERSECTION; + // can be p, r or nothing + if (cln_order(p,r,q)) + return POINT_R; + if (cln_order(q,p,r)) + return POINT_P; + return NO_INTERSECTION; + } + } + } + } + + // supporting_line intersects: points are coplanar + ::CGAL::Orientation pqr = cpl_orient(p, q, r); + ::CGAL::Orientation pqs = cpl_orient(p, q, s); + + if(pqr == COLLINEAR && pqs == COLLINEAR) + { + // segments are collinear + bool r_in_pq = cln_order(p, r, q), + s_in_pq = cln_order(p, s, q), + p_in_rs = cln_order(r, p, s); + + if (r_in_pq) + { + // intersection could be rs, pr or qr + if (s_in_pq) + return COPLANAR_SEGMENT_RS; + if (p_in_rs) + return COPLANAR_SEGMENT_PR; + CGAL_assertion(cln_order(r, q, s)); + return COPLANAR_SEGMENT_QR; + } + else + { + if (s_in_pq) + { + // intersection could be ps or qs + if (p_in_rs) + return COPLANAR_SEGMENT_PS; + CGAL_assertion(cln_order(r, q, s)); + return COPLANAR_SEGMENT_QS; + } + else + if (p_in_rs) + { + CGAL_assertion(cln_order(r, q, s)); + return COPLANAR_SEGMENT_PQ; + } + } + return NO_INTERSECTION; + } + + if(pqr != pqs) + { + ::CGAL::Orientation rsp = cpl_orient(r, s, p); + + if (rsp==COLLINEAR) + { + if (pqr==COLLINEAR || pqs==COLLINEAR) + { + throw std::runtime_error("no expected #1"); + } + return POINT_P; + } + ::CGAL::Orientation rsq = cpl_orient(r, s, q); + if (rsq==COLLINEAR) + { + if (pqr==COLLINEAR || pqs==COLLINEAR) + { + throw std::runtime_error("no expected #2"); + } + return POINT_Q; + } + if (rsp!=rsq) + { + if (pqr==COLLINEAR) return POINT_R; + if (pqs==COLLINEAR) return POINT_S; + return POINT_INTERSECTION; + } } return NO_INTERSECTION; @@ -429,6 +617,7 @@ void generate_subtriangles(std::size_t ti, int c2=0; int c3=0; int c4=0; + int c5=0; int total=0; ~Counter() { @@ -436,6 +625,7 @@ void generate_subtriangles(std::size_t ti, std::cout << "coplanar segment intersection : " << c2 << "\n"; std::cout << "coplanar segment overlap: " << c3 << "\n"; std::cout << "no intersection: " << c4 << "\n"; + std::cout << "intersection filtered with bboxes: " << c5 << "\n"; std::cout << "# pairs of segments : " << total << "\n"; std::cout << "time computing segment intersections: " << timer1.time() << "\n"; std::cout << "time sorting intersection points: " << timer2.time() << "\n"; @@ -480,13 +670,6 @@ void generate_subtriangles(std::size_t ti, if (!segments.empty()) { std::size_t nbs = segments.size(); - //~ std::cout << "nbs " << nbs << "\n"; - - //~ if (nbs==8) - //~ { - //~ for (std::size_t i = 0; i& t) { @@ -510,20 +693,69 @@ void generate_subtriangles(std::size_t ti, return insert_res.first->second; }; - + std::vector point_boxes(points.size()); + for (std::size_t i = 0; i segment_boxes(nbs); + for (std::size_t i = 0; i(points[segments[i].first], points[segments[i].second], - points[segments[j].first], points[segments[j].second]); + do_coplanar_segments_intersect(segments[i].first, segments[i].second, + segments[j].first, segments[j].second, + points); + + + //~ Segment_inter_type_old seg_inter_type_old = + //~ do_coplanar_segments_intersect_old(points[segments[i].first], points[segments[i].second], + //~ points[segments[j].first], points[segments[j].second]); + + + //~ std::cout << std::setprecision(17); + //~ std::cout << points[segments[i].first] << " " << points[segments[i].second] << "\n"; + //~ std::cout << points[segments[j].first] << " " << points[segments[j].second] << "\n"; + //~ std::cout << "OLD: " << print_enum(seg_inter_type_old) << "\n"; + //~ std::cout << "NEW: " << print_enum(seg_inter_type) << "\n"; + switch(seg_inter_type) { + case POINT_P: + { + points_on_segments[j].push_back(segments[i].first); + break; + } + case POINT_Q: + { + points_on_segments[j].push_back(segments[i].second); + break; + } + case POINT_R: + { + points_on_segments[i].push_back(segments[j].first); + break; + } + case POINT_S: + { + points_on_segments[i].push_back(segments[j].second); + break; + } case POINT_INTERSECTION: { + // TODO: use version with no variant auto res = CGAL::intersection(supporting_plane(triangles[in_triangle_ids[i]]), supporting_plane(triangles[in_triangle_ids[j]]), supporting_plane(triangles[ti])); @@ -534,101 +766,78 @@ void generate_subtriangles(std::size_t ti, std::size_t pid = get_point_id(*pt_ptr); points_on_segments[i].push_back(pid); points_on_segments[j].push_back(pid); - break; - //~ std::cout << "new inter " << *pt_ptr << " (" << depth(points_on_segments[i].back()) << ")" << "\n"; - - } - } - // break; No break because of the coplanar case - case COPLANAR_SEGMENTS: - { - // We can have hard cases if two triangles are coplanar.... - - //~ std::cout << "coplanar inter: " << i << " " << j << "\n"; - - typename EK::Segment_3 s1(points[segments[i].first], points[segments[i].second]); - typename EK::Segment_3 s2(points[segments[j].first], points[segments[j].second]);// TODO: avoid this construction - auto inter = CGAL::intersection(s1, s2); - - if (inter == boost::none) throw std::runtime_error("Unexpected case #2"); - - if (const typename EK::Point_3* pt_ptr = boost::get(&(*inter))) - { - COUNTER_INSTRUCTION(++counter.c2;) - std::size_t pid = get_point_id(*pt_ptr); - points_on_segments[i].push_back(pid); - points_on_segments[j].push_back(pid); - break; - //~ std::cout << "new inter bis " << *pt_ptr << " (" << depth(points_on_segments[i].back()) << ")" << "\n"; } else { - if (const typename EK::Segment_3* seg_ptr = boost::get(&(*inter))) + COUNTER_INSTRUCTION(++counter.c2;) + //TODO find better! + typename EK::Segment_3 s1(points[segments[i].first], points[segments[i].second]); + typename EK::Segment_3 s2(points[segments[j].first], points[segments[j].second]);// TODO: avoid this construction + auto inter = CGAL::intersection(s1, s2); + if (inter == boost::none) throw std::runtime_error("Unexpected case #2"); + if (const typename EK::Point_3* pt_ptr = boost::get(&(*inter))) { - //TODO HERE WE SHOULD IMPROVE TO AVOID RECOMPUTING SEGMENTS ENDPOINTS - COUNTER_INSTRUCTION(++counter.c3;) - std::size_t src_pid = get_point_id(seg_ptr->source()); - std::size_t tgt_pid = get_point_id(seg_ptr->target()); - points_on_segments[i].push_back(src_pid); - points_on_segments[j].push_back(src_pid); - points_on_segments[i].push_back(tgt_pid); - points_on_segments[j].push_back(tgt_pid); + std::size_t pid = get_point_id(*pt_ptr); + points_on_segments[i].push_back(pid); + points_on_segments[j].push_back(pid); break; - //~ std::cout << "new inter seg " << *seg_ptr << " (" << depth(*seg_ptr) << ")" << "\n"; } else - throw std::runtime_error("BOOM\n"); + throw std::runtime_error("Unexpected case 1"); + //~ std::ofstream debug ("/tmp/triangles.polylines.txt"); + //~ debug << "4 " << triangles[ti][0] << " " << triangles[ti][1] << " " << triangles[ti][2] << " " << triangles[ti][0] << "\n"; + //~ debug << "4 " << triangles[in_triangle_ids[i]][0] << " " << triangles[in_triangle_ids[i]][1] << " " << triangles[in_triangle_ids[i]][2] << " " << triangles[in_triangle_ids[i]][0] << "\n"; + //~ debug << "4 " << triangles[in_triangle_ids[j]][0] << " " << triangles[in_triangle_ids[j]][1] << " " << triangles[in_triangle_ids[j]][2] << " " << triangles[in_triangle_ids[j]][0] << "\n"; + //~ debug.close(); + //~ throw std::runtime_error("Unexpected case 1"); } - -#if 0 - //this code works if triangles are not coplanar - // coplanar intersection that is not a point - int coord = 0; - const typename EK::Segment_3& s = segments[i]; - typename EK::Point_3 src = s[0], tgt=s[1]; - if (src.x()==tgt.x()) - { - coord=1; - if (src.y()==tgt.y()) - coord==2; - } - - std::vector tmp_pts = { - src, tgt, segments[j][0], segments[j][1] }; - - std::sort(tmp_pts.begin(), tmp_pts.end(), - [coord](const typename EK::Point_3& p, const typename EK::Point_3& q) - {return p[coord](points_on_segments[i].begin(), points_on_segments[i].end()).size()!= points_on_segments[i].size()) + { + std::cout << "coord = " << coord << "\n"; + std::cout << "(src.x()==tgt.x()) " << (src.x()==tgt.x()) << "\n"; + std::cout << "(src.y()==tgt.y()) " << (src.y()==tgt.y()) << "\n"; + std::cout << "(src.z()==tgt.z()) " << (src.z()==tgt.z()) << "\n"; + + for (auto v : points_on_segments[i]) + std::cout << " " << v; + std::cout << std::endl; + for (auto v : points_on_segments[i]) + std::cout << points[v] << "\n"; + std::cout << std::endl; + throw std::runtime_error("unique failed!"); + } + + nb_new_segments+=points_on_segments[i].size()-2; //~ { @@ -721,6 +948,24 @@ void generate_subtriangles(std::size_t ti, //~ std::cout << "done\n"; #endif + // TODO: sorted pair to be constructed when pushing_back + for (std::pair& s : segments) + if (s.second < s.first) + std::swap(s.first,s.second); + std::sort(segments.begin(), segments.end()); + auto last = std::unique(segments.begin(), segments.end()); + segments.erase(last, segments.end()); + + + std::ofstream("/tmp/tri.xyz") << std::setprecision(17) << triangles[ti][0] << "\n" + << triangles[ti][1] << "\n" + << triangles[ti][2] << "\n"; + std::ofstream debug("/tmp/cst.polylines.txt"); + debug << std::setprecision(17); + for(auto s : segments) + debug << "2 " << points[s.first] << " " << points[s.second] << "\n"; + debug.close(); + COUNTER_INSTRUCTION(counter.timer3.start();) cdt.insert_constraints(points.begin(), points.end(), segments.begin(), segments.end()); COUNTER_INSTRUCTION(counter.timer3.stop();) From 48c49add1cd8100ed08cbff3a97f11de244f3fa7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 15 Mar 2023 15:48:44 +0100 Subject: [PATCH 40/99] more debug and enum fix --- .../Polygon_mesh_processing/autorefinement.h | 41 ++++++++----------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 711c3d82ce0..8cc1dd7ff9f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -154,7 +154,7 @@ do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, // first handle case of shared endpoints if (pi==ri) { - if (si==qi || cpl_orient(p, q, s)!=COPLANAR) return NO_INTERSECTION; + if (si==qi || cpl_orient(p, q, s)!=COLLINEAR) return NO_INTERSECTION; // can be s, q or nothing if (cln_order(p,s,q)) return POINT_S; @@ -166,7 +166,7 @@ do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, { if(pi==si) { - if (qi==ri || cpl_orient(p, q, r)!=COPLANAR) return NO_INTERSECTION; + if (qi==ri || cpl_orient(p, q, r)!=COLLINEAR) return NO_INTERSECTION; // can be r, q or nothing if (cln_order(p,r,q)) return POINT_R; @@ -178,7 +178,7 @@ do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, { if (qi==ri) { - if (pi==si || cpl_orient(p, q, s)!=COPLANAR) return NO_INTERSECTION; + if (pi==si || cpl_orient(p, q, s)!=COLLINEAR) return NO_INTERSECTION; // can be p, s or nothing if (cln_order(p,s,q)) return POINT_S; @@ -190,7 +190,7 @@ do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, { if (qi==si) { - if (pi==ri || cpl_orient(p, q, r)!=COPLANAR) return NO_INTERSECTION; + if (pi==ri || cpl_orient(p, q, r)!=COLLINEAR) return NO_INTERSECTION; // can be p, r or nothing if (cln_order(p,r,q)) return POINT_R; @@ -577,7 +577,7 @@ void generate_subtriangles(std::size_t ti, #endif typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_2; - //typedef CGAL::Constrained_triangulation_plus_2 CDT; + //typedef CGAL::Constrained_triangulation_plus_2 CDT; typedef CDT_2 CDT; const std::array& t = triangles[ti]; @@ -630,8 +630,11 @@ void generate_subtriangles(std::size_t ti, std::cout << "time computing segment intersections: " << timer1.time() << "\n"; std::cout << "time sorting intersection points: " << timer2.time() << "\n"; std::cout << "time for cdt of constraints: " << timer3.time() << "\n"; + std::cout << "time coplanar segment intersections: " << timer4.time() << "\n"; + std::cout << "time of do_coplanar_segments_intersect: " << timer5.time() << "\n"; + std::cout << "time of triplane intersection: " << timer6.time() << "\n"; } - CGAL::Real_timer timer1, timer2, timer3; + CGAL::Real_timer timer1, timer2, timer3, timer4, timer5, timer6; }; static Counter counter; @@ -713,11 +716,12 @@ void generate_subtriangles(std::size_t ti, continue; } - // TODO: use point ids to skip some test? + COUNTER_INSTRUCTION(counter.timer5.start();) Segment_inter_type seg_inter_type = do_coplanar_segments_intersect(segments[i].first, segments[i].second, segments[j].first, segments[j].second, points); + COUNTER_INSTRUCTION(counter.timer5.stop();) //~ Segment_inter_type_old seg_inter_type_old = @@ -756,9 +760,11 @@ void generate_subtriangles(std::size_t ti, case POINT_INTERSECTION: { // TODO: use version with no variant + COUNTER_INSTRUCTION(counter.timer6.start();) auto res = CGAL::intersection(supporting_plane(triangles[in_triangle_ids[i]]), supporting_plane(triangles[in_triangle_ids[j]]), supporting_plane(triangles[ti])); + COUNTER_INSTRUCTION(counter.timer6.stop();) if (const typename EK::Point_3* pt_ptr = boost::get(&(*res))) { @@ -770,6 +776,7 @@ void generate_subtriangles(std::size_t ti, else { COUNTER_INSTRUCTION(++counter.c2;) + COUNTER_INSTRUCTION(counter.timer4.start();) //TODO find better! typename EK::Segment_3 s1(points[segments[i].first], points[segments[i].second]); typename EK::Segment_3 s2(points[segments[j].first], points[segments[j].second]);// TODO: avoid this construction @@ -784,6 +791,7 @@ void generate_subtriangles(std::size_t ti, } else throw std::runtime_error("Unexpected case 1"); + COUNTER_INSTRUCTION(counter.timer4.stop();) //~ std::ofstream debug ("/tmp/triangles.polylines.txt"); //~ debug << "4 " << triangles[ti][0] << " " << triangles[ti][1] << " " << triangles[ti][2] << " " << triangles[ti][0] << "\n"; //~ debug << "4 " << triangles[in_triangle_ids[i]][0] << " " << triangles[in_triangle_ids[i]][1] << " " << triangles[in_triangle_ids[i]][2] << " " << triangles[in_triangle_ids[i]][0] << "\n"; @@ -877,24 +885,6 @@ void generate_subtriangles(std::size_t ti, points_on_segments[i].push_back(tgt_id); auto last = std::unique(points_on_segments[i].begin(), points_on_segments[i].end()); points_on_segments[i].erase(last, points_on_segments[i].end()); - - if (std::set(points_on_segments[i].begin(), points_on_segments[i].end()).size()!= points_on_segments[i].size()) - { - std::cout << "coord = " << coord << "\n"; - std::cout << "(src.x()==tgt.x()) " << (src.x()==tgt.x()) << "\n"; - std::cout << "(src.y()==tgt.y()) " << (src.y()==tgt.y()) << "\n"; - std::cout << "(src.z()==tgt.z()) " << (src.z()==tgt.z()) << "\n"; - - for (auto v : points_on_segments[i]) - std::cout << " " << v; - std::cout << std::endl; - for (auto v : points_on_segments[i]) - std::cout << points[v] << "\n"; - std::cout << std::endl; - throw std::runtime_error("unique failed!"); - } - - nb_new_segments+=points_on_segments[i].size()-2; //~ { @@ -1240,6 +1230,7 @@ void autorefine_soup_output(const PointRange& input_points, ); } } + // import refined triangles for (const std::array& t : new_triangles) { From ebb051f0b6e5bd89b17e4eb48f5c0cfdd2b6f1fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 16 Mar 2023 10:26:06 +0100 Subject: [PATCH 41/99] remove debug --- .../Polygon_mesh_processing/autorefinement.h | 96 ++----------------- 1 file changed, 10 insertions(+), 86 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 8cc1dd7ff9f..f6b7bac57bb 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -36,9 +36,9 @@ #include -//#define TEST_RESOLVE_INTERSECTION +#define TEST_RESOLVE_INTERSECTION #define DEDUPLICATE_SEGMENTS -//#define DEBUG_COUNTERS +#define DEBUG_COUNTERS //#define USE_FIXED_PROJECTION_TRAITS //#define DEBUG_DEPTH @@ -56,8 +56,6 @@ namespace Polygon_mesh_processing { #ifndef DOXYGEN_RUNNING namespace autorefine_impl { - -enum Segment_inter_type_old { NO_INTERSECTION_OLD=0, COPLANAR_SEGMENTS, POINT_INTERSECTION_OLD }; enum Segment_inter_type { NO_INTERSECTION=0, POINT_INTERSECTION, POINT_P, @@ -72,68 +70,6 @@ enum Segment_inter_type { NO_INTERSECTION=0, COPLANAR_SEGMENT_QR, }; - - -std::string print_enum(Segment_inter_type_old s) -{ - switch(s) - { - case NO_INTERSECTION_OLD: return "NO_INTERSECTION_OLD"; - case COPLANAR_SEGMENTS: return "COPLANAR_SEGMENTS"; - case POINT_INTERSECTION_OLD: return "POINT_INTERSECTION_OLD"; - } -} - -std::string print_enum(Segment_inter_type s) -{ - switch(s) - { - case NO_INTERSECTION: return "NO_INTERSECTION"; - case POINT_INTERSECTION: return "POINT_INTERSECTION"; - case POINT_P: return "POINT_P"; - case POINT_Q: return "POINT_Q"; - case POINT_R: return "POINT_R"; - case POINT_S: return "POINT_S"; - case COPLANAR_SEGMENT_PQ: return "COPLANAR_SEGMENT_PQ"; - case COPLANAR_SEGMENT_RS: return "COPLANAR_SEGMENT_RS"; - case COPLANAR_SEGMENT_PS: return "COPLANAR_SEGMENT_PS"; - case COPLANAR_SEGMENT_QS: return "COPLANAR_SEGMENT_QS"; - case COPLANAR_SEGMENT_PR: return "COPLANAR_SEGMENT_PR"; - case COPLANAR_SEGMENT_QR: return "COPLANAR_SEGMENT_QR"; - } -} - - -template -Segment_inter_type_old -do_coplanar_segments_intersect_old(const typename K::Point_3& s1_0, const typename K::Point_3& s1_1, - const typename K::Point_3& s2_0, const typename K::Point_3& s2_1, - const K& k = K()) -{ - // supporting_line intersects: points are coplanar - typename K::Coplanar_orientation_3 cpl_orient=k.coplanar_orientation_3_object(); - ::CGAL::Orientation or1 = cpl_orient(s1_0, s1_1, s2_0); - ::CGAL::Orientation or2 = cpl_orient(s1_0, s1_1, s2_1); - - if(or1 == COLLINEAR && or2 == COLLINEAR) - { - // segments are collinear - typename K::Collinear_are_ordered_along_line_3 cln_order = k.collinear_are_ordered_along_line_3_object(); - return (cln_order(s1_0, s2_0, s1_1) || - cln_order(s1_0, s2_1, s1_1) || - cln_order(s2_0, s1_0, s2_1)) ? COPLANAR_SEGMENTS : NO_INTERSECTION_OLD; - } - - if(or1 != or2) - { - or1 = cpl_orient(s2_0, s2_1, s1_0); - return (or1 == COLLINEAR || or1 != cpl_orient(s2_0, s2_1, s1_1)) ? POINT_INTERSECTION_OLD : NO_INTERSECTION_OLD; - } - - return NO_INTERSECTION_OLD; -} - - // test intersection in the interior of segment pq and rs with pq and rs being coplanar segments // note that for coplanar cases, we might report identical endpoints template @@ -723,18 +659,6 @@ void generate_subtriangles(std::size_t ti, points); COUNTER_INSTRUCTION(counter.timer5.stop();) - - //~ Segment_inter_type_old seg_inter_type_old = - //~ do_coplanar_segments_intersect_old(points[segments[i].first], points[segments[i].second], - //~ points[segments[j].first], points[segments[j].second]); - - - //~ std::cout << std::setprecision(17); - //~ std::cout << points[segments[i].first] << " " << points[segments[i].second] << "\n"; - //~ std::cout << points[segments[j].first] << " " << points[segments[j].second] << "\n"; - //~ std::cout << "OLD: " << print_enum(seg_inter_type_old) << "\n"; - //~ std::cout << "NEW: " << print_enum(seg_inter_type) << "\n"; - switch(seg_inter_type) { case POINT_P: @@ -947,14 +871,14 @@ void generate_subtriangles(std::size_t ti, segments.erase(last, segments.end()); - std::ofstream("/tmp/tri.xyz") << std::setprecision(17) << triangles[ti][0] << "\n" - << triangles[ti][1] << "\n" - << triangles[ti][2] << "\n"; - std::ofstream debug("/tmp/cst.polylines.txt"); - debug << std::setprecision(17); - for(auto s : segments) - debug << "2 " << points[s.first] << " " << points[s.second] << "\n"; - debug.close(); + //~ std::ofstream("/tmp/tri.xyz") << std::setprecision(17) << triangles[ti][0] << "\n" + //~ << triangles[ti][1] << "\n" + //~ << triangles[ti][2] << "\n"; + //~ std::ofstream debug("/tmp/cst.polylines.txt"); + //~ debug << std::setprecision(17); + //~ for(auto s : segments) + //~ debug << "2 " << points[s.first] << " " << points[s.second] << "\n"; + //~ debug.close(); COUNTER_INSTRUCTION(counter.timer3.start();) cdt.insert_constraints(points.begin(), points.end(), segments.begin(), segments.end()); From b31dc68889c704f0120e6286fb3bbbacdf19da48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 16 Mar 2023 10:28:24 +0100 Subject: [PATCH 42/99] add another option coplanar orientation --- .../Polygon_mesh_processing/autorefinement.h | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index f6b7bac57bb..7432f1f7d35 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -38,7 +38,7 @@ #define TEST_RESOLVE_INTERSECTION #define DEDUPLICATE_SEGMENTS -#define DEBUG_COUNTERS +//#define DEBUG_COUNTERS //#define USE_FIXED_PROJECTION_TRAITS //#define DEBUG_DEPTH @@ -77,10 +77,20 @@ Segment_inter_type do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, std::size_t ri, std::size_t si, const std::vector& points, + const typename K::Vector_3& plane_normal, const K& k = K()) { typename K::Collinear_are_ordered_along_line_3 cln_order = k.collinear_are_ordered_along_line_3_object(); +#ifdef USE_PROJECTED_ORIENTATION_2_FOR_COPLANAR_ORIENTATION_TESTS + auto cpl_orient = + [&plane_normal](const typename K::Point_3& p, const typename K::Point_3& q, const typename K::Point_3& r) + { + return ::CGAL::orientation(q-p, r-p, plane_normal); + }; +#else typename K::Coplanar_orientation_3 cpl_orient=k.coplanar_orientation_3_object(); + CGAL_USE(plane_normal); +#endif const typename K::Point_3& p=points[pi]; const typename K::Point_3& q=points[qi]; @@ -638,7 +648,7 @@ void generate_subtriangles(std::size_t ti, std::vector segment_boxes(nbs); for (std::size_t i = 0; i(segments[i].first, segments[i].second, segments[j].first, segments[j].second, - points); + points, n); COUNTER_INSTRUCTION(counter.timer5.stop();) switch(seg_inter_type) @@ -767,9 +777,10 @@ void generate_subtriangles(std::size_t ti, points_on_segments[j].push_back(segments[i].second); break; } -// break; case NO_INTERSECTION: + { COUNTER_INSTRUCTION(++counter.c4;) + } } } COUNTER_INSTRUCTION(++counter.total;) @@ -859,7 +870,6 @@ void generate_subtriangles(std::size_t ti, } } } - //~ std::cout << "done\n"; #endif // TODO: sorted pair to be constructed when pushing_back From 38a92ead67a2b471b68ecfc23367b72b710739ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 16 Mar 2023 14:59:08 +0100 Subject: [PATCH 43/99] make the message clearer --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 7432f1f7d35..a54e4d29971 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -36,7 +36,7 @@ #include -#define TEST_RESOLVE_INTERSECTION +//#define TEST_RESOLVE_INTERSECTION #define DEDUPLICATE_SEGMENTS //#define DEBUG_COUNTERS //#define USE_FIXED_PROJECTION_TRAITS @@ -1178,7 +1178,7 @@ void autorefine_soup_output(const PointRange& input_points, #ifdef CGAL_DEBUG_PMP_AUTOREFINE CGAL_PMP_AUTOREFINE_VERBOSE("check soup"); if (does_triangle_soup_self_intersect(exact_soup_points, soup_triangles)) - throw std::runtime_error("invalid output"); + throw std::runtime_error("ERROR: invalid output, there is most probably a bug"); #endif #endif CGAL_PMP_AUTOREFINE_VERBOSE("done"); From 6139fc4119b0c80bd6285e4c1cf1c7c269b85721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 16 Mar 2023 19:10:05 +0100 Subject: [PATCH 44/99] insert points even if no constraints --- .../Polygon_mesh_processing/autorefinement.h | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index a54e4d29971..734a47fcf56 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -465,7 +465,6 @@ void collect_intersections(const std::array& t1, { int j=(i+1)%3; test_edge(t1[i], t1[j], t2[0], t2[1], t2[2], ori[i], ori[j], inter_pts); - //~ if (inter_pts.size()>1) return; } // test edges of t2 vs t1 @@ -475,7 +474,6 @@ void collect_intersections(const std::array& t1, { int j=(i+1)%3; test_edge(t2[i], t2[j], t1[0], t1[1], t1[2], ori[i], ori[j], inter_pts); - //~ if (inter_pts.size()>1) return; } // because we don't handle intersection type and can have edge-edge edge-vertex duplicates @@ -483,9 +481,10 @@ void collect_intersections(const std::array& t1, auto last = std::unique(inter_pts.begin(), inter_pts.end()); inter_pts.erase(last, inter_pts.end()); - +#ifdef DEBUG_DEPTH for (auto p : inter_pts) if (depth(p)>2) throw std::runtime_error("Depth is not 2: "+std::to_string(depth(p))); +#endif } ////////////////////////////////// @@ -507,8 +506,8 @@ void generate_subtriangles(std::size_t ti, const std::vector>& triangles, std::vector>& new_triangles) { - //~ std::cout << "generate_subtriangles()\n"; - std::cout << std::setprecision(17); + // std::cout << "generate_subtriangles()\n"; + // std::cout << std::setprecision(17); #ifdef USE_FIXED_PROJECTION_TRAITS typedef ::CGAL::internal::Projection_traits_3 P_traits; @@ -870,16 +869,16 @@ void generate_subtriangles(std::size_t ti, } } } -#endif // TODO: sorted pair to be constructed when pushing_back + // TODO: only needed in case of coplanar segments? for (std::pair& s : segments) if (s.second < s.first) std::swap(s.first,s.second); std::sort(segments.begin(), segments.end()); auto last = std::unique(segments.begin(), segments.end()); segments.erase(last, segments.end()); - +#endif //~ std::ofstream("/tmp/tri.xyz") << std::setprecision(17) << triangles[ti][0] << "\n" //~ << triangles[ti][1] << "\n" @@ -891,7 +890,10 @@ void generate_subtriangles(std::size_t ti, //~ debug.close(); COUNTER_INSTRUCTION(counter.timer3.start();) - cdt.insert_constraints(points.begin(), points.end(), segments.begin(), segments.end()); + if (segments.empty()) + cdt.insert(points.begin(), points.end()); + else + cdt.insert_constraints(points.begin(), points.end(), segments.begin(), segments.end()); COUNTER_INSTRUCTION(counter.timer3.stop();) #ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS From 85b3f7ed5732f203905086d630b7e35c521e7c23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 27 Mar 2023 17:52:09 +0200 Subject: [PATCH 45/99] working around non-triangular polygons --- .../Polygon_mesh_processing/soup_autorefinement.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index 9ade96e3be8..a46fc6e711c 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -7,6 +7,8 @@ #include #include +#include + #include typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; @@ -22,10 +24,13 @@ int main(int argc, char** argv) : std::string(argv[1]); std::vector input_points; - std::vector> input_triangles; + std::vector> input_triangles; CGAL::IO::read_polygon_soup(filename, input_points, input_triangles); PMP::repair_polygon_soup(input_points, input_triangles); + for (const auto& c : input_triangles) + if (c.size()!=3) return 0; // skipt for now + std::vector output_points; std::vector> output_triangles; PMP::autorefine_soup_output(input_points, input_triangles, output_points, output_triangles); From b06ed794e6e7ffa1f3112ec16ba556128be2ba79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 27 Mar 2023 17:53:36 +0200 Subject: [PATCH 46/99] add more debug --- .../Polygon_mesh_processing/autorefinement.h | 159 +++++++++++++++++- 1 file changed, 155 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 734a47fcf56..7cd083e8338 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -36,7 +36,7 @@ #include -//#define TEST_RESOLVE_INTERSECTION +#define TEST_RESOLVE_INTERSECTION #define DEDUPLICATE_SEGMENTS //#define DEBUG_COUNTERS //#define USE_FIXED_PROJECTION_TRAITS @@ -227,6 +227,69 @@ do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, ////////////////////////////////// ////////////////////////////////// +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION +template +void old_intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3& p, + const typename Kernel::Point_3& q, + const typename Kernel::Point_3& r, + const Kernel& k, + std::list& inter_pts) +{ + typedef typename std::list::iterator Iterator; + + if(inter_pts.empty()) + return; + + typename Kernel::Coplanar_orientation_3 orient = k.coplanar_orientation_3_object(); + typename Kernel::Construct_line_3 line = k.construct_line_3_object(); + + //orient(p,q,r,r) is POSITIVE + std::map orientations; + for (Iterator it=inter_pts.begin();it!=inter_pts.end();++it) + orientations[ &(*it) ]=orient(p,q,r,*it); + + CGAL_kernel_assertion_code(int pt_added = 0;) + + const typename Kernel::Point_3* prev = &(*boost::prior(inter_pts.end())); + Iterator stop = inter_pts.size() > 2 ? inter_pts.end() : boost::prior(inter_pts.end()); + for(Iterator it=inter_pts.begin(); it!=stop; ++it) + { + const typename Kernel::Point_3& curr = *it; + Orientation or_prev = orientations[prev], + or_curr = orientations[&curr]; + + if((or_prev == POSITIVE && or_curr == NEGATIVE) || + (or_prev == NEGATIVE && or_curr == POSITIVE)) + { + typename Intersection_traits::result_type + obj = ::CGAL::Intersections::internal::intersection(line(p,q), line(*prev,curr), k); + + // assert "not empty" + CGAL_kernel_assertion(bool(obj)); + + const typename Kernel::Point_3* inter = ::CGAL::Intersections::internal::intersect_get(obj); + CGAL_kernel_assertion(inter != nullptr); + + prev = &(*inter_pts.insert(it,*inter)); + orientations[prev] = COLLINEAR; + CGAL_kernel_assertion_code(++pt_added;) + } + + prev = &(*it); + } + + CGAL_kernel_assertion(pt_added<3); + Iterator it = inter_pts.begin(); + while(it!=inter_pts.end()) + { + if(orientations[&(*it)] == NEGATIVE) + inter_pts.erase(it++); + else + ++it; + } +} +#endif + // imported from Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h template void coplanar_intersections(const std::array& t1, @@ -242,6 +305,19 @@ void coplanar_intersections(const std::array& t1, l_inter_pts.push_back(Intersections::internal::Point_on_triangle(-1,2)); #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::list old_l_inter_pts; + old_l_inter_pts.push_back(p2); + old_l_inter_pts.push_back(q2); + old_l_inter_pts.push_back(r2); + + + auto enum_to_string = [](CGAL::Orientation o) + { + if (o==COLLINEAR) return std::string("COLLINEAR"); + if (o==POSITIVE) return std::string("POSITIVE"); + return std::string("NEGATIVE"); + }; + auto to_string = [](const auto& t) { std::stringstream sstr; @@ -256,6 +332,32 @@ void coplanar_intersections(const std::array& t1, std::cout << "intersection_coplanar_triangles\n"; std::ofstream("/tmp/t1.polylines.txt") << to_string(t1) << "\n"; std::ofstream("/tmp/t2.polylines.txt") << to_string(t2) << "\n"; + + std::cout << "Position of vertices of t1: "; + std::cout << enum_to_string( coplanar_orientation(p2,q2,r2,p1)) << " - "; + std::cout << enum_to_string( coplanar_orientation(p2,q2,r2,q1)) << " - "; + std::cout << enum_to_string( coplanar_orientation(p2,q2,r2,r1)) << "\n"; + std::cout << " "; + std::cout << enum_to_string( coplanar_orientation(q2,r2,p2,p1)) << " - "; + std::cout << enum_to_string( coplanar_orientation(q2,r2,p2,q1)) << " - "; + std::cout << enum_to_string( coplanar_orientation(q2,r2,p2,r1)) << "\n"; + std::cout << " "; + std::cout << enum_to_string( coplanar_orientation(r2,p2,q2,p1)) << " - "; + std::cout << enum_to_string( coplanar_orientation(r2,p2,q2,q1)) << " - "; + std::cout << enum_to_string( coplanar_orientation(r2,p2,q2,r1)) << "\n"; + std::cout << "Position of vertices of t2: "; + std::cout << enum_to_string( coplanar_orientation(p1,q1,r1,p2)) << " - "; + std::cout << enum_to_string( coplanar_orientation(p1,q1,r1,q2)) << " - "; + std::cout << enum_to_string( coplanar_orientation(p1,q1,r1,r2)) << "\n"; + std::cout << " "; + std::cout << enum_to_string( coplanar_orientation(q1,r1,p1,p2)) << " - "; + std::cout << enum_to_string( coplanar_orientation(q1,r1,p1,q2)) << " - "; + std::cout << enum_to_string( coplanar_orientation(q1,r1,p1,r2)) << "\n"; + std::cout << " "; + std::cout << enum_to_string( coplanar_orientation(r1,p1,q1,p2)) << " - "; + std::cout << enum_to_string( coplanar_orientation(r1,p1,q1,q2)) << " - "; + std::cout << enum_to_string( coplanar_orientation(r1,p1,q1,r2)) << "\n"; + auto print_points = [&]() { for(auto p : l_inter_pts) std::cout << " (" << p.id1() << "," << p.id2() << ",[" << p.alpha << "]) "; std::cout <<"\n"; @@ -270,31 +372,76 @@ void coplanar_intersections(const std::array& t1, #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " ipts size: " << l_inter_pts.size() << "\n"; print_points(); + old_intersection_coplanar_triangles_cutoff(p1,q1,r1,k,old_l_inter_pts); + CGAL_assertion(l_inter_pts.size()==old_l_inter_pts.size()); + for (std::size_t i=0; ipoint(p1,q1,r1,p2,q2,r2,k)) + { + std::cout <<"ERROR with point #" << i << "\n"; + throw std::runtime_error("invalid output 0"); + } + } #endif intersection_coplanar_triangles_cutoff(q1,r1,p1,1,p2,q2,r2,k,l_inter_pts); //line q1r1 #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " ipts size: " << l_inter_pts.size() << "\n"; print_points(); + old_intersection_coplanar_triangles_cutoff(q1,r1,p1,k,old_l_inter_pts); + CGAL_assertion(l_inter_pts.size()==old_l_inter_pts.size()); + for (std::size_t i=0; ipoint(p1,q1,r1,p2,q2,r2,k)) + { + std::cout <<"ERROR with point #" << i << "\n"; + throw std::runtime_error("invalid output 1"); + } + } #endif intersection_coplanar_triangles_cutoff(r1,p1,q1,2,p2,q2,r2,k,l_inter_pts); //line r1p1 #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " ipts size: " << l_inter_pts.size() << "\n"; print_points(); + old_intersection_coplanar_triangles_cutoff(r1,p1,q1,k,old_l_inter_pts); + CGAL_assertion(l_inter_pts.size()==old_l_inter_pts.size()); + for (std::size_t i=0; ipoint(p1,q1,r1,p2,q2,r2,k)) + { + std::cout <<"ERROR with point #" << i << "\n"; + throw std::runtime_error("invalid output 2"); + } + } +#endif + +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::size_t start=inter_pts.size(); #endif for (const Intersections::internal::Point_on_triangle& pot : l_inter_pts) inter_pts.push_back( pot.point(p1,q1,r1,p2,q2,r2,k) ); #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + for (std::size_t i=0; i> i; + // std::cout <<"check!\n"; + // int i; + // std::cin >> i; #endif } @@ -1022,6 +1169,10 @@ void autorefine_soup_output(const PointRange& input_points, std::vector inter_pts; autorefine_impl::collect_intersections(t1, t2, inter_pts); + CGAL_assertion( + CGAL::do_intersect(typename EK::Triangle_3(t1[0], t1[1], t1[2]), typename EK::Triangle_3(t2[0], t2[1], t2[2])) + != inter_pts.empty()); + if (!inter_pts.empty()) { std::size_t nbi = inter_pts.size(); From bd967e7cec9885afb9cee799ae6b39a16abfa609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 27 Mar 2023 17:53:50 +0200 Subject: [PATCH 47/99] avoid duplicated tangency point --- .../Polygon_mesh_processing/autorefinement.h | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 7cd083e8338..c90ba515271 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -778,7 +778,13 @@ void generate_subtriangles(std::size_t ti, std::map point_id_map; for (std::size_t pid=0; pid(points.begin(), points.end()).size()); + CGAL_assertion(points.size()==point_id_map.size()); } // TODO: sorted pair to be constructed when pushing_back @@ -1217,6 +1226,14 @@ void autorefine_soup_output(const PointRange& input_points, return insert_res.first->second; }; + if (!all_points[ti].empty()) + { + std::vector tmp; + tmp.swap(all_points[ti]); + for (const typename EK::Point_3& pt : tmp) + get_point_id(pt); + } + std::size_t nbs = all_segments[ti].size(); std::vector> filtered_segments; std::vector filtered_in_triangle_ids; From 2b74b8f10d561a335e159857e14f109a92aeed50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 28 Mar 2023 14:35:40 +0200 Subject: [PATCH 48/99] fix some bugs --- .../Triangle_3_Triangle_3_intersection.h | 98 ++++++++++++++----- 1 file changed, 76 insertions(+), 22 deletions(-) diff --git a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h index ac376f44350..35aa4f8f0a5 100644 --- a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h +++ b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -86,6 +87,7 @@ struct Point_on_triangle // (-1, id) point on t2 // (id1, id2) intersection of edges std::pair t1_t2_ids; + boost::container::flat_set extra_t1; typename Kernel::FT alpha; Orientation @@ -161,7 +163,7 @@ intersection(const Point_on_triangle& p, #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " calling intersection: "; std::cout << " (" << p.id1() << "," << p.id2() << ",[" << p.alpha << "]) -"; - std::cout << " (" << q.id1() << "," << q.id2() << ",[" << q.alpha << "]) || e" << edge_id_t1 << "\n"; + std::cout << " (" << q.id1() << "," << q.id2() << ",[" << q.alpha << "]) || e" << edge_id_t1; #endif typedef Point_on_triangle Pot; switch(p.id1()) @@ -172,17 +174,26 @@ intersection(const Point_on_triangle& p, { case -1: // (-1, ip2) - (-1, iq2) { + CGAL_assertion((p.id2()+1)%3 == q.id2() || (q.id2()+1)%3 == p.id2()); +// CGAL_assertion(p.extra_t1.empty() && q.extra_t1.empty()); // TMP to see if it's worth implementing special case +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " -- case 1\n"; +#endif typename Kernel::FT alpha = coplanar_segment_segment_alpha_intersection(p1, q1, Pot::point_from_id(p2, q2, r2, p.id2()), Pot::point_from_id(p2, q2, r2, q.id2()), k); - return Point_on_triangle(edge_id_t1, p.id2(), alpha); // intersection with an original edge of t2 + int id2 = (p.id2()+1)%3 == q.id2() ? p.id2() : q.id2(); + return Point_on_triangle(edge_id_t1, id2, alpha); // intersection with an original edge of t2 } default: if (q.id2()!=-1) // (-1, ip2) - (iq1, iq2) { if (p.id2() == q.id2() || p.id2() == (q.id2()+1)%3) { +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " -- case 2\n"; +#endif // points are on the same edge of t2 --> we shorten an already cut edge typename Kernel::FT alpha = coplanar_segment_segment_alpha_intersection(p1, q1, @@ -191,13 +202,23 @@ intersection(const Point_on_triangle& p, return Point_on_triangle(edge_id_t1, q.id2(), alpha); } - // point of t1 - return Point_on_triangle((q.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3 , -1); +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " -- case 3\n"; +#endif + // point of t1: look for an edge of t1 containing both points + CGAL_assertion( p.extra_t1.count(q.id1())!=0 || p.extra_t1.count(3-q.id1()-edge_id_t1)!=0 ); + int eid1 = p.extra_t1.count(q.id1())!=0 ? q.id1() : 3-q.id1()-edge_id_t1; + return Point_on_triangle((eid1+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3, -1); // vertex of t1 } // (-1, ip2) - (iq1, -1) //vertex of t1, special case t1 edge passed thru a vertex of t2 CGAL_assertion(edge_id_t1 == 2); - return Point_on_triangle(2, -1); // point on t1 has to be created from the intersection of edge 0 and edge 1 +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " -- case 4\n"; +#endif + CGAL_assertion(q.id1()==1); + CGAL_assertion(!p.extra_t1.empty()); + return Point_on_triangle(p.extra_t1.count(0)==1?0:2,-1); } } default: @@ -210,13 +231,24 @@ intersection(const Point_on_triangle& p, { case -1: // (ip1, -1) - (-1, iq2) //vertex of t1, special case t1 edge passed thru a vertex of t2 - return Point_on_triangle(0, -1); +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " -- case 5\n"; +#endif + CGAL_assertion(edge_id_t1 == 2); + CGAL_assertion(p.id1()==1); + CGAL_assertion(!q.extra_t1.empty()); + return Point_on_triangle(q.extra_t1.count(0)==1?0:2,-1); default: { +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " -- case 6\n"; +#endif CGAL_assertion(q.id2()!=-1); // (ip1, -1) - (iq2, -1) //(ip1,-1), (iq1, iq2) - CGAL_assertion(edge_id_t1==2 && p.id1()==1); - return Point_on_triangle(q.id1()==1?2:0,-1); // vertex of t1 + CGAL_assertion(edge_id_t1==2); + // p and q are on the same edge of t1 + CGAL_assertion(p.id1()==q.id1() || p.id1()==(q.id1()+1)%3); + return Point_on_triangle((q.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3 , -1); } } } @@ -228,6 +260,9 @@ intersection(const Point_on_triangle& p, { if (q.id2() == p.id2() || q.id2() == (p.id2()+1)%3) { +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " -- case 7\n"; +#endif // points are on the same edge of t2 --> we shorten an already cut edge typename Kernel::FT alpha = coplanar_segment_segment_alpha_intersection(p1, q1, @@ -236,8 +271,14 @@ intersection(const Point_on_triangle& p, return Point_on_triangle(edge_id_t1, p.id2(), alpha); } +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " -- case 8\n"; +#endif // point of t1 - return Point_on_triangle((p.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3 , -1); + //std::cout << "q.extra_t1: "; for(int qet1 : q.extra_t1) std::cout << " " << qet1; std::cout << "\n"; + CGAL_assertion( q.extra_t1.count(p.id1())!=0 || q.extra_t1.count(3-p.id1()-edge_id_t1)!=0 ); + int eid1 = q.extra_t1.count(p.id1())!=0 ? p.id1() : 3-p.id1()-edge_id_t1; + return Point_on_triangle((eid1+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3, -1); // vertex of t1 } default: { @@ -245,21 +286,30 @@ intersection(const Point_on_triangle& p, { case -1: // (ip1, ip2) - (iq1, -1) { - CGAL_assertion(edge_id_t1==2 && q.id1()==1); - return Point_on_triangle(p.id1()==1?2:0); // vertex of t1 + // p and q are on the same edge of t1 + CGAL_assertion(q.id1()==p.id1() || q.id1()==(p.id1()+1)%3); +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " -- case 9\n"; +#endif + return Point_on_triangle((p.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3 , -1); } default: // (ip1, ip2) - (iq1, iq2) { - CGAL_assertion(p.id1()==q.id1() || p.id2()==q.id2() ); - - if (p.id1()==q.id1()) - return Point_on_triangle((p.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3, -1); // vertex of t1 - - typename Kernel::FT alpha = - coplanar_segment_segment_alpha_intersection(p1, q1, - Pot::point_from_id(p2, q2, r2, q.id2()), - Pot::point_from_id(p2, q2, r2, (q.id2()+1)%3), k); - return Point_on_triangle(edge_id_t1, q.id2(), alpha); + if (p.id2()==q.id2()) + { +#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION + std::cout << " -- case 10\n"; +#endif + typename Kernel::FT alpha = + coplanar_segment_segment_alpha_intersection(p1, q1, + Pot::point_from_id(p2, q2, r2, q.id2()), + Pot::point_from_id(p2, q2, r2, (q.id2()+1)%3), k); + return Point_on_triangle(edge_id_t1, q.id2(), alpha); + } + // we are intersecting an edge of t1 + CGAL_assertion(p.id1()==q.id1() || edge_id_t1==2); + int eid1 = p.id1()==q.id1() ? p.id1() : 1; + return Point_on_triangle((eid1+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3, -1); // vertex of t1 } } } @@ -293,8 +343,12 @@ void intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3& p1, //orient(p1,q1,r1,r1) is POSITIVE std::map*,Orientation> orientations; // TODO skip map - for (const Point_on_triangle& pot : inter_pts) + for (Point_on_triangle& pot : inter_pts) + { orientations[ &pot ]=pot.orientation(p1,q1,r1,edge_id,p2,q2,r2,k); + if (pot.id1()==-1 && orientations[ &pot ]==COLLINEAR) + pot.extra_t1.insert(edge_id); + } #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " Orientations:"; From e29d52421e624a416b741e3416d75bc65ee1e101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 28 Mar 2023 16:43:35 +0200 Subject: [PATCH 49/99] fix doc --- .../Polygon_mesh_processing/autorefinement.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index c90ba515271..c7e067916d5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1360,19 +1360,18 @@ void autorefine_soup_output(const PointRange& input_points, * refines a triangle mesh so that no triangles intersects in their interior. * * @tparam TriangleMesh a model of `HalfedgeListGraph`, `FaceListGraph`, and `MutableFaceGraph` - * @tparam NamedParameters a sequence of \ref namedparameters + * @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * * @param tm input triangulated surface mesh * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * - * \cgalParamNBegin{geom_traits} - * \cgalParamDescription{an instance of a geometric traits class} - * \cgalParamType{a class model of `PMPSelfIntersectionTraits`} - * \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`} - * \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.} - * \cgalParamNEnd - * * \cgalNamedParamsBegin + * \cgalParamNBegin{geom_traits} + * \cgalParamDescription{an instance of a geometric traits class} + * \cgalParamType{a class model of `PMPSelfIntersectionTraits`} + * \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`} + * \cgalParamExtra{The geometric traits class must be compatible with the vertex point type.} + * \cgalParamNEnd * \cgalParamNBegin{vertex_point_map} * \cgalParamDescription{a property map associating points to the vertices of `tm`} * \cgalParamType{a class model of `ReadablePropertyMap` with `boost::graph_traits::%vertex_descriptor` @@ -1380,7 +1379,8 @@ void autorefine_soup_output(const PointRange& input_points, * \cgalParamDefault{`boost::get(CGAL::vertex_point, tm)`} * \cgalParamExtra{If this parameter is omitted, an internal property map for `CGAL::vertex_point_t` * must be available in `TriangleMesh`.} - * \cgalParamNEnd + * \cgalParamNEnd + * \cgalNamedParamsEnd * */ template Date: Wed, 29 Mar 2023 16:38:34 +0200 Subject: [PATCH 50/99] triangulate soup --- .../examples/Polygon_mesh_processing/soup_autorefinement.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index a46fc6e711c..d955734853b 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -27,9 +27,7 @@ int main(int argc, char** argv) std::vector> input_triangles; CGAL::IO::read_polygon_soup(filename, input_points, input_triangles); PMP::repair_polygon_soup(input_points, input_triangles); - - for (const auto& c : input_triangles) - if (c.size()!=3) return 0; // skipt for now + PMP::triangulate_polygons(input_points, input_triangles); std::vector output_points; std::vector> output_triangles; From 2a791d2625c885b96f6d12b890d6b482918b48d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 31 Mar 2023 10:24:42 +0200 Subject: [PATCH 51/99] add optional progress display --- .../CGAL/Polygon_mesh_processing/autorefinement.h | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index c7e067916d5..4f56b8a0d81 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -25,6 +25,10 @@ #include #include +#ifdef USE_PROGRESS_DISPLAY +#include +#endif + // output #include #include @@ -1260,6 +1264,11 @@ void autorefine_soup_output(const PointRange& input_points, CGAL_PMP_AUTOREFINE_VERBOSE("triangulate faces"); // now refine triangles std::vector> new_triangles; + +#ifdef USE_PROGRESS_DISPLAY + boost::timer::progress_display pd(triangles.size()); +#endif + for(std::size_t ti=0; ti Date: Fri, 31 Mar 2023 10:26:21 +0200 Subject: [PATCH 52/99] repair soup before orient + to mesh --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 4f56b8a0d81..e38f64ff301 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -1417,6 +1418,7 @@ autorefine( TriangleMesh& tm, out_soup_points, out_soup_triangles); clear(tm); + repair_polygon_soup(out_soup_points, out_soup_triangles); orient_polygon_soup(out_soup_points, out_soup_triangles); polygon_soup_to_polygon_mesh(out_soup_points, out_soup_triangles, tm); } From 55f8bcb12202de6fb6fe70ee3096d979b8f95dbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 6 Apr 2023 18:24:59 +0200 Subject: [PATCH 53/99] fix assertion --- .../internal/Triangle_3_Triangle_3_intersection.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h index 35aa4f8f0a5..4cc5f9be560 100644 --- a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h +++ b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h @@ -372,7 +372,7 @@ void intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3& p1, prev = inter_pts.insert(it,new_pt); orientations[&(*prev)] = COLLINEAR; - CGAL_assertion_code(++pt_added); + CGAL_kernel_assertion_code(++pt_added); } prev = it; From a15956d231a5639cd850c6dde9f37891fdad1e25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 24 May 2023 16:09:31 +0200 Subject: [PATCH 54/99] add clear function and input must mesh should be const in principle --- .../Non_manifold_feature_map.h | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Non_manifold_feature_map.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Non_manifold_feature_map.h index 8177a02d178..e8901ebd727 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Non_manifold_feature_map.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/Non_manifold_feature_map.h @@ -28,8 +28,8 @@ struct Non_manifold_feature_map typedef typename Graph_traits::halfedge_descriptor halfedge_descriptor; typedef dynamic_edge_property_t Edge_to_id_tag; typedef dynamic_vertex_property_t Vertex_to_id_tag; - typedef typename boost::property_map::type Edge_to_nm_id; - typedef typename boost::property_map::type Vertex_to_nm_id; + typedef typename boost::property_map::const_type Edge_to_nm_id; + typedef typename boost::property_map::const_type Vertex_to_nm_id; Edge_to_nm_id e_nm_id; Vertex_to_nm_id v_nm_id; std::vector< std::vector > non_manifold_edges; @@ -39,7 +39,7 @@ struct Non_manifold_feature_map {} template - Non_manifold_feature_map(PolygonMesh& pm, Vpm vpm) + Non_manifold_feature_map(const PolygonMesh& pm, Vpm vpm) : e_nm_id(get(Edge_to_id_tag(), pm)) , v_nm_id(get(Vertex_to_id_tag(), pm)) { @@ -99,6 +99,14 @@ struct Non_manifold_feature_map } } } + + void clear() + { + non_manifold_edges.clear(); + non_manifold_vertices.clear(); + e_nm_id = Edge_to_nm_id(); + v_nm_id = Vertex_to_nm_id(); + } }; } } // end of CGAL::Polygon_mesh_processing From 5d73a7addd778919f50b60b37d87e70886703035 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 25 May 2023 10:06:51 +0200 Subject: [PATCH 55/99] add TODOs for parallelism --- .../examples/Polygon_mesh_processing/CMakeLists.txt | 1 + .../CGAL/Polygon_mesh_processing/autorefinement.h | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt index d2faeb70cb2..306e216be40 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/CMakeLists.txt @@ -120,6 +120,7 @@ if(TARGET CGAL::TBB_support) target_link_libraries(self_intersections_example PUBLIC CGAL::TBB_support) target_link_libraries(hausdorff_distance_remeshing_example PUBLIC CGAL::TBB_support) target_link_libraries(hausdorff_bounded_error_distance_example PUBLIC CGAL::TBB_support) + target_link_libraries(soup_autorefinement PUBLIC CGAL::TBB_support) create_single_source_cgal_program("corefinement_parallel_union_meshes.cpp") target_link_libraries(corefinement_parallel_union_meshes PUBLIC CGAL::TBB_support) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index e38f64ff301..a46f2664803 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1116,7 +1116,7 @@ void autorefine_soup_output(const PointRange& input_points, typedef std::size_t Input_TID; typedef std::pair Pair_of_triangle_ids; - std::vector si_pairs; + std::vector si_pairs; // TODO: check std::vector is fine with Parallel_tag // collect intersecting pairs of triangles CGAL_PMP_AUTOREFINE_VERBOSE("collect intersecting pairs"); @@ -1170,6 +1170,7 @@ void autorefine_soup_output(const PointRange& input_points, CGAL_PMP_AUTOREFINE_VERBOSE("compute intersections"); std::set > intersecting_triangles; + //TODO: PARALLEL_FOR #2 for (const Pair_of_triangle_ids& p : si_pairs) { int i1 = tri_inter_ids[p.first], @@ -1217,6 +1218,7 @@ void autorefine_soup_output(const PointRange& input_points, #ifdef DEDUPLICATE_SEGMENTS // deduplicate inserted segments + //TODO: PARALLEL_FOR #3 std::vector>> all_segments_ids(all_segments.size()); for(std::size_t ti=0; ti> new_triangles; + std::vector> new_triangles; // Need to be threadsafe #ifdef USE_PROGRESS_DISPLAY boost::timer::progress_display pd(triangles.size()); #endif + //TODO: PARALLEL_FOR #1 for(std::size_t ti=0; ti to_input; + // TODO: reuse the fact that maps per triangle are already sorted std::map point_id_map; #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) std::vector exact_soup_points; @@ -1348,6 +1352,7 @@ void autorefine_soup_output(const PointRange& input_points, } // import refined triangles + //TODO: PARALLEL_FOR #4 for (const std::array& t : new_triangles) { soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); @@ -1355,11 +1360,11 @@ void autorefine_soup_output(const PointRange& input_points, #ifndef CGAL_NDEBUG CGAL_PMP_AUTOREFINE_VERBOSE("check soup"); - CGAL_assertion( !does_triangle_soup_self_intersect(exact_soup_points, soup_triangles) ); + CGAL_assertion( !does_triangle_soup_self_intersect(exact_soup_points, soup_triangles) ); #else #ifdef CGAL_DEBUG_PMP_AUTOREFINE CGAL_PMP_AUTOREFINE_VERBOSE("check soup"); - if (does_triangle_soup_self_intersect(exact_soup_points, soup_triangles)) + if (does_triangle_soup_self_intersect(exact_soup_points, soup_triangles)) throw std::runtime_error("ERROR: invalid output, there is most probably a bug"); #endif #endif From 278e1867aa322600cd236413ba305f96b013258e Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Fri, 26 May 2023 17:12:28 +0100 Subject: [PATCH 56/99] parallize #1 --- .../soup_autorefinement.cpp | 7 +- .../Polygon_mesh_processing/autorefinement.h | 89 +++++++++++++------ 2 files changed, 65 insertions(+), 31 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index d955734853b..f1230668948 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include @@ -29,11 +30,13 @@ int main(int argc, char** argv) PMP::repair_polygon_soup(input_points, input_triangles); PMP::triangulate_polygons(input_points, input_triangles); + CGAL::Real_timer t; + t.start(); std::vector output_points; std::vector> output_triangles; PMP::autorefine_soup_output(input_points, input_triangles, output_points, output_triangles); - - CGAL::IO::write_polygon_soup("autorefined.off", output_points, output_triangles, CGAL::parameters::stream_precision(17)); + std::cout << "#points = " << output_points.size() << " and #triangles = " << output_triangles.size() << " in " << t.time() << " sec." << std::endl; + // CGAL::IO::write_polygon_soup("autorefined.off", output_points, output_triangles, CGAL::parameters::stream_precision(17)); return 0; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index a46f2664803..e862d683960 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -39,6 +39,11 @@ #define CGAL_PMP_AUTOREFINE_VERBOSE(MSG) #endif +#ifdef CGAL_LINKED_WITH_TBB +#include +#include +#endif + #include #define TEST_RESOLVE_INTERSECTION @@ -656,7 +661,12 @@ void generate_subtriangles(std::size_t ti, const std::vector& in_triangle_ids, const std::set >& intersecting_triangles, const std::vector>& triangles, - std::vector>& new_triangles) +#ifdef CGAL_LINKED_WITH_TBB + tbb::concurrent_vector>& new_triangles +#else + std::vector>& new_triangles +#endif + ) { // std::cout << "generate_subtriangles()\n"; // std::cout << std::setprecision(17); @@ -1266,46 +1276,67 @@ void autorefine_soup_output(const PointRange& input_points, CGAL_PMP_AUTOREFINE_VERBOSE("triangulate faces"); // now refine triangles - std::vector> new_triangles; // Need to be threadsafe +#ifdef CGAL_LINKED_WITH_TBB + tbb::concurrent_vector> new_triangles; +#else + std::vector> new_triangles; +#endif #ifdef USE_PROGRESS_DISPLAY boost::timer::progress_display pd(triangles.size()); #endif - //TODO: PARALLEL_FOR #1 - for(std::size_t ti=0; ti& t = triangles[ti]; - auto is_constant_in_dim = [](const std::array& t, int dim) - { - return t[0][dim]==t[1][dim] && t[0][dim]!=t[2][dim]; - }; + if (all_segments[ti].empty() && all_points[ti].empty()) + new_triangles.push_back(triangles[ti]); + else + { +#ifdef USE_FIXED_PROJECTION_TRAITS + const std::array& t = triangles[ti]; + auto is_constant_in_dim = [](const std::array& t, int dim) + { + return t[0][dim] == t[1][dim] && t[0][dim] != t[2][dim]; + }; - typename EK::Vector_3 orth = CGAL::normal(t[0], t[1], t[2]); // TODO::avoid construction? - int c = CGAL::abs(orth[0]) > CGAL::abs(orth[1]) ? 0 : 1; - c = CGAL::abs(orth[2]) > CGAL::abs(orth[c]) ? 2 : c; + typename EK::Vector_3 orth = CGAL::normal(t[0], t[1], t[2]); // TODO::avoid construction? + int c = CGAL::abs(orth[0]) > CGAL::abs(orth[1]) ? 0 : 1; + c = CGAL::abs(orth[2]) > CGAL::abs(orth[c]) ? 2 : c; - if(c == 0) { - autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); - } else if(c == 1) { - autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); - } else if(c == 2) { - autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); - } - #else - autorefine_impl::generate_subtriangles(ti, all_segments_ids[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); - #endif - } + if (c == 0) { + autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + } + else if (c == 1) { + autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + } + else if (c == 2) { + autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + } +#else + autorefine_impl::generate_subtriangles(ti, all_segments_ids[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); +#endif + } #ifdef USE_PROGRESS_DISPLAY - ++pd; + ++pd; #endif + }; + +#ifdef CGAL_LINKED_WITH_TBB + tbb::parallel_for(tbb::blocked_range(0, triangles.size()), + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) + func(ti); + } + ); +#else + for (std::size_t ti = 0; ti < triangles.size(); ++ti) { + func(ti); } +#endif + + // brute force output: create a soup, orient and to-mesh CGAL_PMP_AUTOREFINE_VERBOSE("create output soup"); From 1c1ed53c76457c841dab781f76f3eacfb299071c Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 30 May 2023 08:03:29 +0100 Subject: [PATCH 57/99] Parallelize deduplicate_segments() --- .../Polygon_mesh_processing/autorefinement.h | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index e862d683960..ad88f3a6ace 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1178,7 +1178,8 @@ void autorefine_soup_output(const PointRange& input_points, std::vector< std::vector > all_in_triangle_ids(triangles.size()); CGAL_PMP_AUTOREFINE_VERBOSE("compute intersections"); - + Real_timer t; + t.start(); std::set > intersecting_triangles; //TODO: PARALLEL_FOR #2 for (const Pair_of_triangle_ids& p : si_pairs) @@ -1225,16 +1226,22 @@ void autorefine_soup_output(const PointRange& input_points, intersecting_triangles.insert(CGAL::make_sorted_pair(i1, i2)); } } + std::cout << t.time() << " sec. for #2" << std::endl; #ifdef DEDUPLICATE_SEGMENTS // deduplicate inserted segments //TODO: PARALLEL_FOR #3 + Real_timer t3; + t3.start(); std::vector>> all_segments_ids(all_segments.size()); - for(std::size_t ti=0; ti point_id_map; + + auto get_point_id = [&](const typename EK::Point_3& pt) { auto insert_res = point_id_map.insert(std::make_pair(pt, all_points[ti].size())); @@ -1243,6 +1250,7 @@ void autorefine_soup_output(const PointRange& input_points, return insert_res.first->second; }; + if (!all_points[ti].empty()) { std::vector tmp; @@ -1271,9 +1279,25 @@ void autorefine_soup_output(const PointRange& input_points, if (all_segments_ids[ti].size()!=nbs) filtered_in_triangle_ids.swap(all_in_triangle_ids[ti]); } + }; + +#ifdef CGAL_LINKED_WITH_TBB + tbb::parallel_for(tbb::blocked_range(0, triangles.size()), + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) + deduplicate_inserted_segments(ti); + } + ); +#else + for (std::size_t ti = 0; ti < triangles.size(); ++ti) { + deduplicate_inserted_segments(ti); } #endif + + std::cout << t.time() << " sec. for #3" << std::endl; +#endif + CGAL_PMP_AUTOREFINE_VERBOSE("triangulate faces"); // now refine triangles #ifdef CGAL_LINKED_WITH_TBB From 2695834873b41052bb2b8669d74e93de41fb89ea Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 30 May 2023 08:10:06 +0100 Subject: [PATCH 58/99] Rename lambdas --- .../Polygon_mesh_processing/soup_autorefinement.cpp | 2 +- .../CGAL/Polygon_mesh_processing/autorefinement.h | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index f1230668948..d5ebeb78c3f 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -36,7 +36,7 @@ int main(int argc, char** argv) std::vector> output_triangles; PMP::autorefine_soup_output(input_points, input_triangles, output_points, output_triangles); std::cout << "#points = " << output_points.size() << " and #triangles = " << output_triangles.size() << " in " << t.time() << " sec." << std::endl; - // CGAL::IO::write_polygon_soup("autorefined.off", output_points, output_triangles, CGAL::parameters::stream_precision(17)); + CGAL::IO::write_polygon_soup("autorefined.off", output_points, output_triangles, CGAL::parameters::stream_precision(17)); return 0; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index ad88f3a6ace..40a3ed87cbc 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1226,7 +1226,7 @@ void autorefine_soup_output(const PointRange& input_points, intersecting_triangles.insert(CGAL::make_sorted_pair(i1, i2)); } } - std::cout << t.time() << " sec. for #2" << std::endl; + std::cout << t.time() << " sec. for compute_intersections()" << std::endl; #ifdef DEDUPLICATE_SEGMENTS // deduplicate inserted segments @@ -1295,7 +1295,7 @@ void autorefine_soup_output(const PointRange& input_points, #endif - std::cout << t.time() << " sec. for #3" << std::endl; + std::cout << t.time() << " sec. for deduplicate_segments()" << std::endl; #endif CGAL_PMP_AUTOREFINE_VERBOSE("triangulate faces"); @@ -1311,7 +1311,7 @@ void autorefine_soup_output(const PointRange& input_points, #endif - auto func = [&](std::size_t ti) + auto refine_triangles = [&](std::size_t ti) { if (all_segments[ti].empty() && all_points[ti].empty()) new_triangles.push_back(triangles[ti]); @@ -1351,12 +1351,12 @@ void autorefine_soup_output(const PointRange& input_points, tbb::parallel_for(tbb::blocked_range(0, triangles.size()), [&](const tbb::blocked_range& r) { for (size_t ti = r.begin(); ti != r.end(); ++ti) - func(ti); + refine_triangles(ti); } ); #else for (std::size_t ti = 0; ti < triangles.size(); ++ti) { - func(ti); + refine_triangles(ti); } #endif From e34a79864a78c7a19402af066698881d54a22d28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 30 May 2023 10:13:28 +0200 Subject: [PATCH 59/99] debug macro --- .../Polygon_mesh_processing/autorefinement.h | 38 ++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 40a3ed87cbc..eb24d60804a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -48,15 +48,20 @@ #define TEST_RESOLVE_INTERSECTION #define DEDUPLICATE_SEGMENTS +#define USE_DEBUG_PARALLEL_TIMERS //#define DEBUG_COUNTERS //#define USE_FIXED_PROJECTION_TRAITS //#define DEBUG_DEPTH +#ifdef USE_DEBUG_PARALLEL_TIMERS +#include +#endif + #ifdef USE_FIXED_PROJECTION_TRAITS #include #endif -#ifdef DEBUG_COUNTERS +#if defined(DEBUG_COUNTERS) || defined(USE_DEBUG_PARALLEL_TIMERS) #include #endif @@ -1178,8 +1183,10 @@ void autorefine_soup_output(const PointRange& input_points, std::vector< std::vector > all_in_triangle_ids(triangles.size()); CGAL_PMP_AUTOREFINE_VERBOSE("compute intersections"); +#ifdef USE_DEBUG_PARALLEL_TIMERS Real_timer t; t.start(); +#endif std::set > intersecting_triangles; //TODO: PARALLEL_FOR #2 for (const Pair_of_triangle_ids& p : si_pairs) @@ -1226,7 +1233,9 @@ void autorefine_soup_output(const PointRange& input_points, intersecting_triangles.insert(CGAL::make_sorted_pair(i1, i2)); } } - std::cout << t.time() << " sec. for compute_intersections()" << std::endl; +#ifdef USE_DEBUG_PARALLEL_TIMERS + std::cout << t.time() << " sec. for #2" << std::endl; +#endif #ifdef DEDUPLICATE_SEGMENTS // deduplicate inserted segments @@ -1294,8 +1303,9 @@ void autorefine_soup_output(const PointRange& input_points, } #endif - - std::cout << t.time() << " sec. for deduplicate_segments()" << std::endl; +#ifdef USE_DEBUG_PARALLEL_TIMERS + std::cout << t.time() << " sec. for #3" << std::endl; +#endif #endif CGAL_PMP_AUTOREFINE_VERBOSE("triangulate faces"); @@ -1347,6 +1357,11 @@ void autorefine_soup_output(const PointRange& input_points, #endif }; + +#ifdef USE_DEBUG_PARALLEL_TIMERS + t.reset(); + t.start(); +#endif #ifdef CGAL_LINKED_WITH_TBB tbb::parallel_for(tbb::blocked_range(0, triangles.size()), [&](const tbb::blocked_range& r) { @@ -1360,7 +1375,11 @@ void autorefine_soup_output(const PointRange& input_points, } #endif - +#ifdef USE_DEBUG_PARALLEL_TIMERS + t.stop(); + std::cout << t.time() << " sec. for #1" << std::endl; + t.reset(); +#endif // brute force output: create a soup, orient and to-mesh CGAL_PMP_AUTOREFINE_VERBOSE("create output soup"); @@ -1408,10 +1427,19 @@ void autorefine_soup_output(const PointRange& input_points, // import refined triangles //TODO: PARALLEL_FOR #4 +#ifdef USE_DEBUG_PARALLEL_TIMERS + t.reset(); + t.start(); +#endif for (const std::array& t : new_triangles) { soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); } +#ifdef USE_DEBUG_PARALLEL_TIMERS + t.stop(); + std::cout << t.time() << " sec. for #4" << std::endl; + t.reset(); +#endif #ifndef CGAL_NDEBUG CGAL_PMP_AUTOREFINE_VERBOSE("check soup"); From 3d6d9b3edce9890d2b0dae38c2d1231602f98411 Mon Sep 17 00:00:00 2001 From: Andreas Fabri Date: Tue, 30 May 2023 11:10:36 +0100 Subject: [PATCH 60/99] parallelize unique points --- .../Polygon_mesh_processing/autorefinement.h | 73 ++++++++++++++++++- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index eb24d60804a..e5f96d26c3b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -41,6 +41,7 @@ #ifdef CGAL_LINKED_WITH_TBB #include +#include #include #endif @@ -1386,11 +1387,18 @@ void autorefine_soup_output(const PointRange& input_points, Cartesian_converter to_input; // TODO: reuse the fact that maps per triangle are already sorted + +#ifdef CGAL_LINKED_WITH_TBB + tbb::concurrent_map point_id_map; +#else std::map point_id_map; +#endif + #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) std::vector exact_soup_points; #endif + /// Lambda get_point_id() auto get_point_id = [&](const typename EK::Point_3& pt) { auto insert_res = point_id_map.insert(std::make_pair(pt, soup_points.size())); @@ -1404,6 +1412,8 @@ void autorefine_soup_output(const PointRange& input_points, return insert_res.first->second; }; + + std::vector input_point_ids; input_point_ids.reserve(input_points.size()); for (const auto& p : input_points) @@ -1431,13 +1441,70 @@ void autorefine_soup_output(const PointRange& input_points, t.reset(); t.start(); #endif - for (const std::array& t : new_triangles) - { + + bool sequential = +#ifdef CGAL_LINKED_WITH_TBB + false; +#else + true; +#endif + + + std::size_t offset = soup_triangles.size(); + std::string mode; + if(sequential || new_triangles.size() < 100){ + mode = "sequential"; + soup_triangles.reserve(offset + new_triangles.size()); + for (const std::array& t : new_triangles) + { soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); + } } + else { + mode = "parallel"; +#ifdef CGAL_LINKED_WITH_TBB + + tbb::concurrent_vector concurrent_soup_points; + /// Lambda concurrent_get_point_id() + auto concurrent_get_point_id = [&](const typename EK::Point_3& pt) + { + auto insert_res = point_id_map.insert(std::make_pair(pt, concurrent_soup_points.size())); + if (insert_res.second) + { + concurrent_soup_points.push_back(to_input(pt)); +#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) + exact_soup_points.push_back(pt); +#endif + } + return insert_res.first->second; + }; + + + soup_triangles.resize(offset + new_triangles.size()); + std::cout << "soup_triangles.size() = " << soup_triangles.size() << std::endl; + std::cout << "new_triangles.size() = " << new_triangles.size() << std::endl; + tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) { + if (offset + ti > soup_triangles.size()) { + std::cout << "ti = " << ti << std::endl; + } + const std::array& t = new_triangles[ti]; + soup_triangles[offset + ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2])); + } + } + ); + + soup_points.reserve(soup_points.size() + concurrent_soup_points.size()); + soup_points.insert(soup_points.end(), concurrent_soup_points.begin(), concurrent_soup_points.end()); + } +#endif + + + #ifdef USE_DEBUG_PARALLEL_TIMERS t.stop(); - std::cout << t.time() << " sec. for #4" << std::endl; + std::cout << t.time() << " sec. for #4 (" << mode << ")" << std::endl; t.reset(); #endif From a1fbd105dacff034f89de7db2b5086c2f24999ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 30 May 2023 15:07:13 +0200 Subject: [PATCH 61/99] add TODO --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index e5f96d26c3b..16c788c22ec 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -164,7 +164,9 @@ do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, } } + // supporting_line intersects: points are coplanar + // TODO: check if we can write a dedicated predicate taking advantage of p,q being shared ::CGAL::Orientation pqr = cpl_orient(p, q, r); ::CGAL::Orientation pqs = cpl_orient(p, q, s); From 4b2f3e6ec7c10e0d7acf8d40608f4e548db7e091 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 30 May 2023 16:01:05 +0200 Subject: [PATCH 62/99] take np into account for concurrency --- .../soup_autorefinement.cpp | 4 +- .../Polygon_mesh_processing/autorefinement.h | 219 ++++++++++-------- 2 files changed, 119 insertions(+), 104 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index d5ebeb78c3f..823c50974dc 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -34,7 +34,9 @@ int main(int argc, char** argv) t.start(); std::vector output_points; std::vector> output_triangles; - PMP::autorefine_soup_output(input_points, input_triangles, output_points, output_triangles); + PMP::autorefine_soup_output(input_points, input_triangles, + output_points, output_triangles, + CGAL::parameters::concurrency_tag(CGAL::Parallel_if_available_tag())); std::cout << "#points = " << output_points.size() << " and #triangles = " << output_triangles.size() << " in " << t.time() << " sec." << std::endl; CGAL::IO::write_polygon_soup("autorefined.off", output_points, output_triangles, CGAL::parameters::stream_precision(17)); diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 16c788c22ec..ae383a4af29 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -658,10 +658,11 @@ void collect_intersections(const std::array& t1, ////////////////////////////////// ////////////////////////////////// -template void generate_subtriangles(std::size_t ti, std::vector>& segments, @@ -669,11 +670,7 @@ void generate_subtriangles(std::size_t ti, const std::vector& in_triangle_ids, const std::set >& intersecting_triangles, const std::vector>& triangles, -#ifdef CGAL_LINKED_WITH_TBB - tbb::concurrent_vector>& new_triangles -#else - std::vector>& new_triangles -#endif + PointVector& new_triangles ) { // std::cout << "generate_subtriangles()\n"; @@ -1131,6 +1128,14 @@ void autorefine_soup_output(const PointRange& input_points, Sequential_tag > ::type Concurrency_tag; + constexpr bool parallel_execution = std::is_same_v; + +#ifndef CGAL_LINKED_WITH_TBB + CGAL_static_assertion_msg (parallel_execution, + "Parallel_tag is enabled but TBB is unavailable."); +#endif + + typedef std::size_t Input_TID; typedef std::pair Pair_of_triangle_ids; @@ -1294,16 +1299,20 @@ void autorefine_soup_output(const PointRange& input_points, }; #ifdef CGAL_LINKED_WITH_TBB - tbb::parallel_for(tbb::blocked_range(0, triangles.size()), - [&](const tbb::blocked_range& r) { - for (size_t ti = r.begin(); ti != r.end(); ++ti) - deduplicate_inserted_segments(ti); - } - ); -#else - for (std::size_t ti = 0; ti < triangles.size(); ++ti) { - deduplicate_inserted_segments(ti); + if (parallel_execution) + { + tbb::parallel_for(tbb::blocked_range(0, triangles.size()), + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) + deduplicate_inserted_segments(ti); + } + ); } + else +#else + for (std::size_t ti = 0; ti < triangles.size(); ++ti) { + deduplicate_inserted_segments(ti); + } #endif #ifdef USE_DEBUG_PARALLEL_TIMERS @@ -1314,7 +1323,9 @@ void autorefine_soup_output(const PointRange& input_points, CGAL_PMP_AUTOREFINE_VERBOSE("triangulate faces"); // now refine triangles #ifdef CGAL_LINKED_WITH_TBB - tbb::concurrent_vector> new_triangles; + std::conditional_t>, + std::vector>> new_triangles; #else std::vector> new_triangles; #endif @@ -1325,40 +1336,40 @@ void autorefine_soup_output(const PointRange& input_points, auto refine_triangles = [&](std::size_t ti) + { + if (all_segments[ti].empty() && all_points[ti].empty()) + new_triangles.push_back(triangles[ti]); + else { - if (all_segments[ti].empty() && all_points[ti].empty()) - new_triangles.push_back(triangles[ti]); - else - { #ifdef USE_FIXED_PROJECTION_TRAITS - const std::array& t = triangles[ti]; - auto is_constant_in_dim = [](const std::array& t, int dim) - { - return t[0][dim] == t[1][dim] && t[0][dim] != t[2][dim]; - }; + const std::array& t = triangles[ti]; + auto is_constant_in_dim = [](const std::array& t, int dim) + { + return t[0][dim] == t[1][dim] && t[0][dim] != t[2][dim]; + }; - typename EK::Vector_3 orth = CGAL::normal(t[0], t[1], t[2]); // TODO::avoid construction? - int c = CGAL::abs(orth[0]) > CGAL::abs(orth[1]) ? 0 : 1; - c = CGAL::abs(orth[2]) > CGAL::abs(orth[c]) ? 2 : c; + typename EK::Vector_3 orth = CGAL::normal(t[0], t[1], t[2]); // TODO::avoid construction? + int c = CGAL::abs(orth[0]) > CGAL::abs(orth[1]) ? 0 : 1; + c = CGAL::abs(orth[2]) > CGAL::abs(orth[c]) ? 2 : c; - if (c == 0) { - autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); - } - else if (c == 1) { - autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); - } - else if (c == 2) { - autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); - } + if (c == 0) { + autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + } + else if (c == 1) { + autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + } + else if (c == 2) { + autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + } #else - autorefine_impl::generate_subtriangles(ti, all_segments_ids[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + autorefine_impl::generate_subtriangles(ti, all_segments_ids[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); #endif - } + } #ifdef USE_PROGRESS_DISPLAY - ++pd; + ++pd; #endif - }; + }; #ifdef USE_DEBUG_PARALLEL_TIMERS @@ -1366,16 +1377,20 @@ void autorefine_soup_output(const PointRange& input_points, t.start(); #endif #ifdef CGAL_LINKED_WITH_TBB - tbb::parallel_for(tbb::blocked_range(0, triangles.size()), - [&](const tbb::blocked_range& r) { - for (size_t ti = r.begin(); ti != r.end(); ++ti) - refine_triangles(ti); - } - ); -#else - for (std::size_t ti = 0; ti < triangles.size(); ++ti) { - refine_triangles(ti); + if (parallel_execution) + { + tbb::parallel_for(tbb::blocked_range(0, triangles.size()), + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) + refine_triangles(ti); + } + ); } + else +#else + for (std::size_t ti = 0; ti < triangles.size(); ++ti) { + refine_triangles(ti); + } #endif #ifdef USE_DEBUG_PARALLEL_TIMERS @@ -1391,7 +1406,9 @@ void autorefine_soup_output(const PointRange& input_points, // TODO: reuse the fact that maps per triangle are already sorted #ifdef CGAL_LINKED_WITH_TBB - tbb::concurrent_map point_id_map; + std::conditional_t, + std::map> point_id_map; #else std::map point_id_map; #endif @@ -1444,63 +1461,59 @@ void autorefine_soup_output(const PointRange& input_points, t.start(); #endif - bool sequential = -#ifdef CGAL_LINKED_WITH_TBB - false; -#else - true; + std::size_t offset = soup_triangles.size(); +#ifdef USE_DEBUG_PARALLEL_TIMERS + std::string mode = "parallel"; #endif + //TODO: 100 should be fined tune and depends on #threads +#ifdef CGAL_LINKED_WITH_TBB + if(parallel_execution && new_triangles.size() > 100) + { + tbb::concurrent_vector concurrent_soup_points; + /// Lambda concurrent_get_point_id() + auto concurrent_get_point_id = [&](const typename EK::Point_3& pt) + { + auto insert_res = point_id_map.insert(std::make_pair(pt, concurrent_soup_points.size())); + if (insert_res.second) + { + concurrent_soup_points.push_back(to_input(pt)); +#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) + exact_soup_points.push_back(pt); +#endif + } + return insert_res.first->second; + }; - std::size_t offset = soup_triangles.size(); - std::string mode; - if(sequential || new_triangles.size() < 100){ - mode = "sequential"; + + soup_triangles.resize(offset + new_triangles.size()); + std::cout << "soup_triangles.size() = " << soup_triangles.size() << std::endl; + std::cout << "new_triangles.size() = " << new_triangles.size() << std::endl; + tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) { + if (offset + ti > soup_triangles.size()) { + std::cout << "ti = " << ti << std::endl; + } + const std::array& t = new_triangles[ti]; + soup_triangles[offset + ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2])); + } + } + ); + + soup_points.reserve(soup_points.size() + concurrent_soup_points.size()); + soup_points.insert(soup_points.end(), concurrent_soup_points.begin(), concurrent_soup_points.end()); + } + else +#endif + { +#ifdef USE_DEBUG_PARALLEL_TIMERS + mode = "sequential"; +#endif soup_triangles.reserve(offset + new_triangles.size()); for (const std::array& t : new_triangles) - { - soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); - } + soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); } - else { - mode = "parallel"; -#ifdef CGAL_LINKED_WITH_TBB - - tbb::concurrent_vector concurrent_soup_points; - /// Lambda concurrent_get_point_id() - auto concurrent_get_point_id = [&](const typename EK::Point_3& pt) - { - auto insert_res = point_id_map.insert(std::make_pair(pt, concurrent_soup_points.size())); - if (insert_res.second) - { - concurrent_soup_points.push_back(to_input(pt)); -#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) - exact_soup_points.push_back(pt); -#endif - } - return insert_res.first->second; - }; - - - soup_triangles.resize(offset + new_triangles.size()); - std::cout << "soup_triangles.size() = " << soup_triangles.size() << std::endl; - std::cout << "new_triangles.size() = " << new_triangles.size() << std::endl; - tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), - [&](const tbb::blocked_range& r) { - for (size_t ti = r.begin(); ti != r.end(); ++ti) { - if (offset + ti > soup_triangles.size()) { - std::cout << "ti = " << ti << std::endl; - } - const std::array& t = new_triangles[ti]; - soup_triangles[offset + ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2])); - } - } - ); - - soup_points.reserve(soup_points.size() + concurrent_soup_points.size()); - soup_points.insert(soup_points.end(), concurrent_soup_points.begin(), concurrent_soup_points.end()); - } -#endif From 3d6c0da44cdf28be1ebfc4e7818ba78987c7209c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 31 May 2023 09:14:42 +0200 Subject: [PATCH 63/99] remove debug --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index ae383a4af29..18bbfa2ce40 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1323,9 +1323,9 @@ void autorefine_soup_output(const PointRange& input_points, CGAL_PMP_AUTOREFINE_VERBOSE("triangulate faces"); // now refine triangles #ifdef CGAL_LINKED_WITH_TBB - std::conditional_t>, - std::vector>> new_triangles; + std::conditional_t>, + std::vector>> new_triangles; #else std::vector> new_triangles; #endif @@ -1487,8 +1487,6 @@ void autorefine_soup_output(const PointRange& input_points, soup_triangles.resize(offset + new_triangles.size()); - std::cout << "soup_triangles.size() = " << soup_triangles.size() << std::endl; - std::cout << "new_triangles.size() = " << new_triangles.size() << std::endl; tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), [&](const tbb::blocked_range& r) { for (size_t ti = r.begin(); ti != r.end(); ++ti) { From 854aacd671b9936730e97f8bf003bf2969e016fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 6 Jun 2023 15:31:19 +0200 Subject: [PATCH 64/99] add comments --- .../Triangle_3_Triangle_3_intersection.h | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h index 4cc5f9be560..99dcd24ff45 100644 --- a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h +++ b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h @@ -59,6 +59,19 @@ coplanar_segment_segment_alpha_intersection(const typename K::Point_3& p1, const template struct Point_on_triangle { + // triangle points are not stored in this class but are expected + // to always be passed in the same order. For a triangle pqr, + // edge 0 is pq, edge 1 qr and edge 2 rp. Point 0 is p, 1 is q and 2 is r. + // + // (id, -1) point on t1 + // (-1, id) point on t2 + // (id1, id2) intersection of edges + std::pair t1_t2_ids; + boost::container::flat_set extra_t1; // store other ids of edges containing the point + typename Kernel::FT alpha; // + +////// + static inline const typename Kernel::Point_3& @@ -83,13 +96,7 @@ struct Point_on_triangle , alpha(alpha) {} - // (id, -1) point on t1 - // (-1, id) point on t2 - // (id1, id2) intersection of edges - std::pair t1_t2_ids; - boost::container::flat_set extra_t1; - typename Kernel::FT alpha; - + // orientation of the current point wrt to edge id1 (p1q1) Orientation orientation (const typename Kernel::Point_3& p1, // source of edge edge_id1 const typename Kernel::Point_3& q1, // target of edge edge_id1 @@ -116,7 +123,7 @@ struct Point_on_triangle CGAL_assertion((t1_t2_ids.first+1)%3==edge_id1); if (alpha==1) return ZERO; return alpha<=1?POSITIVE:NEGATIVE; - } + } else { //this is an input point of t2 @@ -129,6 +136,7 @@ struct Point_on_triangle int id1() const { return t1_t2_ids.first; } int id2() const { return t1_t2_ids.second; } + // construct the intersection point from the info stored typename Kernel::Point_3 point(const typename Kernel::Point_3& p1, const typename Kernel::Point_3& q1, @@ -147,6 +155,12 @@ struct Point_on_triangle } }; +// the intersection of two triangles is computed by interatively intersection t2 +// with halfspaces defined by edges of t1. The following function is called +// for each each on t1 on edge of the current intersection. +// pq is such an edge and p1q1 from t1 defines the halfspace intersection +// we are currently interseted in. We return the intersection point of +// pq with p1q1 template Point_on_triangle intersection(const Point_on_triangle& p, @@ -172,7 +186,7 @@ intersection(const Point_on_triangle& p, { switch(q.id1()) { - case -1: // (-1, ip2) - (-1, iq2) + case -1: // A: (-1, ip2) - (-1, iq2) { CGAL_assertion((p.id2()+1)%3 == q.id2() || (q.id2()+1)%3 == p.id2()); // CGAL_assertion(p.extra_t1.empty() && q.extra_t1.empty()); // TMP to see if it's worth implementing special case @@ -187,7 +201,7 @@ intersection(const Point_on_triangle& p, return Point_on_triangle(edge_id_t1, id2, alpha); // intersection with an original edge of t2 } default: - if (q.id2()!=-1) // (-1, ip2) - (iq1, iq2) + if (q.id2()!=-1) // B: (-1, ip2) - (iq1, iq2) { if (p.id2() == q.id2() || p.id2() == (q.id2()+1)%3) { @@ -210,7 +224,7 @@ intersection(const Point_on_triangle& p, int eid1 = p.extra_t1.count(q.id1())!=0 ? q.id1() : 3-q.id1()-edge_id_t1; return Point_on_triangle((eid1+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3, -1); // vertex of t1 } - // (-1, ip2) - (iq1, -1) + // C: (-1, ip2) - (iq1, -1) //vertex of t1, special case t1 edge passed thru a vertex of t2 CGAL_assertion(edge_id_t1 == 2); #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION @@ -229,7 +243,7 @@ intersection(const Point_on_triangle& p, { switch(q.id1()) { - case -1: // (ip1, -1) - (-1, iq2) + case -1: // G: (ip1, -1) - (-1, iq2) //vertex of t1, special case t1 edge passed thru a vertex of t2 #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " -- case 5\n"; @@ -243,8 +257,8 @@ intersection(const Point_on_triangle& p, #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " -- case 6\n"; #endif - CGAL_assertion(q.id2()!=-1); // (ip1, -1) - (iq2, -1) - //(ip1,-1), (iq1, iq2) + CGAL_assertion(q.id2()!=-1); // I: (ip1, -1) - (iq2, -1) + //H: (ip1,-1), (iq1, iq2) CGAL_assertion(edge_id_t1==2); // p and q are on the same edge of t1 CGAL_assertion(p.id1()==q.id1() || p.id1()==(q.id1()+1)%3); @@ -256,7 +270,7 @@ intersection(const Point_on_triangle& p, { switch(q.id1()) { - case -1: // (ip1, ip2) - (-1, iq2) + case -1: // D: (ip1, ip2) - (-1, iq2) { if (q.id2() == p.id2() || q.id2() == (p.id2()+1)%3) { @@ -284,7 +298,7 @@ intersection(const Point_on_triangle& p, { switch(q.id2()) { - case -1: // (ip1, ip2) - (iq1, -1) + case -1: // F: (ip1, ip2) - (iq1, -1) { // p and q are on the same edge of t1 CGAL_assertion(q.id1()==p.id1() || q.id1()==(p.id1()+1)%3); @@ -293,7 +307,7 @@ intersection(const Point_on_triangle& p, #endif return Point_on_triangle((p.id1()+1)%3==edge_id_t1?edge_id_t1:(edge_id_t1+1)%3 , -1); } - default: // (ip1, ip2) - (iq1, iq2) + default: // E: (ip1, ip2) - (iq1, iq2) { if (p.id2()==q.id2()) { From 0551cefa5d315c4071dec5c1118bceaaa6bdfcdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 7 Jun 2023 15:02:10 +0200 Subject: [PATCH 65/99] add more test from errors while testing thingi10k models --- .../triangle_3_triangle_3_intersection.cpp | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/Intersections_3/test/Intersections_3/triangle_3_triangle_3_intersection.cpp b/Intersections_3/test/Intersections_3/triangle_3_triangle_3_intersection.cpp index 0098bcd0142..f0875a55ee8 100644 --- a/Intersections_3/test/Intersections_3/triangle_3_triangle_3_intersection.cpp +++ b/Intersections_3/test/Intersections_3/triangle_3_triangle_3_intersection.cpp @@ -96,6 +96,13 @@ void test_coplanar_triangles(){ assert(CGAL::object_cast(&obj)!=nullptr); obj=CGAL::intersection(t2,t1); assert(CGAL::object_cast(&obj)!=nullptr); + // TK10 case C' + t1=Triangle(Point(88.7921, 89.0007, 1.25), Point(88.1912, 88.3997, 1.25), Point(89.8224, 90.031, 1.25)); + t2=Triangle(Point(88.0497, 88.2583, 1.25), Point(82.9292, 81.8747, 1.25), Point(91.1726, 91.3812, 1.25)); + obj=CGAL::intersection(t1,t2); + assert(CGAL::object_cast(&obj)!=nullptr); + obj=CGAL::intersection(t2,t1); + assert(CGAL::object_cast(&obj)!=nullptr); //Intersection is a point //edges are collinear, one vertex in common t1=Triangle( Point(0,0,0),Point(0,1,0),Point(1,0,0) ); @@ -153,6 +160,13 @@ void test_coplanar_triangles(){ assert(CGAL::object_cast(&obj)!=nullptr); obj=CGAL::intersection(t2,t1); assert(CGAL::object_cast(&obj)!=nullptr); + // TK10 case D + t1=Triangle(Point(-34.893700000000003, -16.0351, 3.1334899999999998e-12), Point(-34.893700000000003, -18.5351, 3.1334899999999998e-12), Point(-42.393700000000003, -16.0351, 3.1334899999999998e-12)); + t2=Triangle(Point(-34.893700000000003, -32.0351, 3.1334899999999998e-12), Point(-34.893700000000003, -9.7851400000000002, 3.1334899999999998e-12), Point(-31.643699999999999, -17.201799999999999, 3.1334899999999998e-12)); + obj=CGAL::intersection(t1,t2); + assert(CGAL::object_cast(&obj)!=nullptr); + obj=CGAL::intersection(t2,t1); + assert(CGAL::object_cast(&obj)!=nullptr); //Intersection is a polygon //David's star t1=Triangle( Point(0,0,0),Point(1,0,0),Point(0.5,1.5,0) ); @@ -181,6 +195,51 @@ void test_coplanar_triangles(){ obj=CGAL::intersection(t2,t1); assert(CGAL::object_cast(&obj)!=nullptr); assert(CGAL::object_cast(&obj)->size()==4); + // TK10 case A + t1=Triangle(Point(3.74861, 12.4822, 14.0112), Point(5.40582, 12.4822, 15.6895), Point(5.37748, 12.4822, 15.7206)); + t2=Triangle(Point(5.49972, 12.4822, 13.491), Point(5.27627, 12.4822, 15.8106), Point(5.32119, 12.4822, 15.8126)); + obj=CGAL::intersection(t1,t2); + assert(CGAL::object_cast(&obj)!=nullptr); + assert(CGAL::object_cast(&obj)->size()==4); + obj=CGAL::intersection(t2,t1); + assert(CGAL::object_cast(&obj)!=nullptr); + assert(CGAL::object_cast(&obj)->size()==4); + // TK10 case C + t1=Triangle(Point(5, -94.6659, 3.85175), Point(5, -94.5682, 3.08638), Point(5, -94.8182, 3.08638)); + t2=Triangle(Point(5, -94.4317, 3.76399), Point(5, -97.6182, 3.08638), Point(5, -94.5659, 2.99682)); + obj=CGAL::intersection(t1,t2); + assert(CGAL::object_cast(&obj)!=nullptr); + assert(CGAL::object_cast(&obj)->size()==4); + obj=CGAL::intersection(t2,t1); + assert(CGAL::object_cast(&obj)!=nullptr); + assert(CGAL::object_cast(&obj)->size()==4); + // TK10 case E + t1=Triangle(Point(-955.858, -45.032, -0.016), Point(-955.856, -45.032, -0.004), Point(-955.856, -45.032, -0.002)); + t2=Triangle(Point(-955.856, -45.032, 0.006), Point(-955.854, -45.032, -0.002), Point(-955.876, -45.032, -0.034)); + obj=CGAL::intersection(t1,t2); + assert(CGAL::object_cast(&obj)!=nullptr); + assert(CGAL::object_cast(&obj)->size()==4); + obj=CGAL::intersection(t2,t1); + assert(CGAL::object_cast(&obj)!=nullptr); + assert(CGAL::object_cast(&obj)->size()==4); + // TK10 case F + t1=Triangle(Point(141.172, 20.576, 155.764), Point(141.172, 20.588, 155.766), Point(141.172, 20.59, 155.766)); + t2=Triangle(Point(141.172, 20.602, 155.768), Point(141.172, 20.594, 155.766), Point(141.172, 20.574, 155.764)); + obj=CGAL::intersection(t1,t2); + assert(CGAL::object_cast(&obj)!=nullptr); + assert(CGAL::object_cast(&obj)->size()==4); + obj=CGAL::intersection(t2,t1); + assert(CGAL::object_cast(&obj)!=nullptr); + assert(CGAL::object_cast(&obj)->size()==4); + // TK10 case D + t1=Triangle(Point(152.864, 126.324, 0.950001), Point(152.77, 126.483, 0.950001), Point(153.072, 125.973, 0.950001)); + t2=Triangle(Point(153.322, 125.551, 0.950001), Point(152.218, 127.415, 0.950001), Point(153.66, 124.768, 0.950001)); + obj=CGAL::intersection(t1,t2); + assert(CGAL::object_cast(&obj)!=nullptr); + assert(CGAL::object_cast(&obj)->size()==4); + obj=CGAL::intersection(t2,t1); + assert(CGAL::object_cast(&obj)!=nullptr); + assert(CGAL::object_cast(&obj)->size()==4); //Intersection is empty t1=Triangle( Point(0,0,0),Point(0,1,0),Point(1,0,0) ); t2=Triangle( Point(-0.1,-0.1,0),Point(-0.1,-0.9,0),Point(-1,-0.1,0) ); From 48712f7862f02ce63558de039c603e0d018ae31d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 8 Jun 2023 14:04:55 +0200 Subject: [PATCH 66/99] don't use c++17 features --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 18bbfa2ce40..6b664ec360b 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1128,7 +1128,7 @@ void autorefine_soup_output(const PointRange& input_points, Sequential_tag > ::type Concurrency_tag; - constexpr bool parallel_execution = std::is_same_v; + constexpr bool parallel_execution = std::is_same::value; #ifndef CGAL_LINKED_WITH_TBB CGAL_static_assertion_msg (parallel_execution, From 003bf47781ef69354d9cd388f2fce00168c2e762 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 8 Jun 2023 14:05:09 +0200 Subject: [PATCH 67/99] move alpha computation into a functor --- .../Triangle_3_Triangle_3_intersection.h | 52 +++++-------------- .../include/CGAL/Kernel/function_objects.h | 31 +++++++++++ .../include/CGAL/Kernel/interface_macros.h | 2 + .../Polygon_mesh_processing/autorefinement.h | 6 +-- 4 files changed, 50 insertions(+), 41 deletions(-) diff --git a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h index 99dcd24ff45..68166f18c6e 100644 --- a/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h +++ b/Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h @@ -34,28 +34,6 @@ namespace CGAL { namespace Intersections { namespace internal{ -//TODO: move into a functor -template -typename K::FT -coplanar_segment_segment_alpha_intersection(const typename K::Point_3& p1, const typename K::Point_3& p2, // segment 1 - const typename K::Point_3& p3, const typename K::Point_3& p4, // segment 2 - const K& k) -{ - const typename K::Vector_3 v1 = p2-p1; - const typename K::Vector_3 v2 = p4-p3; - - CGAL_assertion(k.coplanar_3_object()(p1,p2,p3,p4)); - - const typename K::Vector_3 v3 = p3 - p1; - const typename K::Vector_3 v3v2 = cross_product(v3,v2); - const typename K::Vector_3 v1v2 = cross_product(v1,v2); - const typename K::FT sl = v1v2.squared_length(); - CGAL_assertion(!certainly(is_zero(sl))); - - const typename K::FT t = ((v3v2.x()*v1v2.x()) + (v3v2.y()*v1v2.y()) + (v3v2.z()*v1v2.z())) / sl; - return t; // p1 + (p2-p1) * t -} - template struct Point_on_triangle { @@ -179,6 +157,8 @@ intersection(const Point_on_triangle& p, std::cout << " (" << p.id1() << "," << p.id2() << ",[" << p.alpha << "]) -"; std::cout << " (" << q.id1() << "," << q.id2() << ",[" << q.alpha << "]) || e" << edge_id_t1; #endif + typename Kernel::Compute_alpha_for_coplanar_triangle_intersection_3 compute_alpha + = k.compute_alpha_for_coplanar_triangle_intersection_3_object(); typedef Point_on_triangle Pot; switch(p.id1()) { @@ -193,10 +173,9 @@ intersection(const Point_on_triangle& p, #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " -- case 1\n"; #endif - typename Kernel::FT alpha = - coplanar_segment_segment_alpha_intersection(p1, q1, - Pot::point_from_id(p2, q2, r2, p.id2()), - Pot::point_from_id(p2, q2, r2, q.id2()), k); + typename Kernel::FT alpha = compute_alpha(p1, q1, + Pot::point_from_id(p2, q2, r2, p.id2()), + Pot::point_from_id(p2, q2, r2, q.id2())); int id2 = (p.id2()+1)%3 == q.id2() ? p.id2() : q.id2(); return Point_on_triangle(edge_id_t1, id2, alpha); // intersection with an original edge of t2 } @@ -209,10 +188,9 @@ intersection(const Point_on_triangle& p, std::cout << " -- case 2\n"; #endif // points are on the same edge of t2 --> we shorten an already cut edge - typename Kernel::FT alpha = - coplanar_segment_segment_alpha_intersection(p1, q1, - Pot::point_from_id(p2, q2, r2, q.id2()), - Pot::point_from_id(p2, q2, r2, (q.id2()+1)%3), k); + typename Kernel::FT alpha = compute_alpha(p1, q1, + Pot::point_from_id(p2, q2, r2, q.id2()), + Pot::point_from_id(p2, q2, r2, (q.id2()+1)%3)); return Point_on_triangle(edge_id_t1, q.id2(), alpha); } @@ -278,10 +256,9 @@ intersection(const Point_on_triangle& p, std::cout << " -- case 7\n"; #endif // points are on the same edge of t2 --> we shorten an already cut edge - typename Kernel::FT alpha = - coplanar_segment_segment_alpha_intersection(p1, q1, - Pot::point_from_id(p2, q2, r2, p.id2()), - Pot::point_from_id(p2, q2, r2, (p.id2()+1)%3), k); + typename Kernel::FT alpha = compute_alpha(p1, q1, + Pot::point_from_id(p2, q2, r2, p.id2()), + Pot::point_from_id(p2, q2, r2, (p.id2()+1)%3)); return Point_on_triangle(edge_id_t1, p.id2(), alpha); } @@ -314,10 +291,9 @@ intersection(const Point_on_triangle& p, #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " -- case 10\n"; #endif - typename Kernel::FT alpha = - coplanar_segment_segment_alpha_intersection(p1, q1, - Pot::point_from_id(p2, q2, r2, q.id2()), - Pot::point_from_id(p2, q2, r2, (q.id2()+1)%3), k); + typename Kernel::FT alpha = compute_alpha(p1, q1, + Pot::point_from_id(p2, q2, r2, q.id2()), + Pot::point_from_id(p2, q2, r2, (q.id2()+1)%3)); return Point_on_triangle(edge_id_t1, q.id2(), alpha); } // we are intersecting an edge of t1 diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index 71aa268e6d3..780c0b2d4e5 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -2149,6 +2149,37 @@ namespace CommonKernelFunctors { } }; + template + class Compute_alpha_for_coplanar_triangle_intersection_3 + { + typedef typename K::Point_3 Point_3; + typedef typename K::Vector_3 Vector_3; + public: + typedef typename K::FT result_type; + result_type + operator()(const Point_3& p1, const Point_3& p2, // segment 1 + const Point_3& p3, const Point_3& p4) const // segment 2 + { + typename K::Construct_vector_3 vector = K().construct_vector_3_object(); + typename K::Construct_cross_product_vector_3 cross_product = + K().construct_cross_product_vector_3_object(); + + const Vector_3 v1 = vector(p1, p2); + const Vector_3 v2 = vector(p3, p4); + + CGAL_assertion(K().coplanar_3_object()(p1,p2,p3,p4)); + + const Vector_3 v3 = vector(p1, p3); + const Vector_3 v3v2 = cross_product(v3,v2); + const Vector_3 v1v2 = cross_product(v1,v2); + const typename K::FT sl = K().compute_squared_length_3_object()(v1v2); + CGAL_assertion(!certainly(is_zero(sl))); + + const typename K::FT t = ((v3v2.x()*v1v2.x()) + (v3v2.y()*v1v2.y()) + (v3v2.z()*v1v2.z())) / sl; + return t; // p1 + (p2-p1) * t + } + }; + template class Construct_point_on_2 { diff --git a/Kernel_23/include/CGAL/Kernel/interface_macros.h b/Kernel_23/include/CGAL/Kernel/interface_macros.h index 9c85643a977..e5a2ebf8121 100644 --- a/Kernel_23/include/CGAL/Kernel/interface_macros.h +++ b/Kernel_23/include/CGAL/Kernel/interface_macros.h @@ -396,6 +396,8 @@ CGAL_Kernel_cons(Construct_plane_3, construct_plane_3_object) CGAL_Kernel_cons(Construct_plane_line_intersection_point_3, construct_plane_line_intersection_point_3_object) +CGAL_Kernel_cons(Compute_alpha_for_coplanar_triangle_intersection_3, + compute_alpha_for_coplanar_triangle_intersection_3_object) CGAL_Kernel_cons(Construct_point_on_2, construct_point_on_2_object) CGAL_Kernel_cons(Construct_point_on_3, diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 6b664ec360b..6c8ba3f8cd2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -386,7 +386,7 @@ void coplanar_intersections(const std::array& t1, //intersect t2 with the three half planes which intersection defines t1 K k; - intersection_coplanar_triangles_cutoff(p1,q1,r1,0,p2,q2,r2,k,l_inter_pts); //line p1q1 + Intersections::internal::intersection_coplanar_triangles_cutoff(p1,q1,r1,0,p2,q2,r2,k,l_inter_pts); //line p1q1 #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " ipts size: " << l_inter_pts.size() << "\n"; print_points(); @@ -401,7 +401,7 @@ void coplanar_intersections(const std::array& t1, } } #endif - intersection_coplanar_triangles_cutoff(q1,r1,p1,1,p2,q2,r2,k,l_inter_pts); //line q1r1 + Intersections::internal::intersection_coplanar_triangles_cutoff(q1,r1,p1,1,p2,q2,r2,k,l_inter_pts); //line q1r1 #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " ipts size: " << l_inter_pts.size() << "\n"; print_points(); @@ -416,7 +416,7 @@ void coplanar_intersections(const std::array& t1, } } #endif - intersection_coplanar_triangles_cutoff(r1,p1,q1,2,p2,q2,r2,k,l_inter_pts); //line r1p1 + Intersections::internal::intersection_coplanar_triangles_cutoff(r1,p1,q1,2,p2,q2,r2,k,l_inter_pts); //line r1p1 #ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION std::cout << " ipts size: " << l_inter_pts.size() << "\n"; print_points(); From 0684bd203fa818c1dbf6cb4b3fae839e08da94a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 8 Jun 2023 14:17:18 +0200 Subject: [PATCH 68/99] hide debug --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 6c8ba3f8cd2..90174e42753 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -49,7 +49,7 @@ #define TEST_RESOLVE_INTERSECTION #define DEDUPLICATE_SEGMENTS -#define USE_DEBUG_PARALLEL_TIMERS +//#define USE_DEBUG_PARALLEL_TIMERS //#define DEBUG_COUNTERS //#define USE_FIXED_PROJECTION_TRAITS //#define DEBUG_DEPTH @@ -1248,8 +1248,6 @@ void autorefine_soup_output(const PointRange& input_points, #ifdef DEDUPLICATE_SEGMENTS // deduplicate inserted segments //TODO: PARALLEL_FOR #3 - Real_timer t3; - t3.start(); std::vector>> all_segments_ids(all_segments.size()); auto deduplicate_inserted_segments = [&](std::size_t ti) From c5fab1c874248e87abe1f769616f624f8bd0efdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 8 Jun 2023 14:21:59 +0200 Subject: [PATCH 69/99] fix sequential run --- .../CGAL/Polygon_mesh_processing/autorefinement.h | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 90174e42753..11b15fa4ec4 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1307,11 +1307,10 @@ void autorefine_soup_output(const PointRange& input_points, ); } else -#else - for (std::size_t ti = 0; ti < triangles.size(); ++ti) { - deduplicate_inserted_segments(ti); - } #endif + for (std::size_t ti = 0; ti < triangles.size(); ++ti) { + deduplicate_inserted_segments(ti); + } #ifdef USE_DEBUG_PARALLEL_TIMERS std::cout << t.time() << " sec. for #3" << std::endl; @@ -1385,11 +1384,10 @@ void autorefine_soup_output(const PointRange& input_points, ); } else -#else - for (std::size_t ti = 0; ti < triangles.size(); ++ti) { - refine_triangles(ti); - } #endif + for (std::size_t ti = 0; ti < triangles.size(); ++ti) { + refine_triangles(ti); + } #ifdef USE_DEBUG_PARALLEL_TIMERS t.stop(); From 45c7b0015f8f54e8f2fb517b6f5bc54181979467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 12 Jun 2023 10:55:56 +0200 Subject: [PATCH 70/99] add stop --- .../examples/Polygon_mesh_processing/soup_autorefinement.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index 823c50974dc..9e4999287f7 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -37,6 +37,7 @@ int main(int argc, char** argv) PMP::autorefine_soup_output(input_points, input_triangles, output_points, output_triangles, CGAL::parameters::concurrency_tag(CGAL::Parallel_if_available_tag())); + t.stop(); std::cout << "#points = " << output_points.size() << " and #triangles = " << output_triangles.size() << " in " << t.time() << " sec." << std::endl; CGAL::IO::write_polygon_soup("autorefined.off", output_points, output_triangles, CGAL::parameters::stream_precision(17)); From 41449d71cd3c3d7b8be578f0e3f56a3a14fc5842 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 12 Jun 2023 11:05:11 +0200 Subject: [PATCH 71/99] fix bug when setting the ids of points 2 options, one with mutex and one without. As this section is not critical, we do not really see a runtime difference (without mutex seems faster so I pick that one as default) --- .../Polygon_mesh_processing/autorefinement.h | 129 ++++++++++++++---- 1 file changed, 103 insertions(+), 26 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 11b15fa4ec4..9bbc67efb48 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -43,6 +43,9 @@ #include #include #include +#ifdef SET_POINT_IDS_USING_MUTEX +#include +#endif #endif #include @@ -1242,12 +1245,17 @@ void autorefine_soup_output(const PointRange& input_points, } } #ifdef USE_DEBUG_PARALLEL_TIMERS + t.stop(); std::cout << t.time() << " sec. for #2" << std::endl; + t.reset(); #endif #ifdef DEDUPLICATE_SEGMENTS +#ifdef USE_DEBUG_PARALLEL_TIMERS + t.start(); +#endif + // deduplicate inserted segments - //TODO: PARALLEL_FOR #3 std::vector>> all_segments_ids(all_segments.size()); auto deduplicate_inserted_segments = [&](std::size_t ti) @@ -1313,7 +1321,9 @@ void autorefine_soup_output(const PointRange& input_points, } #ifdef USE_DEBUG_PARALLEL_TIMERS + t.stop(); std::cout << t.time() << " sec. for #3" << std::endl; + t.reset(); #endif #endif @@ -1370,7 +1380,6 @@ void autorefine_soup_output(const PointRange& input_points, #ifdef USE_DEBUG_PARALLEL_TIMERS - t.reset(); t.start(); #endif #ifdef CGAL_LINKED_WITH_TBB @@ -1427,8 +1436,7 @@ void autorefine_soup_output(const PointRange& input_points, return insert_res.first->second; }; - - + // TODO: parallel_for? std::vector input_point_ids; input_point_ids.reserve(input_points.size()); for (const auto& p : input_points) @@ -1451,9 +1459,7 @@ void autorefine_soup_output(const PointRange& input_points, } // import refined triangles - //TODO: PARALLEL_FOR #4 #ifdef USE_DEBUG_PARALLEL_TIMERS - t.reset(); t.start(); #endif @@ -1466,37 +1472,108 @@ void autorefine_soup_output(const PointRange& input_points, #ifdef CGAL_LINKED_WITH_TBB if(parallel_execution && new_triangles.size() > 100) { - tbb::concurrent_vector concurrent_soup_points; + +#ifdef SET_POINT_IDS_USING_MUTEX + //option 1 (using a mutex) + CGAL_MUTEX point_container_mutex; /// Lambda concurrent_get_point_id() - auto concurrent_get_point_id = [&](const typename EK::Point_3& pt) + auto concurrent_get_point_id = [&](const typename EK::Point_3 pt) { - auto insert_res = point_id_map.insert(std::make_pair(pt, concurrent_soup_points.size())); - if (insert_res.second) - { - concurrent_soup_points.push_back(to_input(pt)); + auto insert_res = point_id_map.insert(std::make_pair(pt, -1)); + + if (insert_res.second) + { + CGAL_SCOPED_LOCK(point_container_mutex); + insert_res.first->second=soup_points.size(); + soup_points.push_back(to_input(pt)); #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) - exact_soup_points.push_back(pt); + exact_soup_points.push_back(pt); #endif - } - return insert_res.first->second; + } + return insert_res.first; }; - soup_triangles.resize(offset + new_triangles.size()); + //use map iterator triple for triangles to create them concurrently and safely + std::vector::iterator, 3>> triangle_buffer(new_triangles.size()); tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), - [&](const tbb::blocked_range& r) { - for (size_t ti = r.begin(); ti != r.end(); ++ti) { - if (offset + ti > soup_triangles.size()) { - std::cout << "ti = " << ti << std::endl; - } - const std::array& t = new_triangles[ti]; - soup_triangles[offset + ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2])); - } + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) { + const std::array& t = new_triangles[ti]; + triangle_buffer[ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2])); + } + } + ); + tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) + { + soup_triangles[offset + ti] = + CGAL::make_array(triangle_buffer[ti][0]->second, + triangle_buffer[ti][1]->second, + triangle_buffer[ti][2]->second); + } } ); +#else + //option 2 (without mutex) + /// Lambda concurrent_get_point_id() + tbb::concurrent_vector::iterator> iterators; + auto concurrent_get_point_id = [&](const typename EK::Point_3 pt) + { + auto insert_res = point_id_map.insert(std::make_pair(pt, -1)); + if (insert_res.second) + iterators.push_back(insert_res.first); + return insert_res.first; + }; - soup_points.reserve(soup_points.size() + concurrent_soup_points.size()); - soup_points.insert(soup_points.end(), concurrent_soup_points.begin(), concurrent_soup_points.end()); + //use map iterator triple for triangles to create them concurrently and safely + soup_triangles.resize(offset + new_triangles.size()); + std::vector::iterator, 3>> triangle_buffer(new_triangles.size()); + tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) { + if (offset + ti > soup_triangles.size()) { + std::cout << "ti = " << ti << std::endl; + } + const std::array& t = new_triangles[ti]; + triangle_buffer[ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2])); + } + } + ); + + // the map is now filled we can safely set the point ids + std::size_t pid_offset=soup_points.size(); + soup_points.resize(pid_offset+iterators.size()); +#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) + exact_soup_points.resize(soup_points.size()); +#endif + + tbb::parallel_for(tbb::blocked_range(0, iterators.size()), + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) + { + soup_points[pid_offset+ti] = to_input(iterators[ti]->first); +#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) + exact_soup_points[pid_offset+ti] = iterators[ti]->first; +#endif + iterators[ti]->second=pid_offset+ti; + } + } + ); + + tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), + [&](const tbb::blocked_range& r) { + for (size_t ti = r.begin(); ti != r.end(); ++ti) + { + soup_triangles[offset + ti] = + CGAL::make_array(triangle_buffer[ti][0]->second, + triangle_buffer[ti][1]->second, + triangle_buffer[ti][2]->second); + } + } + ); +#endif } else #endif From a8a3d8ab36cf3ad0880aa21dc49c2d29c96df656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 6 Jul 2023 15:39:08 +0200 Subject: [PATCH 72/99] add functor to compute the intersection of 3 independant planes --- .../include/CGAL/Kernel/function_objects.h | 36 +++++++++++++++++++ .../include/CGAL/Kernel/interface_macros.h | 2 ++ 2 files changed, 38 insertions(+) diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index e307e28ae1f..438dc0de14b 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -2192,6 +2192,42 @@ namespace CommonKernelFunctors { } }; + template + class Construct_planes_intersection_point_3 + { + typedef typename K::Plane_3 Plane; + typedef typename K::Point_3 Point; + typename K::Construct_plane_3 construct_plane; + public: + typedef Point result_type; + + Point + operator()(const Point& p1, const Point& q1, const Point& r1, + const Point& p2, const Point& q2, const Point& r2, + const Point& p3, const Point& q3, const Point& r3) const + { + Plane plane1 = construct_plane(p1, q1, r1); + Plane plane2 = construct_plane(p2, q2, r2); + Plane plane3 = construct_plane(p3, q3, r3); + + const auto res = typename K::Intersect_3()(plane1, plane2, plane3); + CGAL_assertion(res!=boost::none); + const Point* e_pt = boost::get(&(*res)); + CGAL_assertion(e_pt!=nullptr); + return *e_pt; + } + + Point + operator()(const Plane& plane1, const Plane& plane2, const Plane& plane3) const + { + const auto res = typename K::Intersect_3()(plane1, plane2, plane3); + CGAL_assertion(res!=boost::none); + const Point* e_pt = boost::get(&(*res)); + CGAL_assertion(e_pt!=nullptr); + return *e_pt; + } + }; + template class Compute_alpha_for_coplanar_triangle_intersection_3 { diff --git a/Kernel_23/include/CGAL/Kernel/interface_macros.h b/Kernel_23/include/CGAL/Kernel/interface_macros.h index 1360aa1bbcd..0acc0a4c690 100644 --- a/Kernel_23/include/CGAL/Kernel/interface_macros.h +++ b/Kernel_23/include/CGAL/Kernel/interface_macros.h @@ -398,6 +398,8 @@ CGAL_Kernel_cons(Construct_plane_3, construct_plane_3_object) CGAL_Kernel_cons(Construct_plane_line_intersection_point_3, construct_plane_line_intersection_point_3_object) +CGAL_Kernel_cons(Construct_planes_intersection_point_3, + construct_planes_intersection_point_3_object) CGAL_Kernel_cons(Compute_alpha_for_coplanar_triangle_intersection_3, compute_alpha_for_coplanar_triangle_intersection_3_object) CGAL_Kernel_cons(Construct_point_on_2, From a0658b6423c95f108868f6ce5c65ad1b7b1149ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 6 Jul 2023 15:51:04 +0200 Subject: [PATCH 73/99] track coplanar triangles and use direct point construction --- .../Polygon_mesh_processing/autorefinement.h | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 9bbc67efb48..68241773f37 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -167,9 +167,7 @@ do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, } } - // supporting_line intersects: points are coplanar - // TODO: check if we can write a dedicated predicate taking advantage of p,q being shared ::CGAL::Orientation pqr = cpl_orient(p, q, r); ::CGAL::Orientation pqs = cpl_orient(p, q, s); @@ -609,7 +607,7 @@ void test_edge(const typename K::Point_3& p, const typename K::Point_3& q, } template -void collect_intersections(const std::array& t1, +bool collect_intersections(const std::array& t1, const std::array& t2, std::vector& inter_pts) { @@ -626,7 +624,7 @@ void collect_intersections(const std::array& t1, if (depth(p)>2) throw std::runtime_error("Depth is not 4: "+std::to_string(depth(p))); #endif - return; + return true; } for (int i=0; i<3; ++i) @@ -653,6 +651,8 @@ void collect_intersections(const std::array& t1, for (auto p : inter_pts) if (depth(p)>2) throw std::runtime_error("Depth is not 2: "+std::to_string(depth(p))); #endif + + return false; } ////////////////////////////////// @@ -672,6 +672,7 @@ void generate_subtriangles(std::size_t ti, std::vector& points, const std::vector& in_triangle_ids, const std::set >& intersecting_triangles, + const std::set >& coplanar_triangles, const std::vector>& triangles, PointVector& new_triangles ) @@ -789,11 +790,6 @@ void generate_subtriangles(std::size_t ti, { std::size_t nbs = segments.size(); - auto supporting_plane = [](const std::array& t) - { - return typename EK::Plane_3(t[0], t[1], t[2]); - }; - std::vector< std::vector > points_on_segments(nbs); COUNTER_INSTRUCTION(counter.timer1.start();) @@ -868,17 +864,19 @@ void generate_subtriangles(std::size_t ti, } case POINT_INTERSECTION: { - // TODO: use version with no variant - COUNTER_INSTRUCTION(counter.timer6.start();) - auto res = CGAL::intersection(supporting_plane(triangles[in_triangle_ids[i]]), - supporting_plane(triangles[in_triangle_ids[j]]), - supporting_plane(triangles[ti])); - COUNTER_INSTRUCTION(counter.timer6.stop();) - - if (const typename EK::Point_3* pt_ptr = boost::get(&(*res))) + if ( coplanar_triangles.count(CGAL::make_sorted_pair(in_triangle_ids[i], in_triangle_ids[j])) == 0 + && coplanar_triangles.count(CGAL::make_sorted_pair(ti, in_triangle_ids[j])) == 0 + && coplanar_triangles.count(CGAL::make_sorted_pair(in_triangle_ids[i], ti)) == 0) { + COUNTER_INSTRUCTION(counter.timer6.start();) + typename EK::Point_3 pt = typename EK::Construct_planes_intersection_point_3()( + triangles[in_triangle_ids[i]][0], triangles[in_triangle_ids[i]][1],triangles[in_triangle_ids[i]][2], + triangles[in_triangle_ids[j]][0], triangles[in_triangle_ids[j]][1],triangles[in_triangle_ids[j]][2], + triangles[ti][0], triangles[ti][1],triangles[ti][2]); + COUNTER_INSTRUCTION(counter.timer6.stop();) + COUNTER_INSTRUCTION(++counter.c1;) - std::size_t pid = get_point_id(*pt_ptr); + std::size_t pid = get_point_id(pt); points_on_segments[i].push_back(pid); points_on_segments[j].push_back(pid); } @@ -1198,7 +1196,8 @@ void autorefine_soup_output(const PointRange& input_points, Real_timer t; t.start(); #endif - std::set > intersecting_triangles; + std::set > intersecting_triangles; // TODO replace with vector>> + std::set > coplanar_triangles; // TODO replace with vector>> //TODO: PARALLEL_FOR #2 for (const Pair_of_triangle_ids& p : si_pairs) { @@ -1211,7 +1210,7 @@ void autorefine_soup_output(const PointRange& input_points, const std::array& t2 = triangles[i2]; std::vector inter_pts; - autorefine_impl::collect_intersections(t1, t2, inter_pts); + bool triangles_are_coplanar = autorefine_impl::collect_intersections(t1, t2, inter_pts); CGAL_assertion( CGAL::do_intersect(typename EK::Triangle_3(t1[0], t1[1], t1[2]), typename EK::Triangle_3(t2[0], t2[1], t2[2])) @@ -1242,6 +1241,8 @@ void autorefine_soup_output(const PointRange& input_points, } } intersecting_triangles.insert(CGAL::make_sorted_pair(i1, i2)); + if (triangles_are_coplanar) + coplanar_triangles.insert(CGAL::make_sorted_pair(i1, i2)); } } #ifdef USE_DEBUG_PARALLEL_TIMERS @@ -1369,7 +1370,7 @@ void autorefine_soup_output(const PointRange& input_points, autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); } #else - autorefine_impl::generate_subtriangles(ti, all_segments_ids[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); + autorefine_impl::generate_subtriangles(ti, all_segments_ids[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, coplanar_triangles, triangles, new_triangles); #endif } From bab2c72674903679a632566debb595c34505efe8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 6 Jul 2023 16:53:51 +0200 Subject: [PATCH 74/99] add functor to compute intersection point of coplanar segments --- .../include/CGAL/Kernel/function_objects.h | 34 +++++++++++++++++++ .../include/CGAL/Kernel/interface_macros.h | 2 ++ 2 files changed, 36 insertions(+) diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index 438dc0de14b..6917a06edcf 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -2228,6 +2228,40 @@ namespace CommonKernelFunctors { } }; + template + class Construct_coplanar_segments_intersection_point_3 + { + typedef typename K::Segment_3 Segment; + typedef typename K::Point_3 Point; + typename K::Construct_segment_3 construct_segment; + public: + typedef Point result_type; + + Point + operator()(const Point& p1, const Point& q1, + const Point& p2, const Point& q2) const + { + Segment s1 = construct_segment(p1, q1); + Segment s2 = construct_segment(p2, q2); + + const auto res = typename K::Intersect_3()(s1, s2); + CGAL_assertion(res!=boost::none); + const Point* e_pt = boost::get(&(*res)); + CGAL_assertion(e_pt!=nullptr); + return *e_pt; + } + + Point + operator()(const Segment& s1, const Segment& s2) const + { + const auto res = typename K::Intersect_3()(s1, s2); + CGAL_assertion(res!=boost::none); + const Point* e_pt = boost::get(&(*res)); + CGAL_assertion(e_pt!=nullptr); + return *e_pt; + } + }; + template class Compute_alpha_for_coplanar_triangle_intersection_3 { diff --git a/Kernel_23/include/CGAL/Kernel/interface_macros.h b/Kernel_23/include/CGAL/Kernel/interface_macros.h index 0acc0a4c690..a2314aef1b7 100644 --- a/Kernel_23/include/CGAL/Kernel/interface_macros.h +++ b/Kernel_23/include/CGAL/Kernel/interface_macros.h @@ -400,6 +400,8 @@ CGAL_Kernel_cons(Construct_plane_line_intersection_point_3, construct_plane_line_intersection_point_3_object) CGAL_Kernel_cons(Construct_planes_intersection_point_3, construct_planes_intersection_point_3_object) +CGAL_Kernel_cons(Construct_coplanar_segments_intersection_point_3, + construct_coplanar_segments_intersection_point_3_object) CGAL_Kernel_cons(Compute_alpha_for_coplanar_triangle_intersection_3, compute_alpha_for_coplanar_triangle_intersection_3_object) CGAL_Kernel_cons(Construct_point_on_2, From e7490ee31fe90b243c558b3742614bd0785f9796 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 6 Jul 2023 16:54:37 +0200 Subject: [PATCH 75/99] use direct construction of coplanar segment intersection --- .../Polygon_mesh_processing/autorefinement.h | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 68241773f37..693c00676f0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -884,20 +884,13 @@ void generate_subtriangles(std::size_t ti, { COUNTER_INSTRUCTION(++counter.c2;) COUNTER_INSTRUCTION(counter.timer4.start();) - //TODO find better! - typename EK::Segment_3 s1(points[segments[i].first], points[segments[i].second]); - typename EK::Segment_3 s2(points[segments[j].first], points[segments[j].second]);// TODO: avoid this construction - auto inter = CGAL::intersection(s1, s2); - if (inter == boost::none) throw std::runtime_error("Unexpected case #2"); - if (const typename EK::Point_3* pt_ptr = boost::get(&(*inter))) - { - std::size_t pid = get_point_id(*pt_ptr); - points_on_segments[i].push_back(pid); - points_on_segments[j].push_back(pid); - break; - } - else - throw std::runtime_error("Unexpected case 1"); + typename EK::Point_3 pt = typename EK::Construct_coplanar_segments_intersection_point_3()( + points[segments[i].first], points[segments[i].second], + points[segments[j].first], points[segments[j].second]); + + std::size_t pid = get_point_id(pt); + points_on_segments[i].push_back(pid); + points_on_segments[j].push_back(pid); COUNTER_INSTRUCTION(counter.timer4.stop();) //~ std::ofstream debug ("/tmp/triangles.polylines.txt"); //~ debug << "4 " << triangles[ti][0] << " " << triangles[ti][1] << " " << triangles[ti][2] << " " << triangles[ti][0] << "\n"; From 806ffa9385e985216b34f870ad21b32982c2272e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 6 Jul 2023 17:40:28 +0200 Subject: [PATCH 76/99] remove TODO I don't think a predicate sorting planes along a ray would be faster than directly using intersection coordinates --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 1 - 1 file changed, 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 693c00676f0..122c595b13e 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -959,7 +959,6 @@ void generate_subtriangles(std::size_t ti, { if(!points_on_segments[i].empty()) { - // TODO: predicate on input triangles int coord = 0; std::size_t src_id = segments[i].first, tgt_id = segments[i].second; typename EK::Point_3 src = points[src_id], tgt=points[tgt_id]; From fdb6b799a9f41d5cfea056801196504351b4da5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 21 Jul 2023 13:32:25 +0200 Subject: [PATCH 77/99] add doc + do the autorefine inplace for the soup --- .../PackageDescription.txt | 2 + .../soup_autorefinement.cpp | 11 +- .../Polygon_mesh_processing/autorefinement.h | 174 ++++++++++++------ 3 files changed, 119 insertions(+), 68 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt index b17c41399d0..95d8794cca1 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/PackageDescription.txt @@ -109,6 +109,8 @@ The page \ref bgl_namedparameters "Named Parameters" describes their usage. - `CGAL::Polygon_mesh_processing::surface_intersection()` - `CGAL::Polygon_mesh_processing::clip()` - `CGAL::Polygon_mesh_processing::split()` +- `CGAL::Polygon_mesh_processing::autorefine_triangle_soup()` +- `CGAL::Polygon_mesh_processing::autorefine()` \cgalCRPSection{Meshing Functions} - \link PMP_meshing_grp `CGAL::Polygon_mesh_processing::isotropic_remeshing()` \endlink diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index 9e4999287f7..a44d47c8b6d 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -32,14 +32,11 @@ int main(int argc, char** argv) CGAL::Real_timer t; t.start(); - std::vector output_points; - std::vector> output_triangles; - PMP::autorefine_soup_output(input_points, input_triangles, - output_points, output_triangles, - CGAL::parameters::concurrency_tag(CGAL::Parallel_if_available_tag())); + PMP::autorefine_triangle_soup(input_points, input_triangles, + CGAL::parameters::concurrency_tag(CGAL::Parallel_if_available_tag())); t.stop(); - std::cout << "#points = " << output_points.size() << " and #triangles = " << output_triangles.size() << " in " << t.time() << " sec." << std::endl; - CGAL::IO::write_polygon_soup("autorefined.off", output_points, output_triangles, CGAL::parameters::stream_precision(17)); + std::cout << "#points = " << input_points.size() << " and #triangles = " << input_triangles.size() << " in " << t.time() << " sec." << std::endl; + CGAL::IO::write_polygon_soup("autorefined.off", input_points, input_triangles, CGAL::parameters::stream_precision(17)); return 0; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 122c595b13e..bfa65df1c73 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -31,10 +31,15 @@ #endif // output -#include +#include #include #include + +#ifdef CGAL_PMP_AUTOREFINE_USE_DEFAULT_VERBOSE +#define CGAL_PMP_AUTOREFINE_VERBOSE(X) std::cout << X << "\n"; +#endif + #ifndef CGAL_PMP_AUTOREFINE_VERBOSE #define CGAL_PMP_AUTOREFINE_VERBOSE(MSG) #endif @@ -1100,13 +1105,54 @@ void generate_subtriangles(std::size_t ti, } } // end of autorefine_impl +#endif -template -void autorefine_soup_output(const PointRange& input_points, - const TriIdsRange& id_triples, - std::vector& soup_points, - std::vector >& soup_triangles, - const NamedParameters& np = parameters::default_values()) +/** +* \ingroup PMP_corefinement_grp +* +* refines a soup of triangles so that no pair of triangles intersects in their interior. +* Note that points in `input_points` can only be added (intersection points) a the end of the container, with the initial order preserved. +* Note that if `input_points` contains two or more identical points and only the first copy (following the order in the `input_points`) +* will be used in `id_triples`. +* `id_triples` will be updated to contain both the input triangles and the new subdivides triangles. Degenerate triangles will be removed. +* Also triangles in `id_triples` will be triangles without intersection first, followed by triangles coming from a subdivision induced +* by an intersection. The named parameter `visitor()` can be used to track +* +* @tparam PointRange a model of the concept `RandomAccessContainer` +* whose value type is the point type +* @tparam TriIdsRange a model of the concepts `RandomAccessContainer`, `BackInsertionSequence` and `Swappable`, whose +* value type is a model of the concept `RandomAccessContainer` whose value type is convertible to `std::size_t` and that +* is constructible from an `std::initializer_list` of size 3. +* @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" +* +* @param input_points points of the soup of polygons +* @param id_triples each element in the range describes a triangle using the indexed position of the points in `input_points` +* @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below +* +* \cgalNamedParamsBegin +* \cgalParamNBegin{point_map} +* \cgalParamDescription{a property map associating points to the elements of the range `input_points`} +* \cgalParamType{a model of `ReadWritePropertyMap` whose value type is a point type} +* \cgalParamDefault{`CGAL::Identity_property_map`} +* \cgalParamNEnd +* \cgalParamNBegin{geom_traits} +* \cgalParamDescription{an instance of a geometric traits class} +* \cgalParamType{a class model of `Kernel`} +* \cgalParamDefault{a \cgal Kernel deduced from the point type, using `CGAL::Kernel_traits`} +* \cgalParamExtra{The geometric traits class must be compatible with the point type.} +* \cgalParamNEnd +* \cgalParamNBegin{visitor} +* \cgalParamDescription{a visitor used to track the creation of new faces} +* \cgalParamType{a class model of `PMPFooBar`} +* \cgalParamDefault{`Autorefinement::Default_visitor`} +* \cgalParamNEnd +* \cgalNamedParamsEnd +* +*/ +template +void autorefine_triangle_soup(PointRange& input_points, + TriIdsRange& id_triples, + const NamedParameters& np = parameters::default_values()) { using parameters::choose_parameter; using parameters::get_parameter; @@ -1121,14 +1167,13 @@ void autorefine_soup_output(const PointRange& input_points, Sequential_tag > ::type Concurrency_tag; - constexpr bool parallel_execution = std::is_same::value; + constexpr bool parallel_execution = std::is_same_v; #ifndef CGAL_LINKED_WITH_TBB - CGAL_static_assertion_msg (parallel_execution, - "Parallel_tag is enabled but TBB is unavailable."); + static_assert (!parallel_execution, + "Parallel_tag is enabled but TBB is unavailable."); #endif - typedef std::size_t Input_TID; typedef std::pair Pair_of_triangle_ids; @@ -1334,7 +1379,6 @@ void autorefine_soup_output(const PointRange& input_points, boost::timer::progress_display pd(triangles.size()); #endif - auto refine_triangles = [&](std::size_t ti) { if (all_segments[ti].empty() && all_points[ti].empty()) @@ -1371,7 +1415,6 @@ void autorefine_soup_output(const PointRange& input_points, #endif }; - #ifdef USE_DEBUG_PARALLEL_TIMERS t.start(); #endif @@ -1415,25 +1458,22 @@ void autorefine_soup_output(const PointRange& input_points, std::vector exact_soup_points; #endif - /// Lambda get_point_id() - auto get_point_id = [&](const typename EK::Point_3& pt) - { - auto insert_res = point_id_map.insert(std::make_pair(pt, soup_points.size())); - if (insert_res.second) - { - soup_points.push_back(to_input(pt)); -#if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) - exact_soup_points.push_back(pt); -#endif - } - return insert_res.first->second; - }; - // TODO: parallel_for? - std::vector input_point_ids; - input_point_ids.reserve(input_points.size()); - for (const auto& p : input_points) - input_point_ids.push_back(get_point_id(to_exact(get(pm,p)))); + // for input points, we on purpose keep duplicated points and isolated points + for (std::size_t pid = 0; pidfirst); +#endif + } + + TriIdsRange soup_triangles; + soup_triangles.reserve(id_triples.size()); // TODO: remove #deg tri? // raw copy of input triangles with no intersection for (Input_TID f=0; fsecond; + }; + #ifdef USE_DEBUG_PARALLEL_TIMERS t.start(); #endif @@ -1465,7 +1518,6 @@ void autorefine_soup_output(const PointRange& input_points, #ifdef CGAL_LINKED_WITH_TBB if(parallel_execution && new_triangles.size() > 100) { - #ifdef SET_POINT_IDS_USING_MUTEX //option 1 (using a mutex) CGAL_MUTEX point_container_mutex; @@ -1477,8 +1529,8 @@ void autorefine_soup_output(const PointRange& input_points, if (insert_res.second) { CGAL_SCOPED_LOCK(point_container_mutex); - insert_res.first->second=soup_points.size(); - soup_points.push_back(to_input(pt)); + insert_res.first->second=input_points.size(); + input_points.push_back(to_input(pt)); #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) exact_soup_points.push_back(pt); #endif @@ -1502,9 +1554,9 @@ void autorefine_soup_output(const PointRange& input_points, for (size_t ti = r.begin(); ti != r.end(); ++ti) { soup_triangles[offset + ti] = - CGAL::make_array(triangle_buffer[ti][0]->second, - triangle_buffer[ti][1]->second, - triangle_buffer[ti][2]->second); + { triangle_buffer[ti][0]->second, + triangle_buffer[ti][1]->second, + triangle_buffer[ti][2]->second }; } } ); @@ -1536,17 +1588,17 @@ void autorefine_soup_output(const PointRange& input_points, ); // the map is now filled we can safely set the point ids - std::size_t pid_offset=soup_points.size(); - soup_points.resize(pid_offset+iterators.size()); + std::size_t pid_offset=input_points.size(); + input_points.resize(pid_offset+iterators.size()); #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) - exact_soup_points.resize(soup_points.size()); + exact_soup_points.resize(input_points.size()); #endif tbb::parallel_for(tbb::blocked_range(0, iterators.size()), [&](const tbb::blocked_range& r) { for (size_t ti = r.begin(); ti != r.end(); ++ti) { - soup_points[pid_offset+ti] = to_input(iterators[ti]->first); + input_points[pid_offset+ti] = to_input(iterators[ti]->first); #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) exact_soup_points[pid_offset+ti] = iterators[ti]->first; #endif @@ -1560,9 +1612,9 @@ void autorefine_soup_output(const PointRange& input_points, for (size_t ti = r.begin(); ti != r.end(); ++ti) { soup_triangles[offset + ti] = - CGAL::make_array(triangle_buffer[ti][0]->second, - triangle_buffer[ti][1]->second, - triangle_buffer[ti][2]->second); + { triangle_buffer[ti][0]->second, + triangle_buffer[ti][1]->second, + triangle_buffer[ti][2]->second }; } } ); @@ -1576,7 +1628,7 @@ void autorefine_soup_output(const PointRange& input_points, #endif soup_triangles.reserve(offset + new_triangles.size()); for (const std::array& t : new_triangles) - soup_triangles.emplace_back(CGAL::make_array(get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2]))); + soup_triangles.push_back({ get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2])}); } @@ -1597,9 +1649,11 @@ void autorefine_soup_output(const PointRange& input_points, throw std::runtime_error("ERROR: invalid output, there is most probably a bug"); #endif #endif + using std::swap; + swap(id_triples, soup_triangles); + CGAL_PMP_AUTOREFINE_VERBOSE("done"); } -#endif /** * \ingroup PMP_corefinement_grp @@ -1639,22 +1693,20 @@ autorefine( TriangleMesh& tm, using parameters::get_parameter; typedef typename GetGeomTraits::type GT; - GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); + // GT traits = choose_parameter(get_parameter(np, internal_np::geom_traits)); - std::vector in_soup_points; - std::vector > in_soup_triangles; - std::vector out_soup_points; - std::vector > out_soup_triangles; + std::vector soup_points; + std::vector > soup_triangles; - polygon_mesh_to_polygon_soup(tm, in_soup_points, in_soup_triangles); + polygon_mesh_to_polygon_soup(tm, soup_points, soup_triangles, np); - autorefine_soup_output(in_soup_points, in_soup_triangles, - out_soup_points, out_soup_triangles); + autorefine_triangle_soup(soup_points, soup_triangles); clear(tm); - repair_polygon_soup(out_soup_points, out_soup_triangles); - orient_polygon_soup(out_soup_points, out_soup_triangles); - polygon_soup_to_polygon_mesh(out_soup_points, out_soup_triangles, tm); + repair_polygon_soup(soup_points, soup_triangles); + + duplicate_non_manifold_edges_in_polygon_soup(soup_points, soup_triangles); + polygon_soup_to_polygon_mesh(soup_points, soup_triangles, tm); } From d6fdc85be9bb5c95b4fdf59379a67033a98b2d36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 21 Jul 2023 13:38:10 +0200 Subject: [PATCH 78/99] rename variables --- .../Polygon_mesh_processing/autorefinement.h | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index bfa65df1c73..0054a9dcdb2 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1111,11 +1111,11 @@ void generate_subtriangles(std::size_t ti, * \ingroup PMP_corefinement_grp * * refines a soup of triangles so that no pair of triangles intersects in their interior. -* Note that points in `input_points` can only be added (intersection points) a the end of the container, with the initial order preserved. -* Note that if `input_points` contains two or more identical points and only the first copy (following the order in the `input_points`) -* will be used in `id_triples`. -* `id_triples` will be updated to contain both the input triangles and the new subdivides triangles. Degenerate triangles will be removed. -* Also triangles in `id_triples` will be triangles without intersection first, followed by triangles coming from a subdivision induced +* Note that points in `soup_points` can only be added (intersection points) a the end of the container, with the initial order preserved. +* Note that if `soup_points` contains two or more identical points and only the first copy (following the order in the `soup_points`) +* will be used in `soup_triangles`. +* `soup_triangles` will be updated to contain both the input triangles and the new subdivides triangles. Degenerate triangles will be removed. +* Also triangles in `soup_triangles` will be triangles without intersection first, followed by triangles coming from a subdivision induced * by an intersection. The named parameter `visitor()` can be used to track * * @tparam PointRange a model of the concept `RandomAccessContainer` @@ -1125,13 +1125,13 @@ void generate_subtriangles(std::size_t ti, * is constructible from an `std::initializer_list` of size 3. * @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * -* @param input_points points of the soup of polygons -* @param id_triples each element in the range describes a triangle using the indexed position of the points in `input_points` +* @param soup_points points of the soup of polygons +* @param soup_triangles each element in the range describes a triangle using the indexed position of the points in `soup_points` * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin * \cgalParamNBegin{point_map} -* \cgalParamDescription{a property map associating points to the elements of the range `input_points`} +* \cgalParamDescription{a property map associating points to the elements of the range `soup_points`} * \cgalParamType{a model of `ReadWritePropertyMap` whose value type is a point type} * \cgalParamDefault{`CGAL::Identity_property_map`} * \cgalParamNEnd @@ -1150,8 +1150,8 @@ void generate_subtriangles(std::size_t ti, * */ template -void autorefine_triangle_soup(PointRange& input_points, - TriIdsRange& id_triples, +void autorefine_triangle_soup(PointRange& soup_points, + TriIdsRange& soup_triangles, const NamedParameters& np = parameters::default_values()) { using parameters::choose_parameter; @@ -1181,12 +1181,12 @@ void autorefine_triangle_soup(PointRange& input_points, // collect intersecting pairs of triangles CGAL_PMP_AUTOREFINE_VERBOSE("collect intersecting pairs"); - triangle_soup_self_intersections(input_points, id_triples, std::back_inserter(si_pairs), np); + triangle_soup_self_intersections(soup_points, soup_triangles, std::back_inserter(si_pairs), np); if (si_pairs.empty()) return; // mark degenerate faces so that we can ignore them - std::vector is_degen(id_triples.size(), false); + std::vector is_degen(soup_triangles.size(), false); for (const Pair_of_triangle_ids& p : si_pairs) if (p.first==p.second) // bbox inter reports (f,f) for degenerate faces @@ -1194,7 +1194,7 @@ void autorefine_triangle_soup(PointRange& input_points, // assign an id per triangle involved in an intersection // + the faces involved in the intersection - std::vector tri_inter_ids(id_triples.size(), -1); + std::vector tri_inter_ids(soup_triangles.size(), -1); std::vector intersected_faces; int tiid=-1; for (const Pair_of_triangle_ids& p : si_pairs) @@ -1219,9 +1219,9 @@ void autorefine_triangle_soup(PointRange& input_points, for(Input_TID f : intersected_faces) { triangles[tri_inter_ids[f]]= CGAL::make_array( - to_exact( get(pm, input_points[id_triples[f][0]]) ), - to_exact( get(pm, input_points[id_triples[f][1]]) ), - to_exact( get(pm, input_points[id_triples[f][2]]) ) ); + to_exact( get(pm, soup_points[soup_triangles[f][0]]) ), + to_exact( get(pm, soup_points[soup_triangles[f][1]]) ), + to_exact( get(pm, soup_points[soup_triangles[f][2]]) ) ); } std::vector< std::vector > > all_segments(triangles.size()); @@ -1460,31 +1460,31 @@ void autorefine_triangle_soup(PointRange& input_points, // TODO: parallel_for? // for input points, we on purpose keep duplicated points and isolated points - for (std::size_t pid = 0; pidfirst); #endif } - TriIdsRange soup_triangles; - soup_triangles.reserve(id_triples.size()); // TODO: remove #deg tri? + TriIdsRange soup_triangles_out; + soup_triangles_out.reserve(soup_triangles.size()); // TODO: remove #deg tri? // raw copy of input triangles with no intersection - for (Input_TID f=0; fsecond=input_points.size(); - input_points.push_back(to_input(pt)); + insert_res.first->second=soup_points.size(); + soup_points.push_back(to_input(pt)); #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) exact_soup_points.push_back(pt); #endif @@ -1538,7 +1538,7 @@ void autorefine_triangle_soup(PointRange& input_points, return insert_res.first; }; - soup_triangles.resize(offset + new_triangles.size()); + soup_triangles_out.resize(offset + new_triangles.size()); //use map iterator triple for triangles to create them concurrently and safely std::vector::iterator, 3>> triangle_buffer(new_triangles.size()); tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), @@ -1553,7 +1553,7 @@ void autorefine_triangle_soup(PointRange& input_points, [&](const tbb::blocked_range& r) { for (size_t ti = r.begin(); ti != r.end(); ++ti) { - soup_triangles[offset + ti] = + soup_triangles_out[offset + ti] = { triangle_buffer[ti][0]->second, triangle_buffer[ti][1]->second, triangle_buffer[ti][2]->second }; @@ -1573,12 +1573,12 @@ void autorefine_triangle_soup(PointRange& input_points, }; //use map iterator triple for triangles to create them concurrently and safely - soup_triangles.resize(offset + new_triangles.size()); + soup_triangles_out.resize(offset + new_triangles.size()); std::vector::iterator, 3>> triangle_buffer(new_triangles.size()); tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), [&](const tbb::blocked_range& r) { for (size_t ti = r.begin(); ti != r.end(); ++ti) { - if (offset + ti > soup_triangles.size()) { + if (offset + ti > soup_triangles_out.size()) { std::cout << "ti = " << ti << std::endl; } const std::array& t = new_triangles[ti]; @@ -1588,17 +1588,17 @@ void autorefine_triangle_soup(PointRange& input_points, ); // the map is now filled we can safely set the point ids - std::size_t pid_offset=input_points.size(); - input_points.resize(pid_offset+iterators.size()); + std::size_t pid_offset=soup_points.size(); + soup_points.resize(pid_offset+iterators.size()); #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) - exact_soup_points.resize(input_points.size()); + exact_soup_points.resize(soup_points.size()); #endif tbb::parallel_for(tbb::blocked_range(0, iterators.size()), [&](const tbb::blocked_range& r) { for (size_t ti = r.begin(); ti != r.end(); ++ti) { - input_points[pid_offset+ti] = to_input(iterators[ti]->first); + soup_points[pid_offset+ti] = to_input(iterators[ti]->first); #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) exact_soup_points[pid_offset+ti] = iterators[ti]->first; #endif @@ -1611,7 +1611,7 @@ void autorefine_triangle_soup(PointRange& input_points, [&](const tbb::blocked_range& r) { for (size_t ti = r.begin(); ti != r.end(); ++ti) { - soup_triangles[offset + ti] = + soup_triangles_out[offset + ti] = { triangle_buffer[ti][0]->second, triangle_buffer[ti][1]->second, triangle_buffer[ti][2]->second }; @@ -1626,9 +1626,9 @@ void autorefine_triangle_soup(PointRange& input_points, #ifdef USE_DEBUG_PARALLEL_TIMERS mode = "sequential"; #endif - soup_triangles.reserve(offset + new_triangles.size()); + soup_triangles_out.reserve(offset + new_triangles.size()); for (const std::array& t : new_triangles) - soup_triangles.push_back({ get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2])}); + soup_triangles_out.push_back({ get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2])}); } @@ -1641,16 +1641,16 @@ void autorefine_triangle_soup(PointRange& input_points, #ifndef CGAL_NDEBUG CGAL_PMP_AUTOREFINE_VERBOSE("check soup"); - CGAL_assertion( !does_triangle_soup_self_intersect(exact_soup_points, soup_triangles) ); + CGAL_assertion( !does_triangle_soup_self_intersect(exact_soup_points, soup_triangles_out) ); #else #ifdef CGAL_DEBUG_PMP_AUTOREFINE CGAL_PMP_AUTOREFINE_VERBOSE("check soup"); - if (does_triangle_soup_self_intersect(exact_soup_points, soup_triangles)) + if (does_triangle_soup_self_intersect(exact_soup_points, soup_triangles_out)) throw std::runtime_error("ERROR: invalid output, there is most probably a bug"); #endif #endif using std::swap; - swap(id_triples, soup_triangles); + swap(soup_triangles, soup_triangles_out); CGAL_PMP_AUTOREFINE_VERBOSE("done"); } From e1d7105c1cf58cabbd38d71cc3a5be8aa871ddf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 21 Jul 2023 16:47:03 +0200 Subject: [PATCH 79/99] add visitor + add calls to the visitor --- .../Concepts/PMPAutorefinementVisitor.h | 25 +++++++ .../Polygon_mesh_processing/autorefinement.h | 75 +++++++++++++++---- 2 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPAutorefinementVisitor.h diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPAutorefinementVisitor.h b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPAutorefinementVisitor.h new file mode 100644 index 00000000000..e3ef90e9be0 --- /dev/null +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPAutorefinementVisitor.h @@ -0,0 +1,25 @@ +/// \ingroup PkgPolygonMeshProcessingConcepts +/// \cgalConcept +/// +/// The concept `PMPAutorefinementVisitor` defines the requirements for the visitor +/// used in `CGAL::Polygon_mesh_processing::autorefine_triangle_soup()` to track +/// the creation of new triangles. +/// +/// \cgalRefines{CopyConstructible} +/// \cgalHasModel `CGAL::Polygon_mesh_processing::Autorefinement::Default_visitor`. + +class PMPAutorefinementVisitor{ +public: + +/// @name Functions called only if at least one intersection has been found +/// @{ + /// called when the final number of output triangles is known, `nbt` being the total number of triangles in the output. + void number_of_output_triangles(std::size_t nbt); + /// called for triangle with no intersection, `tgt_id` is the position in the triangle container after calling + /// `autorefine_triangle_soup()`, while `src_id` was its position before calling the function. + void verbatim_triangle_copy(std::size_t tgt_id, std::size_t src_id); + /// called for each subtriangle created from a triangle with intersection, `tgt_id` is the position in the triangle container after calling + /// `autorefine_triangle_soup()` of the subtriangle, while `src_id` was the position of the original support triangle before calling the function. + void new_subtriangle(std::size_t tgt_id, std::size_t src_id); +/// @} +}; diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 0054a9dcdb2..166c950a983 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -77,6 +77,24 @@ namespace CGAL { namespace Polygon_mesh_processing { +namespace Autorefinement { + +/** \ingroup PMP_corefinement_grp + * %Default visitor model of `PMPAutorefinementVisitor`. + * All of its functions have an empty body. This class can be used as a + * base class if only some of the functions of the concept require to be + * overridden. + */ +struct Default_visitor +{ + inline void number_of_output_triangles(std::size_t /*nbt*/) {} + inline void verbatim_triangle_copy(std::size_t /*tgt_id*/, std::size_t /*src_id*/) {} + inline void new_subtriangle(std::size_t /*tgt_id*/, std::size_t /*src_id*/) {} +}; + +} // end of Autorefinement visitor + + #ifndef DOXYGEN_RUNNING namespace autorefine_impl { @@ -1079,13 +1097,13 @@ void generate_subtriangles(std::size_t ti, for (typename CDT::Face_handle fh : cdt.finite_face_handles()) { if (orientation_flipped) - new_triangles.push_back( CGAL::make_array(fh->vertex(0)->point(), - fh->vertex(cdt.cw(0))->point(), - fh->vertex(cdt.ccw(0))->point()) ); + new_triangles.push_back( { CGAL::make_array(fh->vertex(0)->point(), + fh->vertex(cdt.cw(0))->point(), + fh->vertex(cdt.ccw(0))->point()), ti } ); else - new_triangles.push_back( CGAL::make_array(fh->vertex(0)->point(), - fh->vertex(cdt.ccw(0))->point(), - fh->vertex(cdt.cw(0))->point()) ); + new_triangles.push_back( { CGAL::make_array(fh->vertex(0)->point(), + fh->vertex(cdt.ccw(0))->point(), + fh->vertex(cdt.cw(0))->point()), ti } ); #ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS ++nbt; buffer << fh->vertex(0)->point() << "\n"; @@ -1143,8 +1161,9 @@ void generate_subtriangles(std::size_t ti, * \cgalParamNEnd * \cgalParamNBegin{visitor} * \cgalParamDescription{a visitor used to track the creation of new faces} -* \cgalParamType{a class model of `PMPFooBar`} -* \cgalParamDefault{`Autorefinement::Default_visitor`} +* \cgalParamType{a class model of `PMPAutorefinementVisitor`} +* \cgalParamDefault{`Autorefinement::Default_visitor`} +* \cgalParamExtra{The visitor will be copied.} * \cgalParamNEnd * \cgalNamedParamsEnd * @@ -1167,6 +1186,15 @@ void autorefine_triangle_soup(PointRange& soup_points, Sequential_tag > ::type Concurrency_tag; + // visitor + typedef typename internal_np::Lookup_named_param_def < + internal_np::visitor_t, + NamedParameters, + Autorefinement::Default_visitor//default + > ::type Visitor; + Visitor visitor(choose_parameter(get_parameter(np, internal_np::visitor))); + + constexpr bool parallel_execution = std::is_same_v; #ifndef CGAL_LINKED_WITH_TBB @@ -1369,10 +1397,10 @@ void autorefine_triangle_soup(PointRange& soup_points, // now refine triangles #ifdef CGAL_LINKED_WITH_TBB std::conditional_t>, - std::vector>> new_triangles; + tbb::concurrent_vector, std::size_t>>, + std::vector, std::size_t>>> new_triangles; #else - std::vector> new_triangles; + std::vector, std::size_t>> new_triangles; #endif #ifdef USE_PROGRESS_DISPLAY @@ -1382,7 +1410,7 @@ void autorefine_triangle_soup(PointRange& soup_points, auto refine_triangles = [&](std::size_t ti) { if (all_segments[ti].empty() && all_points[ti].empty()) - new_triangles.push_back(triangles[ti]); + new_triangles.push_back({triangles[ti], ti}); else { #ifdef USE_FIXED_PROJECTION_TRAITS @@ -1475,7 +1503,10 @@ void autorefine_triangle_soup(PointRange& soup_points, TriIdsRange soup_triangles_out; soup_triangles_out.reserve(soup_triangles.size()); // TODO: remove #deg tri? + visitor.number_of_output_triangles(soup_triangles.size()+new_triangles.size()); + // raw copy of input triangles with no intersection + std::vector tri_inter_ids_inverse(triangles.size()); for (Input_TID f=0; f(0, new_triangles.size()), [&](const tbb::blocked_range& r) { for (size_t ti = r.begin(); ti != r.end(); ++ti) { - const std::array& t = new_triangles[ti]; + const std::array& t = new_triangles[ti].first; + visitor.new_subtriangle(offset+ti, tri_inter_ids_inverse[new_triangles[ti].second]); triangle_buffer[ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2])); } } @@ -1581,7 +1618,8 @@ void autorefine_triangle_soup(PointRange& soup_points, if (offset + ti > soup_triangles_out.size()) { std::cout << "ti = " << ti << std::endl; } - const std::array& t = new_triangles[ti]; + const std::array& t = new_triangles[ti].first; + visitor.new_subtriangle(offset+ti, tri_inter_ids_inverse[new_triangles[ti].second]); triangle_buffer[ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2])); } } @@ -1627,8 +1665,13 @@ void autorefine_triangle_soup(PointRange& soup_points, mode = "sequential"; #endif soup_triangles_out.reserve(offset + new_triangles.size()); - for (const std::array& t : new_triangles) - soup_triangles_out.push_back({ get_point_id(t[0]), get_point_id(t[1]), get_point_id(t[2])}); + for (const std::pair, std::size_t>& t_and_id : new_triangles) + { + visitor.new_subtriangle(soup_triangles_out.size(), tri_inter_ids_inverse[t_and_id.second]); + soup_triangles_out.push_back({ get_point_id(t_and_id.first[0]), + get_point_id(t_and_id.first[1]), + get_point_id(t_and_id.first[2]) }); + } } From 9822f371dded06a2538281c5f97b0d343a5c0939 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 21 Jul 2023 16:54:21 +0200 Subject: [PATCH 80/99] doc precision --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 166c950a983..6bbb5571e7a 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1702,6 +1702,9 @@ void autorefine_triangle_soup(PointRange& soup_points, * \ingroup PMP_corefinement_grp * refines a triangle mesh so that no triangles intersects in their interior. * + * Note that this function is only provided as a shortcut for calling `autorefine_triangle_soup()` + * with a mesh. For any advance usage the aforementioned function should be called directly. + * * @tparam TriangleMesh a model of `HalfedgeListGraph`, `FaceListGraph`, and `MutableFaceGraph` * @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" * @@ -1745,7 +1748,7 @@ autorefine( TriangleMesh& tm, autorefine_triangle_soup(soup_points, soup_triangles); - clear(tm); + clear(tm); //TODO: keep properties repair_polygon_soup(soup_points, soup_triangles); duplicate_non_manifold_edges_in_polygon_soup(soup_points, soup_triangles); From d1779ca36d18ecc1be5d1fb50e9f66a66d47ea61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 21 Jul 2023 17:03:34 +0200 Subject: [PATCH 81/99] doc concurrency_tag --- .../CGAL/Polygon_mesh_processing/autorefinement.h | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 6bbb5571e7a..0fb843c31c0 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1148,6 +1148,11 @@ void generate_subtriangles(std::size_t ti, * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin +* \cgalParamNBegin{concurrency_tag} +* \cgalParamDescription{a tag indicating if the task should be done using one or several threads.} +* \cgalParamType{Either `CGAL::Sequential_tag`, or `CGAL::Parallel_tag`, or `CGAL::Parallel_if_available_tag`} +* \cgalParamDefault{`CGAL::Sequential_tag`} +* \cgalParamNEnd * \cgalParamNBegin{point_map} * \cgalParamDescription{a property map associating points to the elements of the range `soup_points`} * \cgalParamType{a model of `ReadWritePropertyMap` whose value type is a point type} @@ -1712,6 +1717,11 @@ void autorefine_triangle_soup(PointRange& soup_points, * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * * \cgalNamedParamsBegin + * \cgalParamNBegin{concurrency_tag} + * \cgalParamDescription{a tag indicating if the task should be done using one or several threads.} + * \cgalParamType{Either `CGAL::Sequential_tag`, or `CGAL::Parallel_tag`, or `CGAL::Parallel_if_available_tag`} + * \cgalParamDefault{`CGAL::Sequential_tag`} + * \cgalParamNEnd * \cgalParamNBegin{geom_traits} * \cgalParamDescription{an instance of a geometric traits class} * \cgalParamType{a class model of `PMPSelfIntersectionTraits`} @@ -1746,7 +1756,7 @@ autorefine( TriangleMesh& tm, polygon_mesh_to_polygon_soup(tm, soup_points, soup_triangles, np); - autorefine_triangle_soup(soup_points, soup_triangles); + autorefine_triangle_soup(soup_points, soup_triangles, np); clear(tm); //TODO: keep properties repair_polygon_soup(soup_points, soup_triangles); From 1f61a84e495f62b71570ad5962411adf4680eb54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Wed, 2 Aug 2023 10:30:05 +0200 Subject: [PATCH 82/99] add demo plugin that support refinement of one or several items (soup or mesh) --- .../Polyhedron/Plugins/PMP/CMakeLists.txt | 6 +- .../Plugins/PMP/Repair_polyhedron_plugin.cpp | 105 +++++++++++++++++- 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt index 152d84952ae..658458acaad 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/CMakeLists.txt @@ -119,7 +119,11 @@ target_link_libraries( 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) +target_link_libraries(repair_polyhedron_plugin PUBLIC scene_points_with_normal_item scene_surface_mesh_item scene_polygon_soup_item) +if(TARGET CGAL::TBB_support) + target_link_libraries(repair_polyhedron_plugin PUBLIC CGAL::TBB_support) +endif() + qt5_wrap_ui(isotropicRemeshingUI_FILES Isotropic_remeshing_dialog.ui) polyhedron_demo_plugin(isotropic_remeshing_plugin Isotropic_remeshing_plugin diff --git a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp index 5ecc8921433..dd4acb43427 100644 --- a/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp +++ b/Polyhedron/demo/Polyhedron/Plugins/PMP/Repair_polyhedron_plugin.cpp @@ -1,6 +1,7 @@ #include #include "Scene_surface_mesh_item.h" +#include "Scene_polygon_soup_item.h" #include "Scene_points_with_normal_item.h" #include #include @@ -19,6 +20,8 @@ #include #include #include +#include +#include #include "ui_RemoveNeedlesDialog.h" #include "ui_SelfSnapDialog.h" @@ -52,8 +55,9 @@ public: actionDuplicateNMVertices = new QAction(tr("Duplicate Non-Manifold Vertices"), mw); actionExtractNMVertices = new QAction(tr("Extract Non-Manifold Vertices"), mw); actionMergeDuplicatedVerticesOnBoundaryCycles = new QAction(tr("Merge Duplicated Vertices on Boundary Cycles"), mw); - actionAutorefine = new QAction(tr("Autorefine Mesh"), mw); - actionAutorefineAndRMSelfIntersections = new QAction(tr("Autorefine and Remove Self-Intersections"), mw); + actionAutorefine = new QAction(tr("Autorefine Mesh (Deprecated)"), mw); + actionNewAutorefine = new QAction(tr("Autorefine"), mw); + actionAutorefineAndRMSelfIntersections = new QAction(tr("Autorefine and Remove Self-Intersections (Deprecated)"), mw); actionRemoveNeedlesAndCaps = new QAction(tr("Remove Needles And Caps")); actionSnapBorders = new QAction(tr("Snap Boundaries")); @@ -65,6 +69,7 @@ public: actionExtractNMVertices->setObjectName("actionExtractNMVertices"); actionMergeDuplicatedVerticesOnBoundaryCycles->setObjectName("actionMergeDuplicatedVerticesOnBoundaryCycles"); actionAutorefine->setObjectName("actionAutorefine"); + actionNewAutorefine->setObjectName("actionNewAutorefine"); actionAutorefineAndRMSelfIntersections->setObjectName("actionAutorefineAndRMSelfIntersections"); actionRemoveNeedlesAndCaps->setObjectName("actionRemoveNeedlesAndCaps"); actionSnapBorders->setObjectName("actionSnapBorders"); @@ -77,6 +82,7 @@ public: actionExtractNMVertices->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); actionMergeDuplicatedVerticesOnBoundaryCycles->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); actionAutorefine->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); + actionNewAutorefine->setProperty("subMenuName", "Polygon Mesh Processing/Repair"); actionAutorefineAndRMSelfIntersections->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); actionSnapBorders->setProperty("subMenuName", "Polygon Mesh Processing/Repair/Experimental"); @@ -93,16 +99,29 @@ public: << actionExtractNMVertices << actionMergeDuplicatedVerticesOnBoundaryCycles << actionAutorefine + << actionNewAutorefine << actionAutorefineAndRMSelfIntersections << actionRemoveNeedlesAndCaps << actionSnapBorders; } - bool applicable(QAction*) const + bool applicable(QAction* action) const { - int item_id = scene->mainSelectionIndex(); - return qobject_cast(scene->item(item_id)); + if (action!=actionNewAutorefine) + { + int item_id = scene->mainSelectionIndex(); + return qobject_cast(scene->item(item_id)); + } + for (Scene_interface::Item_id index : scene->selectionIndices()) + { + if (qobject_cast(scene->item(index))) + return true; + if (qobject_cast(scene->item(index))) + return true; + } + return false; } + template void on_actionRemoveIsolatedVertices_triggered(Scene_interface::Item_id index); template @@ -120,6 +139,8 @@ public: template void on_actionAutorefine_triggered(Scene_interface::Item_id index); template + void on_actionNewAutorefine_triggered(const std::vector& indices); + template void on_actionAutorefineAndRMSelfIntersections_triggered(Scene_interface::Item_id index); public Q_SLOTS: @@ -131,6 +152,7 @@ public Q_SLOTS: void on_actionExtractNMVertices_triggered(); void on_actionMergeDuplicatedVerticesOnBoundaryCycles_triggered(); void on_actionAutorefine_triggered(); + void on_actionNewAutorefine_triggered(); void on_actionAutorefineAndRMSelfIntersections_triggered(); void on_actionRemoveNeedlesAndCaps_triggered(); void on_actionSnapBorders_triggered(); @@ -144,6 +166,7 @@ private: QAction* actionExtractNMVertices; QAction* actionMergeDuplicatedVerticesOnBoundaryCycles; QAction* actionAutorefine; + QAction* actionNewAutorefine; QAction* actionAutorefineAndRMSelfIntersections; QAction* actionRemoveNeedlesAndCaps; QAction* actionSnapBorders; @@ -421,6 +444,78 @@ void Polyhedron_demo_repair_polyhedron_plugin::on_actionAutorefine_triggered() QApplication::restoreOverrideCursor(); } +template +void Polyhedron_demo_repair_polyhedron_plugin::on_actionNewAutorefine_triggered(const std::vector& indices) +{ + namespace PMP = CGAL::Polygon_mesh_processing; + Polygon_soup::Points points; + Polygon_soup::Polygons polygons; + + if (indices.size()==1) + { + if (Scene_surface_mesh_item* smi_ptr = qobject_cast(scene->item(indices[0]))) + PMP::polygon_mesh_to_polygon_soup(*smi_ptr->polyhedron(), points, polygons); + else if (Scene_polygon_soup_item* spi_ptr = qobject_cast(scene->item(indices[0]))) + { + points = spi_ptr->points(); + polygons = spi_ptr->polygons(); + } + } + else + { + for (Scene_interface::Item_id id : indices) + { + Polygon_soup::Points l_points; + Polygon_soup::Polygons l_polygons; + + if (Scene_surface_mesh_item* smi_ptr = qobject_cast(scene->item(id))) + PMP::polygon_mesh_to_polygon_soup(*smi_ptr->polyhedron(), l_points, l_polygons); + else if (Scene_polygon_soup_item* spi_ptr = qobject_cast(scene->item(id))) + { + l_points = spi_ptr->points(); + l_polygons = spi_ptr->polygons(); + } + std::size_t offset=points.size(); + points.insert(points.end(), l_points.begin(), l_points.end()); + std::size_t psize=polygons.size(); + polygons.insert(polygons.end(), l_polygons.begin(), l_polygons.end()); + for (std::size_t i=psize; iload(points, polygons); + QString name = scene->item(indices[0])->name(); + for (std::size_t k=1; kitem(indices[k])->name(); + new_item->setName(name+" autorefined"); + + scene->addItem(new_item); + new_item->invalidateOpenGLBuffers(); + Q_EMIT new_item->itemChanged(); +} + +void Polyhedron_demo_repair_polyhedron_plugin::on_actionNewAutorefine_triggered() +{ + std::vector indices; + for (Scene_interface::Item_id index : scene->selectionIndices()) + { + if (qobject_cast(scene->item(index))) + indices.push_back(index); + else if (qobject_cast(scene->item(index))) + indices.push_back(index); + } + QApplication::setOverrideCursor(Qt::WaitCursor); + on_actionNewAutorefine_triggered(indices); + QApplication::restoreOverrideCursor(); +} + template void Polyhedron_demo_repair_polyhedron_plugin::on_actionAutorefineAndRMSelfIntersections_triggered(Scene_interface::Item_id index) { From 49d6821d9bf3ad827ad664e739c90e0cd8c24909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 28 Aug 2023 13:51:57 +0200 Subject: [PATCH 83/99] accomodate update to c++17 STL --- Kernel_23/include/CGAL/Kernel/function_objects.h | 16 ++++++++-------- .../Polygon_mesh_processing/autorefinement.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Kernel_23/include/CGAL/Kernel/function_objects.h b/Kernel_23/include/CGAL/Kernel/function_objects.h index 8974b762dcb..8309a3c97ce 100644 --- a/Kernel_23/include/CGAL/Kernel/function_objects.h +++ b/Kernel_23/include/CGAL/Kernel/function_objects.h @@ -2211,8 +2211,8 @@ namespace CommonKernelFunctors { Plane plane3 = construct_plane(p3, q3, r3); const auto res = typename K::Intersect_3()(plane1, plane2, plane3); - CGAL_assertion(res!=boost::none); - const Point* e_pt = boost::get(&(*res)); + CGAL_assertion(res!=std::nullopt); + const Point* e_pt = std::get_if(&(*res)); CGAL_assertion(e_pt!=nullptr); return *e_pt; } @@ -2221,8 +2221,8 @@ namespace CommonKernelFunctors { operator()(const Plane& plane1, const Plane& plane2, const Plane& plane3) const { const auto res = typename K::Intersect_3()(plane1, plane2, plane3); - CGAL_assertion(res!=boost::none); - const Point* e_pt = boost::get(&(*res)); + CGAL_assertion(res!=std::nullopt); + const Point* e_pt = std::get_if(&(*res)); CGAL_assertion(e_pt!=nullptr); return *e_pt; } @@ -2245,8 +2245,8 @@ namespace CommonKernelFunctors { Segment s2 = construct_segment(p2, q2); const auto res = typename K::Intersect_3()(s1, s2); - CGAL_assertion(res!=boost::none); - const Point* e_pt = boost::get(&(*res)); + CGAL_assertion(res!=std::nullopt); + const Point* e_pt = std::get_if(&(*res)); CGAL_assertion(e_pt!=nullptr); return *e_pt; } @@ -2255,8 +2255,8 @@ namespace CommonKernelFunctors { operator()(const Segment& s1, const Segment& s2) const { const auto res = typename K::Intersect_3()(s1, s2); - CGAL_assertion(res!=boost::none); - const Point* e_pt = boost::get(&(*res)); + CGAL_assertion(res!=std::nullopt); + const Point* e_pt = std::get_if(&(*res)); CGAL_assertion(e_pt!=nullptr); return *e_pt; } diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 0fb843c31c0..b3133304bb9 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -292,8 +292,8 @@ void old_intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3& CGAL_kernel_assertion_code(int pt_added = 0;) - const typename Kernel::Point_3* prev = &(*boost::prior(inter_pts.end())); - Iterator stop = inter_pts.size() > 2 ? inter_pts.end() : boost::prior(inter_pts.end()); + const typename Kernel::Point_3* prev = &(*std::prev(inter_pts.end())); + Iterator stop = inter_pts.size() > 2 ? inter_pts.end() : std::prev(inter_pts.end()); for(Iterator it=inter_pts.begin(); it!=stop; ++it) { const typename Kernel::Point_3& curr = *it; From 4dc2ad3f36a9f2023e3e0ceaa5e44bf38b7332ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 4 Sep 2023 14:05:18 +0200 Subject: [PATCH 84/99] fix map type --- .../CGAL/Polygon_mesh_processing/autorefinement.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index b3133304bb9..32765252a6f 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1480,12 +1480,13 @@ void autorefine_triangle_soup(PointRange& soup_points, // TODO: reuse the fact that maps per triangle are already sorted #ifdef CGAL_LINKED_WITH_TBB - std::conditional_t, - std::map> point_id_map; + typedef std::conditional_t, + std::map> Point_id_map; #else - std::map point_id_map; + typedef std::map Point_id_map; #endif + Point_id_map point_id_map; #if ! defined(CGAL_NDEBUG) || defined(CGAL_DEBUG_PMP_AUTOREFINE) std::vector exact_soup_points; @@ -1605,7 +1606,7 @@ void autorefine_triangle_soup(PointRange& soup_points, #else //option 2 (without mutex) /// Lambda concurrent_get_point_id() - tbb::concurrent_vector::iterator> iterators; + tbb::concurrent_vector iterators; auto concurrent_get_point_id = [&](const typename EK::Point_3 pt) { auto insert_res = point_id_map.insert(std::make_pair(pt, -1)); @@ -1616,7 +1617,7 @@ void autorefine_triangle_soup(PointRange& soup_points, //use map iterator triple for triangles to create them concurrently and safely soup_triangles_out.resize(offset + new_triangles.size()); - std::vector::iterator, 3>> triangle_buffer(new_triangles.size()); + std::vector> triangle_buffer(new_triangles.size()); tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), [&](const tbb::blocked_range& r) { for (size_t ti = r.begin(); ti != r.end(); ++ti) { From 9d68f5350e491bb1b23a42f14027285477a18780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 4 Sep 2023 14:58:47 +0200 Subject: [PATCH 85/99] doc + changes --- Installation/CHANGES.md | 6 ++++++ .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index 47998400268..b361d15dec7 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -35,6 +35,12 @@ Release date: October 2023 - Removed the class templates `Gray_image_mesh_domain_3`, `Implicit_mesh_domain_3`, and `Labeled_image_mesh_domain_3` which are deprecated since CGAL-4.13. +### [Polygon Mesh Processing](https://doc.cgal.org/6.0/Manual/packages.html#PkgPolygonMeshProcessing) + +- Added the function + `CGAL::Polygon_mesh_processing::autorefine_triangle_soup()` that refines a soup of triangles so that no pair of triangles intersects + (they can share an edge or a vertex). Also added, the function `autorefine()` operating directly on a triangle mesh and updating it + using the aforementioned function on triangle soup. [Release 5.6](https://github.com/CGAL/cgal/releases/tag/v5.6) ----------- diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 32765252a6f..884ce3477aa 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1128,8 +1128,9 @@ void generate_subtriangles(std::size_t ti, /** * \ingroup PMP_corefinement_grp * -* refines a soup of triangles so that no pair of triangles intersects in their interior. -* Note that points in `soup_points` can only be added (intersection points) a the end of the container, with the initial order preserved. +* refines a soup of triangles so that no pair of triangles intersects. +* Output triangles may share a common edge or a common vertex (but with the same indexed position in `points`). +* Note that points in `soup_points` can only be added (intersection points) at the end of the container, with the initial order preserved. * Note that if `soup_points` contains two or more identical points and only the first copy (following the order in the `soup_points`) * will be used in `soup_triangles`. * `soup_triangles` will be updated to contain both the input triangles and the new subdivides triangles. Degenerate triangles will be removed. From 8e36b7b37e6dd2e14d55e3997d70d1ec3b0af26e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 5 Oct 2023 09:32:22 +0200 Subject: [PATCH 86/99] the map is either const or take by copy --- Property_map/include/CGAL/property_map.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Property_map/include/CGAL/property_map.h b/Property_map/include/CGAL/property_map.h index 12fd06503fe..f1115cbf05a 100644 --- a/Property_map/include/CGAL/property_map.h +++ b/Property_map/include/CGAL/property_map.h @@ -661,7 +661,7 @@ struct Boolean_property_map return pm.set_ptr->count(k) != 0; } - friend void put(Boolean_property_map& pm, const key_type& k, bool v) + friend void put(Boolean_property_map pm, const key_type& k, bool v) { CGAL_assertion(pm.set_ptr!=nullptr); if (v) From a193a1d8fb9a7efe5e5b92b2e588fcf1be93df65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 9 Oct 2023 09:08:31 +0200 Subject: [PATCH 87/99] implement comments from review --- Installation/CHANGES.md | 4 ++-- .../CGAL/Polygon_mesh_processing/autorefinement.h | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index b361d15dec7..8748eda2db0 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -39,8 +39,8 @@ Release date: October 2023 - Added the function `CGAL::Polygon_mesh_processing::autorefine_triangle_soup()` that refines a soup of triangles so that no pair of triangles intersects - (they can share an edge or a vertex). Also added, the function `autorefine()` operating directly on a triangle mesh and updating it - using the aforementioned function on triangle soup. + in their interiors. Also added, the function `autorefine()` operating directly on a triangle mesh and updating it + using the aforementioned function on a triangle soup. [Release 5.6](https://github.com/CGAL/cgal/releases/tag/v5.6) ----------- diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 884ce3477aa..5b9cad98277 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1131,15 +1131,15 @@ void generate_subtriangles(std::size_t ti, * refines a soup of triangles so that no pair of triangles intersects. * Output triangles may share a common edge or a common vertex (but with the same indexed position in `points`). * Note that points in `soup_points` can only be added (intersection points) at the end of the container, with the initial order preserved. -* Note that if `soup_points` contains two or more identical points and only the first copy (following the order in the `soup_points`) +* Note that if `soup_points` contains two or more identical points then only the first copy (following the order in the `soup_points`) * will be used in `soup_triangles`. -* `soup_triangles` will be updated to contain both the input triangles and the new subdivides triangles. Degenerate triangles will be removed. +* `soup_triangles` will be updated to contain both the input triangles and the new subdivided triangles. Degenerate triangles will be removed. * Also triangles in `soup_triangles` will be triangles without intersection first, followed by triangles coming from a subdivision induced * by an intersection. The named parameter `visitor()` can be used to track * * @tparam PointRange a model of the concept `RandomAccessContainer` * whose value type is the point type -* @tparam TriIdsRange a model of the concepts `RandomAccessContainer`, `BackInsertionSequence` and `Swappable`, whose +* @tparam TriangleRange a model of the concepts `RandomAccessContainer`, `BackInsertionSequence` and `Swappable`, whose * value type is a model of the concept `RandomAccessContainer` whose value type is convertible to `std::size_t` and that * is constructible from an `std::initializer_list` of size 3. * @tparam NamedParameters a sequence of \ref bgl_namedparameters "Named Parameters" @@ -1174,9 +1174,9 @@ void generate_subtriangles(std::size_t ti, * \cgalNamedParamsEnd * */ -template +template void autorefine_triangle_soup(PointRange& soup_points, - TriIdsRange& soup_triangles, + TriangleRange& soup_triangles, const NamedParameters& np = parameters::default_values()) { using parameters::choose_parameter; @@ -1507,7 +1507,7 @@ void autorefine_triangle_soup(PointRange& soup_points, #endif } - TriIdsRange soup_triangles_out; + TriangleRange soup_triangles_out; soup_triangles_out.reserve(soup_triangles.size()); // TODO: remove #deg tri? visitor.number_of_output_triangles(soup_triangles.size()+new_triangles.size()); From 08b25d8778a06ffc5c82118a3dd4c1a41bf8da6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Thu, 2 Nov 2023 16:08:37 +0100 Subject: [PATCH 88/99] prevent a warning with older versions of TBB --- .../CGAL/Polygon_mesh_processing/autorefinement.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 5b9cad98277..d25ea95fe90 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -46,6 +46,10 @@ #ifdef CGAL_LINKED_WITH_TBB #include +#if TBB_INTERFACE_VERSION < 12010 && !defined(TBB_PREVIEW_CONCURRENT_ORDERED_CONTAINERS) +#define CGAL_HAS_DEFINED_TBB_PREVIEW_CONCURRENT_ORDERED_CONTAINERS +#define TBB_PREVIEW_CONCURRENT_ORDERED_CONTAINERS +#endif #include #include #ifdef SET_POINT_IDS_USING_MUTEX @@ -1770,4 +1774,10 @@ autorefine( TriangleMesh& tm, } } // end of CGAL::Polygon_mesh_processing +#ifdef CGAL_LINKED_WITH_TBB +#ifdef CGAL_HAS_DEFINED_TBB_PREVIEW_CONCURRENT_ORDERED_CONTAINERS +#undef TBB_PREVIEW_CONCURRENT_ORDERED_CONTAINERS +#endif +#endif + #endif // CGAL_POLYGON_MESH_PROCESSING_AUTOREFINEMENT_H From bcdc0f9f92093d0356afa3d3017150badd6ee74f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 8 Dec 2023 11:45:25 +0100 Subject: [PATCH 89/99] remove non needed include --- .../examples/Polygon_mesh_processing/soup_autorefinement.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index a44d47c8b6d..5baea1a3964 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -1,6 +1,4 @@ #include -#include - #include #include #include From d620bcd61a7d7f05946f6bd6173a3b1fea917473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 8 Dec 2023 13:20:23 +0100 Subject: [PATCH 90/99] user manual --- .../Polygon_mesh_processing.txt | 13 +++++++++++++ .../doc/Polygon_mesh_processing/examples.txt | 1 + 2 files changed, 14 insertions(+) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 00ccfd382f6..6a658a5829f 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -864,6 +864,19 @@ vertices at identical positions, can be used to repair this configuration. \section PMPGeometricRepair Geometric Repair **************************************** +\subsection PMPAutoref Self-intersection Resolution (Autorefinement) in Triangle Soups +Given a soup of triangles, a self-intersection is defined as the intersection of two triangles from the soup +such that the intersection is not defined by the convex hull of one, two or three shared vertices. +In other words, it is an intersection that happens in the interior of one of the two triangles, or in the interior +of one their edges, except if identical points are associated to different vertices of the triangle soup which +would then also includes overlaps of duplicated points. + +The function `CGAL::Polygon_mesh_processing::autorefine_triangle_soup()` provides a way to refine a triangle soup +using the intersections of the triangles from the soup. In particular, if some points are duplicated they will be +merged. Note that if a kernel with exact predicates but inexact constructions is used, some new self-intersections +might be introduced due to rounding issues of points coordinates. +To guarantee that the triangle soup is free from self-intersections, a kernel with exact constructions must be used. + \subsection PMPRemoveCapsNeedles Removal of Almost Degenerate Triangle Faces Triangle faces of a mesh made up of almost collinear points are badly shaped elements that might not be desirable to have in a mesh. The function diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt index 146e1261ff4..c582dc76739 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/examples.txt @@ -43,4 +43,5 @@ \example Polygon_mesh_processing/cc_compatible_orientations.cpp \example Polygon_mesh_processing/remesh_planar_patches.cpp \example Polygon_mesh_processing/remesh_almost_planar_patches.cpp +\example Polygon_mesh_processing/soup_autorefinement.cpp */ From 9ac0ef686f157c9311bc5ea969abc1320992e7d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 8 Dec 2023 13:24:55 +0100 Subject: [PATCH 91/99] aspell check --- .../doc/Polygon_mesh_processing/Polygon_mesh_processing.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt index 6a658a5829f..d52fd823cd4 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Polygon_mesh_processing.txt @@ -214,7 +214,7 @@ it can try to equalize the angles between incident edges, or (and) move vertices Border vertices are considered constrained and do not move at any step of the procedure. No vertices are inserted at any time. Angle and area smoothing algorithms are based on Surazhsky and Gotsman \cgalCite{cgal:sg-hqct-04}. Since area smoothing considers only areas as a smoothing criterion, it may result in long and skinny -triangles. To paliate this phenomenon, area smoothing is followed by an (optional) step of Delaunay-based edge flips. +triangles. To palliate this phenomenon, area smoothing is followed by an (optional) step of Delaunay-based edge flips. In any case, area smoothing is guaranteed to improve the spatial distribution of the vertices over the area that is being smoothed. A simple example can be found in \ref Polygon_mesh_processing/mesh_smoothing_example.cpp. @@ -434,7 +434,7 @@ depicted in red); (iii) `clip_volume=true`: clipping of the volume bounded by th \cgalFigureEnd \cgalFigureBegin{coref_clip_compact, clip_compact.png} -Clipping a cube with a halfspace: compacity of the clipper (`clip_volume=false` in both cases). +Clipping a cube with a halfspace: compactivity of the clipper (`clip_volume=false` in both cases). From left to right: (i) initial cube and the plane defining the clipping halfspace, note that a whole face of the cube (2 triangles) is exactly contained in the plane; (ii) `use_compact_clipper=true`: clipping of the surface mesh with a compact halfspace: coplanar faces are part of the output; From e352f2b17c0d871f56f9829bdd7a0c0ca60473fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 8 Dec 2023 13:27:04 +0100 Subject: [PATCH 92/99] fix doc --- .../Concepts/PMPAutorefinementVisitor.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPAutorefinementVisitor.h b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPAutorefinementVisitor.h index e3ef90e9be0..ef2f124329b 100644 --- a/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPAutorefinementVisitor.h +++ b/Polygon_mesh_processing/doc/Polygon_mesh_processing/Concepts/PMPAutorefinementVisitor.h @@ -6,7 +6,9 @@ /// the creation of new triangles. /// /// \cgalRefines{CopyConstructible} -/// \cgalHasModel `CGAL::Polygon_mesh_processing::Autorefinement::Default_visitor`. +/// \cgalHasModelsBegin +/// \cgalHasModels{CGAL::Polygon_mesh_processing::Autorefinement::Default_visitor} +/// \cgalHasModelsEnd class PMPAutorefinementVisitor{ public: From 8d0a047685cfea8e1d2f272efe8aa8468b93b5c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Fri, 8 Dec 2023 14:22:41 +0100 Subject: [PATCH 93/99] remote debug code and abandonned alternatives --- .../Polygon_mesh_processing/autorefinement.h | 512 +++--------------- 1 file changed, 63 insertions(+), 449 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index d25ea95fe90..bb81855edd5 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -26,7 +26,7 @@ #include #include -#ifdef USE_PROGRESS_DISPLAY +#ifdef CGAL_AUTOREF_USE_PROGRESS_DISPLAY #include #endif @@ -52,29 +52,22 @@ #endif #include #include -#ifdef SET_POINT_IDS_USING_MUTEX +#ifdef CGAL_AUTOREF_SET_POINT_IDS_USING_MUTEX #include #endif #endif #include -#define TEST_RESOLVE_INTERSECTION -#define DEDUPLICATE_SEGMENTS -//#define USE_DEBUG_PARALLEL_TIMERS -//#define DEBUG_COUNTERS -//#define USE_FIXED_PROJECTION_TRAITS -//#define DEBUG_DEPTH +//#define CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS +//#define CGAL_AUTOREFINE_DEBUG_COUNTERS +//#define CGAL_AUTOREF_DEBUG_DEPTH -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS #include #endif -#ifdef USE_FIXED_PROJECTION_TRAITS -#include -#endif - -#if defined(DEBUG_COUNTERS) || defined(USE_DEBUG_PARALLEL_TIMERS) +#if defined(CGAL_AUTOREFINE_DEBUG_COUNTERS) || defined(CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS) #include #endif @@ -123,20 +116,11 @@ Segment_inter_type do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, std::size_t ri, std::size_t si, const std::vector& points, - const typename K::Vector_3& plane_normal, + const typename K::Vector_3& /* plane_normal */, const K& k = K()) { typename K::Collinear_are_ordered_along_line_3 cln_order = k.collinear_are_ordered_along_line_3_object(); -#ifdef USE_PROJECTED_ORIENTATION_2_FOR_COPLANAR_ORIENTATION_TESTS - auto cpl_orient = - [&plane_normal](const typename K::Point_3& p, const typename K::Point_3& q, const typename K::Point_3& r) - { - return ::CGAL::orientation(q-p, r-p, plane_normal); - }; -#else typename K::Coplanar_orientation_3 cpl_orient=k.coplanar_orientation_3_object(); - CGAL_USE(plane_normal); -#endif const typename K::Point_3& p=points[pi]; const typename K::Point_3& q=points[qi]; @@ -267,75 +251,6 @@ do_coplanar_segments_intersect(std::size_t pi, std::size_t qi, return NO_INTERSECTION; } -////////////////////////////////// -////////////////////////////////// -////////////////////////////////// -////////////////////////////////// -////////////////////////////////// - -#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION -template -void old_intersection_coplanar_triangles_cutoff(const typename Kernel::Point_3& p, - const typename Kernel::Point_3& q, - const typename Kernel::Point_3& r, - const Kernel& k, - std::list& inter_pts) -{ - typedef typename std::list::iterator Iterator; - - if(inter_pts.empty()) - return; - - typename Kernel::Coplanar_orientation_3 orient = k.coplanar_orientation_3_object(); - typename Kernel::Construct_line_3 line = k.construct_line_3_object(); - - //orient(p,q,r,r) is POSITIVE - std::map orientations; - for (Iterator it=inter_pts.begin();it!=inter_pts.end();++it) - orientations[ &(*it) ]=orient(p,q,r,*it); - - CGAL_kernel_assertion_code(int pt_added = 0;) - - const typename Kernel::Point_3* prev = &(*std::prev(inter_pts.end())); - Iterator stop = inter_pts.size() > 2 ? inter_pts.end() : std::prev(inter_pts.end()); - for(Iterator it=inter_pts.begin(); it!=stop; ++it) - { - const typename Kernel::Point_3& curr = *it; - Orientation or_prev = orientations[prev], - or_curr = orientations[&curr]; - - if((or_prev == POSITIVE && or_curr == NEGATIVE) || - (or_prev == NEGATIVE && or_curr == POSITIVE)) - { - typename Intersection_traits::result_type - obj = ::CGAL::Intersections::internal::intersection(line(p,q), line(*prev,curr), k); - - // assert "not empty" - CGAL_kernel_assertion(bool(obj)); - - const typename Kernel::Point_3* inter = ::CGAL::Intersections::internal::intersect_get(obj); - CGAL_kernel_assertion(inter != nullptr); - - prev = &(*inter_pts.insert(it,*inter)); - orientations[prev] = COLLINEAR; - CGAL_kernel_assertion_code(++pt_added;) - } - - prev = &(*it); - } - - CGAL_kernel_assertion(pt_added<3); - Iterator it = inter_pts.begin(); - while(it!=inter_pts.end()) - { - if(orientations[&(*it)] == NEGATIVE) - inter_pts.erase(it++); - else - ++it; - } -} -#endif - // imported from Intersections_3/include/CGAL/Intersections_3/internal/Triangle_3_Triangle_3_intersection.h template void coplanar_intersections(const std::array& t1, @@ -350,146 +265,14 @@ void coplanar_intersections(const std::array& t1, l_inter_pts.push_back(Intersections::internal::Point_on_triangle(-1,1)); l_inter_pts.push_back(Intersections::internal::Point_on_triangle(-1,2)); -#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION - std::list old_l_inter_pts; - old_l_inter_pts.push_back(p2); - old_l_inter_pts.push_back(q2); - old_l_inter_pts.push_back(r2); - - - auto enum_to_string = [](CGAL::Orientation o) - { - if (o==COLLINEAR) return std::string("COLLINEAR"); - if (o==POSITIVE) return std::string("POSITIVE"); - return std::string("NEGATIVE"); - }; - - auto to_string = [](const auto& t) - { - std::stringstream sstr; - sstr << "4 " - << to_double(t[0].x()) << " " << to_double(t[0].y()) << " " << to_double(t[0].z()) << " " - << to_double(t[1].x()) << " " << to_double(t[1].y()) << " " << to_double(t[1].z()) << " " - << to_double(t[2].x()) << " " << to_double(t[2].y()) << " " << to_double(t[2].z()) << " " - << to_double(t[0].x()) << " " << to_double(t[0].y()) << " " << to_double(t[0].z()) << "\n"; - return sstr.str(); - }; - - std::cout << "intersection_coplanar_triangles\n"; - std::ofstream("/tmp/t1.polylines.txt") << to_string(t1) << "\n"; - std::ofstream("/tmp/t2.polylines.txt") << to_string(t2) << "\n"; - - std::cout << "Position of vertices of t1: "; - std::cout << enum_to_string( coplanar_orientation(p2,q2,r2,p1)) << " - "; - std::cout << enum_to_string( coplanar_orientation(p2,q2,r2,q1)) << " - "; - std::cout << enum_to_string( coplanar_orientation(p2,q2,r2,r1)) << "\n"; - std::cout << " "; - std::cout << enum_to_string( coplanar_orientation(q2,r2,p2,p1)) << " - "; - std::cout << enum_to_string( coplanar_orientation(q2,r2,p2,q1)) << " - "; - std::cout << enum_to_string( coplanar_orientation(q2,r2,p2,r1)) << "\n"; - std::cout << " "; - std::cout << enum_to_string( coplanar_orientation(r2,p2,q2,p1)) << " - "; - std::cout << enum_to_string( coplanar_orientation(r2,p2,q2,q1)) << " - "; - std::cout << enum_to_string( coplanar_orientation(r2,p2,q2,r1)) << "\n"; - std::cout << "Position of vertices of t2: "; - std::cout << enum_to_string( coplanar_orientation(p1,q1,r1,p2)) << " - "; - std::cout << enum_to_string( coplanar_orientation(p1,q1,r1,q2)) << " - "; - std::cout << enum_to_string( coplanar_orientation(p1,q1,r1,r2)) << "\n"; - std::cout << " "; - std::cout << enum_to_string( coplanar_orientation(q1,r1,p1,p2)) << " - "; - std::cout << enum_to_string( coplanar_orientation(q1,r1,p1,q2)) << " - "; - std::cout << enum_to_string( coplanar_orientation(q1,r1,p1,r2)) << "\n"; - std::cout << " "; - std::cout << enum_to_string( coplanar_orientation(r1,p1,q1,p2)) << " - "; - std::cout << enum_to_string( coplanar_orientation(r1,p1,q1,q2)) << " - "; - std::cout << enum_to_string( coplanar_orientation(r1,p1,q1,r2)) << "\n"; - - auto print_points = [&]() - { - for(auto p : l_inter_pts) std::cout << " (" << p.id1() << "," << p.id2() << ",[" << p.alpha << "]) "; std::cout <<"\n"; - }; - std::cout << " ipts size: " << l_inter_pts.size() << "\n"; - print_points(); -#endif - //intersect t2 with the three half planes which intersection defines t1 K k; Intersections::internal::intersection_coplanar_triangles_cutoff(p1,q1,r1,0,p2,q2,r2,k,l_inter_pts); //line p1q1 -#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION - std::cout << " ipts size: " << l_inter_pts.size() << "\n"; - print_points(); - old_intersection_coplanar_triangles_cutoff(p1,q1,r1,k,old_l_inter_pts); - CGAL_assertion(l_inter_pts.size()==old_l_inter_pts.size()); - for (std::size_t i=0; ipoint(p1,q1,r1,p2,q2,r2,k)) - { - std::cout <<"ERROR with point #" << i << "\n"; - throw std::runtime_error("invalid output 0"); - } - } -#endif Intersections::internal::intersection_coplanar_triangles_cutoff(q1,r1,p1,1,p2,q2,r2,k,l_inter_pts); //line q1r1 -#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION - std::cout << " ipts size: " << l_inter_pts.size() << "\n"; - print_points(); - old_intersection_coplanar_triangles_cutoff(q1,r1,p1,k,old_l_inter_pts); - CGAL_assertion(l_inter_pts.size()==old_l_inter_pts.size()); - for (std::size_t i=0; ipoint(p1,q1,r1,p2,q2,r2,k)) - { - std::cout <<"ERROR with point #" << i << "\n"; - throw std::runtime_error("invalid output 1"); - } - } -#endif Intersections::internal::intersection_coplanar_triangles_cutoff(r1,p1,q1,2,p2,q2,r2,k,l_inter_pts); //line r1p1 -#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION - std::cout << " ipts size: " << l_inter_pts.size() << "\n"; - print_points(); - old_intersection_coplanar_triangles_cutoff(r1,p1,q1,k,old_l_inter_pts); - CGAL_assertion(l_inter_pts.size()==old_l_inter_pts.size()); - for (std::size_t i=0; ipoint(p1,q1,r1,p2,q2,r2,k)) - { - std::cout <<"ERROR with point #" << i << "\n"; - throw std::runtime_error("invalid output 2"); - } - } -#endif - -#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION - std::size_t start=inter_pts.size(); -#endif for (const Intersections::internal::Point_on_triangle& pot : l_inter_pts) inter_pts.push_back( pot.point(p1,q1,r1,p2,q2,r2,k) ); - -#ifdef CGAL_DEBUG_COPLANAR_T3_T3_INTERSECTION - for (std::size_t i=0; i> i; -#endif - } // imported from Polygon_mesh_processing/internal/Corefinement/intersect_triangle_segment_3.h @@ -509,23 +292,6 @@ find_intersection(const typename K::Point_3& p, const typename K::Point_3& q, / int nb_coplanar=(ab==COPLANAR?1:0) + (bc==COPLANAR?1:0) + (ca==COPLANAR?1:0); -/* - if ( nb_coplanar==0 ) - return result_type(ON_FACE,hd,is_src_coplanar,is_tgt_coplanar); - - if (nb_coplanar==1){ - if (ab==COPLANAR) - // intersection is ab - return result_type(ON_EDGE,next(hd,tm),is_src_coplanar,is_tgt_coplanar); - if (bc==COPLANAR) - // intersection is bc - return result_type(ON_EDGE,prev(hd,tm),is_src_coplanar,is_tgt_coplanar); - CGAL_assertion(ca==COPLANAR); - // intersection is ca - return result_type(ON_EDGE,hd,is_src_coplanar,is_tgt_coplanar); - } -*/ - if (is_p_coplanar) { inter_pts.push_back(p); @@ -646,7 +412,7 @@ bool collect_intersections(const std::array& t1, if (ori[0]== COPLANAR && ori[1]==COPLANAR && ori[2]==COPLANAR) { coplanar_intersections(t1, t2, inter_pts); -#ifdef DEBUG_DEPTH +#ifdef CGAL_AUTOREF_DEBUG_DEPTH for (auto p : inter_pts) if (depth(p)>2) throw std::runtime_error("Depth is not 4: "+std::to_string(depth(p))); #endif @@ -674,7 +440,7 @@ bool collect_intersections(const std::array& t1, auto last = std::unique(inter_pts.begin(), inter_pts.end()); inter_pts.erase(last, inter_pts.end()); -#ifdef DEBUG_DEPTH +#ifdef CGAL_AUTOREF_DEBUG_DEPTH for (auto p : inter_pts) if (depth(p)>2) throw std::runtime_error("Depth is not 2: "+std::to_string(depth(p))); #endif @@ -682,16 +448,7 @@ bool collect_intersections(const std::array& t1, return false; } -////////////////////////////////// -////////////////////////////////// -////////////////////////////////// -////////////////////////////////// -////////////////////////////////// - template void generate_subtriangles(std::size_t ti, @@ -704,20 +461,8 @@ void generate_subtriangles(std::size_t ti, PointVector& new_triangles ) { - // std::cout << "generate_subtriangles()\n"; - // std::cout << std::setprecision(17); - -#ifdef USE_FIXED_PROJECTION_TRAITS - typedef ::CGAL::internal::Projection_traits_3 P_traits; -#else typedef CGAL::Projection_traits_3 P_traits; -#endif - -#ifndef TEST_RESOLVE_INTERSECTION - typedef CGAL::Exact_intersections_tag Itag; -#else typedef CGAL::No_constraint_intersection_tag Itag; -#endif typedef CGAL::Constrained_Delaunay_triangulation_2 CDT_2; //typedef CGAL::Constrained_triangulation_plus_2 CDT; @@ -729,15 +474,6 @@ void generate_subtriangles(std::size_t ti, typename EK::Vector_3 n = normal(t[0], t[1], t[2]); typename EK::Point_3 o(CGAL::ORIGIN); -#ifdef USE_FIXED_PROJECTION_TRAITS - P_traits cdt_traits; - bool orientation_flipped = false; - CDT cdt(cdt_traits); - // TODO: still need to figure out why I can't make the orientation_flipped correctly - cdt.insert(t[0]); - cdt.insert(t[1]); - cdt.insert(t[2]); -#else bool orientation_flipped = false; if ( typename EK::Less_xyz_3()(o+n,o) ) { @@ -751,9 +487,8 @@ void generate_subtriangles(std::size_t ti, cdt.insert_outside_affine_hull(t[1]); typename CDT::Vertex_handle v = cdt.tds().insert_dim_up(cdt.infinite_vertex(), orientation_flipped); v->set_point(t[2]); -#endif -#ifdef DEBUG_COUNTERS +#ifdef CGAL_AUTOREFINE_DEBUG_COUNTERS struct Counter { int c1=0; @@ -781,37 +516,11 @@ void generate_subtriangles(std::size_t ti, }; static Counter counter; -#define COUNTER_INSTRUCTION(X) X +#define CGAL_AUTOREF_COUNTER_INSTRUCTION(X) X #else -#define COUNTER_INSTRUCTION(X) +#define CGAL_AUTOREF_COUNTER_INSTRUCTION(X) #endif - -#ifdef TEST_RESOLVE_INTERSECTION - //~ static std::ofstream debug("inter_segments.polylines.txt"); - //~ debug.precision(17); - - //~ std::cout << "points.size() " << points.size() << "\n"; - //~ std::set all_triangles_indices(in_triangle_ids.begin(), in_triangle_ids.end()); - //~ all_triangles_indices.insert(ti); - - //~ std::ofstream debug("triangles.polylines.txt"); - //~ debug << std::setprecision(17); - //~ for (std::size_t i : all_triangles_indices) - //~ debug << "4 " - //~ << triangles[i][0] << " " - //~ << triangles[i][1] << " " - //~ << triangles[i][2] << " " - //~ << triangles[i][0] << "\n"; - //~ debug.close(); - //~ debug.open("triangle.off"); - //~ debug << std::setprecision(17); - //~ debug << "OFF\n3 1 0\n"; - //~ debug << triangles[ti][0] << "\n" - //~ << triangles[ti][1] << "\n" - //~ << triangles[ti][2] << "\n 3 0 1 2\n"; - //~ debug.close(); - // pre-compute segment intersections if (!segments.empty()) { @@ -819,7 +528,7 @@ void generate_subtriangles(std::size_t ti, std::vector< std::vector > points_on_segments(nbs); - COUNTER_INSTRUCTION(counter.timer1.start();) + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer1.start();) std::map point_id_map; @@ -831,7 +540,6 @@ void generate_subtriangles(std::size_t ti, CGAL_assertion(insertion_ok); } - auto get_point_id = [&](const typename EK::Point_3& pt) { auto insert_res = point_id_map.insert(std::make_pair(pt, points.size())); @@ -855,17 +563,17 @@ void generate_subtriangles(std::size_t ti, { if ( !do_overlap(segment_boxes[i], segment_boxes[j]) ) { - COUNTER_INSTRUCTION(++counter.c5;) - COUNTER_INSTRUCTION(++counter.total;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.c5;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.total;) continue; } - COUNTER_INSTRUCTION(counter.timer5.start();) + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer5.start();) Segment_inter_type seg_inter_type = do_coplanar_segments_intersect(segments[i].first, segments[i].second, segments[j].first, segments[j].second, points, n); - COUNTER_INSTRUCTION(counter.timer5.stop();) + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer5.stop();) switch(seg_inter_type) { @@ -892,25 +600,25 @@ void generate_subtriangles(std::size_t ti, case POINT_INTERSECTION: { if ( coplanar_triangles.count(CGAL::make_sorted_pair(in_triangle_ids[i], in_triangle_ids[j])) == 0 - && coplanar_triangles.count(CGAL::make_sorted_pair(ti, in_triangle_ids[j])) == 0 - && coplanar_triangles.count(CGAL::make_sorted_pair(in_triangle_ids[i], ti)) == 0) + && coplanar_triangles.count(CGAL::make_sorted_pair(ti, in_triangle_ids[j])) == 0 + && coplanar_triangles.count(CGAL::make_sorted_pair(in_triangle_ids[i], ti)) == 0) { - COUNTER_INSTRUCTION(counter.timer6.start();) + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer6.start();) typename EK::Point_3 pt = typename EK::Construct_planes_intersection_point_3()( triangles[in_triangle_ids[i]][0], triangles[in_triangle_ids[i]][1],triangles[in_triangle_ids[i]][2], triangles[in_triangle_ids[j]][0], triangles[in_triangle_ids[j]][1],triangles[in_triangle_ids[j]][2], triangles[ti][0], triangles[ti][1],triangles[ti][2]); - COUNTER_INSTRUCTION(counter.timer6.stop();) + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer6.stop();) - COUNTER_INSTRUCTION(++counter.c1;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.c1;) std::size_t pid = get_point_id(pt); points_on_segments[i].push_back(pid); points_on_segments[j].push_back(pid); } else { - COUNTER_INSTRUCTION(++counter.c2;) - COUNTER_INSTRUCTION(counter.timer4.start();) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.c2;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer4.start();) typename EK::Point_3 pt = typename EK::Construct_coplanar_segments_intersection_point_3()( points[segments[i].first], points[segments[i].second], points[segments[j].first], points[segments[j].second]); @@ -918,69 +626,63 @@ void generate_subtriangles(std::size_t ti, std::size_t pid = get_point_id(pt); points_on_segments[i].push_back(pid); points_on_segments[j].push_back(pid); - COUNTER_INSTRUCTION(counter.timer4.stop();) - //~ std::ofstream debug ("/tmp/triangles.polylines.txt"); - //~ debug << "4 " << triangles[ti][0] << " " << triangles[ti][1] << " " << triangles[ti][2] << " " << triangles[ti][0] << "\n"; - //~ debug << "4 " << triangles[in_triangle_ids[i]][0] << " " << triangles[in_triangle_ids[i]][1] << " " << triangles[in_triangle_ids[i]][2] << " " << triangles[in_triangle_ids[i]][0] << "\n"; - //~ debug << "4 " << triangles[in_triangle_ids[j]][0] << " " << triangles[in_triangle_ids[j]][1] << " " << triangles[in_triangle_ids[j]][2] << " " << triangles[in_triangle_ids[j]][0] << "\n"; - //~ debug.close(); - //~ throw std::runtime_error("Unexpected case 1"); + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer4.stop();) } break; } case COPLANAR_SEGMENT_PQ: { - COUNTER_INSTRUCTION(++counter.c3;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.c3;) points_on_segments[j].push_back(segments[i].first); points_on_segments[j].push_back(segments[i].second); break; } case COPLANAR_SEGMENT_RS: { - COUNTER_INSTRUCTION(++counter.c3;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.c3;) points_on_segments[i].push_back(segments[j].first); points_on_segments[i].push_back(segments[j].second); break; } case COPLANAR_SEGMENT_PR: { - COUNTER_INSTRUCTION(++counter.c3;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.c3;) points_on_segments[i].push_back(segments[j].first); points_on_segments[j].push_back(segments[i].first); break; } case COPLANAR_SEGMENT_QS: { - COUNTER_INSTRUCTION(++counter.c3;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.c3;) points_on_segments[i].push_back(segments[j].second); points_on_segments[j].push_back(segments[i].second); break; } case COPLANAR_SEGMENT_PS: { - COUNTER_INSTRUCTION(++counter.c3;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.c3;) points_on_segments[i].push_back(segments[j].second); points_on_segments[j].push_back(segments[i].first); break; } case COPLANAR_SEGMENT_QR: { - COUNTER_INSTRUCTION(++counter.c3;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.c3;) points_on_segments[i].push_back(segments[j].first); points_on_segments[j].push_back(segments[i].second); break; } case NO_INTERSECTION: { - COUNTER_INSTRUCTION(++counter.c4;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.c4;) } } } - COUNTER_INSTRUCTION(++counter.total;) + CGAL_AUTOREF_COUNTER_INSTRUCTION(++counter.total;) } } - COUNTER_INSTRUCTION(counter.timer1.stop();) - COUNTER_INSTRUCTION(counter.timer2.start();) + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer1.stop();) + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer2.start();) std::size_t nb_new_segments=0; for (std::size_t i = 0; i 10){ - //~ for (const auto p : cst_points) - //~ std::cout << " -- " << p << "(" << depth(p) << ")\n"; - //~ std::cout << "segments:\n"; - //~ for (auto s : segments) - //~ std::cout << " " << depth(s[0]) << " " << depth(s[1]) << "\n"; - //~ exit(1); - //~ } + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer2.stop();) // now fill segments with new segments segments.reserve(segments.size()+nb_new_segments); @@ -1074,56 +743,25 @@ void generate_subtriangles(std::size_t ti, std::sort(segments.begin(), segments.end()); auto last = std::unique(segments.begin(), segments.end()); segments.erase(last, segments.end()); -#endif - //~ std::ofstream("/tmp/tri.xyz") << std::setprecision(17) << triangles[ti][0] << "\n" - //~ << triangles[ti][1] << "\n" - //~ << triangles[ti][2] << "\n"; - //~ std::ofstream debug("/tmp/cst.polylines.txt"); - //~ debug << std::setprecision(17); - //~ for(auto s : segments) - //~ debug << "2 " << points[s.first] << " " << points[s.second] << "\n"; - //~ debug.close(); - - COUNTER_INSTRUCTION(counter.timer3.start();) + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer3.start();) if (segments.empty()) cdt.insert(points.begin(), points.end()); else cdt.insert_constraints(points.begin(), points.end(), segments.begin(), segments.end()); - COUNTER_INSTRUCTION(counter.timer3.stop();) + CGAL_AUTOREF_COUNTER_INSTRUCTION(counter.timer3.stop();) -#ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS - static int k = 0; - std::stringstream buffer; - buffer.precision(17); - int nbt=0; -#endif - for (typename CDT::Face_handle fh : cdt.finite_face_handles()) - { - if (orientation_flipped) - new_triangles.push_back( { CGAL::make_array(fh->vertex(0)->point(), - fh->vertex(cdt.cw(0))->point(), - fh->vertex(cdt.ccw(0))->point()), ti } ); - else - new_triangles.push_back( { CGAL::make_array(fh->vertex(0)->point(), - fh->vertex(cdt.ccw(0))->point(), - fh->vertex(cdt.cw(0))->point()), ti } ); -#ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS - ++nbt; - buffer << fh->vertex(0)->point() << "\n"; - buffer << fh->vertex(cdt.ccw(0))->point() << "\n"; - buffer << fh->vertex(cdt.cw(0))->point() << "\n"; -#endif - } - -#ifdef CGAL_DEBUG_PMP_AUTOREFINE_DUMP_TRIANGULATIONS - std::ofstream dump("triangulation_"+std::to_string(k)+".off"); - dump << "OFF\n" << 3*nbt << " " << nbt << " 0\n"; - dump << buffer.str(); - for (int i=0; ivertex(0)->point(), + fh->vertex(cdt.cw(0))->point(), + fh->vertex(cdt.ccw(0))->point()), ti } ); + else + new_triangles.push_back( { CGAL::make_array(fh->vertex(0)->point(), + fh->vertex(cdt.ccw(0))->point(), + fh->vertex(cdt.cw(0))->point()), ti } ); + } } } // end of autorefine_impl @@ -1267,7 +905,7 @@ void autorefine_triangle_soup(PointRange& soup_points, std::vector< std::vector > all_in_triangle_ids(triangles.size()); CGAL_PMP_AUTOREFINE_VERBOSE("compute intersections"); -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS Real_timer t; t.start(); #endif @@ -1320,14 +958,13 @@ void autorefine_triangle_soup(PointRange& soup_points, coplanar_triangles.insert(CGAL::make_sorted_pair(i1, i2)); } } -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS t.stop(); std::cout << t.time() << " sec. for #2" << std::endl; t.reset(); #endif -#ifdef DEDUPLICATE_SEGMENTS -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS t.start(); #endif @@ -1396,11 +1033,10 @@ void autorefine_triangle_soup(PointRange& soup_points, deduplicate_inserted_segments(ti); } -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS t.stop(); std::cout << t.time() << " sec. for #3" << std::endl; t.reset(); -#endif #endif CGAL_PMP_AUTOREFINE_VERBOSE("triangulate faces"); @@ -1413,7 +1049,7 @@ void autorefine_triangle_soup(PointRange& soup_points, std::vector, std::size_t>> new_triangles; #endif -#ifdef USE_PROGRESS_DISPLAY +#ifdef CGAL_AUTOREF_USE_PROGRESS_DISPLAY boost::timer::progress_display pd(triangles.size()); #endif @@ -1423,37 +1059,15 @@ void autorefine_triangle_soup(PointRange& soup_points, new_triangles.push_back({triangles[ti], ti}); else { -#ifdef USE_FIXED_PROJECTION_TRAITS - const std::array& t = triangles[ti]; - auto is_constant_in_dim = [](const std::array& t, int dim) - { - return t[0][dim] == t[1][dim] && t[0][dim] != t[2][dim]; - }; - - typename EK::Vector_3 orth = CGAL::normal(t[0], t[1], t[2]); // TODO::avoid construction? - int c = CGAL::abs(orth[0]) > CGAL::abs(orth[1]) ? 0 : 1; - c = CGAL::abs(orth[2]) > CGAL::abs(orth[c]) ? 2 : c; - - if (c == 0) { - autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); - } - else if (c == 1) { - autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); - } - else if (c == 2) { - autorefine_impl::generate_subtriangles(ti, all_segments[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, triangles, new_triangles); - } -#else autorefine_impl::generate_subtriangles(ti, all_segments_ids[ti], all_points[ti], all_in_triangle_ids[ti], intersecting_triangles, coplanar_triangles, triangles, new_triangles); -#endif } -#ifdef USE_PROGRESS_DISPLAY +#ifdef CGAL_AUTOREF_USE_PROGRESS_DISPLAY ++pd; #endif }; -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS t.start(); #endif #ifdef CGAL_LINKED_WITH_TBB @@ -1472,7 +1086,7 @@ void autorefine_triangle_soup(PointRange& soup_points, refine_triangles(ti); } -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS t.stop(); std::cout << t.time() << " sec. for #1" << std::endl; t.reset(); @@ -1552,12 +1166,12 @@ void autorefine_triangle_soup(PointRange& soup_points, return insert_res.first->second; }; -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS t.start(); #endif std::size_t offset = soup_triangles_out.size(); -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS std::string mode = "parallel"; #endif @@ -1565,7 +1179,7 @@ void autorefine_triangle_soup(PointRange& soup_points, #ifdef CGAL_LINKED_WITH_TBB if(parallel_execution && new_triangles.size() > 100) { -#ifdef SET_POINT_IDS_USING_MUTEX +#ifdef CGAL_AUTOREF_SET_POINT_IDS_USING_MUTEX //option 1 (using a mutex) CGAL_MUTEX point_container_mutex; /// Lambda concurrent_get_point_id() @@ -1672,7 +1286,7 @@ void autorefine_triangle_soup(PointRange& soup_points, else #endif { -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS mode = "sequential"; #endif soup_triangles_out.reserve(offset + new_triangles.size()); @@ -1687,7 +1301,7 @@ void autorefine_triangle_soup(PointRange& soup_points, -#ifdef USE_DEBUG_PARALLEL_TIMERS +#ifdef CGAL_AUTOREF_USE_DEBUG_PARALLEL_TIMERS t.stop(); std::cout << t.time() << " sec. for #4 (" << mode << ")" << std::endl; t.reset(); From 93a1549c6515be7b077d9267ca6ba1be377fed28 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 11 Dec 2023 11:34:42 +0100 Subject: [PATCH 94/99] used typedef --- .../examples/Polygon_mesh_processing/soup_autorefinement.cpp | 2 -- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp index 5baea1a3964..a76e1254f6e 100644 --- a/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp +++ b/Polygon_mesh_processing/examples/Polygon_mesh_processing/soup_autorefinement.cpp @@ -13,8 +13,6 @@ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; typedef Kernel::Point_3 Point; -typedef CGAL::Surface_mesh Mesh; - namespace PMP = CGAL::Polygon_mesh_processing; int main(int argc, char** argv) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index bb81855edd5..46f9ed9cbe7 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1126,7 +1126,7 @@ void autorefine_triangle_soup(PointRange& soup_points, } TriangleRange soup_triangles_out; - soup_triangles_out.reserve(soup_triangles.size()); // TODO: remove #deg tri? + soup_triangles_out.reserve(soup_triangles.size()); visitor.number_of_output_triangles(soup_triangles.size()+new_triangles.size()); From d0c224fafbc08c2156d184f6c9841c8a8545aae6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Mon, 11 Dec 2023 14:07:08 +0100 Subject: [PATCH 95/99] handle some todos --- .../Polygon_mesh_processing/autorefinement.h | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 46f9ed9cbe7..05d05637b16 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1,5 +1,3 @@ -//TODO: add for soup face the id of the input face. not sure it is easy to report intersection edge as a pair of vertex id -//TODO: only return intersection segments (pay attention to degenerate triangles that are currently ignored) // Copyright (c) 2023 GeometryFactory (France). // All rights reserved. // @@ -735,8 +733,6 @@ void generate_subtriangles(std::size_t ti, CGAL_assertion(points.size()==point_id_map.size()); } - // TODO: sorted pair to be constructed when pushing_back - // TODO: only needed in case of coplanar segments? for (std::pair& s : segments) if (s.second < s.first) std::swap(s.first,s.second); @@ -853,7 +849,9 @@ void autorefine_triangle_soup(PointRange& soup_points, typedef std::size_t Input_TID; typedef std::pair Pair_of_triangle_ids; - std::vector si_pairs; // TODO: check std::vector is fine with Parallel_tag + // no need for a concurrent vector as the called function itself + // takes care of sequentially writing into the output iterator + std::vector si_pairs; // collect intersecting pairs of triangles CGAL_PMP_AUTOREFINE_VERBOSE("collect intersecting pairs"); @@ -909,8 +907,8 @@ void autorefine_triangle_soup(PointRange& soup_points, Real_timer t; t.start(); #endif - std::set > intersecting_triangles; // TODO replace with vector>> - std::set > coplanar_triangles; // TODO replace with vector>> + std::set > intersecting_triangles; + std::set > coplanar_triangles; //TODO: PARALLEL_FOR #2 for (const Pair_of_triangle_ids& p : si_pairs) { @@ -1096,7 +1094,6 @@ void autorefine_triangle_soup(PointRange& soup_points, CGAL_PMP_AUTOREFINE_VERBOSE("create output soup"); Cartesian_converter to_input; - // TODO: reuse the fact that maps per triangle are already sorted #ifdef CGAL_LINKED_WITH_TBB typedef std::conditional_t 100) + if(parallel_execution && new_triangles.size() > 50) { #ifdef CGAL_AUTOREF_SET_POINT_IDS_USING_MUTEX //option 1 (using a mutex) @@ -1336,6 +1335,8 @@ void autorefine_triangle_soup(PointRange& soup_points, * @param tm input triangulated surface mesh * @param np an optional sequence of \ref bgl_namedparameters "Named Parameters" among the ones listed below * + * @warning `clear(tm)` will be called before filling `tm` with the refined mesh. + * * \cgalNamedParamsBegin * \cgalParamNBegin{concurrency_tag} * \cgalParamDescription{a tag indicating if the task should be done using one or several threads.} @@ -1378,7 +1379,7 @@ autorefine( TriangleMesh& tm, autorefine_triangle_soup(soup_points, soup_triangles, np); - clear(tm); //TODO: keep properties + clear(tm); repair_polygon_soup(soup_points, soup_triangles); duplicate_non_manifold_edges_in_polygon_soup(soup_points, soup_triangles); From 07acb78d302fcad1e4f1264f0a7d7233695f3b2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 12 Dec 2023 09:41:44 +0100 Subject: [PATCH 96/99] add tests for autoref --- .../Polygon_mesh_processing/autorefinement.h | 34 ++++-- .../Polygon_mesh_processing/CMakeLists.txt | 1 + .../test_autorefinement.cmd | 56 +++++----- .../test_autorefinement.cpp | 103 +++++++++++++++--- 4 files changed, 144 insertions(+), 50 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index 05d05637b16..b2d8427875c 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -46,7 +46,7 @@ #include #if TBB_INTERFACE_VERSION < 12010 && !defined(TBB_PREVIEW_CONCURRENT_ORDERED_CONTAINERS) #define CGAL_HAS_DEFINED_TBB_PREVIEW_CONCURRENT_ORDERED_CONTAINERS -#define TBB_PREVIEW_CONCURRENT_ORDERED_CONTAINERS +#define TBB_PREVIEW_CONCURRENT_ORDERED_CONTAINERS 1 #endif #include #include @@ -857,7 +857,16 @@ void autorefine_triangle_soup(PointRange& soup_points, CGAL_PMP_AUTOREFINE_VERBOSE("collect intersecting pairs"); triangle_soup_self_intersections(soup_points, soup_triangles, std::back_inserter(si_pairs), np); - if (si_pairs.empty()) return; + if (si_pairs.empty()) + { + if constexpr (!std::is_same_v) + { + visitor.number_of_output_triangles(soup_triangles.size()); + for(std::size_t i=0; i is_degen(soup_triangles.size(), false); @@ -1125,7 +1134,16 @@ void autorefine_triangle_soup(PointRange& soup_points, TriangleRange soup_triangles_out; soup_triangles_out.reserve(soup_triangles.size()); - visitor.number_of_output_triangles(soup_triangles.size()+new_triangles.size()); + if constexpr (!std::is_same_v) + { + std::size_t nbt=0; + for (Input_TID f=0; f tri_inter_ids_inverse(triangles.size()); @@ -1136,7 +1154,7 @@ void autorefine_triangle_soup(PointRange& soup_points, int tiid = tri_inter_ids[f]; if (tiid == -1) { - visitor.verbatim_triangle_copy(soup_triangles.size(), f); + visitor.verbatim_triangle_copy(soup_triangles_out.size(), f); soup_triangles_out.push_back( {soup_triangles[f][0], soup_triangles[f][1], soup_triangles[f][2]} ); @@ -1200,7 +1218,7 @@ void autorefine_triangle_soup(PointRange& soup_points, soup_triangles_out.resize(offset + new_triangles.size()); //use map iterator triple for triangles to create them concurrently and safely - std::vector::iterator, 3>> triangle_buffer(new_triangles.size()); + std::vector> triangle_buffer(new_triangles.size()); tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), [&](const tbb::blocked_range& r) { for (size_t ti = r.begin(); ti != r.end(); ++ti) { @@ -1238,10 +1256,8 @@ void autorefine_triangle_soup(PointRange& soup_points, std::vector> triangle_buffer(new_triangles.size()); tbb::parallel_for(tbb::blocked_range(0, new_triangles.size()), [&](const tbb::blocked_range& r) { - for (size_t ti = r.begin(); ti != r.end(); ++ti) { - if (offset + ti > soup_triangles_out.size()) { - std::cout << "ti = " << ti << std::endl; - } + for (size_t ti = r.begin(); ti != r.end(); ++ti) + { const std::array& t = new_triangles[ti].first; visitor.new_subtriangle(offset+ti, tri_inter_ids_inverse[new_triangles[ti].second]); triangle_buffer[ti] = CGAL::make_array(concurrent_get_point_id(t[0]), concurrent_get_point_id(t[1]), concurrent_get_point_id(t[2])); diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt index d9ea1a1cf37..248831b5051 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/CMakeLists.txt @@ -105,6 +105,7 @@ if(TARGET CGAL::TBB_support) target_link_libraries(test_pmp_distance PUBLIC CGAL::TBB_support) target_link_libraries(orient_polygon_soup_test PUBLIC CGAL::TBB_support) target_link_libraries(self_intersection_surface_mesh_test PUBLIC CGAL::TBB_support) + target_link_libraries(test_autorefinement PUBLIC CGAL::TBB_support) else() message(STATUS "NOTICE: Intel TBB was not found. Tests will use sequential code.") endif() diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_autorefinement.cmd b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_autorefinement.cmd index a2ffe2c2539..8c848a2f106 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_autorefinement.cmd +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_autorefinement.cmd @@ -1,28 +1,28 @@ -data-autoref/test_01.off 0 0 4 1 4 0 -data-autoref/test_02.off 1 5 13 1 5 0 -data-autoref/test_03.off 4 8 18 0 18 0 -data-autoref/test_04.off 1 5 17 0 17 0 -data-autoref/test_05.off 1 5 17 0 17 0 -data-autoref/test_06.off 3 55 141 1 76 0 -data-autoref/test_07.off 1 4 10 1 4 0 -data-autoref/test_08.off 1 31 87 1 52 0 -data-autoref/test_09.off 1 4 5 1 4 0 -data-autoref/test_10.off 1 3 13 0 13 0 -data-autoref/test_11.off 1 3 12 0 12 0 -data-autoref/test_12.off 2 2 11 1 11 0 -data-autoref/test_13.off 1 5 16 1 8 0 -data-autoref/test_14.off 1 5 16 1 12 0 -data-autoref/test_15.off 3 8 16 1 12 0 -data-autoref/test_16.off 1 2 6 1 4 0 -data-autoref/test_17.off 1 2 6 1 4 0 -data-autoref/triple_inter_exception/triple.off 0 0 0 0 0 1 -data-autoref/triple_inter_exception/cubes_cpln_1.off 0 0 0 0 0 1 -data-autoref/triple_inter_exception/cubes_cpln_2.off 0 0 0 0 0 1 -data-autoref/triple_inter_exception/cubes_cpln_3.off 0 0 0 0 0 1 -data-autoref/open_01.off 1 65 1377 1 1313 0 -data-autoref/open_02.off 1 33 595 1 562 0 -data-autoref/cpln_01.off 18 42 48 1 30 0 -data-autoref/cpln_02.off 28 56 40 1 24 0 -data-autoref/cpln_03.off 15 35 42 1 27 0 -data-autoref/four_cubes.off 12 94 184 1 78 0 -data-autoref/spiral.off 7 14 26 0 26 0 +data-autoref/test_01.off 0 0 4 1 4 0 4 2 +data-autoref/test_02.off 1 5 13 1 5 0 10 17 +data-autoref/test_03.off 4 8 18 0 18 0 14 20 +data-autoref/test_04.off 1 5 17 0 17 0 13 20 +data-autoref/test_05.off 1 5 17 0 17 0 13 20 +data-autoref/test_06.off 3 55 141 1 76 0 92 248 +data-autoref/test_07.off 1 4 10 1 4 0 8 12 +data-autoref/test_08.off 1 31 87 1 52 0 57 148 +data-autoref/test_09.off 1 4 5 1 4 0 4 4 +data-autoref/test_10.off 1 3 13 0 13 0 10 13 +data-autoref/test_11.off 1 3 12 0 12 0 9 12 +data-autoref/test_12.off 2 2 11 1 11 0 9 6 +data-autoref/test_13.off 1 5 16 1 8 0 16 22 +data-autoref/test_14.off 1 5 16 1 12 0 16 22 +data-autoref/test_15.off 3 8 16 1 12 0 16 24 +data-autoref/test_16.off 1 2 6 1 4 0 6 2 +data-autoref/test_17.off 1 2 6 1 4 0 6 2 +data-autoref/triple_inter_exception/triple.off 0 0 0 0 0 1 15 18 +data-autoref/triple_inter_exception/cubes_cpln_1.off 0 0 0 0 0 1 66 224 +data-autoref/triple_inter_exception/cubes_cpln_2.off 0 0 0 0 0 1 54 196 +data-autoref/triple_inter_exception/cubes_cpln_3.off 0 0 0 0 0 1 61 204 +data-autoref/open_01.off 1 65 1377 1 1313 0 1317 2622 +data-autoref/open_02.off 1 33 595 1 562 0 565 1056 +data-autoref/cpln_01.off 18 42 48 1 30 0 30 88 +data-autoref/cpln_02.off 28 56 40 1 24 0 24 72 +data-autoref/cpln_03.off 15 35 42 1 27 0 27 76 +data-autoref/four_cubes.off 12 94 184 1 78 0 106 352 +data-autoref/spiral.off 7 14 26 0 26 0 19 31 diff --git a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_autorefinement.cpp b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_autorefinement.cpp index 9c908d7ec24..3af3402a5f2 100644 --- a/Polygon_mesh_processing/test/Polygon_mesh_processing/test_autorefinement.cpp +++ b/Polygon_mesh_processing/test/Polygon_mesh_processing/test_autorefinement.cpp @@ -3,6 +3,10 @@ #include #include +#include +#include + +#include #include #include @@ -13,23 +17,64 @@ typedef CGAL::Surface_mesh Mesh; namespace PMP = CGAL::Polygon_mesh_processing; template -struct My_visitor : +struct My_exp_visitor : public CGAL::Polygon_mesh_processing::Corefinement::Default_visitor { void after_subface_creations(TriangleMesh&){++(*i);} - My_visitor() + My_exp_visitor() : i (new int(0) ) {} std::shared_ptr i; }; -void test(const char* fname, std::size_t nb_polylines, std::size_t total_nb_points, - std::size_t nb_vertices_after_autorefine, bool all_fixed, std::size_t nb_vertices_after_fix, - bool triple_intersection) +struct My_visitor { - std::cout << "Running tests on " << fname << "\n"; + My_visitor(std::size_t nb_input, std::size_t expected_nb_output) + : nb_input(nb_input) + , expected_nb_output(expected_nb_output) + {} + + ~My_visitor() + { + for(std::size_t i=0; i tgt_check; +}; + +void test_coref_based(const char* fname, std::size_t nb_polylines, std::size_t total_nb_points, + std::size_t nb_vertices_after_autorefine, bool all_fixed, std::size_t nb_vertices_after_fix, + bool triple_intersection) +{ + std::cout << "Running tests (coref based) on " << fname << "\n"; std::ifstream input(fname); Mesh mesh; @@ -41,7 +86,7 @@ void test(const char* fname, std::size_t nb_polylines, std::size_t total_nb_poin input.close(); std::size_t nb_vertices_before_autorefine = num_vertices(mesh); -// Testing surface_self_intersection() +// Testing PMP::experimental::surface_self_intersection() try{ std::vector< std::vector >polylines; PMP::experimental::surface_self_intersection(mesh, std::back_inserter(polylines)); @@ -57,9 +102,9 @@ void test(const char* fname, std::size_t nb_polylines, std::size_t total_nb_poin assert( triple_intersection ); } -// Testing autorefine() +// Testing PMP::experimental::autorefine() try{ - My_visitor visitor; + My_exp_visitor visitor; PMP::experimental::autorefine(mesh, CGAL::parameters::visitor(visitor)); mesh.collect_garbage(); @@ -72,7 +117,7 @@ void test(const char* fname, std::size_t nb_polylines, std::size_t total_nb_poin assert( triple_intersection ); } -// Testing autorefine_and_remove_self_intersections() +// Testing PMP::experimental::autorefine_and_remove_self_intersections() try{ input.open(fname); mesh.clear(); @@ -89,10 +134,42 @@ void test(const char* fname, std::size_t nb_polylines, std::size_t total_nb_poin } } +template +void test(const char* fname, std::size_t nb_vertices_after_autorefine, std::size_t expected_nb_output, Tag tag) +{ + std::cout << "Running tests on " << fname; + if (std::is_same_v) + std::cout << " (Sequential)\n"; + else + std::cout << " (Parallel)\n"; + + std::vector points; + std::vector< std::vector > triangles; + if (!CGAL::IO::read_polygon_soup(fname, points, triangles)) + { + std::cerr << " Input mesh is not a valid file." << std::endl; + exit(EXIT_FAILURE); + } + +// Testing autorefine() + My_visitor visitor(triangles.size(), expected_nb_output); + PMP::autorefine_triangle_soup(points, triangles, CGAL::parameters::visitor(visitor).concurrency_tag(tag)); + assert( nb_vertices_after_autorefine==points.size()); + assert( expected_nb_output==triangles.size()); + assert( !PMP::does_triangle_soup_self_intersect(points, triangles) ); +// CGAL::IO::write_polygon_soup("/tmp/debug.off", points, triangles); +} + int main(int argc, const char** argv) { // file nb_polylines total_nb_points nb_vertices_after_autorefine all_fixed nb_vertices_after_fix triple_intersection - for (int i=0;i<(argc-1)/7; ++i) - test(argv[1+7*i], atoi(argv[1+7*i+1]), atoi(argv[1+7*i+2]), - atoi(argv[1+7*i+3]), atoi(argv[1+7*i+4])==0?false:true, atoi(argv[1+7*i+5]), atoi(argv[1+7*i+6])==0?false:true); + for (int i=0;i<(argc-1)/9; ++i) + { + test_coref_based(argv[1+9*i], atoi(argv[1+9*i+1]), atoi(argv[1+9*i+2]), + atoi(argv[1+9*i+3]), atoi(argv[1+9*i+4])==0?false:true, atoi(argv[1+9*i+5]), atoi(argv[1+9*i+6])==0?false:true); + test(argv[1+9*i], atoi(argv[1+9*i+7]), atoi(argv[1+9*i+8]), CGAL::Sequential_tag()); +#ifdef CGAL_LINKED_WITH_TBB + test(argv[1+9*i], atoi(argv[1+9*i+7]), atoi(argv[1+9*i+8]), CGAL::Parallel_tag()); +#endif + } } From 10f4caa29638b86a15df361a4da9eba9db599391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 12 Dec 2023 11:53:22 +0100 Subject: [PATCH 97/99] add missing ref --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index b2d8427875c..c9751752d75 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -1200,7 +1200,7 @@ void autorefine_triangle_soup(PointRange& soup_points, //option 1 (using a mutex) CGAL_MUTEX point_container_mutex; /// Lambda concurrent_get_point_id() - auto concurrent_get_point_id = [&](const typename EK::Point_3 pt) + auto concurrent_get_point_id = [&](const typename EK::Point_3& pt) { auto insert_res = point_id_map.insert(std::make_pair(pt, -1)); @@ -1243,7 +1243,7 @@ void autorefine_triangle_soup(PointRange& soup_points, //option 2 (without mutex) /// Lambda concurrent_get_point_id() tbb::concurrent_vector iterators; - auto concurrent_get_point_id = [&](const typename EK::Point_3 pt) + auto concurrent_get_point_id = [&](const typename EK::Point_3& pt) { auto insert_res = point_id_map.insert(std::make_pair(pt, -1)); if (insert_res.second) From b267b31bea9737dffaaa4b34f0a284ca991d9174 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 12 Dec 2023 13:12:21 +0100 Subject: [PATCH 98/99] workaround MSVC 2022 bug --- .../include/CGAL/Polygon_mesh_processing/autorefinement.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index c9751752d75..ec3f02633c8 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -996,9 +996,10 @@ void autorefine_triangle_soup(PointRange& soup_points, if (!all_points[ti].empty()) { - std::vector tmp; + using EPoint_3 = EK::Point_3; // workaround for MSVC 2022 bug + std::vector tmp; tmp.swap(all_points[ti]); - for (const typename EK::Point_3& pt : tmp) + for (const EPoint_3& pt : tmp) get_point_id(pt); } From 814a92655dfe38b96032772f3eae5aa351becde2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Loriot?= Date: Tue, 12 Dec 2023 13:12:45 +0100 Subject: [PATCH 99/99] remove non needed typenames + missing ref --- .../Polygon_mesh_processing/autorefinement.h | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h index ec3f02633c8..8a61b92f717 100644 --- a/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h +++ b/Polygon_mesh_processing/include/CGAL/Polygon_mesh_processing/autorefinement.h @@ -447,8 +447,7 @@ bool collect_intersections(const std::array& t1, } template + class PointVector> void generate_subtriangles(std::size_t ti, std::vector>& segments, std::vector& points, @@ -896,7 +895,7 @@ void autorefine_triangle_soup(PointRange& soup_points, // init the vector of triangles used for the autorefinement of triangles typedef CGAL::Exact_predicates_exact_constructions_kernel EK; - std::vector< std::array > triangles(tiid+1); + std::vector< std::array > triangles(tiid+1); Cartesian_converter to_exact; for(Input_TID f : intersected_faces) @@ -926,14 +925,14 @@ void autorefine_triangle_soup(PointRange& soup_points, if (i1==-1 || i2==-1) continue; //skip degenerate faces - const std::array& t1 = triangles[i1]; - const std::array& t2 = triangles[i2]; + const std::array& t1 = triangles[i1]; + const std::array& t2 = triangles[i2]; - std::vector inter_pts; + std::vector inter_pts; bool triangles_are_coplanar = autorefine_impl::collect_intersections(t1, t2, inter_pts); CGAL_assertion( - CGAL::do_intersect(typename EK::Triangle_3(t1[0], t1[1], t1[2]), typename EK::Triangle_3(t2[0], t2[1], t2[2])) + CGAL::do_intersect(EK::Triangle_3(t1[0], t1[1], t1[2]), EK::Triangle_3(t2[0], t2[1], t2[2])) != inter_pts.empty()); if (!inter_pts.empty()) @@ -985,7 +984,7 @@ void autorefine_triangle_soup(PointRange& soup_points, std::map point_id_map; - auto get_point_id = [&](const typename EK::Point_3& pt) + auto get_point_id = [&](const EK::Point_3& pt) { auto insert_res = point_id_map.insert(std::make_pair(pt, all_points[ti].size())); if (insert_res.second) @@ -1010,8 +1009,8 @@ void autorefine_triangle_soup(PointRange& soup_points, std::set> segset; for (std::size_t si=0; si iterators; - auto concurrent_get_point_id = [&](const typename EK::Point_3& pt) + auto concurrent_get_point_id = [&](const EK::Point_3& pt) { auto insert_res = point_id_map.insert(std::make_pair(pt, -1)); if (insert_res.second)