diff --git a/Installation/CHANGES.md b/Installation/CHANGES.md index d56ed1fc281b..900fefb941e6 100644 --- a/Installation/CHANGES.md +++ b/Installation/CHANGES.md @@ -4,6 +4,9 @@ Release date: December 2026 +### [Linear Cell Complex](https://doc.cgal.org/6.3/Manual/packages.html#PkgLinearCellComplex) +- added `tetrahedron_soup_to_lcc()` to import a tetrahedron soup into a linear cell complex. + ### [2D and 3D Fast Intersection and Distance Computation (AABB Tree)](https://doc.cgal.org/6.3/Manual/packages.html#PkgAABBTree) - `CGAL::AABB_tree::build()` now accepts an optional `Concurrency_tag` template parameter (`CGAL::Sequential_tag` by default). When `CGAL::Parallel_tag` is specified, the tree construction is performed in parallel. diff --git a/Linear_cell_complex/doc/Linear_cell_complex/Doxyfile.in b/Linear_cell_complex/doc/Linear_cell_complex/Doxyfile.in index db43fd07ee8d..1e4c4d0545c6 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/Doxyfile.in +++ b/Linear_cell_complex/doc/Linear_cell_complex/Doxyfile.in @@ -1,3 +1,4 @@ @INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS} PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - Linear Cell Complex" +INPUT += ${CGAL_PACKAGE_INCLUDE_DIR}/CGAL/tetrahedron_soup_to_lcc.h \ No newline at end of file diff --git a/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt b/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt index 006190086164..6da4a7527efe 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt @@ -73,6 +73,7 @@ - `CGAL::read_plane_graph_in_lcc` (formerly `import_from_plane_graph`) - `CGAL::triangulation_3_to_lcc` (formerly `import_from_triangulation_3`) - `CGAL::polyhedron_3_to_lcc` (formerly `import_from_polyhedron_3`) +- `CGAL::tetrahedron_soup_to_lcc()` \cgalCRPSubsection{Operations for Linear Cell Complex} - `CGAL::compute_normal_of_cell_0` diff --git a/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt b/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt index 234ae9e83da1..bc3e34caea48 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt +++ b/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt @@ -28,10 +28,12 @@ create_single_source_cgal_program("read_plane_graph_in_lcc_2.cpp") create_single_source_cgal_program("voronoi_2.cpp") create_single_source_cgal_program("voronoi_3.cpp") create_single_source_cgal_program("linear_cell_complex_3_vtk_io.cpp") +create_single_source_cgal_program("tetsoup_to_lcc.cpp") create_single_source_cgal_program("draw_linear_cell_complex.cpp") if(CGAL_Qt6_FOUND) target_link_libraries(draw_linear_cell_complex PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(linear_cell_complex_3_incremental_builder PRIVATE CGAL::CGAL_Basic_viewer) target_link_libraries(linear_cell_complex_3_insert PRIVATE CGAL::CGAL_Basic_viewer) + target_link_libraries(tetsoup_to_lcc PRIVATE CGAL::CGAL_Basic_viewer) endif() diff --git a/Linear_cell_complex/examples/Linear_cell_complex/tetsoup_to_lcc.cpp b/Linear_cell_complex/examples/Linear_cell_complex/tetsoup_to_lcc.cpp new file mode 100644 index 000000000000..a57e78dd4a54 --- /dev/null +++ b/Linear_cell_complex/examples/Linear_cell_complex/tetsoup_to_lcc.cpp @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include + +#include + +using LCC = CGAL::Linear_cell_complex_for_combinatorial_map<3, 3>; +using Point_3 = CGAL::Exact_predicates_inexact_constructions_kernel::Point_3; + +int main(int argc, char** argv) +{ + const std::string filename = (argc > 1) ? argv[1] : CGAL::data_file_path("meshes/elephant.mesh"); + + std::vector points; + std::vector> tetras; + std::vector subdomains; + std::ifstream in(filename); + if(!in) + { + std::cerr << "Cannot open " << filename << std::endl; + return 1; + } + + CGAL::IO::read_MEDIT(in, points, tetras, subdomains); + + //filter out subdomain 0 + std::vector> filtered_tetras; + for (std::size_t i=0; i +// Sebastien Loriot +// + +#ifndef CGAL_TETRAHEDRON_SOUP_TO_LCC_H +#define CGAL_TETRAHEDRON_SOUP_TO_LCC_H + +#include +#include +#include +#include +#include + +namespace CGAL +{ +/** + * @ingroup PkgLinearCellComplexConstructions + * + * \brief imports a 3D tetrahedron soup into a linear cell complex. + * + * Creates a 3D linear cell complex in `lcc` from a set of points and a range + * of tetrahedra defined by indices into `points`. The topological 3-combinatorial + * map is constructed by sewing adjacent 3-volumes (tetrahedra) along matching 2-faces. + * + * @tparam LCC a model of the `LinearCellComplex` concept. + * @tparam PointRange a model of `RandomAccessContainer` with `Point_3` as value type, being compatible with the point type of LCC. + * @tparam TetrahedronRange a model of `ConstRange` where each element is a container of 4 point indices, accessible using `operator[](int)`. + * + * @param points range of 3D points. + * @param tetrahedra range of tetrahedra, where each tetrahedron is represented by 4 indices corresponding to entries in `points`. + * @param lcc the target linear cell complex. + * + * @return a descriptor to a dart of the created complex, or `LCC::null_descriptor` if the input is empty. + * + * @pre `LCC::dimension >= 3` and `LCC::ambient_dimension == 3`. + * @pre Indices in `tetrahedra` must be valid 0-based indices into `points`. + * + * @sa `CGAL::triangulation_3_to_lcc()` + */ + template + typename LCC::Dart_descriptor + tetrahedron_soup_to_lcc(const PointRange& points, + const TetrahedronRange& tetrahedra, + LCC& lcc) + { + static_assert( LCC::dimension>=3 && LCC::ambient_dimension==3 ); + + if (points.empty() || tetrahedra.empty()) + return LCC::null_descriptor; + + using Dart_descriptor = typename LCC::Dart_descriptor; + + std::vector vertices; + vertices.reserve(points.size()); + for(const auto& pt : points) + vertices.push_back(lcc.create_vertex_attribute(pt)); + + struct Array_hasher + { + std::size_t operator()(const std::array& a) const + { + std::size_t seed = 0; + boost::hash_combine(seed, a[0]); + boost::hash_combine(seed, a[1]); + boost::hash_combine(seed, a[2]); + + return seed; + } + }; + + std::unordered_map< std::array, Dart_descriptor, Array_hasher> face_map; + + Dart_descriptor dart = LCC::null_descriptor; + for (const auto& t : tetrahedra) + { + Dart_descriptor res = lcc.make_tetrahedron(vertices[t[0]], + vertices[t[1]], + vertices[t[2]], + vertices[t[3]]); + + if (dart==LCC::null_descriptor) dart = res; + + for (int i=0; i<4; ++i) + { + Dart_descriptor curr= LCC::null_descriptor; + switch (i) + { + case 0: curr = lcc.template opposite<2>(lcc.next(res)); break; + case 1: curr = lcc.template opposite<2>(lcc.previous(res)); break; + case 2: curr = lcc.template opposite<2>(res); break; + default: curr = res; break; + } + + std::array f{t[(i+1)%4],t[(i+2)%4],t[(i+3)%4]}; + std::sort(f.begin(), f.end()); + auto insert_res = face_map.emplace(f, curr); + if (!insert_res.second) + { + Dart_descriptor curr2=insert_res.first->second; + while (lcc.vertex_attribute(curr2) != + lcc.vertex_attribute(lcc.other_extremity(curr)) ) + { + curr2 = lcc.next(curr2); + } + lcc.template topo_sew<3>(curr, lcc.other_orientation(curr2)); + } + } + } + + CGAL_assertion(dart!=LCC::null_descriptor); + return dart; + } +} // end of CGAL namespace + + +#endif // CGAL_TETRAHEDRON_SOUP_TO_LCC_H diff --git a/Stream_support/include/CGAL/IO/MEDIT.h b/Stream_support/include/CGAL/IO/MEDIT.h index 8e3d1fab4083..a9d0c362d0f2 100644 --- a/Stream_support/include/CGAL/IO/MEDIT.h +++ b/Stream_support/include/CGAL/IO/MEDIT.h @@ -46,7 +46,7 @@ bool read_MEDIT(std::istream& is, using FT = typename Kernel_traits::Kernel::FT; using Surface_patch_index = SurfacePatchIndex_; using Facet = std::array; - using Tet_with_ref = std::array; + using Tet_with_ref = typename std::iterator_traits::value_type; if(!is) return false;