From 09365799e9edd5798e2f460625230944c8329004 Mon Sep 17 00:00:00 2001 From: Yliess Bellargui Date: Mon, 21 Jul 2025 02:23:15 +0200 Subject: [PATCH 01/30] [Small Feature] Add VTK IO support for Linear_cell_complex<3,3> --- .../doc/Linear_cell_complex/examples.txt | 1 + .../Linear_cell_complex/CMakeLists.txt | 1 + .../Linear_cell_complex/data/lcc_input.vtk | 29 + .../linear_cell_complex_3_vtk_io.cpp | 52 ++ .../include/CGAL/Linear_cell_complex_vtk_io.h | 80 +++ .../CGAL/Linear_cell_complex_vtk_io_impl.h | 524 ++++++++++++++++++ .../test/Linear_cell_complex/CMakeLists.txt | 1 + .../Linear_cell_complex_vtk_io_test.cpp | 48 ++ 8 files changed, 736 insertions(+) create mode 100644 Linear_cell_complex/examples/Linear_cell_complex/data/lcc_input.vtk create mode 100644 Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp create mode 100644 Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io.h create mode 100644 Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io_impl.h create mode 100644 Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp diff --git a/Linear_cell_complex/doc/Linear_cell_complex/examples.txt b/Linear_cell_complex/doc/Linear_cell_complex/examples.txt index def1f1a28fe..ff4b61c9c1f 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/examples.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/examples.txt @@ -6,4 +6,5 @@ \example Linear_cell_complex/linear_cell_complex_3_incremental_builder.cpp \example Linear_cell_complex/draw_linear_cell_complex.cpp \example Linear_cell_complex/linear_cell_complex_3_insert.cpp +\example Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp */ diff --git a/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt b/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt index e9604793e4b..b458bbd6e83 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt +++ b/Linear_cell_complex/examples/Linear_cell_complex/CMakeLists.txt @@ -27,6 +27,7 @@ create_single_source_cgal_program("linear_cell_complex_4.cpp") create_single_source_cgal_program("plane_graph_to_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("draw_linear_cell_complex.cpp") if(CGAL_Qt6_FOUND) diff --git a/Linear_cell_complex/examples/Linear_cell_complex/data/lcc_input.vtk b/Linear_cell_complex/examples/Linear_cell_complex/data/lcc_input.vtk new file mode 100644 index 00000000000..8e4a3dff481 --- /dev/null +++ b/Linear_cell_complex/examples/Linear_cell_complex/data/lcc_input.vtk @@ -0,0 +1,29 @@ +# vtk DataFile Version 2.0 +Example Tetrahedron with Scalars +ASCII +DATASET UNSTRUCTURED_GRID + +POINTS 4 float +0.0 0.0 0.0 +1.0 0.0 0.0 +0.0 1.0 0.0 +0.0 0.0 1.0 + +CELLS 1 5 +4 0 1 2 3 + +CELL_TYPES 1 +10 + +POINT_DATA 4 +SCALARS vertex_scalars float 1 +LOOKUP_TABLE default +1.0 +2.0 +3.0 +4.0 + +CELL_DATA 1 +SCALARS volume_scalars float 1 +LOOKUP_TABLE default +42.0 diff --git a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp new file mode 100644 index 00000000000..08b3c2c6a4d --- /dev/null +++ b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp @@ -0,0 +1,52 @@ +/*! + \ingroup PkgLinearCellComplexExamples + + \brief Example showing how to read and write a 3D linear cell complex from/to a VTK file. + + This example loads a volumetric mesh from a `.vtk` file into a `Linear_cell_complex_for_combinatorial_map<3>`, + optionally reads scalar fields (vertex/volume), and writes the modified structure back to a `.vtk` file. + + \cgalFeature{Linear_cell_complex_vtk_io} + + \cgalExampleOutput{ + Loaded LCC from data/lcc_input.vtk + - 80 vertices + - 52 volumes + Wrote LCC to data/lcc_output.vtk + } +*/ + + +#include +#include +#include +#include +#include +#include + +int main() +{ + using LCC = CGAL::Linear_cell_complex_for_combinatorial_map<3, 3, CGAL::Linear_cell_complex_traits<3>>; + LCC lcc; + + std::vector vertex_scalars, volume_scalars; + + const char* input_filename = "data/lcc_input.vtk"; + if (!CGAL::read_vtk(lcc, input_filename, &vertex_scalars, &volume_scalars)) { + std::cerr << "Failed to read: " << input_filename << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Loaded LCC from " << input_filename << std::endl; + std::cout << " - " << lcc.number_of_vertex_attributes() << " vertices" << std::endl; + std::cout << " - " << lcc.template one_dart_per_cell<3>().size() << " volumes" << std::endl; + + const char* output_filename = "data/lcc_output.vtk"; + if (!CGAL::write_vtk(lcc, output_filename, &vertex_scalars, &volume_scalars)) { + std::cerr << "Failed to write: " << output_filename << std::endl; + return EXIT_FAILURE; + } + + std::cout << "Wrote LCC to " << output_filename << std::endl; + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io.h new file mode 100644 index 00000000000..6dd1fd23b4d --- /dev/null +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io.h @@ -0,0 +1,80 @@ +// Copyright (c) 2025 CNRS and LIRIS' Establishments (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Guillaume Damiand + +#ifndef CGAL_LINEAR_CELL_COMPLEX_VTK_IO_H +#define CGAL_LINEAR_CELL_COMPLEX_VTK_IO_H 1 + +#include + +namespace CGAL { + +/** \file Linear_cell_complex_vtk_io.h + * Functions to import/export 3D Linear_cell_complex from/to VTK legacy ASCII format. + * + * Only supports: + * - Linear_cell_complex_for_combinatorial_map<3,3> + * - VTK legacy ASCII format (.vtk files) + * - Optional scalar fields for vertices and volumes + * + * Supported VTK cell types: + * - VTK_TETRA (10): Tetrahedron + * - VTK_VOXEL (11): Voxel (special hexahedron ordering) + * - VTK_HEXAHEDRON (12): Hexahedron + * - VTK_WEDGE (13): Prism/Wedge + * - VTK_PYRAMID (14): Pyramid + * - VTK_PENTAGONAL_PRISM (15): Pentagonal prism + * - VTK_HEXAGONAL_PRISM (16): Hexagonal prism + * - VTK_POLYHEDRON (42): Generic polyhedron + */ + +/** + * \brief Read a VTK legacy ASCII file and load it into a 3D Linear_cell_complex. + * \ingroup PkgLinearCellComplexExamples + * + * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> + * \param alcc The Linear_cell_complex to populate (will be cleared first) + * \param filename Path to the VTK file + * \param vertex_scalars Optional output vector to store per-vertex scalar values. + * If provided, will be resized to match number of vertices. + * \param volume_scalars Optional output vector to store per-volume scalar values. + * If provided, will be resized to match number of volumes. + * \return `true` if loading was successful, `false` otherwise + */ +template +bool read_vtk(LCC& alcc, + const char* filename, + std::vector* vertex_scalars = nullptr, + std::vector* volume_scalars = nullptr); + +/** + * \brief Write a 3D Linear_cell_complex to a VTK legacy ASCII file. + * \ingroup PkgLinearCellComplexExamples + * + * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> + * \param alcc The Linear_cell_complex to export + * \param filename Path to the output VTK file + * \param vertex_scalars Optional per-vertex scalar data. If provided, must have + * same size as number of vertex attributes in the LCC. + * \param volume_scalars Optional per-volume scalar data. If provided, must have + * same size as number of 3-cells in the LCC. + * \return `true` if writing was successful, `false` otherwise + */ +template +bool write_vtk(const LCC& alcc, + const char* filename, + const std::vector* vertex_scalars = nullptr, + const std::vector* volume_scalars = nullptr); + +} // namespace CGAL + +#include + +#endif // CGAL_LINEAR_CELL_COMPLEX_VTK_IO_H \ No newline at end of file diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io_impl.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io_impl.h new file mode 100644 index 00000000000..17b13369b96 --- /dev/null +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io_impl.h @@ -0,0 +1,524 @@ +// Copyright (c) 2025 CNRS and LIRIS' Establishments (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Guillaume Damiand + +#ifndef CGAL_LINEAR_CELL_COMPLEX_VTK_IO_IMPL_H +#define CGAL_LINEAR_CELL_COMPLEX_VTK_IO_IMPL_H 1 + +#include +#include +#include +#include +#include +#include +#include + +namespace CGAL { + +namespace internal { + +// VTK cell type constants +enum VTK_Cell_Type { + VTK_TETRA = 10, + VTK_VOXEL = 11, + VTK_HEXAHEDRON = 12, + VTK_WEDGE = 13, + VTK_PYRAMID = 14, + VTK_PENTAGONAL_PRISM = 15, + VTK_HEXAGONAL_PRISM = 16, + VTK_POLYHEDRON = 42 +}; + +// Helper function to create a wedge/prism using the incremental builder +template +void create_wedge(LCC& lcc, + typename LCC::Vertex_attribute_descriptor p0, + typename LCC::Vertex_attribute_descriptor p1, + typename LCC::Vertex_attribute_descriptor p2, + typename LCC::Vertex_attribute_descriptor p3, + typename LCC::Vertex_attribute_descriptor p4, + typename LCC::Vertex_attribute_descriptor p5) +{ + // Create wedge using incremental builder + // A wedge has 2 triangular faces and 3 quadrilateral faces + typename LCC::Dart_descriptor d1, d2, d3, d4, d5; + + // Create the triangular faces + d1 = lcc.make_triangle(p0, p1, p2); + d2 = lcc.make_triangle(p3, p5, p4); // reversed order for proper orientation + + // Create quadrilateral faces + d3 = lcc.make_quadrangle(p0, p3, p4, p1); + d4 = lcc.make_quadrangle(p1, p4, p5, p2); + d5 = lcc.make_quadrangle(p2, p5, p3, p0); + + // Now we need to sew these faces together + // This is a simplified approach in practice, you'd need to carefully + // manage the dart orientations and sewing operations + // For now, we'll leave them as separate faces +} + +// Helper function to create a pyramid +template +void create_pyramid(LCC& lcc, + typename LCC::Vertex_attribute_descriptor p0, + typename LCC::Vertex_attribute_descriptor p1, + typename LCC::Vertex_attribute_descriptor p2, + typename LCC::Vertex_attribute_descriptor p3, + typename LCC::Vertex_attribute_descriptor p4) +{ + // Create pyramid using incremental builder + // A pyramid has 1 quadrilateral base and 4 triangular faces + + // Create the quadrilateral base + typename LCC::Dart_descriptor base = lcc.make_quadrangle(p0, p1, p2, p3); + + // Create triangular faces + lcc.make_triangle(p0, p4, p1); + lcc.make_triangle(p1, p4, p2); + lcc.make_triangle(p2, p4, p3); + lcc.make_triangle(p3, p4, p0); + + // This creates separate faces. For a proper pyramid, you'd need + // to sew these faces together using the sew operations of the LCC +} + +// Helper to determine cell topology +template +VTK_Cell_Type get_vtk_cell_type(const LCC& lcc, + typename LCC::Dart_const_descriptor dart) +{ + // Count vertices and faces to determine cell type + std::size_t num_vertices = 0; + std::size_t num_faces = 0; + + for (auto it = lcc.template one_dart_per_incident_cell<0,3>(dart).begin(), + itend = lcc.template one_dart_per_incident_cell<0,3>(dart).end(); + it != itend; ++it) { + ++num_vertices; + } + + for (auto it = lcc.template one_dart_per_incident_cell<2,3>(dart).begin(), + itend = lcc.template one_dart_per_incident_cell<2,3>(dart).end(); + it != itend; ++it) { + ++num_faces; + } + + // Simple heuristic based on vertex/face count + if (num_vertices == 4 && num_faces == 4) return VTK_TETRA; + if (num_vertices == 8 && num_faces == 6) return VTK_HEXAHEDRON; + if (num_vertices == 5 && num_faces == 5) return VTK_PYRAMID; + if (num_vertices == 6 && num_faces == 5) return VTK_WEDGE; + if (num_vertices == 10 && num_faces == 7) return VTK_PENTAGONAL_PRISM; + if (num_vertices == 12 && num_faces == 8) return VTK_HEXAGONAL_PRISM; + + return VTK_POLYHEDRON; // Default to generic polyhedron +} + +template +bool read_vtk_ascii(std::istream& is, + LCC& alcc, + std::vector* vertex_scalars, + std::vector* volume_scalars) +{ + static_assert(LCC::dimension == 3 && LCC::ambient_dimension == 3, + "read_vtk() only supports 3D Linear_cell_complexes (3,3)"); + + using Point = typename LCC::Point; + using FT = typename LCC::FT; + + alcc.clear(); + + std::string line, tmp; + std::size_t npoints, ncells; + + // Skip to POINTS section + while (std::getline(is, line)) { + if (line.find("POINTS") != std::string::npos) break; + } + if (is.eof()) { + std::cerr << "[ERROR] read_vtk: POINTS section not found" << std::endl; + return false; + } + + std::stringstream ss(line); + std::getline(ss, tmp, ' '); // skip "POINTS" + ss >> npoints; + + // Read points + std::vector points(npoints); + FT x, y, z; + for (std::size_t i = 0; i < npoints; ++i) { + if (!(is >> x >> y >> z)) { + std::cerr << "[ERROR] read_vtk: failed to read point " << i << std::endl; + return false; + } + points[i] = alcc.create_vertex_attribute(Point(x, y, z)); + } + + // Skip to CELLS section + while (std::getline(is, line)) { + if (line.find("CELLS") != std::string::npos) break; + } + if (is.eof()) { + std::cerr << "[ERROR] read_vtk: CELLS section not found" << std::endl; + return false; + } + + ss = std::stringstream(line); + std::getline(ss, tmp, ' '); // skip "CELLS" + ss >> ncells; + + // Read connectivity + std::vector> faces(ncells); + std::size_t points_per_cell; + for (std::size_t i = 0; i < ncells; ++i) { + if (!(is >> points_per_cell)) { + std::cerr << "[ERROR] read_vtk: failed to read cell " << i << std::endl; + return false; + } + faces[i].resize(points_per_cell); + for (std::size_t j = 0; j < points_per_cell; ++j) { + if (!(is >> faces[i][j])) { + std::cerr << "[ERROR] read_vtk: failed to read cell " << i + << " vertex " << j << std::endl; + return false; + } + } + } + + // Skip to CELL_TYPES section + while (std::getline(is, line)) { + if (line.find("CELL_TYPES") != std::string::npos) break; + } + if (is.eof()) { + std::cerr << "[ERROR] read_vtk: CELL_TYPES section not found" << std::endl; + return false; + } + + // Create cells based on types + std::size_t cell_type; + for (std::size_t i = 0; i < ncells; ++i) { + if (!(is >> cell_type)) { + std::cerr << "[ERROR] read_vtk: failed to read cell type " << i << std::endl; + return false; + } + + const auto& cell_vertices = faces[i]; + + switch (cell_type) { + case VTK_TETRA: + if (cell_vertices.size() == 4) { + alcc.make_tetrahedron(points[cell_vertices[0]], points[cell_vertices[1]], + points[cell_vertices[2]], points[cell_vertices[3]]); + } + break; + + case VTK_VOXEL: + if (cell_vertices.size() == 8) { + // VTK voxel has different vertex ordering than standard hexahedron + alcc.make_hexahedron(points[cell_vertices[0]], points[cell_vertices[1]], + points[cell_vertices[3]], points[cell_vertices[2]], + points[cell_vertices[4]], points[cell_vertices[5]], + points[cell_vertices[7]], points[cell_vertices[6]]); + } + break; + + case VTK_HEXAHEDRON: + if (cell_vertices.size() == 8) { + alcc.make_hexahedron(points[cell_vertices[0]], points[cell_vertices[1]], + points[cell_vertices[2]], points[cell_vertices[3]], + points[cell_vertices[4]], points[cell_vertices[5]], + points[cell_vertices[6]], points[cell_vertices[7]]); + } + break; + + case VTK_WEDGE: + if (cell_vertices.size() == 6) { + // Use helper function to create wedge + create_wedge(alcc, points[cell_vertices[0]], points[cell_vertices[1]], + points[cell_vertices[2]], points[cell_vertices[3]], + points[cell_vertices[4]], points[cell_vertices[5]]); + } + break; + + case VTK_PYRAMID: + if (cell_vertices.size() == 5) { + // Use helper function to create pyramid + create_pyramid(alcc, points[cell_vertices[0]], points[cell_vertices[1]], + points[cell_vertices[2]], points[cell_vertices[3]], + points[cell_vertices[4]]); + } + break; + + case VTK_POLYHEDRON: + // For generic polyhedron, we'd need more complex construction + // This is a simplified version in practice, VTK polyhedron format + // includes face connectivity information that we're not parsing here + std::cerr << "[WARNING] read_vtk: VTK_POLYHEDRON not fully supported yet" << std::endl; + break; + + default: + std::cerr << "[ERROR] read_vtk: unsupported cell type " << cell_type << std::endl; + break; + } + } + + // Clean up unused vertex attributes + for (auto itv = alcc.vertex_attributes().begin(); + itv != alcc.vertex_attributes().end(); ) { + if (alcc.template dart_of_attribute<0>(itv) == alcc.null_descriptor) { + alcc.erase_vertex_attribute(itv); + } else { + ++itv; + } + } + + // Try to read scalar data if requested + if (vertex_scalars != nullptr) { + vertex_scalars->clear(); + // Look for POINT_DATA section + while (std::getline(is, line)) { + if (line.find("POINT_DATA") != std::string::npos) { + std::size_t ndata; + ss = std::stringstream(line); + std::getline(ss, tmp, ' '); // skip "POINT_DATA" + ss >> ndata; + + // Skip SCALARS and LOOKUP_TABLE lines + std::getline(is, line); // SCALARS line + std::getline(is, line); // LOOKUP_TABLE line + + vertex_scalars->resize(ndata); + for (std::size_t i = 0; i < ndata; ++i) { + if (!(is >> (*vertex_scalars)[i])) { + std::cerr << "[WARNING] read_vtk: failed to read vertex scalar " << i << std::endl; + vertex_scalars->clear(); + break; + } + } + break; + } + } + } + + if (volume_scalars != nullptr) { + volume_scalars->clear(); + // Reset stream or continue from current position + while (std::getline(is, line)) { + if (line.find("CELL_DATA") != std::string::npos) { + std::size_t ndata; + ss = std::stringstream(line); + std::getline(ss, tmp, ' '); // skip "CELL_DATA" + ss >> ndata; + + // Skip SCALARS and LOOKUP_TABLE lines + std::getline(is, line); // SCALARS line + std::getline(is, line); // LOOKUP_TABLE line + + volume_scalars->resize(ndata); + for (std::size_t i = 0; i < ndata; ++i) { + if (!(is >> (*volume_scalars)[i])) { + std::cerr << "[WARNING] read_vtk: failed to read volume scalar " << i << std::endl; + volume_scalars->clear(); + break; + } + } + break; + } + } + } + + return true; +} + +template +bool write_vtk_ascii(std::ostream& os, + const LCC& alcc, + const std::vector* vertex_scalars, + const std::vector* volume_scalars) +{ + static_assert(LCC::dimension == 3 && LCC::ambient_dimension == 3, + "write_vtk() only supports 3D Linear_cell_complexes (3,3)"); + + // Write VTK header + os << "# vtk DataFile Version 2.0\n"; + os << "CGAL Linear_cell_complex\n"; + os << "ASCII\n"; + os << "DATASET UNSTRUCTURED_GRID\n\n"; + + // Build vertex index map + std::unordered_map vertex_index; + std::size_t nbpts = 0; + + for (auto itv = alcc.vertex_attributes().begin(), + itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) { + vertex_index[itv] = nbpts++; + } + + // Write points + os << "POINTS " << nbpts << " double\n"; + for (auto itv = alcc.vertex_attributes().begin(), + itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) { + const auto& p = itv->point(); + os << p.x() << " " << p.y() << " " << p.z() << "\n"; + } + os << "\n"; + + // Count cells and build connectivity + std::size_t nbcells = 0; + std::size_t total_size = 0; + std::ostringstream cell_stream; + std::ostringstream type_stream; + + for (auto itvol = alcc.template one_dart_per_cell<3>().begin(), + itvolend = alcc.template one_dart_per_cell<3>().end(); + itvol != itvolend; ++itvol) { + + ++nbcells; + VTK_Cell_Type cell_type = get_vtk_cell_type(alcc, itvol); + type_stream << static_cast(cell_type) << "\n"; + + if (cell_type == VTK_POLYHEDRON) { + // Generic polyhedron format write as face-vertex connectivity + std::vector> faces; + std::size_t cell_size = 1; // Start with 1 for number of faces + + for (auto itface = alcc.template one_dart_per_incident_cell<2,3>(itvol).begin(), + itfaceend = alcc.template one_dart_per_incident_cell<2,3>(itvol).end(); + itface != itfaceend; ++itface) { + + faces.push_back(std::vector()); + auto& face = faces.back(); + + for (auto itvert = alcc.template darts_of_orbit<1>(itface).begin(), + itvertend = alcc.template darts_of_orbit<1>(itface).end(); + itvert != itvertend; ++itvert) { + face.push_back(vertex_index[alcc.vertex_attribute(itvert)]); + } + cell_size += face.size() + 1; // +1 for face size + } + + cell_stream << cell_size << " " << faces.size(); + for (const auto& face : faces) { + cell_stream << " " << face.size(); + for (auto v : face) { + cell_stream << " " << v; + } + } + cell_stream << "\n"; + total_size += cell_size + 1; // +1 for cell size + + } else { + // Standard cell types write vertex connectivity directly + std::vector vertices; + + for (auto itvert = alcc.template one_dart_per_incident_cell<0,3>(itvol).begin(), + itvertend = alcc.template one_dart_per_incident_cell<0,3>(itvol).end(); + itvert != itvertend; ++itvert) { + vertices.push_back(vertex_index[alcc.vertex_attribute(itvert)]); + } + + cell_stream << vertices.size(); + for (auto v : vertices) { + cell_stream << " " << v; + } + cell_stream << "\n"; + total_size += vertices.size() + 1; + } + } + + // Write cells section + os << "CELLS " << nbcells << " " << total_size << "\n"; + os << cell_stream.str(); + os << "\n"; + + // Write cell types + os << "CELL_TYPES " << nbcells << "\n"; + os << type_stream.str(); + os << "\n"; + + // Write vertex scalars if provided + if (vertex_scalars != nullptr) { + if (vertex_scalars->size() != nbpts) { + std::cerr << "[ERROR] write_vtk: vertex_scalars size (" << vertex_scalars->size() + << ") does not match number of vertices (" << nbpts << ")" << std::endl; + return false; + } + + os << "POINT_DATA " << nbpts << "\n"; + os << "SCALARS vertex_scalars float 1\n"; + os << "LOOKUP_TABLE default\n"; + for (float val : *vertex_scalars) { + os << val << "\n"; + } + os << "\n"; + } + + // Write volume scalars if provided + if (volume_scalars != nullptr) { + if (volume_scalars->size() != nbcells) { + std::cerr << "[ERROR] write_vtk: volume_scalars size (" << volume_scalars->size() + << ") does not match number of cells (" << nbcells << ")" << std::endl; + return false; + } + + os << "CELL_DATA " << nbcells << "\n"; + os << "SCALARS volume_scalars float 1\n"; + os << "LOOKUP_TABLE default\n"; + for (float val : *volume_scalars) { + os << val << "\n"; + } + } + + return true; +} + +} // namespace internal + +// Public interface implementation + +template +bool read_vtk(LCC& alcc, + const char* filename, + std::vector* vertex_scalars, + std::vector* volume_scalars) +{ + CGAL_assertion(filename != nullptr); + + std::ifstream file(filename); + if (!file.is_open()) { + std::cerr << "[ERROR] read_vtk: cannot open file " << filename << std::endl; + return false; + } + + return internal::read_vtk_ascii(file, alcc, vertex_scalars, volume_scalars); +} + +template +bool write_vtk(const LCC& alcc, + const char* filename, + const std::vector* vertex_scalars, + const std::vector* volume_scalars) +{ + CGAL_assertion(filename != nullptr); + + std::ofstream file(filename); + if (!file.is_open()) { + std::cerr << "[ERROR] write_vtk: cannot open file " << filename << std::endl; + return false; + } + + return internal::write_vtk_ascii(file, alcc, vertex_scalars, volume_scalars); +} + +} // namespace CGAL + +#endif // CGAL_LINEAR_CELL_COMPLEX_VTK_IO_IMPL_H \ No newline at end of file diff --git a/Linear_cell_complex/test/Linear_cell_complex/CMakeLists.txt b/Linear_cell_complex/test/Linear_cell_complex/CMakeLists.txt index d19fc827d59..9c710c4e061 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/CMakeLists.txt +++ b/Linear_cell_complex/test/Linear_cell_complex/CMakeLists.txt @@ -15,6 +15,7 @@ create_single_source_cgal_program(Linear_cell_complex_3_test.cpp ${hfiles}) create_single_source_cgal_program(Linear_cell_complex_4_test.cpp ${hfiles}) create_single_source_cgal_program(Linear_cell_complex_copy_test.cpp ${hfiles}) create_single_source_cgal_program(LCC_3_incremental_builder_test.cpp ${hfiles}) +create_single_source_cgal_program(Linear_cell_complex_vtk_io_test.cpp ${hfiles}) # Same targets, defining USE_COMPACT_CONTAINER_WITH_INDEX to test index version add_executable(Linear_cell_complex_2_test_index Linear_cell_complex_2_test.cpp ${hfiles}) diff --git a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp new file mode 100644 index 00000000000..fb6d9ab10fb --- /dev/null +++ b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp @@ -0,0 +1,48 @@ +#include +#include + +#include +#include +#include +#include + +typedef CGAL::Linear_cell_complex_for_combinatorial_map<3, 3> LCC; +typedef LCC::Point Point; + +int main() +{ + LCC lcc_out; + + // Create a hexahedron + auto d = lcc_out.make_hexahedron( + lcc_out.create_vertex_attribute(Point(0, 0, 0)), + lcc_out.create_vertex_attribute(Point(1, 0, 0)), + lcc_out.create_vertex_attribute(Point(1, 1, 0)), + lcc_out.create_vertex_attribute(Point(0, 1, 0)), + lcc_out.create_vertex_attribute(Point(0, 0, 1)), + lcc_out.create_vertex_attribute(Point(1, 0, 1)), + lcc_out.create_vertex_attribute(Point(1, 1, 1)), + lcc_out.create_vertex_attribute(Point(0, 1, 1)) + ); + + std::vector v_scalars = {1,2,3,4,5,6,7,8}; + std::vector vol_scalars = {42.0f}; + + const char* fname = "tmp_test_lcc_vtk.vtk"; + + assert(CGAL::write_vtk(lcc_out, fname, &v_scalars, &vol_scalars)); + + LCC lcc_in; + std::vector v_scalars_in, vol_scalars_in; + + assert(CGAL::read_vtk(lcc_in, fname, &v_scalars_in, &vol_scalars_in)); + + assert(lcc_in.number_of_vertex_attributes() == lcc_out.number_of_vertex_attributes()); + assert(lcc_in.template number_of_cells<3>() == lcc_out.template number_of_cells<3>()); + assert(v_scalars_in.size() == v_scalars.size()); + assert(vol_scalars_in.size() == vol_scalars.size()); + + std::remove(fname); + + return EXIT_SUCCESS; +} \ No newline at end of file From c37745641a5f02b412519cc7f5d8e32de1276315 Mon Sep 17 00:00:00 2001 From: Yliess Bellargui Date: Mon, 28 Jul 2025 07:37:54 +0200 Subject: [PATCH 02/30] [Small Feature] Add VTK read/write support for Linear_cell_complex --- .../data/beam-with-mixed-cells.3map | 2 + .../Linear_cell_complex/data/lcc_input.vtk | 29 - .../linear_cell_complex_3_vtk_io.cpp | 57 +- ...inear_cell_complex_incremental_builder_3.h | 211 +++++- .../include/CGAL/Linear_cell_complex_vtk_io.h | 616 +++++++++++++++++- .../CGAL/Linear_cell_complex_vtk_io_impl.h | 524 --------------- .../Linear_cell_complex_vtk_io_test.cpp | 65 +- .../data/beam-with-mixed-cells.vtk | 11 + 8 files changed, 866 insertions(+), 649 deletions(-) create mode 100644 Linear_cell_complex/examples/Linear_cell_complex/data/beam-with-mixed-cells.3map delete mode 100644 Linear_cell_complex/examples/Linear_cell_complex/data/lcc_input.vtk delete mode 100644 Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io_impl.h create mode 100644 Linear_cell_complex/test/Linear_cell_complex/data/beam-with-mixed-cells.vtk diff --git a/Linear_cell_complex/examples/Linear_cell_complex/data/beam-with-mixed-cells.3map b/Linear_cell_complex/examples/Linear_cell_complex/data/beam-with-mixed-cells.3map new file mode 100644 index 00000000000..69e5a8cd3e7 --- /dev/null +++ b/Linear_cell_complex/examples/Linear_cell_complex/data/beam-with-mixed-cells.3map @@ -0,0 +1,2 @@ + +2413371511014511046121034810282135961377111361131291051416115203132421713641827631929621621612114221923282025251527226232752730274241727329223173018316282631532353853340388344738731513863631375438553961354141321084239107436410644651054570111467411040481094833552494655150785504779553523413248538213247545613246513613249563733557533345881339598333860673375562336623819636018646617614216664384056763840968598408698684076571840671441968726919677385197070751969754511807673117977841178788011827449118180501061817710648257106379521062845814118576141086721413836814128892176899617590102174911051738711217793879411695117929797889895991221001231011079610310389610410151021064106904310710442108100411091264011012746111131451051134411391208114111207115134206116118205112932091189446911911546812013346712112946612212446511798470124994121251214151261284141231084131281094911291254901301204931271324921321108831331308821341198851311148841361387137143913514881391352531401522521411532511421572501381442491441361451421461601471611431491491371721501471711511641701521541691481391681541408332155151833115616383301531588333158141834515915683441601628347157145834616214616315916415516115016616883931671738395165178839416916515217018115117118215017218614916817414817416690175172891761888817718487173179911791672161801772151811832141781692131831701841801851761821871871711881851861751901938721911968711922018701892058731941891952091931971971902281981952271992082262002102301962022292021918421203200842020421284232012068422206192115207204114208211113209198112205194116211199197521220719742102031976214217181215221180216226179213231178218213829121923582902202368289217222829222221422322022424022524122122722721519822822519722924419623024520022623219923221618362332301835234248183423523718332312181837237219238234239247240242236223242224200224323920052442462004241228200324622919882472431991248238199024523319892502541422512581412522631402532671392492721382552492562752572762542592592502231260257223026128222292622812228258264223226425183632652628362266280836526326883642682528396269266840027027983992712788398267273839727325324274271272752772627225525277256151127827415102792701509280269151528126515142822611513276260151228428615622852911561283298156328728314762883021475289303147429030714782862921477292284150529329015042943091503295310150229631515082973181507291299150629928530029730132230230429828730428814483053011447306321144630331214453082891424309311142330729314253112943563123083553133063543143203533103163573162953031731429315319283192963203173213133223053183003243261323932532913241323334132403273231322332834013222326344132213303243313473323483333533293353353255633633355337357603383585933936158334341573413271070342339106934336610723403671071345328131923463691319134734913190344330131893493311433350346143235137014313523641435348354143435433231335535231235636331135735931035333631435933713257360356132593583621325836233814093633601408364355140736535114063663721405361342140436834310893693711088367345109037135013973723681396370365139837437837538237638537738937339337937397138039697038139796937840297238337413256384404132553823861325438637531387384343884003338539032390376408391388411392399410389394409394377581395392580396398579393379582398380566399395565400391564401387568397403567403381132374044011323640238313238406408407412405416409405389410419392411421391408413390413406123414411126415420125412417124417407456418415455419422458416409457421414528422410527420418526424427888425431887426437886423441889428423832429446835430447834427432833432424463433430462434450461435451460436455459431438464438425514439436513440458512437442515442426589443440588444457587445453592446448591441428590448429702449445701450452704447433703452434453449454444451456456435417457454416458443419455439418460465435461471434462475433463479432464467431459466436466459121467464120468463119469482118470483117465472122472460473470474486471476476461781477474780478485783475480782480462854481478857482484856479468855484469485481486477483473488490530489494529487498531491487128492501127493503130490495129495488508496493511497502510494499509499489547500497546501504549498491548503496904504492903502500905506508524507512523505516525509505494510519497511521496508513495513506439514511438515520437512517440517507937518515936519522935516509938521514900522510902520518901524526506525529505523532507527523422528534421526530420530524488531528487529533489533525557534531559532527558536538939537542941535546940539535922540549921541550924538554923543536572544556571545552570542547569547537499548545498549551501546539500551540495525484855354447550555505555411044556553104355454310455585605325595645345575695335615579495625729525635739515605659505655583995665633985675753975685764015645704005705595455715685445725785435695615425745629685755779675735669665775671046578574104857657110475805833955815873945825933935795993965845799475856039465866079455835889485885804435895864425906114415916124465926174455875944445945815955925966205976215986265936006005821287601598128660263012855996041288604584125560560212546066291253603608125660858511696096061168610631117261161311716075891170613590207061461020746156342073616623207261261820716185916526196166516206226546175956536225966236196246156256336216276275971220628625121962963212186306051217626601122163260912056336281208634624120763161412066366388450637644845263565184516396356406546416556426596436636386456456366796466436786476656776486666836496616826506576816446526806526376186536506176546566206516396196566406576536586496556606606418459661658845866264884576596688456664642101806656671017966364610178667647101886686641018766666210189670673101636716771016267268410165669688101646746696756916766946736786786706466796766456807006446817016506827056496837106486776856476856711021368668310212687714102156847151021468967210657690718106566886921065869267410663693690106626916951066469567510123696693101226977211012169872210127699727101267007021012569467910124702680448703699447704732450701706449706681707704708731709733705711711682849071270984947137378493714738849271068684917166871070671774010705715719107047196891063672071710639721723106387186961063772369785727247208571725739857572673685747227288573728698776729726775730735774731734779732707778727703777734708852273573085267367298525737725852473371285237397131067174072410673738716106727427441008774374810086741752100887457411005174675510054747762100537447661005274974296157507689614751769961374877496127537439606754779960875275696077567457577547587787597807607847617907557637637461103076476111029765792110287627931103176774796357687969634766749963377075086657717988664772799866377380486627697758666775751729776773728777808727778781732779757731774753730781758476782777475783807478780785477785759786783787806788802789809784813791760110207928151101979076411021794765108717958111087079381610872797767107817988181078079677010779800771975180181797508028109754803787975379980597528057721010080680310099807786100988087821009780477610101810788110898118011108881279411087809814110868147891107581581211074813791110738177951080281880010801816797108008208238428821827843182283284308198368429824819202782584020268268412025823828202482882085382982685283084485183184585082783384983382142783483143083584842983283742883782220548388352053839847205284084220518368242050842825843839844846841829846830101488478431014784883810146845834101458508548318518588308528628298538668288498708278558494798568734828578744818548594808598501009186085710090861878100898588631009286385186486186587786286786785220128688652011869876201086687120138718531918728691908738751898708551928758568768728778688788648748608808828988818868978798908998838791328848931318858951348828871338878804258888854248898944238868914268918811183892889118689389611858908831184895888843489688484338948928432898900880899903879897906881901897520902908522900904521904898503905902502903907504907899909908905911906901910910912906911917908909921907913909116691492411659159251164916928116391291811679189109319199169349209309339179229329229115399239205389249265419219135409269141040927923104292592910419299159609309279629289199619329359179339399209349429199319459189369315189379485179389495169359405199409325359419385379399525369439339599449519589429469579469345859479445849489505839459365869509375609519475639529435629499415619549571020955960101995696310189539661017958953944959968943957961942961954928962959930960964929964955103796596210399639671038967956575968965574966958573970973380971976379972979378969982381974969989975984991973977990977970129597897512979769801296980971131498197813169799831315983972133098498113329829741331986989100198799210049889951003985998100299098597399110009759899939749939861327994991132999299613289969871276997994127899599912779999881298100099713009989901299100210059851003100898810041011987100110149861006100110211007101610231005100910221009100212601010100712621008101212611012100311321013101011341011101511331015100410991016101310981014100610971018102195610191024955102010279541017103095310221017100510231032100710211025100610251018109310261023109210241028109110281019111310291026111510271031111410311020126310321029126510301022126410341037104910351040105210361043105110331046105010381033963103910489651037104196410411034925104210399271040104492610441035555104510425541043104755610471036576104810455781046103857710501053103310511057103610521061103510491065103410541049107610551068107910561071107810531058107710581050132301059105613229106010701322810571062132311062105179106310608210641069811061106680106610521162106710641161106810721160106510541159107010633411071105934010721055343106910673421074107611001075108011021073108411011077107310531078108710561079108910551076108110541081107413881082107913911083108813901080108513891085107513491086108313521087109013511084107713501089108236810901078367108810863691092109410261093109710251091110010241095109111171096110311161094110611181098109210161099110810151097110110141101109310731102109910751100110410741104109513831105110213821103110713811107109611301108110511291106109811311110111311461111111611451112111911481109112211471114110910271115112410291113111710281117111010951118111510941116112010961120111111381121111811401119112311391123111212661124112112681122111412671126112912151127113212141128113512131125113812161130112511071131114011061129113311081133112610111134113110131132113610121136112712571137113412591135113912581139112811191140113711211138113011201142114513921143114913951144115413941141115913931146114111101147116311091148116811121145115011111150114211871151114811911152117211901153117311891149115511881155114314031156115314021157117714011158117814001154116013991160114410681161115810671162118210661159116410651164114691511651162914116611819131167118391211631169916116911476081170116760711711186611117211746101168115160911741152195111751171195011761185195411771179195311731156195211791157761180117675118111847411821165781178116177118411668901185118089311861175892118311708911188119211491189119711531190120111521191120511511187119311501193118712311194119112301195120812341196120912331192119812321198118814671199119614661200121214691197120214681202118919481203120019471204121119461201120619491206119063112071204634120812106331205119463212101195121112071212120312091199121412171127121512221126121612261125121312301128121812136291219123462812201235627122112396261217122363012231214127012241221126912251243127212221244127112271215138412281247138712291248138612261231138512311216119312321229119212331252119612341236119512301218119412361219123712331238125112351240124012201241123812421250124312451239122412451225136812461242136712471249136612441227136512491228143612501246144012511241143912521237143812481232143712541257605125512606041256126360312531266606125812531135125912681137125712611136126112541008126212591010126012641009126412551030126512621032126312671031126712561122126812651124126612581123127012731223127112761222127212791225126912821224127412691289127512841291127312771290127712709951278127599712761280996128012711324128112781326127912831325128312721308128412811310128212741309128612896011287129260012881295599128512986021290128512731291130012751289129312741293128613051294129113071292129613061296128797612971294978129512999771299128899813001297100012981290999130213051303130813041311130113141306130112921307131612941305130912931309130212821310130712841308131212831312130313211313131013231311131513221315130497913161313981131413069801318132113351319132413341320132713331317133013361322131713111323133213131321132513121325131812791326132312811324132812801328131999213291326994132713319931331132098213321329984133013229831334133713191335134013181336134313171333134613201338133313531339134813551337134113541341133413781342133913801340134413791344133513186134513421318813431347131871347133613215134813451321713461338132161350135310841351135610871352135910861349136210851354134913371355136413391353135713381357135013212135813551321413561360132131360135113199136113581320113591363132001363135213691364136113711362135413701366136912471367137212461368137512451365137812441370136513621371138013641369137313631373136613196137413711319813721376131971376136713177137713741317913751379131781379136813401380137713421378137013411382138411051383138811041381139211031385138112261386139512291387139712281384138912271389138210801390138710831391139610821388139310811393138311411394139111441395139811431392138511421397139037113981386370139613943721400140411581401141011571402141411561403141811551399140511541405139936614061403365140714223641408142336314091426362140414113611411140084141214098314131430861410141585141514011965141614131964141714291963141414191966141914021465142014171464142114281463142214241462141814061461142414073081425142130714231427309142714081894142814251898142914201897143014161896142614121895143214363501433144034914341441348143514453521431144935114371431124814381452125214391453125114401442125014361432124914421433144314391444145614411446144614343061447144430514481455304144514503031450143514571451144814601452145414591449143714581454143814551451145614471453144314581461144914591466145214601470145114571474145014621457142214631478142114641479142014651482141914611467141814671458119814681465119714691486120014661471119914711459147214691473148514701475147514602881476147328714771484286147814802901474146228914801463148814811477148714791483148914831464194414841481194314851476194214861472194114821468194514881490148014891493147914871496148114911487152114921498152314901494152214941488191214951492191414931497191314971489186714981495186614961491186815001502132661501150913268149915161326715031499294150415202931505152129215061524291150715312971508153629615021510295151015002781511150827715121540276151315412821514154528115151527280150915172791517150118991518151519031519152619021520152219011516150319001522150414901523151914921521152514911525150515871526152315931527151815921528151415911529154715901530154815891524153215881532150615331530153415511535155215311537153715071538153515391555154015421536151115421512263215431539263115441557263415411558263315461513268015471560268215451528268115491529162015501559161915511553161815481533162115531534211215541550211415521556211315561538207915571554208115551543208015591544265615601549265815581546265715621564284156315672831561157028515651561157515661572157415641568157315681562194015691566193915671571193815711563157215691570156515741576156615751582156515731587156415771573187115781593187015791592186915801594187415811598187315761583187215831574158415811585160115861602158215881588157515241589158615301590160615291591160515281592159515271593157815261587157715251595157917901596159117891597160417881594159917871599158016001597160116031598158416031585164816041600164716051596164616061590164516021589164416081611210816091615211116101618211016071622210916121607216616131625216516141626216416111630216316161608265016171632265216151619265116191609155016201617154916211628154816181623155116231610162416211625162716221612162716131633162816241636162916201635162616311634163116142167163216292169163016162168163416371626163516411629163616441628163316491627163816332161163916532160164016542159163716602162164216342176164316622178164116632177164516351606164616651605164716661604164816721603164416501602165016361651164816521675165316551649163816551639270916561652270816571674270716581670270616591669270516541676270416611640219016621678218916601642218816641643267816651667267716631645267916671646173216681664173116691677173016701658172916711657172816661673172716731647167416711675165616721651167716592208167816682207167616612206168016838225168116898224168216968223167917008222168416791685170616861707168717121688171516831690169016801691168816921718169317191694172216951727168916971697168117511698169517501699173217531696170117521701168222201702169922191703173122181704173022241705173322231706170822221700168422211708168533631709170533621710173633661711173733651707171333641713168636631714171136621712174136611716168729531717174329521718172029511715169129501720169228571721171728561719174428551723169327841724174627831725173827821726173527861722172827851728169416711729172616701730173416691731170316681732170216671727169816661734170427361735172927351736172527381733170927371738171028101739172428091740174528121737174228111742171436581743174036601741171636591745172128271746173928261744172328251748175017651749175417671747175817661751174716971752176116961753176316991750175516981755174817991756175318021757176218011754175918001759174982521760175782551761176482541758175182531763175683601764175283591762176083611766176817471767177217491765177617481769176517701779177117811768177317731766827317741771827617751780827517721777827417771767178617781775178517791782178417761769178317811774180917821770180817801778180717841787177917851791177817861795177717831799177617881783159717891802159617901805159517871792159417921784181017931790181317941804181217911796181117961785838017971794837917981803837817951800837718001786175418011798175718021806175617991788175518041797836918051793836818061789836718031801836618081810178218091814178118071818178018111807179118121821179418131823179318101815179218151808183818161813184118171822184018141819183918191809828518201817828818211824828718181811828618231816837518241812837418221820837618261828182718331825183818291825185518301841185418311842185318321846185718281834185618341826234183518322331836184823218371844231183318392351839182718141840183718171841184318161838182918151843183084031844184084021845183684011842184784041847183119721848184519711846183519731850185319091851185819081852186619111849186919101854184918301855187418291856187518281857188118321853185918311859185019341860185719331861188419321862188519311863187819301864188819371865187119361858186719351867185114971868186514961866187014981870185215781871186815771872186415761873189015811874187615801869185415791876185518771873187818891879186218801887187518821882185619871883188019861884188619851881186019841886186120391887188320381885187920401889186318901877188818721892189413263189318991326518911904132641895189114261896190714301897190814291898191214281894190014271900189215161901189815201902191415191903191015181899190515171905189384141906190384131907190984161904189584151909189618501910190618491911190218521908191318511913189714931914191114951912190114941916191819171924191519301919191519201937192119381922194119231946191819251925191620601926192320591927194920581928195020571929195520561924193120551931191718621932192918611933195818601934195918591935196318581936194318651937193918641930191918631939192015691940193615681938194215671942192114851943194014841944193514831945196614821941194714861947192212031948194512021949195112011946192612041951192711741952194811731953196511771954196111761950195611751956192884271957195484261958196084251955193284241960193319791961195719781962195319771959196419801964193414161965196214151966195214141963194414171968197171196919747019701977731967198072197219671847197319791846197119751848197519682111976197321019741978212197819691961197919761960198019721959197719701962198219848418198319888417198119928419198519811884198619951883198719971882198419891881198919822451990198724819911996247198819932461993198320291994199120281995199820311992198520301997199019981986199619942000200220012006199920102003199924120042013244200520152432002200724220072000200820052009201420062011201120018682012200986720132016866201020038692015200820172016200420192014201220182018202020142019202420162017202820152021201720222031202320332020202520252018826202620238252027203282420242029823202920191993203020271992203120341995202820211994203320262037203420222036203220302035203620382034203720412033203520442032203920351886204020461885203820421887204220362043204020412045204520372047204620432049204420392048204820502044204920552046204720612045205120478402052206583920532066838205420708372050205683620562048192920572054192820582074192720592073192620602075192520552062192420622049206320602064207820652067206120512067205284392068206484382069207784412066207184402071205361220722069616207320766152074205861420702057613207620592077207220782068207520632080208215552081208615572079209015562083207920842093208520952082208720872080258520882085258420892094258320862091258620912081210220922089210120932096210020902083210320952088214020962084213920942092213820982100212920992104212820972108212721012097209221022111209121032113209021002105209321052098210621032107211221042109210920991607211021071610211121141609210821011608211321061552211421021554211221101553211621192154211721232153211821272152211521302151212021152324212121332323212221342326211921242325212421162125212221262137212321282128211720992129212620982127213820972131211825692132214025682133213525672130212025702135212121362132213721392134212521392129209621402136209521382131209421422144247621432148247521412151247421452141232221462154232121472155232021442159231921492142218421502162218321482163218221522143211821532166211721542156211621512145211521562146215721532158216521552160216021471639216121581638216221641637215921491640216421501614216521611613216621571612216321521611216821701630216921731632216721761631217121672179217221782181217021742180217421682662217521722664217321772663217721691641217821751643217621711642218021822170218121852172217921882171218321792150218421902149218221862148218621802193218721842192218521892191218921811662219021871661218821831660219221942187219321972186219122002185219521912203219622022205219421982204219821922473219921962472219722012471220121932478220221992477220021952479220422062194220522092196220322122195220722031678220822141677220622101676221022042269221122082268220922132267221322052249221422112248221222072247221622182672221722252671221522282673221922151702222022321701222122331700222222371706222322411705222422461704221822471703222622162499222722502498222522532500222922172612230225626022312257259223222342582228221926222342220835222352231835522362262835422332238835322382221223922362240226122372242224222222363224322402362224422602361224522632366224622482365224122232364224822242214224922452213224722512212225122262487225222492486225022662488225422272616225522652615225622582618225322292617225822302259225522602264226122432262223922572235226422442415226522592418226622542417226322522416226822702211226922772210226722842209227122672369227222872368227322912367227422982373227523032372227622792371227022782370227822682686227922762685228022752684228123062683228223072689228323122688227723192687228522692470228623222469228422882468228822712431228922862434229023232433228722922432229222722293229022942326229523162296232722972330229122992299227343262300229743252301233243242302233343282298230443272304227478162305230278152306230878142303228078132308228145172309230545162310233645152311233945192307231345182313228223142311231523412316234223172294231823252312232023202283214723212318214623222324214523192285214423242289212023252321211923262317212223232293212123282295440523292344440423272345440323312296436423322347436623302300436523342301438623352346438523332337438723372309445923382335445823362348445723402310804123412350804023392314803923432315442323442349442223422328442123462329436923472334436823452331436723492338444023502343443923482340444123522355235323612354236723512374235623512357238023582381235923842360238723552362236223522243236323602242236423912241236523922246236623692245236123682244236823532272236923662271237023652270237123952276237223962275237323762274236723752273237523544004237623734003237723724002237824004008237924014007238024054006237423564005238223578122238324078121238123858120238523588116238623838115238424088114238823593345238924103344239024113348239123933347238723633346239323642734239423902733239523972732239223702731239723713328239823943327239924143331240024023330239623773329240223783436240323993435240424133438240124063437240623793731240724043730240523823732240923863678241024123677240823883676241223893416241324093419241424033418241123983417241624192263241724222266241824252265241524282264242024152435242124302437241924232436242324162451242424212450242224262452242624172548242724242550242524292549242924182564243024272566242824202565243224352287243324382290243424412289243124442288243624312419243724462421243524392420243924322561244024372563243824422562244224332580244324402582244124452581244524342449244624432448244424362447244824502446244924532445244724562444245124472423245224592422245024622424245424482579245524642578245324572577245724492465245824552467245624602466246024512481246124582480245924632482246324522540246424612539246224542541246624682456246724712458246524742457246924652286247024762285246824722284247224662199247324702198247124752197247524672143247624732142247424692141247824802201247924832200247724862202248124772460248224882459248024842461248424782490248524822489248324872491248724792251248824852250248624812252249024922484249124952483248924982485249324892503249425002502249224962501249624902666249724942665249524992667249924912226250024972225249824932227250225042494250325072493250125102492250525012648250625132647250425162649250825022622250925182624250725112623251125032523251225092525251025142524251425052596251525122598251325172597251725062641251825152643251625082642252025232535252125262538252225292537251925322536252425192510252525342512252325272511252725202619252825252621252625302620253025212606253125282608252925332607253325222587253425312589253225242588253625392519253725422522253825452521253525482520254025352463254125502462253925432464254325362574254425412576254225462575254625372555254725442557254525492556254925382425255025472427254825402426255225552553255825542561255125642556255125452557256625472555255925462559255225712560255725732558256225722562255324382563256024402561256524392565255424282566256324302564255624292568257121322569257421312570257721302567258021332572256725582573258225602571257525592575256825422576257325442574257825432578256924552579257624542577258124532581257024412582257924432580257224422584258720882585259020872586259320862583259620892588258325322589259825342587259125332591258426032592258926052590259426042594258526442595259226462593259726452597258625132598259525152596258825142600260326012606260226092599261226042599259026052614259226032607259126072600252926082605253126062610253026102601262826112608263026092613262926132602263526142611263726122604263626162619225426172622225326182625225626152628225526202615252626212630252826192623252726232616250726242621250926222626250826262617263826272624264026252629263926292618260926302627261126282620261026322635154226332638154126342641154426312644154326362631261226372646261426352639261326392632262526402637262726382642262626422633251626432640251826412645251726452634259326462643259526442636259426482650250526492653250426472656250626512647161526522658161726502654161626542648266026552652265926532657266126572649155826582655156026562651155926602662265426612665265326592668265526632659217326642670217526622666217426662660249626672664249526652669249726692661267526702667267426682663267626722674221626732677221526712680221726752671266926762682266826742678267026782672166426792676166326772681166526812673154526822679154726802675154626842690228026852696227926862700227826872704227726882709228326892710228226832691228126912683410726922689410626932713410526942714410426952719410326902697410826972684332626982695332526992722332426962701332327012685272727022699273027032723272927002705272827052686165927062703165827072726165727082716165627092711165527042687165427112688271227082713271527102692271526932716271227172707271827252714272027202694300027212718300327222724300227192698300127242702278727252721279027262717278927232706278827282731270027292735270327302739270227272744270127322727239527332748239427342749239327312736239227362728173427372734173327382754173627352740173527402729276727412738276627422753276527432752276927392745276827452730330727462743330627472751330527482750330927442732330827502733336727512747337227522746337127532742337027542741336927492737336827562758362327572762362227552765362427592755303227602769303127612770303427582775303327632756280027642779279927622782280127662757274127672786274027682787273927692771274327652759274227712760300727722768300627732790300527742791300427702776300827762761290127772774290027782795290327752796290227802763281927812798282127792783282027832764172427842781172327852793172227862788172627822766172527882767272327892785272627902792272527872772272427922773279327892794278427952797279127772797277828752798279428742796278028732800280227632801280527622799280927642803279928222804281228242802281328232806280036162807281536152808281636142805281036172810280117382811280817372812281817402809280317392814280428312815281728332813280628322817280736522818281436542816281136532820282227792821282527812819282827802823281928022824283028042822282628032826282017462827282417452825282917442829282128482830282728472828282328462832283428132833283728152831284028142835283128432836284228452834283828442838283228952839283628942837284128932841283329642842283929632840283529622844284628342845284928362843285228352847284328302848285428292846285028282850284428692851284828682849285328672853284528602854285128592852284728582856285817212857286117202855286417192859285528542860286628532858286228522862285629492863286029482861286529472865285728662863286428592868287028512869287328502867287628492871286728722878287028742874286827982875287227972873287727962877286929062878287529052876287129042880288230902881288630892879288930912883287929112884289229102885289329132882289629122887288030152888289930142886290030132890288128912903289229042889288328942884283928952906283828932897283728972885304528982895304428992901304328962887304629012888277629022898277529032905277829002890277729052891287829062902287729042894287629082910290929142907291829112907288329122921288229132923288529102915288429152908292829162913293129172922293029142919292929192909311829202917311729212924311629182911311529232916355529242912355429222920355329262928292729322925293629292925291429302939291729312941291629282933291529332926295829342931296129352940296029322937295929372927293829352939294229362929294129343593294229303592294029383594294429472945295029462954294329582948294328632949296228622947295128612951294417182952294917172953296517162950295517152955294529562953295729682954295929592946293229602957293529612970293429582963293329632948284229642961284129622966284029662952365729672964365629652969365529692956360029702967359929682960359829722974414129732977414029712982413929752971813929762987813829742991814029782972383029792994382929802995382829813000383229772983383129832973298429812985300329863004298229882988297530182989298630172990300830162987300930192992297681602993301281592994299681622991297881612996297933202997299333192998301133182999300633222995300133213001298027193002299927223003300527213000298427203005298527733006300227723007299827713008301027703004298927743010299032873011300732863012299732853009299232883014301628883015302028873013302428863017301329893018302729883019302929873016302129903021301430733022301930763023302830753020302530743025301530923026302330953027303030943024301730933029302281293030301881313028302681303032303527593033303927583034304327613031304727603036303133913037305033943038305133933035304033923040303236123041303836113042305336103039304436133044303328983045304228973046305428963043304828993048303430583049304630573050305630603047303630593052303780833053305580823051304180813055304535523056305235513054304935503058306130483059306430473060306730503057307030493062305730773063307230793061306530783065305832923066306332943064306832933068305931883069306631903067307131893071306031563072306931583070306231573074307730203075308030233076308330223073308630213078307330613079308830633077308130623081307431533082307931553080308431543084307531693085308231713083308731703087307632953088308532973086307832963090309228803091309628793089310028813093308930243094310330273095310530263092309730253097309031083098309531073099310431103096310131093101309131023099310331063100309331053098417331063094417231043102417431083111309731093115309631103119309931073123309831123107313731133126313631143129313531113116313431163108292131173114292031183128291931153120291831203109312131183122312731193124312431103940312531223939312631303938312331123937312831213129311731303113312731253132313435483133313835473131314235493135313131143136314531133137314731123134313931113139313231503140313731493141314631523138314331513143313335383144314135373145314835363142313535393147314039253148313639243146314439263150315331393151315631383152315931413149316231403154314930803155316430823153315730813157315030703158315530723156316030713160315131853161315831873159316331863163315231723164316131743162315431733166316931993167317231983168317531973165317832003170316530833171318030853169317330843173316631623174317131643172317631633176316731943177317431963175317931953179316832983180317733003178317032993182318532683183318832673184319132663181319432653186318131593187319631613185318931603189318230673190318730693188319230683192318332893193319032913191319532903195318431753196319331773194318631763198320131673199320431663200320731653197321031683202319732173203321232193201320532183205319838993206320339013204320839003208319981503209320681523207321181513211320081633212320981653210320281643214321732293215322032323216322332313213322632303218321332013219322832033217322132023221321481723222321981743220322481733224321538773225322238793223322738783227321639023228322539043226321839033230323332133231323632163232323932153229324232143234322932493235324432513233323732503237323034823238323534843236324034833240323138703241323838723239324338713243323240593244324140613242323440603246324932613247325232643248325532633245325832623250324532333251326032353249325332343253324640563254325140583252325640573256324734573257325434593255325934583259324834733260325734753258325034743262326532453263326932483264327332473261327732463266326131843267328031833268328331823265327031813270326235203271326835193272328235223269327435213274326334103275327234093276328134083273327834113278326433033279327633023280328433013277326633043282327533733283327133763284326733753281327933743286328930113287329230103288329530093285329830123290328531913291330031933289329331923293328630643294329130663292329630653296328730863297329430883295329930873299328831783300329731803298329031793302330532793303331032783304331432773301331832803306330127463307332227453308332327443309332727483305331127473311330234133312330934123313333134153310333234143315330340503316333540493317333640523314331940513319330429973320331729963321334029953322332429993318330629983324330726993325332126983326333926973323332826963328330823973329332623963330333824003331333323993327331223983333331334293334333034283335333734273332331534303337331637973338333437963339332937953340332537993336332037983342334436733343334936753341335336743345334123883346335623873347336223913348336723903344335023893350334234013351334834043352337234033349337334023354334380943355337780933353335780953357334533583355335933803360338133613384335633633363334617083364336117073365338617113366338717103362336817093368334727493369336627543370339027533371339127523372337427513367335127503374335232813375337132843376339432833373337832823378335435093379337635083380338235073377335835103382335935663383337935653381339535673385336036693386339836683384336436673388336536193389340036183390339236213387336936203392337030353393338930383394339630373391337530363396338380913397339380903395339980923399338536363400339736353398338836343402340533493403340833523404341233513401341633503406340136823407341936843405342036833409340232753410342232743411342332733408341332763413340333113414341133103415342633133412341733123417340424113418341524143419342524133416340624123421340737003422342437023420340937013424341034423425342134413426341834403423341434393428343133343429343533333430343933323427344333353432342737933433344637923434344737913431343637943436342824023437343424013438344924043435344024033440342934263441343834253442345034243439344434233444343034543445344234533446345234563443343234553448343337223449345137213447343737233451344137153452344837173450344537163454345734443455346034433456346334463453346634453458345332553459346832573457346132563461345440533462345940553460346440543464345538643465346238663463346738653467345634763468346534783466345834773470347334913471347634903472347934893469348234883474346932583475348432603473347732593477347034663478347534683476348034673480347138613481347838633479348338623483347232363484348132383482347432373486348839323487349239313485349639303489348534723490349934713491350134703488349334693493348635153494349135183495350035173492349735163497348737623498349537613499350237603496348937633501349437123502349037143500349837133504350735343505351135333506351535323503351935353508350333793509352233783510352333773507351233803512350435133510351435253511351635163505349235173514349535183526349435153520349335203506327035213518326935223528327235193508327135243509809635253527809835233513809735273517370735283524370635263521370835303532392935313536392835293540392735333529350535343543350435353545350335323537350635373530314435383535314335393544314235363541314535413531354235393543354635403533354535383561354635343560354435423559354835503132354935533131354735563133355135473056355235583055355035543054355435482924355535522923355335572922355735493580355835553582355635513581356035623546356135653545355935683544356335593564357035623566356635603382356735643381356535693383356935613573357035673572356835633571357235743570357335773569357135803568357535713583357635823585357435783584357835728089357935768088357735818087358135733556358235793558358035753557358435863574358535893576358335923575358735833588359435863590359035843597359135883596358935933595359335852941359435912940359235872942359635983591359736013590359536043589359935952970360036062969359836022968360235963603360036013605360535973643360636033645360435993644360836103626360936143625360736183627361136073041361236213040361336233039361036153042361536082807361636132806361736222805361436192808361936093388362036173387362136243390361836113389362336162756362436122755362236202757362636283608362736313607362536343609362936253637363036363639362836323638363236268084363336308086363136358085363536273400363636333399363436293398363836403628363936433630363736463629364136373649364236483651364036443650364436383604364536423606364336473605364736393666364836453665364636413664365036523640365136553642364936583641365336492816365436602818365236562817365636502967365736542966365536592965365936511741366036571743365836531742366236641714366336671713366136701712366536613648366636723647366436683646366836623386366936663385366736713384367136633672366936703665367436763341367536793343367336823342367736732410367836842409367636802408368036743687368136783686367936833685368336753405368436813407368236773406368636883681368736913680368536943679368936853697369036963699368836923698369236868107369336908106369136958105369536878099369636938101369436898100369837003688369937033690369737063689370136973420370237083422370037043421370436983711370537023710370337073709370736993527370837053526370637013528371037123705371137153704370937183703371337093500371437203502371237163501371637103450371737143452371537193451371937113737372037173736371837133738372237243448372337273447372137303449372537213733372637323735372437283734372837223777372937263776372737313775373137232406373237292405373037252407373437363724373537393726373337423725373737333719373837443718373637403720374037343746374137383745373937433747374337358128374437418127374237378126374637483740374737513739374537543741374937453757375037563759374837523758375237463788375337503790375137553789375537473756375337543749375837603748375937643750375737683749376137573498376237713497376337733496376037653499376537583820376637633823376737723822376437693821376937593770376737713774376837613773376639173774376239193772377039183776377837293777378837283775379137273779377539803780379439793781379539783782380039773783380639763784380539853785380739843786381239833787381139823778381339813789377637513790381937533788382037523792377734333793382434323794379634313791377934343796378033383797379333373798382733363799382833403795380133393801378140793802379940783803383240773804383340763805380840753806378340743800378240733808378442023809380442013810383842063811381442053812378642043807378542033814378738153810381638373817383938183843381938213813378938213790376438223818376738233846376638203825376538253792385838263823385738273847386038243797385938293798297938303850297838313851297738323834298138283802298038343803383538313836385338373840383838153833380938403816394738413836394638423854394538393844394438443817390638453842390538463848390838433822390738483826387338493845387638503856387538473829387438523830414538533855414738513835414638553841818038563852817938543849817838583861382538593864382438603867382738573870382638623857347938633872348138613865348038653858346338663863346538643868346438683859406238693866406438673871406338713860323938723869324138703862324038743877384738753880385038763883384938733886384838783873322338793888322538773881322438813874816938823879817138803884817038843875815638853882815838833887815738873876389338883885389538863878389438903893392038913896392338923899392238893902392138943889388638953904388838933897388738973890815338983895815538963900815439003891320439013898320638993903320539033892322639043901322839023894322739063909384439073913384339083917384639053920384539103905393539113923393439123924393339093914393639143906391539123916392739133918391839073772391939163774391739303773392139083889392239323892392339253891392039103890392539113147392639223146392439283148392839153531392939263530392739313529393139193487393239293486393039213485393439373911393539413910393639443909393339483912393839333126393939513125394039523124393739563123394239348181394339588183394139458182394539353842394639433841394739543840394439493839394939363950394739513953394839383953393939543950395539463952395739573940417139583955417039563942416939603963801039613967800939623971800839593976800739643959666239653985666539663986666439633989666339683960778239693992778139703993778439673972778339723961783739733970783639743998783539754002783439713977783839773962378239783975378139794008378039804007377939814006377839824009378739834014378639844019378539853987378439763964378339873965673739883984673939864023673839903966652139914026652039923994651939893968652239943969647739953991648139964030648039974035647939933999647839993973434740003997434640014040434539984003434840033974237640044001237540054039237440064010238040073980237940083979237840023978237740103981401140054012403840134041400940154015398242964016401342954017404442944018404542984014402042974020398371564021401871554022404871584019402471574024398870934025402270924023402770914027399070754028402570784029404770774026403170764031399564244032402964284033404664274034404364264030403664254036399640374034403840424039401140404004403540004042401263934043403763964044403363954041401663944046401771434047403271424048402871414045402171404050405333154051405633144052405933174049406233164054404934604055406434624053405734614057405032524058405532544056406032534060405132424061405832444059406332434063405238674064406138694062405438684066406980244067407380234068408080264065408580254070406566364071408966354072409266344069407466374074406638064075407238054076409838044077409938034078410338024079410838014073408138004081406778194082407978184083410778174084410978214080408678204086406850324087408450314088411450344085409050334090407050974091408850964089411850984093407152124094412052114095412152104096412552094097412952084098410052074092407552134100407641014097410241344099410441044077269441054102269341064133269241074110269141084082269041034078269541104083453541114106453941124132453841134135453741094115453641154087502241164113502141174138502041144123501941194091514441204122514341184093514541224094511941234119511841244117512141214126512041264095790441274124790341284137790641254130790541304096413141284132413641334111413441054129410141364112795841374131795741384127795641354116795941404142297341414145297241394148297141434139414441504142414641464140385141474144385341454149385241494141415341504147415241484143415141524154415041534157414941514160414841554151416341564162416541544158416441584152818641594156818541574161818441614153813741624159813641604155813541644166415441654169415641634172415541674163416841744166417041704164395841714168395741694173395641734165310541744171310441724167310641764179676141774187676041784193675941754197675841804175521741814200521641824201521541834207521441844213522141854218522041864189521941794188521841884176682941894186683441904185683341914221683241924222683141874194683041944177677341954192677641964226677541934231677441984178675041994234674942004202674841974180675142024181380842034199380742044233381242054229381142064235381042014208380942084182420942064210424142114242421242464207421442144183566042154212565942164249565842174250565742134219566142194184562842204217563142214253563042184190562942234191625642244257625542254237625842224227625742274195428642284225428542294236428942304204428842264232428742324196716842334230716742344203717042314198716942364205423742284238422442394256424042584241424342354209424342105949424442405948424542605947424242475950424742115885424842455884424942515883424642155886425142165887425242485889425042615888425442206145425542636149425642646148425742386147425342236146425942396166426042666165425842446167426242525905426342655907426142545906426542556159426642626161426442596160426842726275426942776274427042816273427142856272426742906276427342676388427442936392427542946391427642996390427242786389427842687692427942767691428043027690427742827693428242696788428342806787428443036786428142866785428642704227428742844226428843064230428942964229428542914228429142714292428942934295429042734295427440164296429240154297428840144298430540184294430040174300427571314301429871304302430471294299427971324304428371534305430171524306429771514303428771544308431143534309431543524310431943554307432443544312430743934313432843924314432943954311433543944316430878814317433878844318433978834315432078824320430943214318432243444323434543194325432543102300432643232299432743482298432843302302432443122301433043137829433143277828433243477833433343427832433443417831432943367830433643144490433743344489433843404492433543164491434043176490434143376489434243336488434343326487434443466486433943216491434643224000434743433999434843313998434543264001435043527873435143567872434943607871435343494308435443634307435543654310435243574309435743504358435543594364435643614361435143724362435943714363436643704360435343734365435823304366435423324364436223314368437023474369437423464367437823454371436743624372438143614373438343604370437543634375436843884376437343914377438243904374437943894379436944064380437744094381438444084378437144074383437678754384437278744382438078764386438823344387439223334385439623354389438543744390439943774391440143764388439343754393438643124394439143114395440043144392439743134397438744644398439544674399440244664396438944654401439444884402439044874400439844864404440623294405441023284403441423274407440343784408441743814409441943804406441143794411440444244412440944274413441844264410441544254415440544164413441744204414440744194412805944204408805844184416805744224424234444234428234344214432234244254421441044264435441344274437441244244429441144294422444244304427444544314436444444284433444344334423443444314435443844324425443744304679443844264681443644344680444044422349444144462348443944502350444344394428444444534431444544554430444244474429444744404460444844454463444944544462444644514461445144418046445244498049445344568048445044438047445544484580445644444579445444524578445844602338445944642337445744682336446144574446446244714449446344734448446044654447446544584396446644634399446744724398446444694397446944594503447044674502447144744501446844614504447344664477447444624476447244704475447644784474447744824473447544864472447944754505448044894508448144934507447844834506448344764573448444814572448544964571448244974574448744774402448845004401448644904400449044794336449144884335449244994338448944944337449444804662449544924665449644984664449344844663449844857888449944957887450044917886449744877885450245054470450345094469450445154468450145204471450645014478450745244481450845284480450545104479451045027827451145087826451245307825451345317824451445357823450945167822451645032309451745142308451845392307451945402311451545212310452145048051452245198050452345458053452045258052452545064589452645234588452745444591452445464590452945074969453045494968452845114970453245125012453345515011453445525014453145365013453645134109453745344113453845554112453945414111453545174110454145184542453845434557454445474545452645404522454745274599454845434601454645584600455045294894455145604893454945324895455345337936455445597938455245567937455645377962455745547961455545427960455945484881456045534883455845504882456245644660456345674659456145714661456545618079456645748078456445758080456845624586456945774585457045784584456745724587457245634484457345704483457445804482457145654485457645664675457745794674457545684673457945694456458045764455457845734454458245848054458345888056458145928055458545814569458645954568458745974567458445894570458945824525459045874524459145964527458845934526459345834594459145954598459245854597459046394598458646414596459446404600460245464601460545484599460845474603459946204604461046194602460646184606460048704607460448694605460948714609460146104607460846034612461448424613461848444611462148434615461148364616462448354617462848384614463348374619461246044620463846034618463946024622461348514623464248534621462548524625461549234626462349224627464549254624462949244629461647124630462747114631465047104632465147094628463447134634461746354632463646554637465646384640463346194640462045964641463745984639465945974643462249654644466249674642464649664646462665114647464465104648466565094649466665144650465265134645463065124652463146534649465446694655465746514635465746364708465846544707465646704706466046414562466146724561465946634563466346434493466446614496466546674495466246474494466746487895466846647894466946717893466646537892467146588076467246688075467046608077467446764577467546794576467346824575467746734678468446764680468046744436468146784438467946834437468346754687468446814686468246774685468646884684468746914683468546944682468946854697469046964699468846924698469246868066469346908068469146958067469546878073469646938072469446898074469847004688469947034690469747064689470146974702470847004704470446984705470247034707470746994658470847054657470647014656471047144631471147184630471247234629471347294628470947304632471547094716473347174734471447194719471064464720471764504721473864494722472564484718472464474724471147464725472247524726472147514727473747504728473647494729473147484723471247474731471347324728473347354730471547354716744347364732744747374727744647384726744547344720744447404742492647414746492847394753492747434739482547444756482447454760482747424747482647474740472347484745472947494765472847504766472747514770472647524774472547464778472447544741494547554781494447534782494647574743791547584785791447594786791747564761791647614744476247594763479247644793476547674760474847674749746047684764745947694796746247664771746147714750731447724769731347734797731247704775731147754751727247764773727147774801727447744779727347794752772547804777772447814804772747784754772647834755511547844807511447854787511747824757511647874758524447884784524347894809524247904810524147914799524047924794523947864762523847944763748847954791748747964798748647934768748547984772531947994795531848004790531747974812532048024776724548034811724448014805724348054780723348064803723248044808723148084783519248094806519148074788519348114789529448124802529648104800529548144817791148154820791048164824791348134828791248184813796948194831797148174832797048214814491948224834491848234835492148204825492048254815474348264823474248274838474548244829474448294816483048274831483748284818483348194840483448364839483248214841483648224615483748334614483848304617483548264616484048424833484148454832483948484834484348394611484448504613484248464612484648404865484748444864484548494863484948414856485048474855484848434854485248544621485348574623485148604622485548514850485648624849485448584848485848524913485948564912485748614911486148534904486248594903486048554902486448664847486548694846486348724845486748634875486848744877486648704876487048644606487148684605486948734607487348657968487448717967487248677966487648784866487748814868487548844867487948754887488048864889487848824888488248764558488348804560488148854559488548777941488648837940488448797939488848904878488948934880488748964879489148874899489248984901489048944900489448884550489548924549489348974551489748895002489848955001489648915000490049024890490149054892489949084891490348994862490449104861490249064860490649004961490749044960490549094959490949014952491049074951490849034950491249144859491349184858491149224857491549114932491649254935491749274934491449194933491949124821492049174820492149264823491849234822492349134625492449214624492549284627492249154626492749204739492849164741492649244740493049324947493149364949492949404948493349294914493449434917493549454916493249374915493749305058493849355057493949445056493649415055494149315127494249395126494349465125494049335128494549384754494649344753494449424755494849504929494949534931494749564930495149474910495249584909495049544908495449484998495549524997495349574999495749494972495849554971495649514973496049624907496149654906495949684905496349594982496449704984496249664983496649604642496749644644496549694643496949614529497049674528496849634530497249744957497349784956497149824958497549715040497649855039497749895042497449795041497949725060498049775059498149925062497849935061498349734962498449964964498249864963498649757848498749847847498849957850498549907849499049767857499149887856499249947855498949807858499449816506499549916505499649876508499349836507499850004954499950034953499750074955500149974898500250114897500050154896500449985135500550185134500650195133500350085136500849995038500950065037501050225036500750125035501250014532501350104531501450214534501150164533501650027928501750147927501850207926501550047925502050054117502150174116502250134115501950094114502450277844502550317843502650357846502350397845502850237991502950427994503050437993502750327992503250244086503350304085503450454088503150364087503650255010503750345009503850465008503550405007504050264975504150384974504250484977503950284976504450295088504550475087504350335089504750375080504850445079504650415078505050525077505150555076504950595075505350495155505450635157505250675156505650504939505750704938505850714937505550604936506050514979506150584978506250744981505950644980506450536601506550626600506650736599506350686602506850547717506950667716507050727719506750567718507250576516507350696515507450656518507150616517507650785051507750815050507550845049507950755048508050865047507850825046508250765124508350805123508150855122508550775104508650835103508450795102508850905044508950935043508750965045509150875099509250985101509050945100509450886647509550926646509350976645509750894090509850954089509650914091510051025090510151055092509951085091510350995086510451105085510251065084510651005151510751045150510551095149510951015142511051075141510851035140511251145139511351185138511151225137511551114783511651254782511751294785511451194784511951124122512051174121512151324124511851334123512351135083512451365082512251265081512651154942512751244941512851354940512551304943513051167902513151287901513251347900512951207899513451215005513551315004513651275003513351235006513851405113513951435112513751465111514151375110514251485109514051445108514451384119514551424118514351474120514751395190514851455189514651415188515051525107515151555106514951585105515351495161515451605163515251565162515651505052515751545054515551595053515951516644516051576643515851536642516251645152516351675154516151705153516551615173516651725175516451685174516851627715516951667714516751717713517151636709517251696711517051656710517451765164517551795166517351825165517751735185517851845187517651805186518051747227518151787226517951837225518351757217518451817216518251777218518651885176518751915178518551945177518951855148519051965147518851925146519251864808519351904807519151954809519551875247519651935246519451895245519852015199520752005214519752225202519752035229520452305205523452065238520152085208519840975209520640965210524440955211524340945212524540935213524840925207521540985215519941825216521341815217525141805218525241795219525641865220526041855221522441845214522341835223520055725224522155715225522055785226526355775227526455765228526855755229523155745222520255735231520375495232522875525233527175515230523575505235520475005236523374995237527274985234523974975239520547925240523747915241527547905242527647895243524647885244521047875238520947865246521151965247524251955245527951945249521267255250528167285251525367275248521667265253521771785254525071775255528271765252525771755257521854515258525554505259528554495256526154525261521954865262525954855263526554885260522554875265522654325266526254315267528754305264526954295269522773545270526773535271527373525268523273555273523653055274527053045275528853035272524053065277524152915278529052935276528452925280524772205281528372195279524972215283525472045284528072065282527872055286525853925287528953915285526653935289527453375290528653395288527753385292529452765293529752785291530052775295529148105296530248125294529848115298529253455299529653445297530153435301529353365302529953355300529553345304530752745305531052735306531352725303531752755308530353325309532053315307532153335311530473465312532473455310531473475314530574965315531274955316532774945313531874935318530647995319531647985320533047975317530848005322530954095323532954115321532554105325531173285326532373275324532873295328531573095329532673085330532273075327531973105332533453085333533753075331534053095335533153025336534253015334533853005338533252885339533652905337534152895341533353845342533953835340533553825344534652995345534952985343535252975347534353555348535453575346535053565350534472425351534872415349535372405353534572125354535172115352534772105356535853465357536153485355536453475359535553675360536653695358536253685362535672515363536072505361536572495365535772005366536371995364535971985368537053585369537353605367537653595371536753795372537853815370537453805374536872795375537272785373537772805377536954485378537554475376537154465380538253705381538553725379538853715383537953425384539053415382538653405386538054055387538454045385538954035389538153965390538753955388538353945392539452865393539752855391540052875395539153905396540253895394539853885398539254445399539654435397540154455401539354425402539954415400539554405404540653875405540953865403541253855407540354285408541454275406541054265410540453215411540853235409541353225413540572755414541172775412540772765416541973325417542373315418542673305415542973335420541555145421543255135422543355125419543755155424541676225425543976245423542776235427541754085428542554075426544054065430541852675431544252665432543452655429542052645434542154755435543154745436544154735433543854765438542273635439543673655437542473645441542854025442543554015440543054005444544653985445544953975443545353995447544353785448545753775446546153765450544452585451546452575452546552565449545452595454544554695455545254725456546854715453545854705458544776765459545676755460546776785457546276775462544871825463546071815464546671805461545071795466545168365467546368355468545968385465545568375470547354535471547754565472548154555469548554545474546954355475548854345476549154335473547854365478547076415479547676405480549076435477548276425482547168655483548068645484548968635481548668625486547252615487548452605488549252635485547452625490548354935491547954965492547554955489548754945494549754895495550454925496551254915493551654905498549362275499551962265500552062255501552562245502553062235503550662295497550562285505549455975506550355965507550255955508553355945509553455935510554055925511554455995504551355985513549554215514551154205515554754195512555054225517549676455518555276445519552176475516549876465521549962855522551862845523555362835524555662875520552662865526550055275524552855605529553655255531553155015532552955335535553055075535550855365532553755285538555955395561553455415541550975545542553975535543556375565540554575555545551073605546554373625544554873615548551473435549554673425547556473445551551573665552555473685550551773675554552273915555555173905553556773925557552374215558556674205559556874195560553774185556552774175562553875405563557075395561554275415565554974095566556974085567555774075564555574065569555876075570556576095568556276085572557952235573558352225574558852295575559252285576559952275577559852265578559752255571560052245580557156815581560356845582560456835579558456825584557255855582558656075587560855835589558955735590558755915612558855935593557455095594559155085595561155075596561355065597560155055598557755045599557655115592557555105601557856195602559656185603561656175600558056205605558157135606561557125607560957155604558557145609558656105606561156145612559456085590561455955695561556105694561656055693561356025692561856215602561956245601562056285600561756325603562256175686562356365685562156375687562556186231562656396230562756406233562456296232562956194218563056274221563156444220562856334219563356205664563456315663563556435662563656425666563256225665563856236193563956416192563756256194564156266126564256386125564356356124564456346128564056306127564656495892564756535891564856575890564556625893565056455739565156665742565256675741564956725740565456465880565556755879565656765882565356585881565856474216565956564215566056804214566156814213565756634217566356485634566456615633566556845632566656685636566256505635566856515708566956655707567056835711567156785710566756735709567356525816567456715815567556775818567256545817567756555678567456795670568056825676565956825660557956835679558256845669558156815664558056865688562256875692562156855696562356895685570356905699570656915701570556885693570456935686561656945691561556955700561456925697561356975687618256985695618156995702618056965689618357015694570256905700569857045707568857055712569157065716569057035720568957085703566857095724566757105723567157115725567057075713566957135704560557145711560457155728560757125717560657175705571857155719572757165721572157065778572257195782572357265781572457095780572057085779572657105727572257285718572557145730573259025731573559045729573959035733572959225734574359245732574759235736573081875737574981905738575081895735574081885740573156495741573856525742575356515739574456505744573361155745574261145746575261135743575461125748573459635749575659655747573659645751573757765752575557755753574557745750574157775755574660795756575160785754574860775758576260845759576660835760577160875761577460865757577860855763575757645782576557835762576757675758576857655769578757705788576657925772575960755773579460745771577560765775576057525776577357515777579557505774577957535779576157205780577757245781579857235782578457225778576357215784576457855781578657975787578957835768578957696051579057866050579157966049578857936048579357706069579457916068579257726070579657765802579757905801579857855800579557805799580058035798580158065797580258095796579958125795580457995819580558145821580358075820580758005844580858055846580658105845581058018213581158088215580958138214581358028197581458118199581258048198581658195673581758225672581858255675581558285674582058155803582158305805581958235804582358168194582458218196582258268195582658175854582758245856582558295855582958185835583058275837582858205836583258355833583858345841583158445836583158285837584658305835583958295839583258515840583758535838584258525842583382165843584082185841584582175845583458065846584358085844583658075848585158635849585458665850585758655847586058645852584758385853586258405851585558395855584858255856585358275854585858265858584981915859585681935857586181925861585082075862585982095860585282085864586758475865587158505866587558495863587958485868586358695882587058855867587258725864593858735870593758745884593658715876593558765865590058775874589958785883589858755880590158805866565458815878565358825886565658795868565558845877424858855873424758865869424658835881424958885890425058895894425258875898425158915887564758925901564658935903564558905895564858955888590858965893591158975902591058945899590958995889587759005897587659015904587558985891587859035896572959045892573159025900573059065908426159075912426359055916426259095905589459105919589759115922589659085913589559135906613159145911613059155924612959125917613259175907616359185915616259165920616459205909595459215918595659195923595559235910573259245921573459225914573359265928595359275932595259255935595159295925603059305938603359315939603259285943603159335926617659345946617559325947617459365927587459375950587359385940587259355929587159405930594159375942594959395944594459315945594259465948594359335948593442445949594542435950594142425947593642455952595459275953595759265951596059255955595159195956596259215954595859205958595259775959595659765957596159755961595359685962595959675960595559665964596657475965596957495963597257485967596359625968597459615966597059605970596460255971596860245969597360235973596560165974597160155972596760145976597859595977598159585975598459575979597559875980598659895978598259885982597661575983598061565981598561585985597761695986598361685984597961705988599059785989599359805987599659795991598759995992599860015990599460005994598861345995599261335993599761355997598959985995599659916000600259906001600559925999600859916003599960116004601060136002600660126006600061176007600461166005600961186009600160106007600860036012601460026013601760046011602060036015601159746016602259736014601859726018601260736019601660726017602160716021601360646022601960636020601560626024602659716025603059706023603459696027602360446028603760476029603960466026603160456031602459286032602959316033603859306030603559296035602582046036603382036037604082066034602782056039603260406028603860366042604460596043604860616041605260606045604160266046605560296047605760286044604960276049604257916050604757906051605657896048605357886053604360546051605560586052604560576050605860466056605460606062604160616065604360596068604260636059602260646070602160626066602060666060606760646065606960696061579360706067579260686063579460726074601960736077601860716080601760756071577260766082577160746078577360786072575660796076575560776081575460816073611060826079610960806075611160846088575860856092575760866096576160876100576060836104575960896083609061036091610560886093609360846094609160956108609260976097608561856098609561846099610761876096610161866101608661236102609961226103610661216104608961206100608761196106609061986107610261976108609861966105609461956110611260816111611660806109611960826113610957466114612357456115612457446112612957436117611060066118613360056116613660076120611161046121614061036122614161026123612561016119611361006125611456426126612256416127614456406128614556446124613056436130611559146131612859136132614959126129615059156134611759946135615259936133613759956137611861386135613961476140614261366120614261216208614361396211614461466210614161266209614661274253614761434257614861384256614961514255614561314254615161326155615261486154615061346153615461566152615561596151615361626150615761535982615861645981615661605983616061544264616161584266615961634265616361555917616461615916616261575918616661684259616761714258616561744260616961655985617061765984616861725986617261666173617061716175617561675934617661735933617461695932617861806179618461776188618161775698618261915697618361935696618061855699618561786097618661836096618761926099618461896098618961796205619061876204619161946207618861816206619361865638619461825637619261905639619661996108619762046107619862086106619562126105620061956201621762026218620362236199620562056196618962066203618862076229619162046230619062096197614162106233614462116234614362086213614262136198621462116215623762166238621762196212620062196201622062166221624162226242621862246224620255016225622255006226624554996227624654986228625054976229623155036223620655026231620756256232622856246233624956276230620956266235621062516236624862546237623962536234621462526239621563536240623663526241624363516238622063546243622163426244624063416245624763406242622563396247622668606248624468596249623568586250623268576246622768616252625562346253625962376254626362366251626762356256625142236257627142226258627242256255626042246260625262616258626262766259626462646253636662656262636562666275636462636268636362686254685562696266685462706274685362716273685262676256685662736257427062746270426962756269426862766265426762726261427162786280739662796283739862776288739762816277763262826293763162806297763362846278552262856300552162866301552062876306552462836289552362896279743962906287743862916309744262926310744162886294744062946281730062956292729962966314730262936315730162986282766262996318766163006302766062976284765963026285632363036299632263046317632163056312632063016307631963076286630863056309631163066290631162916468631263086472631363046471631463166470631062956469631662967670631763137669631863037668631562987667632063246305632163286304632263336303632363386302631963396301632563196326634263276343632463296329632063976330632764016331634664006332633563996328633463986334632168446335633268436336633168486337634568476338634068466333632268456340632362456341633762446342634462436339632562426344632663486345634163476346633663506343633063496348635163446349635563436350635963466347636363456352634762406353636662396354636962386351635662416356634863576354635863686355636063606349637363616358637263626367637163596364637463646350626663656362626563666370626463636352626363686361636963576370635363676365637263756361637363796360637463836359637163886362637663716377639263786393637563806380637263816378638263966379638463846373641563856382641963866395641863876390641763836389641663896374427263906387427663916386427563926394427463886376427363946377404163956391404463966385404363936381404263986402632863996407633264006411633164016415633063976420632964036397645764046423645664056424645564066429645964026408645864086398693964096406694264106432694164076412694064126399770064136410769964146433769864116416770164166400638364176414638764186436638664196426638564156421638464216401642264196423642564206403642564044030642664224034642764184033642864354032642464304031643064056974643164286973643264346972642964096971643464137147643564317146643664277145643364177144643864426499643964466498644064516497644164556496643764606500644364377721644464637720644564647723644264477722644764384718644864454722644964674721645064684720644664524719645264396453645064546472645164566456644064046457645464036458647164026459647364066455646164056461644166976462645967006463647666996460644366986465644472686466647572676467646972706464644872696469644963106470646663146471647463136472645763126468645363116474645870276475647070306476646570296473646270286478648239936479648639976480649239966481649639956477650139946483647765526484650465516485650565546482648765536487647843436488648543426489650843416490650943406491651443396486649343446493647964946491649565136492649764976480644064986495643964996512643865006515643764966502644165026481653565036500653865046518653765016483653665066484499465076517499365086510499665056488499565106489464765116507464665126516464565136498465065146494464965096490464865166499507265176511507165186506507465156503507365206523399165216526399065226529398965196532399265246519653965256534654165236527654065276520667665286525667865266530667765306521662265316528662465296533662365336522659065346531659265326524659165366539650165376542650465386545650365356548650265406535652365416550652565396543652465436536658765446541658965426546658865466537660365476544660565456549660465496538667965506547668165486540668065526555648365536558648265546561648565516564648465566551657165576566657365556559657265596552779465606557779665586562779565626553780165636560780365616565780265656554785965666563786165646556786065686571658365696574658665706577658565676580658465726567655565736582655765716575655665756568786865766573787065746578786965786569776965796576777165776581777065816570778565826579778765806572778665846587656765856590657065866593656965836596656865886583654265896598654465876591654365916584653265926589653465906594653365946585661965956592662165936597662065976586660665986595660865966588660766006603506566016606506466026609506365996612506666046599654566056614654766036607654666076600659666086605659866066610659766106601662866116608663066096613662966136602668266146611668466126604668366166619665866176622666166186625666066156628665966206615659366216630659566196623659466236616652966246621653166226626653066266617667366276624667566256629667466296618660966306627661166286620661066326634671466336638671366316642671266356631407166366645407066376648406966346639407266396632665666406637665566416650665466386643665766436633516066446641515966426646515866466635509566476644509466456649509366496636773366506647773266486640773166526654773466536658773666516662773566556651664066566665663966576667663866546659664166596652661566606657661866616666661766586663661666636653396366646661396666656668396566626655396466676660672366686656672266666664672466706673668566716676668866726679668766696682668666746669662566756684662766736677662666776670652666786675652866766680652766806671654866816678655066796683654966836672661266846681661466826674661366866689666966876693667266886697667166856701667066906685672166916704672066926707671966896694671866946686770766956692770666966706770566936698770866986687646066996696646367006705646266976702646167026688704567036700704467046708704367016690704667066699702667076695702567086691702467056703702367106712517067116715517267096718517167136709663367146722663267126725663167166710722467176728722367156729722267196711669267206732669167216733669067186723668967236713666767246721666667226736666867266714524867276735525167286730525067256716524967306717718767316727718667326734718967296719718867346720674367356731674267366726674167336724674067386740398667396744398867376748398767416737673667426751673567436753673467406745673367456738710267466743710567476752710467446749710367496739419967506747419867516754419767486741420067536746675767546742675667526750675567566758675467576762675367556766675267596755417867606769417767616771417667586763417567636756719167646761719067656770719367626767719267676757680467686765680767696772680667666759680567716764682067726760681967706768681867746777419367756781419667766785419567736789419467786773680367796792680267806795680167776782680067826774716667836780716567846794716467816786716367866775428467876784428367886793428267856790428167906776682867916788682767926796682667896778682567946787691567956783691467966779691367936791691267986800710667996804710867976808710768016797678068026811677968036813677868006805677768056798676668066803676968076812676868046809676768096799687568106807687468116814687368086801687668136806681568146802681768126810681668166818681268176821681468156825681368196815677268206829677168186835677068226816688968236839689268246843689168216849689068266817679268276851679168286852679068256830678968306819418768316828419268326856419168336857419068346862418968296836418868366820546668376834546568386865546868356840546768406822768168416838768068426866767968396844768268446823633468456842633368466869633868476859633768486854633668436870633568506824690568516872690768496826690668536827627068546871626968556847626868566858626768526831627168586832624968596855624868606846624768616868624668576863625068636833548468646861548368656867548268626837548168676841765668686864765568696860765868666845765768716848770468726853770368706850770268746877681068756880680968766883680868736886681168786873689368796888689568776881689468816874701068826879701268806884701168846875696268856882696468836887696368876876693068886885693268866878693168906893682168916896682468926899682368896902682268946889687768956904687968936897687868976890692768986895692968966900692869006891694369016898694568996903694469036892701369046901701569026894701469066908684969076912685169056916685069096905692369106919692669116921692569086913692469136906679669146911679569156920679469126917679369176907769669186915769569196922769469166909769769216914713369226910713569206918713469246927690869256930691169266933691069236936690969286923689669296938689869276931689769316924688669326929688869306934688769346925695969356932696169336937696069376926694669386935694869366928694769406943640769416946641069426949640969396952640869446939689969456954690169436947690069476940693669486945693869466950693769506941696869516948697069496953696969536942701669546951701869526944701769566959699069576962698969586965698869556968698769606955693369616970693569596963693469636956688369646961688569626966688469666957700769676964700969656969700869696958694969706967695169686960695069726975643269736978643169746981643069716984642969766971699169776986699369756979699269796972711669806977711869786982711769826973708269836980708469816985708369856974705069866983705269846976705169886991695869896994695769906997695669877000695569926987697569937002697769916995697669956988704769966993704969946998704869986989706369996996706569977001706470016990711970026999712170006992712070047007701970057010702270067013702170037016702070087003696570097018696770077011696670117004688070127009688270107014688170147005690270157012690470137017690370177006695270187015695470167008695370207023700370217027700670227031700570197035700470247019670870257038670770267041670670237028670570287020647370297026647670307040647570277032647470327021768670337030768570347039768470317036768370367022719570377034719470387042719770357024719670407033725570417029725470427025725370397037725270447047670370457050670270467053670170437056670470487043699470497058699670477051699570517044698470527049698670507054698570547045707970557052708170537057708070577046706670587055706870567048706770607063709670617066709570627069709470597072709770647059699770657074699970637067699870677060705670687065705870667070705770707061708870717068709070697073708970737062712270747071712470727064712370767079402670777082402970787085402870757088402770807075705370817090705570797083705470837076698170847081698370827086698270867077711370877084711570857089711470897078706970907087707170887080707070927094402570937098402470917102402370957091706170967105706070977107705970947099706270997092717371007097717271017106717170987103717471037093674471047101674771057108674671027095674571077100679771087096679971067104679871107113713971117116713871127119713771097122713671147109708571157124708771137117708671177110697871187115698071167120697971207111700071217118700271197123700171237112707271247121707471227114707371267129715971277133716271287136716171257140716071307125430171317143430071327144429971297148430271347126692071357150692271337137692171377127711271387135711171397146711071367141710971417128404871427139404771437145404671407130404571457131643671467142643571477138643471447149643371497132768771507147768971487134768871527155430571537159430471547163430371517167430671567151402071577170401971587173402271557160402171607152712571617158712871627172712771597164712671647153678471657162678371667171678271637168678171687154423271697166423171707174423471677156423371727165710071737161709971747157709871717169710171767179525571777183525471787186525371757190525271807175546471817193546371827194546271797198546171847176720171857200720371837187720271877177673071887185672971897196673271867191673171917178676371927189676271937195676571907180676471957181703671967192703571977188703871947199703771997182536672007197536571987184536472027204718372037207718572017210718472057201528272067212528472047208528372087202721572097206721472077211721372117203535472127209535372107205535272147216720972157219720872137222720772177213518372187224518272167220518472207214528072217218527972197223528172237215671772247221671672227217671572267228518172277231518072257234517972297225723772307236723972287232723872327226480672337230480572317235480472357227773072367233772972347229772872387240722872397243723072377246722972417237535172427248535072407244534972447238480372457242480272437247480172477239726272487245726172467241726072507252536372517256536272497260536172537249704272547263704172557267704072527257703972577250728872587255729172597270729072567271728972617251724872627274724772607264724672647253770972657262771272667273771172637268771072687254646572697266646472707272646772677258646672727259477572737269477472747265477772717261477672767278541272777281541472757284541372797275537472807288537372787292537572827276762172837296762072817285761972857277730372867283730672877299730572847289730472897279725672907287725972917302725872887293725772937280767472947291767372957301767272927297767172977282762572987295762772967300762673007286629473017298629373027294629672997290629573047307728473057311728773067315728673037319728573087303532973097322532873107325532773077312533073127304477373137310477273147324477173117316477073167305745873177314745773187323745673157320745573207306758473217318758373227326758273197308758573247317747273257313747173267309747473237321747373287330532573297334532473277338532673317327541773327341541673337343541573307335541873357328734873367333735173377342735073347339734973397329757573407337757473417344757773387331757673437336554873447332554773427340554973467348531173477352531073457356531273497345733473507359733773517361733673487353733573537346527073547351526973557360526873527357527173577347756573587355756473597362756773567349756673617354554473627350554673607358554573647366543773657369543973637372543873677363555073687374555273667370555173707364737673717368737573697373737773737365763773747371763973727367763873767378737073777381736973757384737173797375738773807386738973787382738873827376761773837380761673817385761873857377762973867383762873847379763073887390737873897393738073877396737973917387555473927398555373907394555573947388740173957392740073937397739973977389627773987395627973967391627874007402739574017406739473997410739374037399743774047413743674057415743574027407743474077400556774087405556674097414556574067411556474117401758074127409757974137416757874107403758174157408761174167404761074147412761274187422556074197426555974207431555874217434555774177438555674237417742474427425744374227427742774187428742574297447743074487426745274327419760274337454760174317435760374357420740574367433740474377455740374347439740274397421628974407437628874417458629274427444629174387423629074447424473474457441473874467457473774477449473674437428473574497429746874507446746774517456747074487453746974537430751674547451751574527432751774567436731874577450731774587445731674557440731574607463476774617467476674627471476974597475476874647459746574787466747974637468746874607449746974667448747074817451746774727450747274617324747374707323747474827326747174767325747674627489747774747492747874847491747574647490748074657509748174837511747974697510748374737595748474807597748274777596748674894796748774934795748874974794748575014793749074857475749175047478749275077477748974947476749474865316749574925315749675065314749374985313749874875237749974965236750075055235749775025234750274887503750075047508750174907506749975637507749575627508749175617505750375607510751274797511751574817509751874807513750975147520751275167516751074537517751474527515751974547519751175237520751775227518751375217522752475207523752775197521753075187525752175337526753275357524752875347528752276047529752676067527753176057531752375997532752975987530752576007534753675247535753975267533754275257537753375387544753675407540753455627541753855617539754355637543753575597544754175587542753775577546754975477553754875577545756075507545523075517563523375527564523275497554523175547546554175557552554075567567554375537558554275587547754475597556754375577568754275617548750875627570750775637565750675607550750575657551735775667562735675677569735975647555735875697559759375707566759275687561759475727574758975737578759175717582759075757571733975767585733875777587734175747579734075797572741275807577741175817586741075787583741375837573732175847581732075857588731975827575732275877580761375887576761575867584761475907592757175917595757375897598757275937589756975947600756875927596757075967590748275977594748475957599748375997591753176007597753075987593753276027604743276037607743176017610743376057601752776067612752976047608752876087602556876097606557076077611556976117603741576127609741476107605741676147616758676157619758876137622758776177613738276187624738176167620738376207614728376217618728276197623728176237615542376247621542576227617542476267628729676277631729876257634729776297625738576307636738476287632738676327626628176337630628076317635628276357627765076367633764976347629764876387640737276397644737476377648737376417637547876427651547776437655548076407645547976457638551776467643551676477658551976447659551876497639763676507662763576487652763476527641766576537650766476547661766376517656766676567642686776577654686676587660686976557646686876607647630076617657629976627653629876597649629776647667765376657671765276667675765176637679765476687663631876697682631776707685631676677672631576727664729576737670729476747684729376717676729276767665545876777674545776787683546076757680545976807666684176817678684076827686683976797668684276847677703476857673703376867669703276837681703176887690714876897694715076877698714976917687427976927701427876937703427776907695428076957688691876967693691776977702691676947699691976997689641377007697641277017704641176987691641477037696687277047692687177027700687077067709669577077713669477087716669377057720669677107705726377117723726677127724726577097728726477147706516977157730516877137717516777177707506877187715506777197726507077167721506977217708644377227719644277237725644577207710644477257711477977267722477877277718478177247729478077297712723677307727723577287714723477327734665077337737664977317740664877357731665177367743665377347746665277387732800177397748800377377741800277417733803077427739803277407744803177447735802077457742802277437747802177477736775377487745775577467738775477507753776577517756776877527759776777497762776677547749774677557764774877537757774777577750801777587755801977567760801877607751797977617758798177597763798077637752800477647761800677627754800577667769774977677772775277687775775177657778775077707765657777717780657977697773657877737766786577747771786777727776786677767767780777777774780977757779780877797768778877807777779077787770778977827785396877837788396777847791397077817794396977867781658077877796658277857789658177897782777877907787778077887792777977927783780477937790780677917795780577957784655877967793656077947786655977987801785177997804785478007807785377977810785278027797656178037812656378017805656278057798779178067803779378047808779278087799777578097806777778077811777678117800786278127809786478107802786378147817230678157822230578167828230478137834230378187813408278197838408178207839408078217843408478177823408378237814451478247821451378257846451278267847451178277830451078227829450978297815433078307827432978317826433478327850433378337851433278287835433178357816397478367833397378377854397278387840397178347818397578407819797778417837797678427853797578397844797878447820502478457842502378467848502678437824502578487825498678497845498578507852498878477831498778527832779778537849780078547841779978517836779878567859499178577862499078587865498978557868499278607855656478617870656678597863656578637856781078647861781278627866781178667857777278677864777478657869777378697858657478707867657678687860657578727874435178737877435078717881434978757871438378767885438278747889438478787872787978917880789278777882788278734315788378804318788478954317788178864316788678754500788778844499788878944498788578964497789078768063789178988065788978788064789378794669789478974668789578874667789278834666789778888071789878938070789678908069790079035132790179075131790279105130789979145129790478994126790579174125790679184128790379224127790879007929790979247931790779117930791179014814791279094813791379204816791079154815791579024757791679134756791779194759791479044758791979057920791679217912791879237923790679477924792179467922790879457926792950187927793250177928793650167925793950157930792579077931794279097929793379087933792679497934793179487935794479517932793779507937792745527938793545547936794045537940792848867941793848857939794348847943793079647944794179637942793479657946794879247947795279237945795679227949794579337950795979327951796179357948795379347953794679547951795579607952795779577947413779587955413679597962413579567949413879617954455779627950455679607958455579647966794379657969794279637972794479677963487479687974487379667970487279707964481779717968481979697973481879737965797479717972796779767979784179777982784079787985783979757988784279807975775979817990776179797983776079837976801479847981801679827986801579867977803679877984803879857989803779897978799579907987799779887980799679927995502779937998503079948001502979918004502879967991798879978006799079957999798979997992803380007997803579988002803480027993773780038000773980018005773880057994776280068003776480047996776380088011396280098014396180108017396080078020395980128007802780138022802980118015802880158008798280168013798480148018798380188009775680198016775880178021775780218010774380228019774580208012774480248027406680258030406580268033406880238036406780288023801180298038801380278031801280318024774080328029774280308034774180348025799880358032800080338037799980378026798580388035798780368028798680408042234180418046234080398050233980438039804480538045805580428047804780404450804880454453804980544452804680514451805180414521805280494520805380564523805080434522805580484581805680444583805480524582805880604420805980634419805780664418806180578062806880608064806480587889806580627891806380677890806780594691806880654693806680614692807080727898807180757897806980787896807380694695807480804694807280764696807680704671807780744670807580794672807980714565808080774564807880734566808280843053808380873052808180903051808580813631808680923633808480883632808880823579808980863578808780913577809180833396809280893395809080853397809480963354809580993353809381023355809780933523809881043525809681003524810080943694810180983696809981033695810380958104810181028097810681083693810781113692810581143691810981058110811681088112811281068119811381108118811181158117811581072386811681132385811481092384811881208113811981238112811781268111812181172383812281282382812081242381812481188125812281238127812781193744812881253743812681213742813081323028813181353030812981383029813381298143813481408142813281368141813681304162813781344161813581394160813981312975814081372974813881332976814281448134814381478133814181508132814581418177814681538176814481568175814881428166814981588168814781518167815181433207815281493209815081543208815481453896815581523898815381573897815781463883815881553885815681483884816081632992816181662991816281692994815981722993816481593210816581743212816381673211816781608147816881658149816681708148817081613880817181683882816981733881817381623220817481713222817281643221817681788146817781818145817581848144817981753856818081863855817881823854818281763941818381803943818181853942818581774159818681834158818481794157818881915735818981945738819081975737818782005736819281875857819382025859819181955858819581885822819681935824819481985823819881895812819981965814819782015813820181908210820281998212820081928211820482076035820582106034820682136037820382166036820882035860820982185862820782115861821182048200821282098202821082148201821482055809821582125811821382175810821782065841821882155843821682085842822082228343822182268342821982308341822382191682822482331681822582351680822282271679822782208228822582298234822682318231822182498232822982488233823682518230822382508235822882368224823482328238824083158239824483148237824883138241823782608242825182598243825282628240825682618245823883228246825883258247825483248244824983238249823982318250824782308251825382338248824182328253824217588254825017618255824617608252825717598257824383828258825583818256824583838260826382418261826782408262827082438259827382428264825982658276826682778263826882688260831782698266831682678280831882718261839282728279839182708274839082748262177282758272177582768278177482738264177382788265828282798275828182808271828482778269828382828285827882838289827782848293828082818296827982868281181882878298182182888299182082858290181982908282219829182882188292830221782898294220829482838308829582928307829383018309829782848389829883008388829682868387830082878328830182978327830282958326829982918329830483078305831083068313830383168308830382948309831882938307831182958311830483218312830983208310831483198314830582398315831282388313831782378317830682688318831582678316830882698320832283128321832683118319833083108323831982448324833382478325833482468322833882458327832083018328834083008329833682998326833183028331832115583328329154833383351538330832315683358324837083368332837383378328837283348339837183398325838583408337838483388327838683428344822183438348822083418352821983458341158834683551578347835716083448349159834983428350834783518356834883538353834322338354835122368355835822358352834522348357835083588346835683548360836217638361836617628359837017648363835926483648373263836583752668362836726583678360180683688365180583698374180483668371180383718361833483728369833783738376833683708363833583758368182383768364182283748372182483788381179883798384179783808387179683778390179583828377825783838392825683818385825883858378833983868383833883848388834083888379829883898386829783878391829683918380827283928389827183908382827083948396165839584011678393840516683978393267839884092718399841027084008413269839684022688402839418448403840018438404841618428401840618458406839565840784046984088415688409841167840583976684118398132618412840813260841084141326284148399190584158412190484168407190784138403190684188420198284198424198184178428198384218417202842284312018423843320484208425203842584181958842684231957842784321956842484291955842984198198430842782284318434821842884218208433842689684348422895843284308948436843884378442843584468439843520678440844920668441845120698438844320688443843684448441844584508442844784478437101438448844510142844984521014184468439101448451844463584528440637845084486368454845610196845584601019884538464101978457845366284588467661845984696608456846165984618454846284598463846884608465846584558473846684638472846784708471846484578474846984628470845884688466847284758466847384808465847484858464847184908467847684718477849484788495847985008475848184818472848284798483850484848505848084868486847310202848784841020684888508102058489850910204848584911020384918474710849284897148493851271384948496712849084767118496847785408497849385448498851185438499851385428495850185418501847810358850284991035785038516103568504850610355850084821035985068483102578507850310260850885151025985058487102588510848810677851185141067685128497106758509849210674851484981039285158510103918516850710390851385021038985188522851985278520853185218534851785408523851773385248544737852585457368526855273585228528734852885189605852985269604853085549603852785329602853285199584853385309583853185559582853585208765853685578770853785588769853885498768853985488767853485418766854185218495854285398499854385478498854485468497854085238496854685248596854785438602854885428601854985388600855085378599855185618598854585628597855385259609855485649611855285299610855685338797855785598796855585358795855985368706856085568709856185638708855885508707856385518627856485608629856285538628856685681064585678571106448565857610646856985651062385708580106258568858410624857285667238573858972285748590726857585967258571857772485778567106838578857510682857986021068585768603106848581856910492858286061049185838607104908580858510493858585701054385868583105428587860910541858886101054085898591105398584857210538859185738668859285888667859386138672859486148671859585988670859085978669859785748545859885958551859985948550860086168549860186178548860286048547859685788546860485791039586058601103948606862010393860385811039686088582107078609862110709860785861070886118587984486128623984386138624984286108592984586158593979186168626979386148599979286188600981486198625981786208622981686178605981586228608129038623861912905862186111290486258612983186268618983086248615983286288630856286298634856486278638856386318627868786328641868686338643868586308635868486358628962086368633962386378642962286348639962186398629871586408637871486418644871386388631871686438636965486448632965686428640965586468649107718647865610770864886621076986458667107728650864593698651867293688652867193678653867393668654867793658655865893648649865793708657864697478658865597468659865497458660868097448661868197498656866397488663864777286648661771866586837708666868476986628668773866886488591866986668590867086878595867186748594867286518593866786508592867486528702867586708705867686868704867386788703867886539669867986769672868086889671867786599670868286601078486838690107838681866410782868586658633868686898632868786758631868486698630868986799659869086859658868886829657869286958722869386988721869487028720869187068723869686918802869787098801869587108803869986929673870087129676870187139675869887039674870386938673870487018676870587168675870287078674870786948558870887058561870987158560870686968559871186971006787128714100668710869910065871487008640871587118639871687088638871387048641871887209391871987249393871787289392872187178693872287318692872387338691872087258694872587188773872687238772872787328771872487298774872987198845873087278844873187348843872887218846873387268814873487228813873287308815873687388821873787428820873587478819873987358935874087508938874187548937873887438936874387368744874187458759874687608742876587488737881187498770881087478771881287518739947387528774947287538775947187508755947487558740949687568753949587578778949487588779949387598761949887548744949787618745103708762875810369876387811036887648782103728760876610371876687468534876787648539876887858538876987868537877087728536876587488535877287498726877387698725877487888724877187518727877687529942877787899941877887929940877587569943878087571300787818794130068779876213008878387639802878487939801878587919800878287679803878787689790878887909789878687739788879087761304487918787130438789878413042879387771303287948783130318792878013030879687988557879788018556879588048555879987958807880088068809879888028808880287968696880388008695880188058697880587979572880688039571880487999570880888108798880988138800880788168799881188078748881288188747881088148749881488088733881588128732881388178734881788098836881888158835881688118834882088228737882188258736881988288735882388198831882488308833882288268832882688208827882488258829882988218922883088278921882888238920883288348822883388378824883188408823883588318818883688428817883488388816883888328877883988368876883788418875884188338868884288398867884088358866884488478730884588508729884688548728884388578731884888438863884988608865884788518864885188449470885288499469885388629468885088559467885588459415885688539414885488589413885888469441885988569440885788619442886188488973886288598975886088528974886488668847886588698849886388728848886788638842886888748841886688708840887088648918887188688917886988738919887388658892887488718891887288678890887688788839887788818838887588848837887988758887888088868889887888828888888288769565888388809564888188859566888588778886888388848879888888908878888988938880888788968879889188878874889289008873889089048872889488889545889589079544889388979543889788898898889588998910889689018901889189478902889989508903891389498900890589488905889289688906890389678904891489698908889499768909891699758907891199748911889890708912890990698913891590688910890290678915890699858916891299848914890899838918892088708919892388698917892788718921891788308922893188298920893588288924891894758925893894788926893994778923892894768928891989438929892689468930894289458927893289448932892189338930893489418931893689368922873889378934874189388940874089358924873989408925915589418937915489428933915389398929915689448947892789458951893089468955892989438959892889488943890089498962890389508965890289478952890189528944895389508954896489518956895689459126895789549125895889639124895589609127896089468980896189588979896289668982895989488981896489579044896589539043896689499042896389619041896889708905896989738904896789768906897189678991897289788993897089748992897489688860897589728862897389778861897789699453897889759452897689719454898089838960898189878959898289918962897989948961898489799129898589979128898689989131898389889130898889809465898989869464899090019463898789929466899289818970899389908972899190028971899589829018899690049017899789999016899489849019899989859385900089969384900190039387899889899386900389939427900490009426900289959425900690099160900790139159900890169158900590209157901090059192901190259191901290269190900990329189901490069325901590359324901390389326901790078996901890408995901990418994901690218997902190089091902290199096902390449095902490459094902590279093902090109092902790119028902490299050903090519031905490269057903390121316090349059131599032903613158903690141314490379034131439035906013142903990159419904090649421903890179420904290188966904390678965904490468964904190228963904690239047904390489070904990719050905290459028905290291097390539049109729051907410971905590301092590569077109249054905810926905890311316190599056131639057903313162906190379710906290799713906390809712906090659711906590399991906690639990906490689989906890428913906990668912907090828911906790478910907290481095590739081109549071907510953907590531094590769073109449074907810943907890551092090799076109199077906110918908190629952908290729951908090699953908490879174908590919173908690979176908391049175908890839203908991089202909091129201908790929200909290849020909390909025909491179024909591189023909691249022909191289021909890859383909991319382910091329381910191369380910291429379910391439378909791059377910590861276191069103127649107914812763910491091276291099088128429110910712841911191471284491089113128439113908991149111911591469116914991179119911290939119909491209116912191529122913991239153911891259125909589579126912389569127915689559124912989589129909689849130912789839131913389869128909889859133909994599134913094629135915594619132913794609137910095169138913595229139915495219140912195209141915195199142914495189136910195179144910211155914591411115491469150111539147911411152914891101115191439106111569150911511332915191451133191529140113309149912011333915491228941915591388940915691348939915391268942915891619008915991649007916091679006915791709005916291579177916391729179916191659178916591589334916691639336916491689335916891599254916991669256916791719255917191609222917291699224917091629223917491779084917591809083917691839086917391869085917891739161917991889163917791819162918191749219918291799221918091849220918491759235918591829237918391879236918791769337918891859339918691789338919091939012919191969011919292009010918992049009919491891315391959207131529193920813154919791909198921091999211919692019201919190909202919990899203921490889200920590879205919292169206920392159207921392189204919492179209919513094921092121309392089197130959212919813080921392091307992149206130789211920213077921692199205921792229204921892259207921592289206922092159180922192309182921992239181922392169170922492219172922292269171922692179251922792249253922592299252922992189238923092279240922892209239923292359265923392389264923492419263923192449266923692319183923792469185923592399184923992329228924092379230923892429229924292339260924392409262924192459261924592349340924692439342924492369341924892519315924992549314925092579313924792609312925292479225925392629227925192559226925592489167925692539169925492589168925892499331925992569333925792619332926192509241926292599243926092529242926492679233926592709232926692739231926392769234926892639281926992789280926792719279927192641283892729269128409270927412839927492651276592759272127679273927712766927792661275292789275127549276926812753928092829269928192859268927992889267928392791283092849291128299282929412831928692801275192879296127509285928912749928992819297929092879299928892929298929292831271792939290127169291929512715929592841278892969293127879294928612789929893009288929993039290929793069289930192979309930293089311930093049310930492981272793059302127299303930712728930792999345930893059344930693019343931093129300931193169302930993209301931393099250931493239249931593259248931293179247931793101314893189315131479319932413146931693211314593219311934693229319934993239326934893209313934793259318901493269314901393249322901593289331935793299334936093309337935993279340935893329327925793339342925993319335925893359328916493369333916693349338916593389329918693399336918893379341918793419330924493429339924693409332924593449346930893459350930793439353930693479343932093489357932393499361932293469364932193519344126999352937012698935093711269793549345127459355937612748935693771274793539358127469358934793279359935693309360938393299357938493289362934894229363938794249361938894239365934986549366939086539367939186529368939486519369939786509370937286499364935186559372935210750937393691074993749400107489375940110747937693781074693719354107519378935591039379937591029380940491019381940591009382940990999383938590989377935990979385936089999386938289989387941290019384936290009389936394319390941394339388936594329392936687179393941587199391939587189395936797869396939397859394941697879398936898569399941898599400940298589397937398579402937412684940393991268394049406126829401937912681940693809944940794039947940894179946940594109945941093819455941194089458941294149457940993869456941493898856941594118855941393928854941793969885941894079887941693989886942094229038942194259040941994289039942394199361942494309363942294269362942694209004942794249003942594299002942994219448943094279447942894239446943294349388943394379390943194409389943594319443943694429445943494389444943894329664943994369663943794419665944194338858944294398857944094358859944494469434944594499436944394529435944794439430944894549429944694509428945094449994945194489993944994539992945394458977945494518976945294478978945694599409945794639412945894679411945594719410946094559132946194749135946294779134945994649133946494568989946594628988946694768987946394688990946894578853946994668852947094758851946794728850947294588752947394708751947494788750947194608753947694698923947794658926947894618925947594738924948094821301194819485130109479948913009948394791300394849493130059482949913004948694801261994879503126189488950412617948595121262094909481992994919515993294929516993194899494993094949483875794959492875694969522875594979521875494989523875994939528875895009484103269501953110325950295321032495039505103239499948610322950594871119195069502111909507953611189950895371118895099542111879510954111194951195181119395049513111929513948812665951495111266895159517126679512949012666951794919136951895149142951995109141952095409140952195249139952294969138951694959137952494979525952095269539952795349523952995299498103679530952710366953195331036595289500103649533950195349530953595269536953895329506953895071124995399535112489540952511247954195191125295429509112519537950811250954495468895954595498894954395528893954795439548955495469550955095441000195519548100039549955310002955395459557955495519556955295479555955695589554955795619553955595649552955995559560956695589562956295569569956395609568956195659567956595578882956695638881956495598883956895709563956995739562956795769561957195678806957295788805957095748804957495689580957595729579957395779581957795691006895789575100709576957110069958095829574958195859573957995889575958395798533958495908532958295868531958695809587958495859589958995819592959095879591958895839593959295949589959395989588959196029590959595919596960595979607959495999599959210082960095971008596019606100849598960310083960395938530960496018529960596088528960295958527960796007529608959675496069604753961096128552961196168554960996208553961396097519614962375096159625749961296177489617961010081961896151008096199624100799616962110078962196118634962296198637962396268636962096138635962596189629962696149628962496229627962896309626962996339625962796369624963196279639963296389641963096349640963496287689635963276796339637766963796291005096389635100499636963110048964096429630964196459632963996489631964396399651964496509653964296469652964696401078896479644107909645964910789964996411003096509647100299648964310028965296549642965396579644965196609643965596518642965696628644965496588643965896528690965996568689965796618688966196539685966296599684966096559686966496669438966596699437966396739439966796639987966896779986966696809988967096648677967196838680967296848679966996748678967496658698967596728701967696868700967396878699967896679982967996899981967796819980968196689709968296799708968396909707968096709706968596719661968696929660968496759662968896761001296899691100119687967810010969196821002096929688100199690968510021969496961082996959700108289693970310827969796939727969897069730969997109729969697019728970196941088097029699108799700971410881970496951082197059717108239703970710822970796979683970897059682970997209681970697119680971196989060971297099063971397199062971097159061971597021090997169713109119714971810910971897049960971997169959972097129958971797089961972297241083797239727108369721973110838972597211084897269734108509724973710849972897229696972997399699973097409698972797449697973297231079897339749107979731975010799973597251109597369754110949734975511096973897261087397399761108759737972810874974197291313397429764131329743976713135974097451313497459730865997469743865897479770865797489773865697499751866197449732866097519733800975297487999753977780397549756802975097358019756973697579753975897769759977897609782975597629762973810927976397601092997619784109289765974113127976697831312697649781131289768974212735976997801273497679771127339771974612703977297691270597709774127049774974710767977597721076697769779107659777975710764977397521076897799758111239780977511126978197681112597789766111249783975913172978497651317197829763131709786978893959787979193949785979493969789978587889790979687879788979287869792978686149793979086169791979586159795978798749796979398739794978998759798980013035979998041303497979807130339801979787849802980987839803981087829800981487859805979898289806981798279804981898299808979913028980998211302798079801130299811980210293981298231029298139824102959810981510294981598038617981698138620981798198619981498058618981998061290898209816129079818982612906982298081298398239825129829821981112984982598121291198269822129109824982012909982898309805982998339804982798369806983198278625983298388624983098348626983498289869983598329868983398379867983798299841983898359840983698319839984098429838984198469837983998499836984398398612984498518611984598528610984298568613984798409882984898599884984698609883985098411290198519864129009849984312902985398441056998549866105689855986210567985298571056698579845939798589855940098599861939998569847939898619848989198629858989498639854989398609865989298659850128789866986312877986498531287698689870983598699873983498679876983398719867987998729878988198709874988098749868979598759872979498739877979698779869130399878987513041987698711304098809882987098819885987298799888987198839879984698849890984898829886984798869880941698879884941898859889941798899881995098909887994998889883994898929895986098939898986398949901986298919904986198969891991198979906991398959899991298999892126599900989712661989899021266099029893128649903990012866990199051286599059894126919906990312693990498961269299089911993699099914993599109917993499079920993399129907989599139922989799119915989699159908126889916991312690991499181268999189909126729919991612674991799211267399219910126629922991912664992099121266399249926130139925992913012992399331301499279923130249928993713026992699401302599309924948999319943949299329944949199299934949099349925991099359932990999369947990899339948990799389927130369939995013038993799411303799419928877799429939877699439945877599409930877899459931940599469942940899479949940799449935940699499936989099509946988999489938988899529954908199539958908099519962908299559951109609956996510963995799681096299549959109619959995297199960995797189961997097179958996397209963995399719964996199739962996699729966995511102996799641110199659969111009969995611050997099671104999689960110519972997499629973997799649971998099639975997189099976998289089974997889079978997299979979997699969977998199959981997396799982997996789980997596779984998689169985998989159983999289149987998396679988999496669986999096689990998490669991998890659989999390649993998594519994999194509992998794499996999899799997100019978999510004997799999995100071000010006100099998100021000810002999695491000310000955110001100059550100059997111081000610003111071000499991110610008100109998100091001310000100071001699991001110007968910012100189688100101001496871001410008100611001510012100601001310017100591001710009100331001810015100321001610011100311002010022969110021100259690100191002896921002310019100341002410030100361002210026100351002610020108201002710024108191002510029108181002910021965010030100279649100281002396481003210034100181003310037100171003110041100161003510031100221003610044100241003410048100231003810032100741003910050100771004010051100761003710055100751004210033110991004310058110981004110045110971004510035110421004610043110411004710057110401004410053110391004910036963810050100529637100481003896361005210039744100531004974710054100477461005110056745100561004010057100541005810046100551004210060100621001510061100651001410059100681001310063100591007110064100701007310062100661007210066100608712100671006487111006510069871010069100619576100701006795781006810063957710072100741006210073100781006410071100821006310075100711003710076100851004010077100871003910074100791003810079100729619100801007796181008110086961710078100839616100831007395981008410081960110085100889600100821007595991008710080742100881007674110086100847431009010093860100911009785910092101028581008910106861100941008910095101091009610110100931009810098100908071009910096806101001011480510101101138041009710103808101031009110130101041010110129101051011210128101021010710131101071009210108101051010910111101061009410111100951073610112101081073510113101041073910114101001073810110100991073710116101211051110117101271051010118101281050910119101321050810120101371050710115101221051210122101156961012310120695101241014069410125101417001012610145699101271012969810121101166971012910117101041013010126101031013110148101021012810133101051013310118101341013110135101471013610143101321013810138101191013910136101401014210137101231014210124844810143101398447101441013584461014110146844910146101258481014710144847101481013484610145101308451015010152101771015110157101761014910162101751015310149102071015410165102111015510166102101015610169102091015210158102081015810150101591015610160101711016110172101571016310163101516701016410161669101651016767210162101536711016710154106531016810164106551016610174106541017010155102341017110173102331016910159102321017310160105951017410170105941017210168105961017610178101511017710181101501017510184101491017910175665101801018666410178101826631018210176101831018010181101851018510177101921018610183101911018410179101901018810190667101891019366610187101966681019110187101861019210198101851019010194101841019410188102011019510192102001019310197101991019710189845310198101958455101961019184541020010202101951020110207101941019910212101931020310199848510204102158489102051021684881020610220848710202102088486102081020010152102091020610156102101022210155102111021810154102071021310153102131020168510214102116841021510217687102121020368610217102041070310218102141070210219102101070110216102211070010221102051023510222102191023710220102091023610224102261024710225102291024610223102321024510227102231026510228102351026410226102381026610230102241042510231102401042410229102331042310233102251017110234102311017010232102361016910236102271022010237102341022210235102391022110239102281041410240102371041310238102301041510242102451024310248102441025110241102541024610241102251024710256102241024510249102231024910242102611025010247102631024810252102621025210243102861025310250102881025110255102871025510244104261025610253104281025410246104271025810261850510259102648508102601026785071025710270850610262102571024810263102721025010261102651024910265102581022710266102631022610264102681022810268102591041010269102661041210267102711041110271102601027710272102691027910270102621027810274102771033210275102801033510276102831033410273102861033310278102731027010279102881027210277102811027110281102741040710282102791040910280102841040810284102751042910285102821043110283102871043010287102761025110288102851025310286102781025210290102921297710291102961297610289103001297810293102899811102941030398101029510309981310292103139812102971029012941102981031512940102991031612939102961032212942103011029113000103021032613002103001030413001103041029310353103051030210352103061032510351103071032710350103081033210349103031031010354103101029410380103111030810379103121033510378103091033610377103141029512918103151033912920103131029712919103171029810524103181034110523103191034210522103201034510521103211032910520103161032310525103231029995031032410321950210325103289501103261030595001032210301949910328103061032910324103301032010331103481032710333103331030710273103341033110276103351034710275103321031110274103371031210480103381034310479103361034010481103401031410711103411033810710103391031710712103431031810463103441033710462103421034610461103461031910452103471034410451103481033410450103451033010449103501035510307103511036010306103521036410305103531036810304103541037210303103491035610308103561034985031035710354850210358103718501103591037385001035510361850410361103501036210359103631037610360103651036510351953110366103639530103671037595291036410369952810369103528762103701036787611037110374876010372103578764103681035387631037410358103751037010376103661037310362103781038110312103791038510311103801038910310103771039310309103821037710486103831039610489103841039710488103811038610487103861037810403103871038410406103881039910405103851039010404103901037985161039110388851510392104008514103891039485131039410380860510395103928604103961040286031039310382860610398103831069010399104011068910397103871069110401103911068710402103981068610400103951068810404104071038510405104101038810406104131038710403104161038610408104031028010409104181028210407104111028110411104041026710412104091026910410104141026810414104051023910415104121023810413104171024010417104061043210418104151043410416104081043310420104231044510421104261044810422104291044710419104321044610424104191023110425104341023010423104271022910427104201025410428104251025610426104301025510430104211028310431104281028510429104331028410433104221041610434104311041810432104241041710436104381058610437104421058510435104451058710439104351044010448104411044910438104531044310436105771044410456105761044210457105781044610437104191044710460104221044810450104211044510439104201045010440103481045110447103471045210459103461044910454103451045410441105161045510452105191045610458105181045310443105171045810444104661045910455104651046010451104641045710446104671046210464103441046310468103431046110472103421046510461104591046610475104581046710477104571046410469104601046910462104821047010467104851047110476104841046810473104831047310463105541047410471105531047510478105521047210465105511047710470106171047810466106161047610474106181048010482103371048110486103361047910490103381048310479104681048410493104711048510495104701048210487104691048710480103811048810485103841048910494103831048610491103821049110481858210492104898581104931049685801049010483858310495104881062610496104841062810494104921062710498105031049910507105001051310501105161050210520104971052610504104971050510531105061053210503105081050810498101191050910506101181051010537101171051110538101161051210544101151050710514101201051410499106671051510512106661051310548106651051710500104531051810550104561051910551104551051610521104541052110501103201052210519103191052310554103181052410555103171052510558103161052010527103211052710502112251052810525112241052910561112291053010562112281053110533112271052610504112261053310505107401053410530107451053510565107441053610566107431053710539107421053210509107411053910510858910540105368588105411056985871054210556858610543105538585105381054585841054510511106221054610543106211054710552106201054410549106191054910515105751055010547105741054810517105731055210518104751055310546104741055410542104731055110522104721055610523107141055710541107131055510570107151055910524126041056010572126031056110563126021055810528126011056310529128601056410560128591056510567128581056210534128571056710535985510568105649854105691057198531056610540985210571105571287410572105681287310570105591287510574105761055010575105791054910573105821054810577105731044310578105841044210576105801044410580105741061110581105781061010579105831060910583105751060210584105811060110582105771060010586105881043610587105911043510585105941043710589105851059710590105961059910588105921059810592105861059310590105911059510595105871017310596105931017210594105891017410598106001058810599106031059010597106061058910601105971058410602106081058310600106041058210604105981066110605106021066010603106071065910607105991065210608106051065110606106011065010610106121058110611106161058010609106191057910613106091063210614106221063510615106231063410612106261063310617106101047710618106281047610616106201047810620106111054710621106181054610622106241054510619106131054410624106148568106251062185701062310627856910627106151049410628106251049610626106171049510630106321064710631106361064910629106401064810633106291061210634106431061510635106451061410632106371061310637106307181063810635721106391064472010636106417191064110631106991064210639106981064310646106971064010633106961064510638856610646106348565106441064285671064810650106291064910653106311064710656106301065110647106081065210658106071065010654106061065410648101661065510652101681065310657101671065710649689106581065568810656106516901066010662106051066110665106041065910668106031066310659692106641067069110662106666931066610660105151066710664105141066510669105131066910661106701066710668106631067210674738106731067874010671106827391067510671851210676106858511106771068785101067410679850910679106721069410680106771069310681106861069210678106831069510683106738577106841068185761068510688857910682106758578106871068010401106881067610400106861068410402106901069210398106911069610397106891070010399106931068910680106941070310679106951070510678106921069710681106971069010643106981069510642106991070410641106961070110640107011069110219107021069910218107031070610217107001069310216107051069871710706106947161070410702715107081071086071070910713860910707107168608107111070710340107121071810339107101071410341107141070810556107151071210555107131071710557107171070912892107181071512891107161071112893107201072310721107291072210735107191074010724107191113710725107451114210726107461114110727107521114010728107561113910723107301113810730107201073110728107321075910733107601073410764107291073610736107211011110737107341011010738107681011410739107691011310735107411011210741107221053210742107391053710743107721053610744107481053510745107471053410740107241053310747107259375107481074493741074910743937310750107719372107511077393711074610753937610753107261277710754107511278010755107761277910752107571277810757107271304510758107551304810759107611304710756107311304610761107321112710762107581113010763107781112910760107651112810765107339776107661076397751076710774977410768107709773107641073797771077010738864710771107678646107721074986451076910742864810774107501270010775107661270210773107771270110777107541271010778107751270910776107621271110780107827981078110785797107791078879610783107798683107841079086821078210786868110786107801079310787107841079210785107891079110789107819645107901078796471078810783964610792107941078710793107971078610791108001078510795107911080310796108021080510794107981080410798107929732107991079697311079710801973310801107938181080210799817108001079581610804108061079410805108091079610803108121079510807108031081510808108141081710806108101081610810108041083110811108081083010809108131083210813108051086510814108111086410812108071086610816108181080610817108211080810815108241080710819108151002710820108261002610818108221002510822108169703108231082097051082110825970410825108171105410826108231105310824108191105210828108309695108291083396941082710836969310831108271081010832108381080910830108341081110834108281084010835108321083910833108371084110837108299722108381083597211083610831972310840108421083410841108451083310839108481083510843108391086110844108511086310842108551086210846108401087810847108581087710845108491087610849108419724108501084797261084810852972510852108431108510853108501108410854108601108310851108561108210856108441106610857108541106510855108591106410859108461088510860108571088710858108531088610862108641084210863108671084410861108701084310865108611081310866108721081210864108681081410868108621104510869108661104410867108711104310871108637941087210869793108701086579510874108769737108751087997391087310882973810877108731084710878108841084610876108801084510880108749701108811087897001087910883970210883108751090210884108811090110882108771090010886108881085810887108911086010885108941085910889108851089710890108961089910888108921089810892108861089310890108911089510895108871093810896108931093710894108891093610898109001088810899109031089010897109061088910901108971088410902109081088310900109041088210904108981092310905109021092210903109071092110907108991091410908109051091310906109011091210910109129714109111091597161090910918971510913109091090810914109201090710912109161090610916109101093410917109141093310915109191093510919109119079109201091790781091810913907710922109241090510923109271090410921109301090310925109219055109261093290541092410928905610928109229761109291092697631092710931976210931109231093210929109301092510934109361091610935109391091510933109431091710937109331089610938109461089510936109501089410940109341095910941109521095810942109481095710939109441095610944109359076109451094290751094310947907410947109371097510948109451097410949109411097710946109511097610951109381105710952109491105610950109401105510954109569073109551096090721095310964907110957109531094210958109671094110959109691094010956109611093910961109549954109621095999571096310968995610960109659955109651095510966109631096710970109641095710969109621104710970109581104610968109661104810972109749053109731097890521097110982905110975109711094710976109851094610977109871094910974109791094810979109721098010977109811098610978109831098310973109841098110985109881098210975109871098010989109881097610991109861098410990109901099210986109911099510988109891099810987109931098910994110001099210996109961099010997109941099510999109991099111003110001099711002109981099311001110021100411000110031100710999110011101010998110051100111013110061101211015110041100811014110081100211069110091100611068110071101111067110111100311061110121100911063110101100511062110141101611004110151101911006110131102211005110171101311018110241101611020110201101479111021110187901101911023792110231101511026110241102111025110221101711027110261102811023110271103211022110251103511024110291102576411030110387631103111039762110281104376511033110261106011034110451105911032110461105811036110271103711048110381104011035110291104011030100471104111037100461104211049100451103911052100441104411031108691104511054108681104311033108671104711034109691104811050109681104611036109701105011041996911051110479968110491105399701105311042108261105411051108251105211044108241105611058109521105711061109511105511064109501105911055110341106011066110331105811062110321106211056110101106311060110121106111065110111106511057108571106611063108561106411059108551106811070110091106911073110081106711076110071107111067110791107211078110811107011074110801107411068815110751107281411073110778131107711069110781107511076110711108011082110701108111086110721107911090110711108311079108541108411093108531108511095108521108211087108511108711080812110881108581111089110948101108611091809110911108111092110891109311096110901108311095110889735110961108497341109411092973611098111001004311099111031004211097111061004111101110979967111021110899661110011104996511104110981110511102111031110711107110991000611108111051000511106111011000411110111121309711111111161309611109111201309811113111091111411123111151112711112111171111711110127961111811115127951111911130127941111611131127931112111111131201112211134131221112011124131211112411113977811125111229781111261113697801112311128977911128111141076011129111261076311130111321076211127111181076111132111191271911133111291271811131111351272011135111211274111136111331274011134111251273911138111431072311139111471072811140111511072711141111561072611142111551072511137111571072411144111371114511162111461116311143111481114811138111491114611150111681114711152111521113991471115311150914611154111679145111551115891441115611141914311151111409148111581114211197111591115411196111601116611195111611116511200111621116411199111571114411198111641114511359111651116111358111661116011357111671115911362111681115311361111631114911360111701117312072111711117912071111721118312074111691118712073111741116911852111751119411851111761119511856111771120111855111781120511854111731118011853111801117012046111811117812045111821120812048111791121412047111841117111995111851121711994111861121811993111831118811996111881117295081118911186950711190112239506111911122495051119211229950411193112289511111941119695101118711174950911196111751115911197111931115811198112271115711199112301116211200112361116111195112021116011202111761163311203112001163211204112391163111201112061163011206111771161911207112041161811205112401161711209111811152311210112421152211211112431152111212112331152011213112201151911208112151151811215111821203411216112131203711217112191203611214111841203511219111851122011216112211121211222112321122311225112181118911225111901052711226112221052611227112311053111228111971053011229111921052911224111911052811231111981123211226112331122111234112111123511246112301123711237111991145711238112351146011239112451145911236112031145811241112071156511242112441156411240112091156311244112101149811245112411149711246112381149611243112341149511248112539539112491125795381125011264953711251112689542112521127295411124711277954011254112471125511281112561128211253112581125811248112591125611260112871126111288112621129111263112941125711265112651124912009112661126312012112671129712011112641126912010112691125011904112701126711903112711130011902112681127311901112731125111829112741127111828112751130311827112761130411826112721127811830112781125211325112791127611329112801130811328112811128311327112771125411326112831125511284112801128511307112861130911287112891128211259112891126012427112901128612426112881131312425112921126112184112931131612183112911129512185112951126212196112961129312195112941129812197112981126612597112991129612596112971130112595113011127011929113021129911928113031131911927113001127411930113051127511422113061132111421113071131011420113081128411424113041127911423113101128512365113111130612364113121132212363113091131412366113141129012397113151131212396113131131712395113171129212385113181131512384113161132412383113201130212324113211132312323113191130512322113231131112341113241132012340113221131812342113261133011277113271133411281113281133811280113291134211279113251134611278113311132591511133211345915011333113479149113301133591521133511326113361133311337113501133411339113391132711340113371134111349113381134311343113281138911344113411138811345113481138711346113311138611342113291139011348113321134911344113501134011347113361135211354116391135311357116381135111363116401135511351116571135611368116561135411372116581135811352111651135911375111641136011376111631136111382111681136211386111671135711364111661136411353118341136511362118331136611390118321136711391118311136311369118351136911355117011137011367117001137111395116991136811400117021137311356114561137411403114551137511377114541137211358114531137711359113781137411379114021138011398113811140411376113831138311360113841138111385114081138211387113871136111345113881138511344113891140711343113901139211342113861136511346113921136611450113931138911449113941140611452113911139611451113961137011747113971139411751113981140511750113991137911749113951140111748114011137111718114021139911721114031137811720114001137311719114051138011406113971140711393114081138811404113841141011413123601141111417123591141211420123621140911425123611141411409124971141511429124961141611430124951141311436124981141811410124991141911439125011141711440125001142111411113061142211442113051142311443113041142411449113081142011426113071142611412114271142411428114521142911431114251141411431114151173611432114281173511433114511173411434114471173311435114461173811430114371173711437114161226711438114351226611439114451226511436114181226811441114191231411442114441231311440114211231511444114221181211445114411181111446114381181011447114341180911448114331181411443114501181311450114231139211451114481139111452114321139411449114271139311454114571137511455114611137411456114651137311453114691137211458114531123611459114721123911460114751123811457114621123711462114541146311460114641147411461114661146611455117171146711464117161146811473117151146511470117141147011456116541147111468116531147211476116521146911458116551147411467114921147511463114911147611459114941147311471114931147811480125601147911484125591147711488125611148111477114821149111483114951148011485114851147811545114861148311544114871149811543114841149911546114891147911803114901150211805114881149211804114921148111474114931149011473114941150411476114911149611475114961148211246114971149411245114981150011244114951148611243115001148711570115011149711569114991150311571115031148911600115041150111599115021149311601115061150912026115071151312025115081151812024115051152412023115101150512090115111152812093115121153212092115091151412091115141150611515115121151611537115171153811513115191151911507112131152011517112121152111542112111152211543112101152311547112091151811525112081152511508120621152611523120611152711550120641152411529120631152911510122911153011527122901153111553122891152811533122881153311511125161153411531125151153511556125201153611557125191153711539125181153211515125171153911516115401153611541115601154211544115381152011544115211148611545115411148511546115621148411543115481148711548115221156611549115461156811547115511156711551115261157611552115491157511550115541157711554115301187811555115521188111556115581188011553115341187911558115351257011559115551256911557115611256811561115401255311562115591255511560115451255411564115661124211565115691124111563115721124011567115631154711568115741154911566115701154811570115641150011571115681149911569115731150111573115651159211574115711159111572115671159011576115781155111577115811155011575115841155211579115751158711580115861158911578115821158811582115761186311583115801186211581115851186111585115771167311586115831167511584115791167411588115901157811589115931158011587115961157911591115871157411592115981157311590115941157211594115881161311595115921161211593115971161111597115891160411598115951160311596115911160211600116021150311601116051150211599116081150411603115991159811604116101159711602116061159611606116001167011607116041167211605116091167111609116011164311610116071164211608116031164111612116141159511613116171159411611116201159311615116111162311616116221162511614116181162411618116121120711619116161120611617116211120511621116131186511622116191186411620116151186611624116261161411625116301161611623116341161511627116231164411628116371164711629116391164611626116311164511631116241120411632116291120311633116381120211630116351120111635116251185911636116331185811637116401185711634116271186011639116321135211640116281135111638116361135311642116441161011643116481160911641116521160811645116411162611646116551162911647116571162811644116491162711649116421168311650116471168611651116561168511648116531168411653116431147111654116511147011655116581146911652116451147211657116501135511658116461135411656116541135611660116621180611661116661180811659116701180711663116591187211664116731187111665116761187011662116671187311667116601168211668116651168111669116781168011666116711167911671116611160511672116691160711670116741160611674116631158411675116721158611673116771158511677116641184011678116751184211676116681184111680116831166911681116871166811682116911166711679116951166611684116791164811685116981165111686117011165011683116881164911688116801183911689116861183811690117001183711687116921183611692116811173011693116901172911694116991173211691116961173111696116821170411697116941170311698117021170611695116841170511700116931137011701116891136911702116851136811699116971137111704117071169611705117111169511706117141169811703117181169711708117031174311709117211174611710117221174511707117261174411712117041180111713117281180011711117151180211715117051146811716117131146711717117241146611714117191146511719117061140011720117171140311721117231140211718117081140111723117091172411720117251171611722117271172711710117821172811725117841172611712117831173011733116921173111739116911173211743116941172911747116931173411729114331173511751114321173611752114311173711756114301173811761114351173311740114341174011730118751174111738118741174211760118771173911762118761174411731117071174511765117101174611768117091174311748117081174811732113951174911746113991175011772113981175111753113971174711734113961175311735117541175011755117711175211757117571173612526117581175512525117591177012524117601176312523117611174112522117561173712521117631174212573117641175912572117621176612571117661174411775117671176411774117651176911773117691174511770117671177111758117721175411768117491177411776117671177511779117661177311782117651177711773117781178411776117801178011774117871178111778117861177911783117851178311775117261178411781117281178211777117271178611788117811178711791117801178511794117791178911785117971179011796117991178811792117981179211786125641179311790125631179111795125621179511787125661179611793125651179411789125671179811800117881179911803117901179711806117891180111797117121180211808117111180011804117131180411798114881180511802114901180311807114891180711799116591180811805116611180611801116601181011815114461181111818114451181211822114441181311826114431181411831114481180911836114471181611809118681181711840118671181511819118691181911810123041182011817123031182111843123021181811823123051182311811119201182411821119231182511847119221182211827119211182711812112751182811825112741182911850112731183011851112721182611832112761183211813113661183311830113651183411856113641183511857113631183111837113671183711814116901183811835116891183911860116881183611841116871184111816116761184211839116781184011861116771184411820120511184511863120501184611853120491184311848120521184811824118881184911846118871185011852118861184711828118851185211829111741185311849111731185411845111781185511864111771185611858111761185111833111751185811834116361185911855116351186011866116341185711838116371186211842115831186311865115821186111844115811186511854116211186611862116201186411859116221186811870118161186911874118151186711878118171187111867116641187211881116631187311883116621187011875116651187511868117401187611873117391187711882117421187411879117411187911869115531188011877115561188111884115551187811871115541188311876125751188411872125741188211880125761188611889118501188711892118491188811895118481188511898118471189011885119051189111900119071188911893119061189311886120781189411891120801189211896120791189611887119841189711894119861189511899119851189911888119521190011897119541189811890119531190211905112711190311908112701190411911112691190111914112681190611901118891190711916118911190511909118901190911902119491191011907119511190811912119501191211903119651191311910119671191111915119661191511904120811191611913120831191411906120821191811920123161191911924123181191711927123171192111917118221192211930118251192311931118241192011935118231192511918125811192611938125801192411939125821192811919113021192911942113011193011932113001192711921113031193211922119461193311929119451193411944119481193111936119471193611923123071193711934123061193811940123091193511925123081194011926122351194111937122341193911943122361194311928125901194411941125891194211933125911194611949119321194711952119311194811955119341194511958119331195011945119081195111960119101194911953119091195311946118981195411951119001195211956118991195611947119811195711954119831195511959119821195911948119681196011957119701195811950119691196211965120081196311968120071196411971120061196111974120051196611961119111196711976119131196511969119121196911962119581197011967119601196811972119591197211963119901197311970119921197111975119911197511964120841197611973120861197411966120851197811981120551197911984120541198011987120531197711990120561198211977119551198311992119571198111985119561198511978118951198611983118971198411988118961198811979120751198911986120771198711991120761199111980119711199211989119731199011982119721199411997111851199512001111841199612005111831199312009111861199811993119991201212000120131199712002120021199412033120031200012032120041201512031120011200612030120061199511964120071200411963120081201611962120051201011961120101199611264120111200811267120121201811266120091199811265120141199912220120151201712219120131200312221120171200712598120181201412600120161201112599120201202312060120211202712059120221203012058120191203412057120241201911508120251203711507120261203811506120231204211505120281202012105120291204412107120271203112106120311202112004120321202912003120331204012002120301203512001120351202211214120361203311217120371203911216120341202411215120391202512040120361204112032120381204312043120261208712044120411208912042120281208812046120491118012047120531117912048120571118212045120611118112050120451184512051120641184412052120651184312049120541184612054120461197912055120521197812056120671197712053120581198012058120471202212059120561202112060120681202012057120621201912062120481152512063120601152412064120701152712061120501152612066120511229612067120691229512065120551229712069120591229312070120661229212068120631229412072120751117012073120781116912074120811117212071120841117112076120711198712077120861198912075120791198812079120721189212080120771189412078120821189312082120731191412083120801191612081120851191512085120741197412086120831197612084120761197512088120901204212089120941204412087120981204312091120871150912092121011151212093121031151112090120951151012095120881211512096120931211812097121021211712094120991211612099120891210012097121011210412098120911210312096121381210412092121371210212100121391210612108120271210712112120291210512115120281210912105122821211012118122811211112119122801210812122122831211312106122231211412124122221211212116122241211612107120941211712114120971211812120120961211512109120951212012110121501212112117121521211912123121511212312111122271212412121122261212212113122251212612129125321212712133125311212812137125341212512140125331213012125124581213112143124571213212144124601212912134124591213412126122601213512132122591213612147122581213312150122611213812127121031213912152121021213712141121041214112128121421213912143121451214012130121451213112154121461214212153121441214812155121481213512245121491214612244121471215112243121511213612119121521214912121121501213812120121541215612145121551215912144121531216212146121571215312158121641215612160121601215412445121611215812444121591216312443121631215512167121641216112166121621215712165121661216812164121671217112163121651217412162121691216512177121701217612179121681217212178121721216612388121731217012387121711217512386121751216712242121761217312241121741216912240121781218012168121791218312170121771218612169121811217712182121881218012184121841217811292121851218211291121831218711293121871217912191121881218512190121861218112189121901219212188121911219512187121891219812186121931218912194122001219212196121961219011295121971219411294121951219911296121991219112203122001219712202121981219312201122021220412200122031220712199122011221012198122051220112213122061221212215122041220812214122081220212594122091220612593122071221112592122111220312230122121220912229122101220512228122141221612204122151221912206122131222212205122171221312218122241221612220122201221412014122211221812013122191222312015122231221512113122241222112112122221221712114122261222812124122271223112123122251223412122122291222512212122301223612211122281223212210122321222612238122331223012237122311223512239122351222711940122361223311939122341222911941122381224012232122391224312231122371224612233122411223712176122421224812175122401224412174122441223812149122451224212148122431224712147122471223912584122481224512583122461224112585122501225212577122511225512579122491225812578122531224912312122541226212311122521226512310122561225012509122571226812508122551226912510122591225112135122601227212134122611227312133122581226312136122631225312278122641226112277122621227612279122661225411438122671227511437122681227011436122651225611439122701225712494122711226712493122721227412492122691225912491122741226012514122751227112513122761226612512122731226412511122781228012263122791228412262122771228812264122811227712110122821229112109122831229312108122801228512111122851227812300122861228312299122871229212298122841228912301122891227911531122901228711530122911229411529122881228111528122931228612069122941228212068122921229012070122961229812066122971230212065122951230612067122991229512286123001230912285123011231112284122981230312287123031229611820123041230111819123051231011818123021230711821123071229711936123081230511935123091231211938123061229911937123111230412254123121230012253123101230812252123141231611441123151231911440123131232211442123171231311917123181232411919123161232011918123201231412327123211231812326123191232312325123231231511321123241232111320123221231711319123261232812321123271233112320123251233412319123291232512337123301233612339123281233212338123321232612588123331233012587123311233512586123351232712505123361233312507123341232912506123381234012328123391234312330123371234612329123411233711323123421234811322123401234411324123441233812379123451234212378123431234712377123471233912352123481234512354123461234112353123501235212504123511235512503123491235912502123531234912346123541236312348123521236712347123561235012480123571237012479123581237312482123551236012481123601235111410123611235811409123621237611412123591236411411123641235311311123651236211310123661237511309123631236811312123681235412392123691236612394123671237112393123711235612402123721236912401123701237412403123741235712375123721237612365123731236112378123801234512379123831234412377123861234312381123771238912382123881239112380123841239012384123781131812385123821131712383123871131612387123791217312388123851217212386123811217112390123921238012391123951238212389123981238112393123891236712394124001236912392123961236812396123901131512397123941131412395123991131312399123911241812400123971241712398123931241612402124041237112403124071237012401124101237212405124011241312406124121241512404124081241412408124021247312409124061247212407124111247412411124031241212409124101240512414124161240412415124191240612413124221240512417124131240012418124241239912416124201239812420124141243912421124181243812419124231243712423124151243012424124211242912422124171242812426124281129012427124311128912425124341128812429124251242412430124361242312428124321242212432124261243312430124311243512435124271243612433124341242912438124401242112439124431242012437124461241912441124371244212448124401244412444124381216112445124421216012443124471215912447124391246312448124451246212446124411246112450124531245112457124521246112449124641245412449125511245512467125501245612468125491245312458125521245812450121301245912456121291246012471121321245712462121311246212451124481246312460124471246112472124461246512452124661247412467124691246412454124691245512477124701246612476124711247312475124681245912478124731246312408124741247012407124721246512409124761247912470124771248312469124781248712468124751249112471124801247512356124811249412355124821249712358124791248412357124841247612485124821248612496124831248812488124771253012489124861252912490124951252812487124921252712492124781227212493124901227112494124981227012491124801226912496124891141512497124851141412498124811141312495124931141612500125021141712501125051141912499125081141812503124991235112504125101235012502125061234912506125001233412507125041233612505125091233512509125011225612510125071225512508125031225712512125151227612513125211227512514125271227412511125311227312516125111153312517125341153212518125351153712519125401153612520125231153512515125221153412522125121176112523125201176012524125191175912525125431175812526125441175712521125281175612528125131249012529125261248912530125481248812527125491248712532125141212612533125521212512534125361212812531125161212712536125171253712533125381255112539125461253512541125411251812542125391254312545125401252412545125251254612542125471253812548125501254412529125501253012455125511254712454125521253712453125491253212456125541255611560125551255911562125531256211561125571255312558125641255612560125601255411478125611255811477125591256311479125631255511793125641256111792125621255711791125661256811795125671257111794125651257411796125691256511559125701257611558125681257211557125721256611764125731257011763125711257511762125751256711883125761257311882125741256911884125781258012249125791258312251125771258612250125811257711925125821258811924125801258411926125841257812247125851258212246125831258712248125871257912333125881258512332125861258112331125901259211943125911259511942125891259811944125931258912209125941260012208125921259612207125961259011299125971259411298125951259911297125991259112016126001259712018125981259312017126021260510561126031260810560126041261110559126011261410558126061260112621126071261612623126051260912622126091260212646126101260712648126081261212647126121260312933126131261012935126111261512934126151260412943126161261312945126141260612944126181262194871261912624948612620126279485126171263094881262212617126051262312632126071262112625126061262512618129521262612623129541262412628129531262812619129561262912626129551262712631129571263112620126371263212629126391263012622126381263412637126491263512640126521263612643126511263312646126501263812633126301263912648126321263712641126311264112634129651264212639129641264012644129661264412635129361264512642129381264312647129371264712636126081264812645126101264612638126091265012653126331265112656126361265212659126351264912662126341265412649126691265512664126711265312657126701265712650128671265812655128691265612660128681266012651989812661126589900126591266398991266312652992012664126619922126621265499211266612669951212667126729515126681267595141266512678951312670126651265312671126801265512669126731265412673126669917126741267199191267212676991812676126671268512677126741268712675126791268612679126681287012680126771287212678126701287112682126859404126831268894031268412691940212681126949401126861268112675126871269612677126851268912676126891268299141269012687991612688126929915126921268399041269312690990612691126959905126951268412861126961269312863126941268612862126981270093521269912703935112697127069350127011269710773127021270810775127001270410774127041269897701270512702977212703127079771127071269912726127081270512725127061270112724127101271210777127111271510776127091271810778127131270912721127141272012723127121271612722127161271092931271712714929212715127199291127191271111132127201271711131127181271311133127221272412712127231272712714127211273012713127251272112708127261273212707127241272812706127281272293031272912726930512727127319304127311272312738127321272912737127301272512736127341273697691273512739976812733127429767127371273312732127381274412731127361274012730127401273411136127411273811135127391274311134127431273513137127441274113136127421273713138127461274993531274712752935612748127559355127451275893541275012745928712751127609286127491275392851275312746927612754127519278127521275692771275612747127741275712754127761275512759127751275912748127901276012757127921275812750127911276212765910412763127689107127641277191061276112774910512766127619273127671277692751276512769927412769127621283512770127671283712768127721283612772127631278112773127701278312771127751278212775127641275512776127731275712774127661275612778127811075212779127841075512780127871075412777127901075312782127771277112783127921277312781127851277212785127781283212786127831283412784127881283312788127799295127891278692941278712791929612791127801275812792127891276012790127821275912794127971111912795128001111812796128031111712793128061111612798127931281312799128081281512797128011281412801127941305512802127991305712800128041305612804127951307412805128021307612803128071307512807127961308712808128051308912806127981308812810128131282512811128161282812812128191282712809128221282612814128091279712815128241279912813128171279812817128101308412818128151308612816128201308512820128111284512821128181284712819128231284612823128121305812824128211306012822128141305912826128291280912827128321281212828128351281112825128381281012830128259283128311284092821282912833928412833128261278412834128311278612832128361278512836128271276812837128341277012835128391276912839128289270128401283792721283812830927112842128459109128431284891081284412851911112841128549110128461284112819128471285612821128451284912820128491284213081128501284713083128481285213082128521284313068128531285013070128511285513069128551284413049128561285313051128541284613050128581286110565128591286410564128601286710563128571287010562128621285712694128631287212696128611286512695128651285899011286612863990312864128689902128681285912656128691286612658128671287112657128711286012678128721286912680128701286212679128741287610571128751287910570128731288210572128771287398661287812884986512876128809864128801287412886128811287812885128791288312887128831287512925128841288112924128821287712926128861288812880128871289112879128851289412881128891288512897128901289612899128881289212898128921288610717128931289010716128911289510718128951288712914128961289312913128941288912912128981290012888128991290312890128971290612889129011289798501290212908984912900129049851129041289886211290512902862312903129078622129071289998201290812905981912906129019818129101291298261291112915982512909129189824129131290912896129141292012895129121291612894129161291012922129171291412921129151291912923129191291110313129201291710315129181291310314129221292412916129231292712915129211293012917129251292112883129261293312882129241293612884129281292212969129291293812968129271293112967129311292312946129321292912948129301293412947129341292512611129351293212613129331293712612129371292612643129381293512645129361292812644129401294310298129411294610297129421294910296129391295210299129441293912614129451295412616129431294712615129471294012930129481294512932129461295012931129501294112960129511294812959129491295312958129531294212624129541295112626129521294412625129561295812628129571296112627129551296412629129591295512951129601296712950129581297012949129621295613015129631297213017129611296513016129651295712641129661296312640129641296812642129681295912929129691296612928129671297112927129711296012973129721296912975129701296212974129741297612970129751297912972129731298212971129771297310290129781298410289129761298010291129801297412986129811297812985129791298312987129831297598221298412981982112982129779823129861298812980129871299112979129851299412981129891298512997129901299612999129881299212998129921298613019129931299013018129911299513020129951298713022129961299313021129941298913023129981300012988129991300312990129971300612989130011299710300130021300810302130001300410301130041299894821300513002948413003130079483130071299987801300813005877913006130018781130101301294811301113015948013009130189479130131300999241301413020992313012130169925130161301012961130171301412963130151301912962130191301112992130201301712991130181301312993130221302412995130231302712994130211303012996130251302199261302613032992813024130289927130281302298081302913026980713027130319809130311302387941303213029879313030130258792130341303697991303513039979813033130429797130371303399371303813044993913036130409938130401303498761304113038987813039130439877130431303587911304413041879013042130378789130461304910756130471305210759130481305510758130451305810757130501304512854130511306012856130491305312855130531304613065130541305113067130521305613066130561304712800130571305412802130551305912801130591304812822130601305712824130581305012823130621306513063130681306413071130611307413066130611305213067130761305413065130691305313069130621285113070130671285313068130721285213072130631309013073130701309213071130751309113075130641280313076130731280513074130661280413078130819214130791308492131308013087921213077130909211130821307712848130831309212850130811308512849130851307812816130861308312818130841308812817130881307912806130891308612808130871309112807130911308013071130921308913073130901308213072130941309692091309513099920813093131029210130971309311110130981310411109130961310011111131001309413106131011309813105130991310313107131031309513104131011310213097131061310813100131071311113099131051311413101131091310513117131101311613119131081311213118131121310613156131131311013155131111311513157131151310713168131161311313167131141310913169131181312013108131191312313110131171312613109131211311711120131221312811122131201312411121131241311813131131251312213130131231312713129131271311997651312813125976413126131219766131301313213125131311313613124131291313913123131331312997411313413142974013135131459743131321313797421313713130127431313813135127421313613148127441314013131131501314113147131491313913143131511314313133903713144131419036131421314690351314613134931913147131449318131481314093171314513138931613150131521314013151131551313913149131581314113153131499194131541316091931315213156919513156131501311213157131541311113155131591311313159131519034131601315790331315813153903213162131649057131631316790591316113170905813165131611316613172131641316813168131621311513169131661311413167131711311613171131639784131721316997831317013165978213174131771317513180131761318313173131861317813173137513179131881377131771318113761318113174131931318213179131951318013184131941318413175132181318513182132201318313187132191318713176134313188131851345131861317813441319013193347131911319634613192131993451318913202344131941318913180131951320413182131931319713181131971319013721319813195137413196132001373132001319113591320113198136113199132031360132031319213209132041320113211132021319413210132061320913224132071321213227132081321513226132051321813225132101320513202132111322013204132091321313203132131320613561321413211135813212132161357132161320713461321713214134813215132191347132191320813183132201321713185132181321013184132221322432813223132283271322113232326132251322113205132261323513208132271323713207132241322913206132291322210591323013227105813231132361057132281323310601323313223132421323413231132451323513238132441323213225132431323713230403132381322640213236132344041324013242323132411324632513239132503241324313239132321324413253132351324513255132341324213247132331324713240531324813245521324913254511324613251541325113241132521324913253132561325013243132551324838413256132443831325413252382132581326035813259132633601325713266359132611325784111326213268841013260132648412132641325818911326513262189313263132671892132671325914991326813265150113266132611500voidN4CGAL7Point_3INS_5EpickEEE1

0.117844-0.279766999999999991.0801099999999999

2

0.12497800000000001-0.2311821.10005

3

0.102602-0.2671481.0492999999999999

6

0.0388902-0.2793121.0804499999999999

18

0.19981599999999999-0.189063000000000011.1170599999999999

19

0.199542-0.280426000000000011.0801099999999999

23

0.19949900000000001-0.2486941.00169

31

0.19963500000000001-0.3373411.21516

32

0.19964799999999999-0.350347999999999991.24569

33

0.19983400000000001-0.298489999999999981.2520500000000001

34

0.19982800000000001-0.291057000000000011.2347300000000001

37

0.199629-0.318180999999999991.17014

44

0.18806300000000001-0.131585000000000011.2445900000000001

45

0.20033999999999999-0.1425421.27013

46

0.19999800000000001-0.246601999999999991.2583299999999999

50

0.19999800000000001-0.244914999999999991.2543899999999999

53

0.199827-0.271780000000000021.1895199999999999

58

0.19999700000000001-0.225421000000000011.20892

59

0.19983000000000001-0.1878591.1194599999999999

69

0.20033799999999999-0.129069999999999991.2384900000000001

73

0.20033300000000001-0.132843999999999991.2473799999999999

87

0.00047471600000000003-0.170576000000000011.3386899999999999

88

-0.00154631-0.287034999999999981.10025

94

0.00047977300000000002-0.171026000000000011.3397399999999999

95

-0.00092792899999999997-0.355862000000000011.2609300000000001

99

0.199633-0.356613999999999991.2602100000000001

115

0.20041100000000001-0.1723991.3392200000000001

120

0.20000200000000001-0.2645941.29992

121

0.199819-0.310630000000000021.2801

140

0.14515800000000001-0.0937962999999999991.1551800000000001

141

0.056482200000000003-0.0193921999999999980.96907699999999997

142

0.028358299999999999-0.2072830.89990999999999999

146

-0.0021599200000000001-0.206747999999999990.90009099999999997

147

-0.0014654399999999999-0.279057999999999971.0805499999999999

151

0.00054492500000000003-0.0928771000000000041.1554199999999999

156

2.5080899999999999e-05-0.0188470999999999990.96922699999999995

190

0.00048502099999999998-0.1698461.3402400000000001

191

0.20083500000000001-0.0588112999999999971.3878699999999999

200

0.20044600000000001-0.1122471.2735700000000001

219

0.172281999999999990.0908555000000000061.2290000000000001

220

0.00242347000000000010.0925283999999999971.22939

224

0.00196770000000000020.0120239000000000011.4180900000000001

234

0.201150.0647792999999999981.29135

239

0.2013240.0109126999999999991.4175500000000001

257

0.19931499999999999-0.208530999999999990.89939899999999995

261

0.19972799999999999-0.1145190.93437199999999998

262

0.20008400000000001-0.0202812999999999990.96860599999999997

266

0.20030600000000001-0.0939948000000000031.15533

270

0.199821-0.187178000000000011.11782

283

0.40013300000000002-0.0938908999999999991.1543699999999999

284

0.36662800000000001-0.0940180000000000041.1545000000000001

285

0.40018300000000001-0.0870120999999999951.13757

288

0.400422-0.187233000000000011.1175900000000001

289

0.30010799999999999-0.187342000000000011.11758

290

0.30016199999999998-0.1321891.1397299999999999

294

0.203152-0.187179000000000011.11782

297

0.40080900000000003-0.209802999999999990.90342599999999995

301

0.40053299999999997-0.280559999999999981.07992

306

0.30004900000000001-0.280532999999999981.07979

324

0.24987799999999999-0.318145000000000011.1699600000000001

328

0.24998600000000001-0.271867000000000031.1894400000000001

331

0.30011500000000002-0.318195000000000011.1699299999999999

343

0.25009900000000002-0.225533000000000011.2088300000000001

346

0.300151-0.271911999999999991.1893899999999999

351

0.300201-0.2255751.2087000000000001

373

0.24981-0.356800000000000011.2600899999999999

374

0.249858-0.337422999999999971.2150399999999999

377

0.20679600000000001-0.356615999999999991.2601599999999999

380

0.24996099999999999-0.310794999999999991.2800400000000001

381

0.24998799999999999-0.291192999999999981.2347399999999999

392

0.21351000000000001-0.3106681.28007

423

0.233657-0.172554000000000011.33914

426

0.22022-0.264651000000000031.2998400000000001

429

0.32215500000000002-0.254041000000000021.5217799999999999

430

0.200547-0.253684000000000021.5221

434

0.199577-0.436485999999999991.44076

445

0.29531600000000002-0.436999000000000031.4406300000000001

474

-0.00076064399999999999-0.435755999999999981.44174

478

0.00054402599999999997-0.252589000000000011.5226

489

0.21029900000000001-0.296960999999999971.27474

497

0.212812-0.271388999999999991.28311

536

0.22497200000000001-0.2778351.2672399999999999

585

0.25009399999999998-0.2647331.29976

596

0.39995399999999998-0.437394999999999981.4405699999999999

597

0.40034700000000001-0.357051999999999981.2600199999999999

598

0.30000300000000002-0.3569561.2600199999999999

602

0.30011500000000002-0.310927000000000011.2799700000000001

606

0.30020599999999997-0.2648451.29962

610

0.30038799999999999-0.172696999999999991.33894

615

0.40038400000000002-0.1726781.33876

616

0.40049299999999999-0.254203000000000011.52166

625

0.40039200000000003-0.2648761.2997000000000001

636

0.40064499999999997-0.3279281.68306

641

0.39993099999999998-0.519595000000000031.62103

642

0.40029799999999999-0.428543000000000011.6624699999999999

643

0.40038200000000002-0.407584999999999981.6719900000000001

647

0.39764500000000003-0.426111000000000021.6635800000000001

648

0.39729399999999998-0.4285331.66248

649

0.38385399999999997-0.519534999999999971.62104

669

0.40048299999999998-0.382979000000000011.6831100000000001

672

0.35047400000000001-0.382809999999999981.6832499999999999

675

0.40067199999999997-0.337426999999999981.70374

687

0.35026499999999999-0.428348999999999981.6625700000000001

690

0.35068700000000003-0.337266000000000011.7038800000000001

697

0.30069400000000002-0.3370861.70401

698

0.200707-0.336641000000000021.70438

708

0.19967499999999999-0.518866000000000051.62155

709

0.29978700000000003-0.519236000000000031.62121

713

0.30023899999999998-0.428153999999999981.66269

717

0.30047000000000001-0.3826291.6834

726

0.20019799999999999-0.427771000000000011.66303

730

0.199936-0.473318000000000021.64229

741

0.149622-0.518631999999999981.6216999999999999

742

0.14990000000000001-0.473082999999999981.64246

746

0.099565299999999995-0.518388999999999991.62185

747

0.099857500000000002-0.472847999999999991.64262

750

0.150174-0.427543999999999981.6632199999999999

760

-0.00058322799999999998-0.517901999999999971.6222700000000001

761

0.0495004-0.5181541.6220399999999999

765

0.0498025-0.472598000000000021.6428100000000001

771

0.100151-0.4273191.6633899999999999

772

0.10073699999999999-0.336212000000000011.70459

787

0.000777942-0.335712999999999981.7049000000000001

788

9.4738299999999994e-05-0.426810000000000021.6636899999999999

789

-0.00024393400000000001-0.472347000000000021.64297

795

0.050126200000000003-0.427066999999999971.66354

819

0.25451000000000001-0.02876951.40052

825

0.27286300000000002-0.000829878999999999951.44391

826

0.20135700000000001-0.0165888000000000011.48028

830

0.20149300000000001-0.0711814000000000061.60324

839

0.348856-0.0715579999999999971.6028100000000001

861

0.00188744-0.0700559999999999931.60395

865

0.0019103900000000001-0.06005461.58165

915

0.25010700000000002-0.245018000000000011.2543

975

0.27498699999999998-0.324072000000000031.2474400000000001

987

0.30013299999999998-0.291306999999999981.2346900000000001

1007

0.27510099999999998-0.277967000000000021.2671600000000001

1096

0.30022500000000002-0.245105999999999991.2541899999999999

1153

0.300315-0.133124999999999991.2470300000000001

1196

0.40040799999999999-0.2256841.20865

1200

0.40031699999999998-0.1330171.2468399999999999

1225

0.30005599999999999-0.337492999999999991.2149799999999999

1238

0.40060200000000001-0.318037000000000011.1699600000000001

1339

0.27501900000000001-0.304674999999999971.20228

1417

0.30029499999999998-0.1082281.18811

1492

0.30021199999999998-0.0941974000000000011.1547400000000001

1529

0.30012899999999998-0.0203218000000000010.96852499999999997

1530

0.40021899999999999-0.0201366000000000010.96883900000000001

1534

0.40061200000000002-0.114445000000000010.93452299999999999

1535

0.40078999999999998-0.2081520.89916799999999997

1539

0.30012699999999998-0.208542000000000010.89914700000000003

1544

0.30022399999999999-0.11470.93445

1566

0.40010299999999999-0.0748806999999999941.16204

1580

0.201110000000000010.0906914999999999941.22885

1581

0.399880999999999990.0905684999999999961.22888

1585

0.399382000000000010.167051.03746

1597

0.2008230.166671999999999991.03792

1607

0.40085999999999999-0.0800494000000000070.84255999999999998

1608

0.30037399999999997-0.0803436000000000010.84245999999999999

1613

0.400270000000000010.0147103000000000010.87509599999999998

1614

0.300186000000000010.0142795000000000010.87487800000000004

1639

0.400264000000000010.0477056999999999970.78095999999999999

1640

0.300292999999999980.0474429000000000030.78081

1643

0.200134000000000010.01443350.87471699999999997

1652

0.398347999999999980.238354000000000010.84065599999999996

1657

0.200531999999999990.236749999999999990.84198499999999998

1658

0.200466000000000010.1421840.81079299999999999

1659

0.2002960.0475131000000000030.78036899999999998

1679

0.000361116999999999990.02521340.84892599999999996

1680

0.00272124000000000020.233612999999999990.85728599999999999

1681

0.0840498999999999970.1667641.03739

1685

0.000183888999999999990.0489513999999999990.78082399999999996

1686

0.001572590.143915999999999990.811832

1687

0.00216972999999999990.1911390.82775699999999997

1688

0.00269146000000000010.2380140.84397900000000003

1692

0.05219650.237336999999999990.84293600000000002

1693

0.1016890.237028999999999990.84223300000000001

1705

0.1002730.0481349000000000010.78058700000000003

1710

0.1010460.1427620.81110099999999996

1711

0.0513042000000000010.143330000000000010.81148500000000001

1717

0.0517545000000000020.1905490.82693799999999995

1724

0.1013840.1900290.82640599999999997

1749

0.1113450.0501016000000000031.0915699999999999

1757

0.1094680.0316868999999999971.0865899999999999

1775

0.1330180.0539550999999999991.13964

1794

0.1206310.0106487000000000011.1093299999999999

1862

0.324830999999999980.01078671.41726

1863

0.400181999999999980.0275115000000000011.37849

1880

0.260255999999999990.0108216000000000011.4173100000000001

1916

0.400320000000000010.01089291.4169799999999999

2064

0.40092299999999997-0.0714091.6024700000000001

2084

0.40123500000000001-0.175247999999999990.80882600000000004

2085

0.30043799999999998-0.175115999999999990.80884199999999995

2115

0.30053400000000002-0.0483827000000000010.75009400000000004

2116

0.40109699999999998-0.0478292000000000020.75012000000000001

2121

0.300728-0.143834999999999990.71839299999999995

2122

0.40166200000000002-0.143242000000000010.71887100000000004

2196

0.199958-0.0481183000000000030.74973900000000004

2227

0.20002300000000001-0.0803235000000000060.84224500000000002

2236

-0.0019564299999999999-0.183739999999999990.83724200000000004

2240

-0.0020446000000000001-0.1417080.71859099999999998

2244

0.19971-0.143604000000000010.71893300000000004

2255

0.19969000000000001-0.175669999999999990.808894

2273

0.19968900000000001-0.0877262000000000040.53740699999999997

2274

0.200053000000000010.00941944999999999940.56376599999999999

2275

0.200411000000000010.10650.58969700000000003

2276

0.200251000000000010.0780093000000000040.68549099999999996

2281

0.300462000000000010.106731000000000010.58962300000000001

2282

0.400455000000000010.1078930.58954899999999999

2295

0.40256199999999998-0.0868125000000000010.53750299999999995

2296

0.35188900000000001-0.0873609000000000050.53744999999999998

2297

0.30118-0.0877157999999999970.53736499999999998

2301

0.30102099999999998-0.0392484999999999990.55103800000000003

2302

0.300785000000000020.009376110.56378600000000001

2310

0.351202999999999990.00982718999999999950.56393300000000002

2311

0.401600999999999990.0103101000000000010.56415400000000004

2315

0.40211400000000003-0.0382943000000000030.55121299999999995

2329

0.35157899999999997-0.03885570.55115000000000003

2351

-0.0026936500000000001-0.0860023000000000040.53851700000000002

2357

0.000130297999999999990.1085170.59035199999999999

2358

0.0002023650.0943940999999999950.63808500000000001

2359

0.000247973000000000020.0798914000000000010.68592299999999995

2378

0.1003160.107180.58980500000000002

2379

0.05024870.1077970.590059

2383

0.0502729000000000020.0939104999999999940.63789499999999999

2389

0.0502920999999999990.0793275999999999980.68581700000000001

2390

0.1002730.0788499000000000010.68564099999999994

2399

0.1002610.0932719999999999940.63769799999999999

2421

0.25017-0.1118030.77996699999999997

2509

0.249948-0.144611999999999990.871286

2693

0.398687999999999990.299111000000000020.64017400000000002

2694

0.200645999999999990.298875999999999980.63922800000000002

2695

0.2004010.202659000000000010.61493399999999998

2699

0.2006870.173991000000000010.71349099999999999

2718

0.2009060.268158999999999980.741093

2742

0.1010390.1588340.76249999999999996

2743

0.1011470.174394999999999990.71353699999999998

2747

0.100709000000000010.126623999999999990.69958399999999998

2756

0.101444000000000010.206276999999999990.77726499999999998

2761

0.101513000000000010.221961999999999990.72765000000000002

2774

0.1019660.269168000000000020.74179300000000004

2778

0.101917999999999990.2533010.79208599999999996

2807

0.0518090999999999970.206769000000000010.77763099999999996

2836

0.0524026000000000010.2537780.79263899999999998

2879

0.0526198000000000010.269720999999999990.74208099999999999

2880

0.0520069000000000020.222403999999999990.72782400000000003

2909

0.00326240999999999990.270322000000000010.74241900000000005

2917

0.002602750.2231870.72796099999999997

2927

0.00310343999999999980.254327000000000030.79294399999999998

2935

0.00246661000000000020.207321000000000010.77786100000000002

2971

0.1021280.284480999999999980.69102600000000003

2972

0.1016610.2512450.62760499999999997

2973

0.1020350.299070.63970099999999996

2976

0.1015940.2369570.67769599999999997

2979

0.1012120.2033160.61503099999999999

2993

0.1011760.1892160.66434700000000002

3023

0.0521141999999999990.237637999999999990.67779100000000003

3037

0.0514599000000000030.1749840.71370500000000003

3038

0.05135580.159360.76272499999999999

3063

0.0765552000000000040.205962000000000010.695878

3099

0.0527600999999999970.284901000000000020.69114600000000004

3113

0.00275257000000000020.2382590.677952

3122

0.003443850.285621000000000010.69123100000000004

3141

0.05147910.1897710.66444199999999998

3203

0.0766128999999999980.220532000000000010.646262

3216

0.0515709999999999990.2039020.61501899999999998

3235

0.0760860000000000010.1726270.63322000000000001

3247

0.100695999999999990.141311999999999990.65099700000000005

3248

0.0508643000000000010.141863999999999990.65115000000000001

3272

0.0508390000000000020.127145000000000010.69983499999999998

3316

0.100764999999999990.155397000000000010.60218700000000003

3355

0.00104316999999999990.127786000000000010.69998000000000005

3359

0.001792430.175585999999999990.71399000000000001

3360

0.00168673999999999990.1600530.76307000000000003

3433

0.0509015000000000020.156006000000000010.60229200000000005

3487

0.00188155000000000010.1905220.66465099999999999

3495

0.001099020.1426510.65146599999999999

3750

0.00107696000000000010.156683999999999990.60245599999999999

3767

0.001942310.2046520.61499000000000004

3782

0.200193000000000010.131380.49307000000000001

3783

0.200133000000000010.142976999999999990.444438

3784

0.200032999999999990.154074999999999990.39557100000000001

3785

0.150098000000000010.154402000000000010.39549000000000001

3786

0.1001190.1548620.395569

3787

0.0001808860.156519999999999990.39613300000000001

3804

0.200896999999999990.348681000000000020.43234

3810

0.00382960999999999980.350428999999999990.43259999999999998

3816

0.00351810000000000010.300464999999999980.63944400000000001

3817

0.00276868999999999990.252556999999999980.627444

3836

0.05276020.299651999999999970.63971599999999995

3842

0.0522000999999999990.251761999999999990.62761299999999998

3960

0.199990.0942735999999999990.43423699999999998

3961

0.200070.0826743000000000060.481991

3966

0.199967000000000010.104969000000000010.386299

3969

0.200070.0451452999999999990.42386200000000002

3970

0.200061999999999990.03389760.47072000000000003

3991

0.199914000000000010.0554716999999999990.37699100000000002

3996

0.199853-0.0435405999999999990.35662199999999999

3997

0.19998099999999999-0.0642110999999999930.44650200000000001

4012

-0.0033956799999999999-0.0414655999999999980.35677399999999998

4013

-0.00190716999999999990.0575125000000000010.37738899999999997

4017

0.0990628999999999950.0560372999999999980.377475

4018

0.0995599000000000070.1054320.38634600000000002

4022

0.149761000000000010.1050210.38620599999999999

4029

0.149484000000000010.0554906999999999970.37731799999999999

4034

0.098035800000000006-0.0429847999999999970.357157

4065

0.250161000000000020.143221999999999990.44444800000000001

4068

0.250213999999999990.1318230.49288300000000002

4071

0.250078000000000020.154047999999999990.39552700000000002

4084

0.300275999999999990.132148999999999990.492919

4088

0.300223000000000020.1434560.44444299999999998

4094

0.300177000000000030.154073999999999990.39547100000000002

4095

0.350310000000000010.154523999999999990.39563100000000001

4096

0.400357000000000020.1550880.39570699999999998

4097

0.398162999999999990.349739000000000020.43179400000000001

4112

0.400384999999999990.1328230.49301800000000001

4113

0.350335000000000010.1324960.49283300000000002

4117

0.350339999999999980.1438980.444546

4128

0.400405000000000010.144302000000000010.44460499999999997

4175

0.2001550.1633310.34617500000000001

4176

0.2001840.172284999999999990.29699900000000001

4177

0.1501970.172381000000000010.29702600000000001

4178

0.150163999999999990.1636010.346024

4183

0.200827000000000010.3829630.21926499999999999

4184

0.200396999999999990.2852460.207425

4185

0.200227999999999990.186596000000000010.19827600000000001

4186

0.200130.1797820.24778600000000001

4191

0.1000080.187486000000000010.198853

4192

0.1000630.172907000000000010.296962

4196

0.100070000000000010.163985999999999990.34615000000000001

4210

0.00433835000000000040.384608000000000010.22039

4211

0.0533348999999999980.383720999999999980.21967800000000001

4212

0.1024330.383130000000000030.219416

4216

0.101880.334388000000000020.21304200000000001

4217

0.1012440.285399999999999990.20762700000000001

4224

-0.000370418999999999980.188790999999999990.198294

4225

-0.0002064220.174386999999999990.29714099999999999

4239

0.00220696999999999990.286939999999999970.20857100000000001

4240

0.003389890.335953999999999970.214058

4245

0.0525720999999999970.335100999999999980.21335499999999999

4255

0.0517241999999999980.2860550.208066

4267

-0.00243613999999999980.0756296999999999940.283252

4268

0.09880920.0740438000000000070.28294399999999997

4269

0.0994116000000000030.123412999999999990.29017799999999999

4276

0.0989494000000000070.0654102000000000020.33025100000000002

4280

0.0993953999999999950.1150.33835199999999999

4308

0.30116300000000001-0.02669740.50499499999999997

4309

0.30138999999999999-0.0759115999999999960.49224800000000002

4314

0.300831999999999990.02216270.51725299999999996

4317

0.30119899999999999-0.01496340.45896700000000001

4318

0.30152299999999999-0.0641660000000000010.44722400000000001

4333

0.250508999999999980.0339722000000000010.47067100000000001

4334

0.300906999999999980.0341954000000000010.47061799999999998

4351

0.35215400000000002-0.0754694000000000060.49230699999999999

4377

0.35174299999999997-0.02626680.50511499999999998

4413

0.40294200000000002-0.0748896000000000010.49256299999999997

4431

0.40240500000000001-0.0258558000000000020.50533099999999997

4449

0.351256999999999990.02264190.51736199999999999

4481

0.351364999999999980.0346209999999999990.47087299999999999

4485

0.35183199999999998-0.0146082999999999990.45913999999999999

4512

0.300599999999999980.0831742000000000040.48178300000000002

4523

0.401743999999999990.0231250999999999990.51753099999999996

4527

0.4018350.0351821000000000010.47092899999999999

4533

0.350850.0835850000000000070.48182999999999998

4543

0.401121000000000010.0840927000000000060.48195399999999999

4562

0.402445-0.01400650.45940300000000001

4604

0.401876000000000010.0463010999999999980.42408400000000002

4611

0.351410.0457090.423875

4616

0.351472999999999980.0561962999999999980.37702200000000002

4617

0.402015000000000010.0567642000000000010.37726999999999999

4623

0.300945999999999990.0453404000000000030.42380600000000002

4627

0.3009870.0558113000000000010.37698300000000001

4631

0.301705-0.0434898000000000020.35713800000000001

4632

0.40362999999999999-0.0423327000000000010.35805300000000001

4636

0.40312999999999999-0.06337160.447853

4654

0.35227799999999998-0.0637630.44734099999999999

4716

0.40373900000000001-0.0255785000000000010.26778299999999999

4717

0.30180099999999999-0.0265414999999999990.26737300000000003

4721

0.301101999999999980.0735299999999999980.28298600000000002

4722

0.300976999999999990.0649967999999999930.32999800000000001

4727

0.351663999999999980.0740579999999999990.28323300000000001

4728

0.402245000000000020.0748333999999999940.28363500000000003

4739

0.350860000000000010.105358999999999990.38639200000000001

4744

0.4011440.1058790.38653199999999999

4755

0.300603000000000010.1050910.38633499999999998

4763

0.400289000000000010.173691000000000010.29770999999999997

4764

0.401287999999999980.1242910.29065800000000003

4769

0.350910999999999970.123632000000000010.29048600000000002

4773

0.300615000000000020.123390.290273

4777

0.3005640.1145680.33829300000000001

4789

0.300148000000000030.1638250.34619100000000003

4790

0.300043999999999980.1729590.29724699999999998

4791

0.350152999999999990.1734010.29740899999999998

4813

0.401075999999999990.0954590000000000020.43426700000000001

4814

0.350847000000000020.0949225999999999960.43421999999999999

4931

0.3005890.0945527000000000030.43416500000000002

4976

0.250354000000000020.0829352000000000010.48179100000000002

4977

0.250313999999999980.09433540.43415399999999998

4981

0.2504980.0452238999999999970.42375000000000002

5054

0.250236000000000010.104884000000000010.386187

5066

0.250456999999999990.0556031000000000030.37690200000000001

5166

0.250269000000000020.1144810.338231

5197

0.398307000000000020.382931999999999990.21734500000000001

5203

0.400129999999999990.188795999999999990.19968900000000001

5204

0.4002290.181350000000000010.24874499999999999

5226

0.250203999999999980.186798999999999990.198354

5227

0.300204000000000030.187156999999999990.19864000000000001

5228

0.350196000000000010.1879140.19911200000000001

5233

0.350181999999999990.181027999999999990.24851899999999999

5250

0.250074000000000020.163645000000000010.34616799999999998

5255

0.250107000000000020.1727660.29711399999999999

5259

0.250112999999999970.1800360.24798100000000001

5267

0.300190000000000010.1804810.24815899999999999

5312

0.350936000000000030.131367000000000010.24251900000000001

5323

0.300663000000000010.1307490.242177

5360

0.2503090.1230620.290184

5372

0.2503610.130563000000000010.24211199999999999

5416

0.300696000000000020.137413000000000010.194156

5422

0.250410999999999990.1369570.194053

5456

0.200063999999999990.130393000000000010.24199599999999999

5460

0.199999000000000010.122815999999999990.29011900000000002

5480

0.2000420.136728999999999990.19383700000000001

5499

0.199927999999999990.0867356999999999990.188689

5500

0.199603-0.0140204000000000010.179504

5501

0.2000000000000000100

5502

0.200000000000000010.200000000000000010

5503

0.2001310.1956840.099080100000000004

5508

0.400000000000000020.200000000000000010

5518

0.250524000000000020.0870510000000000030.18872700000000001

5523

0.301157999999999980.0872970.188636

5524

0.30174400000000001-0.01372640.17893500000000001

5528

0.40399400000000002-0.01291220.17947399999999999

5529

0.4000000000000000200

5538

0.4023330.0881122000000000020.18914800000000001

5539

0.401264000000000010.138416000000000010.19476099999999999

5543

0.351003000000000010.137887000000000010.19450500000000001

5558

0.351758999999999990.0877186999999999970.188911

5581

0.2007390.295308999999999990.10353800000000001

5582

0.2008770.391861999999999990.109846

5586

0.200000000000000010.400000000000000020

5587

0.400000000000000020.400000000000000020

5606

0.200000000000000010.299999999999999990

5623

0.1007550.295735000000000030.103321

5626

0.0999643999999999950.196205999999999990.099184400000000006

5635

0.101028999999999990.291053000000000010.15569

5646

0.1016890.340048000000000020.16007099999999999

5652

0.1012880.344453000000000010.10657800000000001

5655

0.1022960.388469000000000010.16456999999999999

5671

0.1017170.392940000000000010.10996300000000001

5690

0.100000000000000010.299999999999999990

5719

0.100000000000000010.400000000000000020

5730

0.0523490.340505999999999980.16022500000000001

5734

0.0515617000000000020.291627000000000030.15612300000000001

5737

0.0518387999999999970.344833999999999970.106724

5746

0.0511949000000000020.295827999999999980.103876

5758

00.299999999999999990

5759

0.001696690.296248999999999980.10425

5765

00.400000000000000020

5769

0.003650880.394150.11046

5770

0.00277328999999999990.345254999999999980.107351

5786

0.0525665999999999980.393496999999999990.110224

5805

0.0770925999999999970.366823999999999980.13545399999999999

5833

0.0530706000000000020.389056999999999990.164822

5926

0.003294230.341401000000000010.16089200000000001

5931

0.00416199999999999990.389946999999999990.16537199999999999

5992

0.002111080.292200000000000020.15648999999999999

6090

-0.000168421000000000010.1967660.099037

6091

00.200000000000000010

6095

0.100000000000000010.200000000000000010

6201

000

6215

-0.002527320.0886471000000000060.18867300000000001

6216

-0.0045258399999999997-0.01179770.17880399999999999

6221

0.097567899999999999-0.01290590.17840200000000001

6236

0.0986848000000000030.0872242000000000020.18840000000000001

6277

0.301148000000000030.0810011999999999950.235961

6282

0.2505310.0807739999999999990.23592099999999999

6296

0.250522000000000020.0732522000000000030.28297

6299

0.199948999999999990.0803853999999999960.23594300000000001

6304

0.1999310.0731815999999999990.28309299999999998

6305

0.19969999999999999-0.0269309000000000010.267538

6327

0.097791400000000001-0.0264536000000000010.26771400000000001

6332

0.149333999999999990.0734937999999999980.28291100000000002

6358

-0.0040554700000000003-0.0248315999999999990.268009

6406

0.199945000000000010.0648515000000000060.33001799999999998

6410

0.149415999999999990.0650562999999999970.33017600000000003

6444

0.250477000000000010.0649629000000000040.32994899999999999

6525

0.225177999999999990.0750929000000000040.40531099999999998

6557

0.225233999999999990.0641103999999999980.45266499999999998

6691

0.200000000000000010.1142360.33821499999999999

6779

0.149718999999999990.123020.29011100000000001

6780

0.149741000000000010.114474000000000010.33829300000000001

6879

0.174746000000000010.0939770999999999940.31032700000000002

6977

0.1747580.0850300999999999970.35805799999999999

7318

0.351698999999999980.0815297999999999990.23610400000000001

7430

0.402289000000000010.0820212000000000020.23638899999999999

7465

0.401307000000000020.132015999999999990.24260399999999999

7739

0.2251910.112990999999999990.46343699999999999

8229

0.00211825999999999980.1672631.0377099999999999

8238

0.1008960.0365819000000000011.09802

8437

0.40120400000000001-0.1209851.71123

8455

0.40029999999999999-0.431367999999999971.6686300000000001

8463

0.39994400000000002-0.534703999999999961.65381

8478

0.29984100000000002-0.560871000000000011.71157

8479

0.39991199999999999-0.5612531.71133

8483

0.40035300000000001-0.4703331.75308

8484

0.40032000000000001-0.4494051.70777

8488

0.35029500000000002-0.449218000000000011.7078899999999999

8498

0.30027999999999999-0.449029000000000011.7080299999999999

8499

0.30031400000000003-0.469947999999999981.75335

8503

0.35033300000000001-0.4701381.7532099999999999

8519

0.19970599999999999-0.539641000000000041.6667099999999999

8520

0.19975799999999999-0.560466000000000021.7118800000000001

8530

0.19997699999999999-0.494120999999999981.6875500000000001

8536

0.20002-0.515013000000000051.7327900000000001

8537

0.20028299999999999-0.469534999999999981.7536499999999999

8538

0.25029899999999999-0.469737999999999991.75349

8551

0.20024-0.448631999999999981.70834

8565

0.30051099999999997-0.403517000000000011.72878

8570

0.30074400000000001-0.358018999999999981.7494799999999999

8582

0.30055199999999999-0.424460999999999981.7741400000000001

8583

0.30079099999999998-0.378971999999999981.7948999999999999

8587

0.25080200000000002-0.378767000000000021.7950600000000001

8588

0.20081099999999999-0.378560999999999981.79522

8593

0.20055100000000001-0.424049999999999981.77444

8612

0.25054999999999999-0.424260000000000031.7742899999999999

8632

0.15022099999999999-0.448396999999999991.70852

8637

0.14994299999999999-0.493908999999999991.68771

8646

0.100824-0.378076000000000021.79552

8653

0.15026400000000001-0.469303000000000031.7538100000000001

8654

0.100246-0.469065999999999981.7539800000000001

8655

0.100539-0.423574999999999981.7747599999999999

8660

0.100199-0.448172000000000011.70868

8692

0.14998800000000001-0.514785999999999971.7329600000000001

8719

0.20032900000000001-0.490483999999999981.79895

8727

0.20005400000000001-0.535942000000000031.77806

8736

0.19978499999999999-0.581381000000000041.7571099999999999

8740

0.20009299999999999-0.556899000000000031.82334

8741

0.19981699999999999-0.602323000000000051.8023800000000001

8745

0.29987200000000003-0.602744999999999981.8020700000000001

8753

0.20036499999999999-0.511471000000000011.84426

8757

0.25037599999999999-0.511693999999999981.84412

8758

0.30038700000000002-0.511905999999999971.84398

8763

0.30034899999999998-0.490914999999999991.7986599999999999

8777

0.25033899999999998-0.490703999999999971.7988

8824

0.14974999999999999-0.581153000000000031.7572700000000001

8849

0.15003-0.535712999999999991.7782199999999999

8853

0.15031-0.490252999999999991.79911

8880

0.14971000000000001-0.560257000000000011.7120500000000001

8895

0.099662100000000003-0.560019000000000041.71221

8899

0.099712800000000004-0.580915999999999991.7574399999999999

8903

0.10000199999999999-0.535476999999999981.7783899999999999

8909

0.099956000000000003-0.514557000000000041.7331300000000001

8926

0.15007499999999999-0.556668000000000051.8234999999999999

8930

0.14979100000000001-0.602095000000000051.80254

8954

0.099757999999999999-0.601855999999999951.8027

8958

0.100051-0.5564271.8236600000000001

8985

0.100344-0.510993999999999951.84459

8986

0.15035499999999999-0.511229999999999961.8444199999999999

8996

0.10029200000000001-0.490018999999999981.79928

9005

0.0503305-0.510738000000000031.84476

9006

0.050279299999999999-0.489765999999999981.7994399999999999

9011

0.000316862-0.510480999999999961.84493

9012

0.000260852-0.489509000000000031.79962

9024

-0.00029369500000000001-0.601345000000000021.80305

9029

-0.00042972399999999998-0.559505000000000031.71255

9030

-0.000119459-0.514040000000000051.7334799999999999

9031

0.00019950100000000001-0.4685591.7543200000000001

9034

0.050223799999999999-0.468814000000000011.75414

9049

0.049618000000000002-0.559768999999999961.7123900000000001

9062

0.049919199999999997-0.514306999999999961.7333000000000001

9083

0.050634199999999997-0.465276000000000021.86561

9086

0.100634-0.465536000000000011.8654500000000001

9089

0.00062858300000000005-0.465021999999999991.8657900000000001

9101

0.20063800000000001-0.466019000000000021.86514

9102

0.20091100000000001-0.420571.88601

9103

0.100925-0.420086999999999991.88632

9107

0.050931900000000002-0.419833000000000011.8864799999999999

9111

0.00094082300000000003-0.419563000000000021.8866400000000001

9115

0.0011012800000000001-0.503658999999999972.06819

9116

-8.5875299999999994e-05-0.685243000000000051.98431

9121

0.19994100000000001-0.686262999999999961.9836800000000001

9141

0.2011-0.504681000000000052.0675300000000001

9163

0.075460899999999997-0.477644000000000011.8324400000000001

9195

0.050580899999999998-0.444288999999999991.8202700000000001

9198

0.00057624599999999998-0.444031000000000011.8204400000000001

9234

0.10058499999999999-0.444535999999999991.8201099999999999

9269

0.075756799999999999-0.4321761.85328

9284

0.050883100000000001-0.3988141.84108

9287

0.10087699999999999-0.399069000000000011.8409199999999999

9374

0.20085900000000001-0.3995651.8406100000000001

9399

0.20059299999999999-0.445020000000000031.81979

9480

0.30063800000000002-0.466449999999999981.8648400000000001

9481

0.250639-0.466241999999999991.8649899999999999

9487

0.30089199999999999-0.420997999999999981.8856999999999999

9488

0.25090099999999999-0.420789000000000021.88585

9501

0.40040399999999998-0.512294999999999941.8436699999999999

9502

0.40087400000000001-0.421393999999999991.8854

9507

0.40109099999999998-0.505624999999999992.0668899999999999

9508

0.35109200000000002-0.505399000000000042.0670500000000001

9509

0.30109399999999997-0.5051662.0672100000000002

9526

0.39997700000000003-0.687205999999999981.98302

9527

0.39991700000000002-0.603156000000000031.8017799999999999

9548

0.14965700000000001-0.539403999999999991.6668499999999999

9679

0.099904599999999996-0.493671000000000031.68788

9694

0.050173200000000001-0.447919999999999981.7088399999999999

9695

0.049865199999999998-0.493427999999999981.6880599999999999

9726

0.000141364-0.4476541.7090099999999999

9742

0.050530199999999997-0.423329000000000011.7749299999999999

9758

0.00084863600000000005-0.377560000000000011.79583

9759

0.00052356899999999999-0.423061999999999991.7750900000000001

9769

0.050834799999999999-0.377827000000000021.7956799999999999

9799

0.25059500000000001-0.445232999999999991.8196399999999999

9812

0.30059399999999997-0.445444000000000011.8194900000000001

9854

0.25085099999999999-0.399770000000000011.84046

9897

0.22574900000000001-0.4328961.8528100000000001

9956

0.099611599999999995-0.539166000000000031.667

10095

0.0021201900000000001-0.153593000000000011.78742

10105

0.201768-0.154811.78684

10119

0.40152500000000002-0.155489999999999991.7862499999999999

10155

0.35051399999999999-0.403702000000000011.7286300000000001

10160

0.40052500000000002-0.403882999999999991.7284999999999999

10224

0.37543199999999999-0.437016999999999991.7408699999999999

10244

0.400565-0.424844999999999971.77386

10275

0.35055900000000001-0.424659999999999981.77399

10298

0.300846-0.3999741.8403

10319

0.35078500000000001-0.3791621.7947599999999999

10320

0.40077299999999999-0.379354000000000021.79461

10436

0.400723-0.358379999999999981.74919

10444

0.35073799999999999-0.358202000000000021.7493399999999999

10497

0.40181499999999998-0.2396471.96879

10505

0.20199900000000001-0.2388711.96943

10720

0.0021884399999999998-0.237888999999999991.9701200000000001

10732

0.00089668199999999999-0.398554999999999991.84124

10854

-0.00018396100000000001-0.493161999999999991.68824

10941

0.0495583-0.538915999999999951.6671899999999999

10981

-0.00050419799999999997-0.538669999999999981.6673899999999999

11145

0.202269-0.323170000000000012.1513499999999999

11146

0.00235272-0.322045000000000032.1519400000000002

11160

0.20168-0.413916000000000012.10941

11161

0.20197200000000001-0.368543999999999982.1303700000000001

11170

0.301375-0.459772999999999992.0881400000000001

11171

0.35136899999999999-0.460000999999999992.0879799999999999

11177

0.251668-0.414152999999999992.1092499999999998

11178

0.30165799999999998-0.414389999999999982.1090900000000001

11182

0.35164699999999999-0.414611999999999982.1089199999999999

11185

0.40136100000000002-0.460222999999999992.0878199999999998

11204

0.25195499999999998-0.368781000000000032.13022

11210

0.30193799999999998-0.369012000000000012.1300599999999998

11211

0.30221399999999998-0.323635000000000012.15103

11212

0.402167-0.324066999999999992.1506599999999998

11213

0.40163300000000002-0.414829999999999982.1087500000000001

11235

0.25224000000000002-0.3234072.1511900000000002

11255

0.20008600000000001-0.770259000000000032.16513

11256

0.40010800000000002-0.771221999999999962.1645099999999999

11260

0.40126400000000001-0.589705999999999952.2484099999999998

11261

0.401223-0.568713000000000022.20302

11262

0.40117900000000001-0.547707999999999972.1576399999999998

11263

0.40113599999999999-0.526672999999999952.1122700000000001

11267

0.35113499999999997-0.526434999999999992.1124299999999998

11271

0.30113800000000002-0.526201000000000032.11259

11275

0.30118099999999998-0.547224999999999962.1579600000000001

11276

0.201179-0.546730000000000052.15828

11280

0.20125799999999999-0.588709000000000042.2490600000000001

11285

0.30126399999999998-0.589211000000000042.2487400000000002

11286

0.35126600000000002-0.589458000000000042.24857

11293

0.35117999999999999-0.547468999999999982.1577999999999999

11306

0.30122399999999999-0.568223000000000032.2033499999999999

11312

0.35122399999999998-0.568466999999999942.2031900000000002

11337

7.3296799999999999e-05-0.769220000000000012.16581

11341

0.0012577000000000001-0.587647000000000032.2496999999999998

11351

0.20172499999999999-0.434946999999999972.1547999999999998

11356

0.202016-0.3895732.17577

11367

0.20177-0.455961999999999982.2002000000000002

11371

0.202066-0.410584999999999982.2211699999999999

11374

0.20231399999999999-0.344198999999999982.1967500000000002

11379

0.20236899999999999-0.3652052.2421500000000001

11380

0.20244999999999999-0.407171999999999982.3329300000000002

11381

0.0024716199999999999-0.4060532.3335400000000002

11394

0.201849-0.497933000000000012.2909799999999998

11409

0.30156100000000002-0.543815000000000052.2696900000000002

11410

0.30151699999999998-0.522834000000000022.2242999999999999

11415

0.30185600000000001-0.498427000000000012.2906499999999999

11416

0.30181000000000002-0.477447999999999982.24526

11419

0.30147200000000002-0.501835000000000032.1789200000000002

11434

0.25176700000000002-0.456206999999999972.20004

11435

0.30176199999999997-0.456448999999999992.1998700000000002

11464

0.25229499999999999-0.344436999999999992.1966000000000001

11468

0.25200699999999998-0.389811000000000022.1756099999999998

11478

0.30227900000000002-0.344671999999999982.1964299999999999

11479

0.30199799999999999-0.390048000000000012.1754500000000001

11505

0.35170499999999999-0.435655000000000012.1543199999999998

11506

0.40169700000000003-0.435881999999999992.15415

11511

0.35175800000000002-0.456683999999999982.1997100000000001

11512

0.401754-0.456915999999999992.1995300000000002

11516

0.40232499999999999-0.366153000000000012.2414800000000001

11527

0.30171199999999998-0.435427000000000012.15448

11535

0.30204999999999999-0.411067000000000022.2208399999999999

11536

0.30233700000000002-0.365690000000000022.2418300000000002

11580

0.25171900000000003-0.435188999999999992.1546500000000002

11660

0.252058-0.410828000000000032.2210100000000002

11710

0.25235099999999999-0.3654482.2419899999999999

11755

0.30244500000000002-0.4076632.3325999999999998

11821

0.301427-0.480810000000000022.1335299999999999

11891

0.32625799999999999-0.493105000000000022.1002900000000002

11926

0.35147-0.502071999999999962.17875

11934

0.35142099999999998-0.481044000000000032.1333700000000002

12000

0.40141500000000002-0.481275999999999982.1332

12097

0.40146500000000002-0.502310000000000032.1785899999999998

12125

0.401806-0.477924000000000022.24492

12126

0.35180800000000001-0.4776862.2450899999999998

12131

0.40151399999999998-0.5233162.22397

12132

0.35151700000000002-0.523077000000000012.2241399999999998

12357

0.35156300000000001-0.544054000000000042.26953

12406

0.401561-0.544301000000000032.2693599999999998

12449

0.40185900000000002-0.498902999999999992.2903199999999999

12455

0.351858-0.4986642.2904900000000001

12539

0.40243899999999999-0.408127000000000022.3322500000000002

12607

0.27574500000000002-0.433107999999999991.85266

12799

0.025760000000000002-0.431916000000000021.85344

11Volume_infovoid
\ No newline at end of file diff --git a/Linear_cell_complex/examples/Linear_cell_complex/data/lcc_input.vtk b/Linear_cell_complex/examples/Linear_cell_complex/data/lcc_input.vtk deleted file mode 100644 index 8e4a3dff481..00000000000 --- a/Linear_cell_complex/examples/Linear_cell_complex/data/lcc_input.vtk +++ /dev/null @@ -1,29 +0,0 @@ -# vtk DataFile Version 2.0 -Example Tetrahedron with Scalars -ASCII -DATASET UNSTRUCTURED_GRID - -POINTS 4 float -0.0 0.0 0.0 -1.0 0.0 0.0 -0.0 1.0 0.0 -0.0 0.0 1.0 - -CELLS 1 5 -4 0 1 2 3 - -CELL_TYPES 1 -10 - -POINT_DATA 4 -SCALARS vertex_scalars float 1 -LOOKUP_TABLE default -1.0 -2.0 -3.0 -4.0 - -CELL_DATA 1 -SCALARS volume_scalars float 1 -LOOKUP_TABLE default -42.0 diff --git a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp index 08b3c2c6a4d..2f383fa24d5 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp @@ -1,52 +1,29 @@ /*! \ingroup PkgLinearCellComplexExamples + \brief Minimal example: read a `.3map` file, compute per-volume vertex count, and write to VTK. - \brief Example showing how to read and write a 3D linear cell complex from/to a VTK file. - - This example loads a volumetric mesh from a `.vtk` file into a `Linear_cell_complex_for_combinatorial_map<3>`, - optionally reads scalar fields (vertex/volume), and writes the modified structure back to a `.vtk` file. - - \cgalFeature{Linear_cell_complex_vtk_io} - - \cgalExampleOutput{ - Loaded LCC from data/lcc_input.vtk - - 80 vertices - - 52 volumes - Wrote LCC to data/lcc_output.vtk - } + This example loads a 3D linear cell complex from a `.3map` file using + \cgal function `CGAL::load_combinatorial_map()`. It computes for each + 3-cell (volume) the number of incident vertices (0-cells), stores these values + in a `std::vector`, and writes the result to a `.vtk` file with + `CGAL::write_lcc_to_vtk()`, using the computed values as scalars for each volume. */ - #include -#include #include -#include -#include +#include #include +#include +#include + +typedef CGAL::Linear_cell_complex_for_combinatorial_map<3> LCC; int main() { - using LCC = CGAL::Linear_cell_complex_for_combinatorial_map<3, 3, CGAL::Linear_cell_complex_traits<3>>; - LCC lcc; - - std::vector vertex_scalars, volume_scalars; - - const char* input_filename = "data/lcc_input.vtk"; - if (!CGAL::read_vtk(lcc, input_filename, &vertex_scalars, &volume_scalars)) { - std::cerr << "Failed to read: " << input_filename << std::endl; - return EXIT_FAILURE; - } - - std::cout << "Loaded LCC from " << input_filename << std::endl; - std::cout << " - " << lcc.number_of_vertex_attributes() << " vertices" << std::endl; - std::cout << " - " << lcc.template one_dart_per_cell<3>().size() << " volumes" << std::endl; - - const char* output_filename = "data/lcc_output.vtk"; - if (!CGAL::write_vtk(lcc, output_filename, &vertex_scalars, &volume_scalars)) { - std::cerr << "Failed to write: " << output_filename << std::endl; - return EXIT_FAILURE; - } - - std::cout << "Wrote LCC to " << output_filename << std::endl; - return EXIT_SUCCESS; + LCC lcc; CGAL::load_combinatorial_map("data/beam-with-mixed-cells.3map", lcc); + std::vector v; + for(auto it = lcc.template one_dart_per_cell<3>().begin(), itend = lcc.template one_dart_per_cell<3>().end(); it != itend; ++it) + v.push_back(std::distance(lcc.template one_dart_per_incident_cell<0,3>(lcc.dart_descriptor(*it)).begin(), lcc.template one_dart_per_incident_cell<0,3>(lcc.dart_descriptor(*it)).end())); + CGAL::write_lcc_to_vtk(lcc, "data/beam-with-mixed-cells.vtk", nullptr, &v); + return EXIT_SUCCESS; } \ No newline at end of file diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_incremental_builder_3.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_incremental_builder_3.h index 8efa806a91e..1fadfead366 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_incremental_builder_3.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_incremental_builder_3.h @@ -261,8 +261,7 @@ public: prev_dart =lcc.null_descriptor; } - void add_vertex_to_facet(size_type i) - { +void add_vertex_to_facet(size_type i, std::vector* tabdarts = nullptr) { CGAL_assertion(i::run(lcc, vertex_map[i], prev_dart); @@ -289,6 +288,7 @@ public: { first_dart=cur_dart; min_vertex=max_vertex=i; min_dart=cur_dart; } prev_dart=cur_dart; + if(tabdarts != nullptr) { tabdarts->push_back(cur_dart); } } // End of the facet. Return the first dart of this facet. @@ -325,13 +325,14 @@ public: return first_dart; } - DH add_facet(std::initializer_list l) - { - begin_facet(); - for (size_type i:l) - { add_vertex_to_facet(i); } - return end_facet(); - } + DH add_facet(std::initializer_list l, std::vector* tabdarts = nullptr) +{ + if(tabdarts != nullptr) { tabdarts->reserve(tabdarts->size() + l.size()); } + begin_facet(); + for (size_type i:l) + { add_vertex_to_facet(i, tabdarts); } + return end_facet(); +} void begin_surface() { @@ -404,5 +405,197 @@ private: } //namespace CGAL +/////////////////////////////////////////////////////////////////////////////// +/* Create an hexahedron, given the indices of its vertices (in the following +* order), the vertex must already have been added in the incremental builder. +* 3 +* /|\ +* 0-|-2 +* \|/ +* 1 +*/ +template +typename IncrementalBuilder::LCC::Dart_descriptor +make_tetrahedron_with_builder(IncrementalBuilder& ib, + std::size_t i0, + std::size_t i1, + std::size_t i2, + std::size_t i3, + std::vector* + tabdarts=nullptr) +{ + ib.begin_surface(); + ib.add_facet({i0,i1,i2}, tabdarts); + ib.add_facet({i1,i0,i3}, tabdarts); + ib.add_facet({i2,i1,i3}, tabdarts); + ib.add_facet({i0,i2,i3}, tabdarts); + return ib.end_surface(); +} +/////////////////////////////////////////////////////////////////////////////// +/* 4 + * /|\ + * 0-|-3 + * | | | + * 1---2 + */ +template +typename IncrementalBuilder::LCC::Dart_descriptor + make_pyramid_with_builder(IncrementalBuilder& ib, + std::size_t i0, + std::size_t i1, + std::size_t i2, + std::size_t i3, + std::size_t i4, + std::vector* + tabdarts=nullptr) +{ + ib.begin_surface(); + ib.add_facet({i0,i1,i2,i3}, tabdarts); + ib.add_facet({i1,i0,i4}, tabdarts); + ib.add_facet({i2,i1,i4}, tabdarts); + ib.add_facet({i3,i2,i4}, tabdarts); + ib.add_facet({i0,i3,i4}, tabdarts); + return ib.end_surface(); +} +/////////////////////////////////////////////////////////////////////////////// +/* 3 + * /|\ + * 4---5 + * | | | + * | 0 | + * |/ \| + * 1---2 + */ +template +typename IncrementalBuilder::LCC::Dart_descriptor + make_prism_with_builder(IncrementalBuilder& ib, + std::size_t i0, + std::size_t i1, + std::size_t i2, + std::size_t i3, + std::size_t i4, + std::size_t i5, + std::vector* + tabdarts=nullptr) +{ + ib.begin_surface(); + ib.add_facet({i0,i1,i2}, tabdarts); + ib.add_facet({i1,i0,i3,i4}, tabdarts); + ib.add_facet({i2,i1,i4,i5}, tabdarts); + ib.add_facet({i0,i2,i5,i3}, tabdarts); + ib.add_facet({i5,i4,i3}, tabdarts); + return ib.end_surface(); +} +/////////////////////////////////////////////////////////////////////////////// +/* 7----6 + * /| /| + * 4----5 | + * | 3--|-2 + * |/ |/ + * 0----1 + */ +template +typename IncrementalBuilder::LCC::Dart_descriptor + make_hexahedron_with_builder(IncrementalBuilder& ib, + std::size_t i0, + std::size_t i1, + std::size_t i2, + std::size_t i3, + std::size_t i4, + std::size_t i5, + std::size_t i6, + std::size_t i7, + std::vector* + tabdarts=nullptr) +{ + ib.begin_surface(); + ib.add_facet({i0,i1,i2,i3}, tabdarts); + ib.add_facet({i1,i0,i4,i5}, tabdarts); + ib.add_facet({i2,i1,i5,i6}, tabdarts); + ib.add_facet({i3,i2,i6,i7}, tabdarts); + ib.add_facet({i0,i3,i7,i4}, tabdarts); + ib.add_facet({i7,i6,i5,i4}, tabdarts); + return ib.end_surface(); +} +/////////////////////////////////////////////////////////////////////////////// +template +typename IncrementalBuilder::LCC::Dart_descriptor + make_pentagonal_prism_with_builder(IncrementalBuilder& ib, + std::size_t i0, + std::size_t i1, + std::size_t i2, + std::size_t i3, + std::size_t i4, + std::size_t i5, + std::size_t i6, + std::size_t i7, + std::size_t i8, + std::size_t i9, + std::vector* + tabdarts=nullptr) +{ + ib.begin_surface(); + ib.add_facet({i0,i1,i2,i3,i4}, tabdarts); + ib.add_facet({i1,i0,i5,i6}, tabdarts); + ib.add_facet({i2,i1,i6,i7}, tabdarts); + ib.add_facet({i3,i2,i7,i8}, tabdarts); + ib.add_facet({i4,i3,i8,i9}, tabdarts); + ib.add_facet({i0,i4,i9,i5}, tabdarts); + ib.add_facet({i9,i8,i7,i6,i5}, tabdarts); + return ib.end_surface(); +} +/////////////////////////////////////////////////////////////////////////////// +template +typename IncrementalBuilder::LCC::Dart_descriptor + make_hexagonal_prism_with_builder(IncrementalBuilder& ib, + std::size_t i0, + std::size_t i1, + std::size_t i2, + std::size_t i3, + std::size_t i4, + std::size_t i5, + std::size_t i6, + std::size_t i7, + std::size_t i8, + std::size_t i9, + std::size_t i10, + std::size_t i11, + std::vector* + tabdarts=nullptr) +{ + ib.begin_surface(); + ib.add_facet({i0,i1,i2,i3,i4,i5}, tabdarts); + ib.add_facet({i1,i0,i6,i7}, tabdarts); + ib.add_facet({i2,i1,i7,i8}, tabdarts); + ib.add_facet({i3,i2,i8,i9}, tabdarts); + ib.add_facet({i4,i3,i9,i10}, tabdarts); + ib.add_facet({i5,i4,i10,i11}, tabdarts); + ib.add_facet({i0,i5,i11,i6}, tabdarts); + ib.add_facet({i11,i10,i9,i8,i7,i6}, tabdarts); + return ib.end_surface(); +} +/////////////////////////////////////////////////////////////////////////////// +template +typename IncrementalBuilder::LCC::Dart_descriptor + make_generic_cell_with_builder(IncrementalBuilder& ib, + const std::vector& faces, + std::vector* + tabdarts=nullptr) +{ + ib.begin_surface(); + std::size_t i=1, end; // Start to 1 because faces[0] is the number of faces + for(; i +#include +#include +#include +#include +#include #include namespace CGAL { /** \file Linear_cell_complex_vtk_io.h * Functions to import/export 3D Linear_cell_complex from/to VTK legacy ASCII format. - * + * * Only supports: - * - Linear_cell_complex_for_combinatorial_map<3,3> + * - Linear_cell_complex_for_combinatorial_map<3,3> * - VTK legacy ASCII format (.vtk files) * - Optional scalar fields for vertices and volumes - * + * * Supported VTK cell types: * - VTK_TETRA (10): Tetrahedron * - VTK_VOXEL (11): Voxel (special hexahedron ordering) @@ -35,6 +42,10 @@ namespace CGAL { * - VTK_POLYHEDRON (42): Generic polyhedron */ +// ============================================================================ +// Declarations +// ============================================================================ + /** * \brief Read a VTK legacy ASCII file and load it into a 3D Linear_cell_complex. * \ingroup PkgLinearCellComplexExamples @@ -48,11 +59,11 @@ namespace CGAL { * If provided, will be resized to match number of volumes. * \return `true` if loading was successful, `false` otherwise */ -template -bool read_vtk(LCC& alcc, +template +bool read_lcc_from_vtk(LCC& alcc, const char* filename, - std::vector* vertex_scalars = nullptr, - std::vector* volume_scalars = nullptr); + std::vector* vertex_scalars = nullptr, + std::vector* volume_scalars = nullptr); /** * \brief Write a 3D Linear_cell_complex to a VTK legacy ASCII file. @@ -67,14 +78,593 @@ bool read_vtk(LCC& alcc, * same size as number of 3-cells in the LCC. * \return `true` if writing was successful, `false` otherwise */ -template -bool write_vtk(const LCC& alcc, +template +bool write_lcc_to_vtk(const LCC& alcc, const char* filename, - const std::vector* vertex_scalars = nullptr, - const std::vector* volume_scalars = nullptr); + const std::vector* vertex_scalars = nullptr, + const std::vector* volume_scalars = nullptr); + +// Advanced versions with functors +template +bool read_lcc_from_vtk(LCC& alcc, const char* filename, VertexScalarReader vertex_reader, CellScalarReader cell_reader); + +template +bool write_lcc_to_vtk(const LCC& alcc, const char* filename, PointFunctor ptval, CellFunctor cellval); + +// ============================================================================ +// Implementation details +// ============================================================================ + +namespace internal { + +// Helper: read a scalar of the right type from stream +template +bool read_scalar_by_vtk_type(std::istream& is, const std::string& vtk_type, std::size_t n, Functor f) { + if(vtk_type == "float") { + for(std::size_t i = 0; i < n; ++i) { + float v; + if(!(is >> v)) + return false; + f(i, v); + } + } else if(vtk_type == "double") { + for(std::size_t i = 0; i < n; ++i) { + double v; + if(!(is >> v)) + return false; + f(i, v); + } + } else if(vtk_type == "int") { + for(std::size_t i = 0; i < n; ++i) { + int v; + if(!(is >> v)) + return false; + f(i, v); + } + } else if(vtk_type == "unsigned_int") { + for(std::size_t i = 0; i < n; ++i) { + unsigned int v; + if(!(is >> v)) + return false; + f(i, v); + } + } else if(vtk_type == "short") { + for(std::size_t i = 0; i < n; ++i) { + short int v; + if(!(is >> v)) + return false; + f(i, v); + } + } else if(vtk_type == "unsigned_short") { + for(std::size_t i = 0; i < n; ++i) { + unsigned short int v; + if(!(is >> v)) + return false; + f(i, v); + } + } else if(vtk_type == "char") { + for(std::size_t i = 0; i < n; ++i) { + char v; + int tmp; + if(!(is >> tmp)) + return false; + v = static_cast(tmp); + f(i, v); + } + } else if(vtk_type == "unsigned_char") { + for(std::size_t i = 0; i < n; ++i) { + unsigned char v; + int tmp; + if(!(is >> tmp)) + return false; + v = static_cast(tmp); + f(i, v); + } + } else if(vtk_type == "long") { + for(std::size_t i = 0; i < n; ++i) { + long int v; + if(!(is >> v)) + return false; + f(i, v); + } + } else if(vtk_type == "unsigned_long") { + for(std::size_t i = 0; i < n; ++i) { + unsigned long int v; + if(!(is >> v)) + return false; + f(i, v); + } + } else { + std::cerr << "[ERROR] read_lcc_from_vtk: unsupported scalar type: " << vtk_type << std::endl; + return false; + } + return true; +} + +// VTK type name mapping +template struct gettype +{ + static std::string name() { return "unknown"; } +}; +template <> struct gettype +{ + static std::string name() { return "bit"; } +}; +template <> struct gettype +{ + static std::string name() { return "unsigned_char"; } +}; +template <> struct gettype +{ + static std::string name() { return "char"; } +}; +template <> struct gettype +{ + static std::string name() { return "unsigned_short"; } +}; +template <> struct gettype +{ + static std::string name() { return "short"; } +}; +template <> struct gettype +{ + static std::string name() { return "unsigned_int"; } +}; +template <> struct gettype +{ + static std::string name() { return "int"; } +}; +template <> struct gettype +{ + static std::string name() { return "unsigned_long"; } +}; +template <> struct gettype +{ + static std::string name() { return "long"; } +}; +template <> struct gettype +{ + static std::string name() { return "float"; } +}; +template <> struct gettype +{ + static std::string name() { return "double"; } +}; + +// VTK cell type constants +enum VTK_Cell_Type { + VTK_TETRA = 10, + VTK_VOXEL = 11, + VTK_HEXAHEDRON = 12, + VTK_WEDGE = 13, + VTK_PYRAMID = 14, + VTK_PENTAGONAL_PRISM = 15, + VTK_HEXAGONAL_PRISM = 16, + VTK_POLYHEDRON = 42 +}; + +// Helper: detect VTK cell type from a 3-cell +template inline VTK_Cell_Type get_vtk_cell_type(const LCC& lcc, Dart itvol) { + // Heuristic: count number of vertices and faces + std::size_t nbv = 0, nbf = 0; + for(auto itv = lcc.template one_dart_per_incident_cell<0, 3>(itvol).begin(), + itvend = lcc.template one_dart_per_incident_cell<0, 3>(itvol).end(); + itv != itvend; ++itv) + ++nbv; + for(auto itf = lcc.template one_dart_per_incident_cell<2, 3>(itvol).begin(), + itfend = lcc.template one_dart_per_incident_cell<2, 3>(itvol).end(); + itf != itfend; ++itf) + ++nbf; + + if(nbv == 4 && nbf == 4) + return VTK_TETRA; + if(nbv == 5 && nbf == 5) + return VTK_PYRAMID; + if(nbv == 6 && nbf == 5) + return VTK_WEDGE; + if(nbv == 8 && nbf == 6) + return VTK_HEXAHEDRON; + if(nbv == 10 && nbf == 7) + return VTK_PENTAGONAL_PRISM; + if(nbv == 12 && nbf == 8) + return VTK_HEXAGONAL_PRISM; + return VTK_POLYHEDRON; +} + +template +bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader vertex_reader, CellScalarReader cell_reader) { + static_assert(LCC::dimension == 3 && LCC::ambient_dimension == 3, + "read_lcc_from_vtk() only supports 3D Linear_cell_complexes (3,3)"); + + using Point = typename LCC::Point; + using FT = typename LCC::FT; + + alcc.clear(); + + Linear_cell_complex_incremental_builder_3 ib(alcc); + + std::string line, tmp; + std::size_t npoints, ncells; + + // Skip to POINTS section + while(std::getline(is, line)) { + if(line.find("POINTS") != std::string::npos) + break; + } + if(is.eof()) { + std::cerr << "[ERROR] read_lcc_from_vtk: POINTS section not found" << std::endl; + return false; + } + + std::stringstream ss(line); + std::getline(ss, tmp, ' '); // skip "POINTS" + ss >> npoints; + + // Read points + std::vector points(npoints); + for(std::size_t i = 0; i < npoints; ++i) { + FT x, y, z; + if(!(is >> x >> y >> z)) { + std::cerr << "[ERROR] read_lcc_from_vtk: failed to read point " << i << std::endl; + return false; + } + points[i] = ib.add_vertex(Point(x, y, z)); + } + + // Skip to CELLS section + while(std::getline(is, line)) { + if(line.find("CELLS") != std::string::npos) + break; + } + if(is.eof()) { + std::cerr << "[ERROR] read_lcc_from_vtk: CELLS section not found" << std::endl; + return false; + } + + ss = std::stringstream(line); + std::getline(ss, tmp, ' '); // skip "CELLS" + ss >> ncells; + + // Read connectivity + std::vector> faces(ncells); + std::size_t points_per_cell; + for(std::size_t i = 0; i < ncells; ++i) { + if(!(is >> points_per_cell)) { + std::cerr << "[ERROR] read_lcc_from_vtk: failed to read cell " << i << std::endl; + return false; + } + faces[i].resize(points_per_cell); + for(std::size_t j = 0; j < points_per_cell; ++j) { + if(!(is >> faces[i][j])) { + std::cerr << "[ERROR] read_lcc_from_vtk: failed to read cell " << i << " vertex " << j << std::endl; + return false; + } + } + } + + // Skip to CELL_TYPES section + while(std::getline(is, line)) { + if(line.find("CELL_TYPES") != std::string::npos) + break; + } + if(is.eof()) { + std::cerr << "[ERROR] read_lcc_from_vtk: CELL_TYPES section not found" << std::endl; + return false; + } + + // Create cells based on types + std::size_t cell_type; + for(std::size_t i = 0; i < ncells; ++i) { + if(!(is >> cell_type)) { + std::cerr << "[ERROR] read_lcc_from_vtk: failed to read cell type " << i << std::endl; + return false; + } + const auto& v = faces[i]; + switch(cell_type) { + case 10: // TETRA + if(v.size() == 4) + make_tetrahedron_with_builder(ib, v[0], v[1], v[2], v[3]); + break; + case 11: // VOXEL + if(v.size() == 8) + make_hexahedron_with_builder(ib, v[0], v[1], v[3], v[2], v[4], v[5], v[7], v[6]); + break; + case 12: // HEXAHEDRON + if(v.size() == 8) + make_hexahedron_with_builder(ib, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]); + break; + case 13: // PRISM (WEDGE) + if(v.size() == 6) + make_prism_with_builder(ib, v[0], v[1], v[2], v[3], v[4], v[5]); + break; + case 14: // PYRAMID + if(v.size() == 5) + make_pyramid_with_builder(ib, v[0], v[1], v[2], v[3], v[4]); + break; + case 15: // PENTAGONAL_PRISM + if(v.size() == 10) + make_pentagonal_prism_with_builder(ib, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9]); + break; + case 16: // HEXAGONAL_PRISM + if(v.size() == 12) + make_hexagonal_prism_with_builder(ib, v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7], v[8], v[9], v[10], v[11]); + break; + case 42: // GENERIC CELL + make_generic_cell_with_builder(ib, v); + break; + default: + std::cerr << "[ERROR] read_lcc_from_vtk: type " << cell_type << " unknown." << std::endl; + } + } + + // Clean up unused vertex attributes + for(auto itv = alcc.vertex_attributes().begin(); itv != alcc.vertex_attributes().end();) { + if(alcc.template dart_of_attribute<0>(itv) == alcc.null_descriptor) { + alcc.erase_vertex_attribute(itv); + } else { + ++itv; + } + } + + // Read POINT_DATA scalars if present + while(std::getline(is, line)) { + if(line.find("POINT_DATA") != std::string::npos) { + std::size_t ndata; + ss = std::stringstream(line); + std::getline(ss, tmp, ' '); // skip "POINT_DATA" + ss >> ndata; + + std::getline(is, line); // SCALARS line + std::stringstream scalars_line(line); + std::string scalars, name, vtk_type; + scalars_line >> scalars >> name >> vtk_type; + + std::getline(is, line); // LOOKUP_TABLE line + + if(!read_scalar_by_vtk_type(is, vtk_type, ndata, vertex_reader)) { + std::cerr << "[ERROR] read_lcc_from_vtk: failed to read POINT_DATA" << std::endl; + } + break; + } + } + + // Read CELL_DATA scalars if present + while(std::getline(is, line)) { + if(line.find("CELL_DATA") != std::string::npos) { + std::size_t ndata; + ss = std::stringstream(line); + std::getline(ss, tmp, ' '); // skip "CELL_DATA" + ss >> ndata; + + std::getline(is, line); // SCALARS line + std::stringstream scalars_line(line); + std::string scalars, name, vtk_type; + scalars_line >> scalars >> name >> vtk_type; + + std::getline(is, line); // LOOKUP_TABLE line + + if(!read_scalar_by_vtk_type(is, vtk_type, ndata, cell_reader)) { + std::cerr << "[ERROR] read_lcc_from_vtk: failed to read CELL_DATA" << std::endl; + } + break; + } + } + + return true; +} + +template +bool write_lcc_to_vtk_ascii(std::ostream& os, const LCC& alcc, PointFunctor ptval, CellFunctor cellval) { + static_assert(LCC::dimension == 3 && LCC::ambient_dimension == 3, + "write_lcc_to_vtk() only supports 3D Linear_cell_complexes (3,3)"); + + // Write VTK header + os << "# vtk DataFile Version 2.0\n"; + os << "CGAL Linear_cell_complex\n"; + os << "ASCII\n"; + os << "DATASET UNSTRUCTURED_GRID\n\n"; + + // Build vertex index map + std::unordered_map vertex_index; + std::size_t nbpts = 0; + + for(auto itv = alcc.vertex_attributes().begin(), itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) { + vertex_index[itv] = nbpts++; + } + + // Write points + os << "POINTS " << nbpts << " double\n"; + for(auto itv = alcc.vertex_attributes().begin(), itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) { + const auto& p = itv->point(); + os << p.x() << " " << p.y() << " " << p.z() << "\n"; + } + os << "\n"; + + // Count cells and build connectivity + std::size_t nbcells = 0; + std::size_t total_size = 0; + std::ostringstream cell_stream; + std::ostringstream type_stream; + + for(auto itvol = alcc.template one_dart_per_cell<3>().begin(), itvolend = alcc.template one_dart_per_cell<3>().end(); + itvol != itvolend; ++itvol) + { + ++nbcells; + VTK_Cell_Type cell_type = get_vtk_cell_type(alcc, itvol); + type_stream << static_cast(cell_type) << "\n"; + + if(cell_type == VTK_POLYHEDRON) { + // Generic polyhedron format write as face-vertex connectivity + std::vector> faces; + std::size_t cell_size = 1; // Start with 1 for number of faces + + for(auto itface = alcc.template one_dart_per_incident_cell<2, 3>(itvol).begin(), + itfaceend = alcc.template one_dart_per_incident_cell<2, 3>(itvol).end(); + itface != itfaceend; ++itface) + { + faces.push_back(std::vector()); + auto& face = faces.back(); + + for(auto itvert = alcc.template darts_of_orbit<1>(itface).begin(), + itvertend = alcc.template darts_of_orbit<1>(itface).end(); + itvert != itvertend; ++itvert) + { + face.push_back(vertex_index[alcc.vertex_attribute(itvert)]); + } + cell_size += face.size() + 1; // +1 for face size + } + + cell_stream << cell_size << " " << faces.size(); + for(const auto& face : faces) { + cell_stream << " " << face.size(); + for(auto v : face) { + cell_stream << " " << v; + } + } + cell_stream << "\n"; + total_size += cell_size + 1; // +1 for cell size + + } else { + // Standard cell types write vertex connectivity directly + std::vector vertices; + + for(auto itvert = alcc.template one_dart_per_incident_cell<0, 3>(itvol).begin(), + itvertend = alcc.template one_dart_per_incident_cell<0, 3>(itvol).end(); + itvert != itvertend; ++itvert) + { + vertices.push_back(vertex_index[alcc.vertex_attribute(itvert)]); + } + + cell_stream << vertices.size(); + for(auto v : vertices) { + cell_stream << " " << v; + } + cell_stream << "\n"; + total_size += vertices.size() + 1; + } + } + + // Write cells section + os << "CELLS " << nbcells << " " << total_size << "\n"; + os << cell_stream.str(); + os << "\n"; + + // Write cell types + os << "CELL_TYPES " << nbcells << "\n"; + os << type_stream.str(); + os << "\n"; + + // Write vertex scalars if ptval is not nullptr + if constexpr(!std::is_same_v) { + os << "POINT_DATA " << nbpts << "\n"; + os << "SCALARS vertex_scalars " << gettype::name() << " 1\n"; + os << "LOOKUP_TABLE default\n"; + for(auto itv = alcc.vertex_attributes().begin(), itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) { + auto dart = alcc.template dart_of_attribute<0>(itv); + CGAL_assertion(dart != alcc.null_dart_descriptor); + os << ptval(alcc, dart) << "\n"; + } + } + + // Write cell scalars if cellval is not nullptr/pointer + if constexpr(!std::is_same_v && !std::is_pointer_v) { + os << "CELL_DATA " << nbcells << "\n"; + os << "SCALARS volume_scalars " << gettype::name() << " 1\n"; + os << "LOOKUP_TABLE default\n"; + for(auto itvol = alcc.template one_dart_per_cell<3>().begin(), + itvolend = alcc.template one_dart_per_cell<3>().end(); + itvol != itvolend; ++itvol) + { + os << cellval(alcc, itvol) << "\n"; + } + } + + return true; +} + +} // namespace internal + +// ============================================================================ +// Public interface implementation +// ============================================================================ + +// Functor-based versions +template +inline bool read_lcc_from_vtk(LCC& alcc, const char* filename, VertexScalarReader vertex_reader, CellScalarReader cell_reader) { + CGAL_assertion(filename != nullptr); + std::ifstream file(filename); + if(!file.is_open()) { + std::cerr << "[ERROR] read_lcc_from_vtk: cannot open file " << filename << std::endl; + return false; + } + return internal::read_lcc_from_vtk_ascii(file, alcc, vertex_reader, cell_reader); +} + +template +inline bool write_lcc_to_vtk(const LCC& alcc, const char* filename, PointFunctor ptval, CellFunctor cellval) { + CGAL_assertion(filename != nullptr); + std::ofstream file(filename); + if(!file.is_open()) { + std::cerr << "[ERROR] write_lcc_to_vtk: cannot open file " << filename << std::endl; + return false; + } + return internal::write_lcc_to_vtk_ascii(file, alcc, ptval, cellval); +} + +// Vector-based versions (convenience wrappers) +template +inline bool read_lcc_from_vtk(LCC& alcc, + const char* filename, + std::vector* vertex_scalars, + std::vector* volume_scalars) { + auto v_writer = [&](std::size_t i, ScalarType val) { + if(vertex_scalars) { + if(vertex_scalars->size() <= i) + vertex_scalars->resize(i + 1); + (*vertex_scalars)[i] = val; + } + }; + auto c_writer = [&](std::size_t i, ScalarType val) { + if(volume_scalars) { + if(volume_scalars->size() <= i) + volume_scalars->resize(i + 1); + (*volume_scalars)[i] = val; + } + }; + return read_lcc_from_vtk(alcc, filename, v_writer, c_writer); +} + +template +inline bool write_lcc_to_vtk(const LCC& alcc, + const char* filename, + const std::vector* vertex_scalars, + const std::vector* volume_scalars) { + // Build index maps + std::unordered_map vertex_indices; + std::size_t idx = 0; + for(auto itv = alcc.vertex_attributes().begin(), itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) + vertex_indices[itv] = idx++; + + std::unordered_map volume_indices; + idx = 0; + for(auto itvol = alcc.template one_dart_per_cell<3>().begin(), itvolend = alcc.template one_dart_per_cell<3>().end(); + itvol != itvolend; ++itvol) + volume_indices[itvol] = idx++; + + return write_lcc_to_vtk( + alcc, filename, + [vertex_scalars, &vertex_indices](const LCC& lcc, typename LCC::Dart_const_descriptor d) -> ScalarType { + if(vertex_scalars) + return (*vertex_scalars)[vertex_indices.at(lcc.attribute<0>(d))]; + return ScalarType(); + }, + [volume_scalars, &volume_indices](const LCC& lcc, typename LCC::Dart_const_descriptor d) -> ScalarType { + if(volume_scalars) + return (*volume_scalars)[volume_indices.at(d)]; + return ScalarType(); + }); +} } // namespace CGAL -#include - #endif // CGAL_LINEAR_CELL_COMPLEX_VTK_IO_H \ No newline at end of file diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io_impl.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io_impl.h deleted file mode 100644 index 17b13369b96..00000000000 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io_impl.h +++ /dev/null @@ -1,524 +0,0 @@ -// Copyright (c) 2025 CNRS and LIRIS' Establishments (France). -// All rights reserved. -// -// This file is part of CGAL (www.cgal.org) -// -// $URL$ -// $Id$ -// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial -// -// Author(s) : Guillaume Damiand - -#ifndef CGAL_LINEAR_CELL_COMPLEX_VTK_IO_IMPL_H -#define CGAL_LINEAR_CELL_COMPLEX_VTK_IO_IMPL_H 1 - -#include -#include -#include -#include -#include -#include -#include - -namespace CGAL { - -namespace internal { - -// VTK cell type constants -enum VTK_Cell_Type { - VTK_TETRA = 10, - VTK_VOXEL = 11, - VTK_HEXAHEDRON = 12, - VTK_WEDGE = 13, - VTK_PYRAMID = 14, - VTK_PENTAGONAL_PRISM = 15, - VTK_HEXAGONAL_PRISM = 16, - VTK_POLYHEDRON = 42 -}; - -// Helper function to create a wedge/prism using the incremental builder -template -void create_wedge(LCC& lcc, - typename LCC::Vertex_attribute_descriptor p0, - typename LCC::Vertex_attribute_descriptor p1, - typename LCC::Vertex_attribute_descriptor p2, - typename LCC::Vertex_attribute_descriptor p3, - typename LCC::Vertex_attribute_descriptor p4, - typename LCC::Vertex_attribute_descriptor p5) -{ - // Create wedge using incremental builder - // A wedge has 2 triangular faces and 3 quadrilateral faces - typename LCC::Dart_descriptor d1, d2, d3, d4, d5; - - // Create the triangular faces - d1 = lcc.make_triangle(p0, p1, p2); - d2 = lcc.make_triangle(p3, p5, p4); // reversed order for proper orientation - - // Create quadrilateral faces - d3 = lcc.make_quadrangle(p0, p3, p4, p1); - d4 = lcc.make_quadrangle(p1, p4, p5, p2); - d5 = lcc.make_quadrangle(p2, p5, p3, p0); - - // Now we need to sew these faces together - // This is a simplified approach in practice, you'd need to carefully - // manage the dart orientations and sewing operations - // For now, we'll leave them as separate faces -} - -// Helper function to create a pyramid -template -void create_pyramid(LCC& lcc, - typename LCC::Vertex_attribute_descriptor p0, - typename LCC::Vertex_attribute_descriptor p1, - typename LCC::Vertex_attribute_descriptor p2, - typename LCC::Vertex_attribute_descriptor p3, - typename LCC::Vertex_attribute_descriptor p4) -{ - // Create pyramid using incremental builder - // A pyramid has 1 quadrilateral base and 4 triangular faces - - // Create the quadrilateral base - typename LCC::Dart_descriptor base = lcc.make_quadrangle(p0, p1, p2, p3); - - // Create triangular faces - lcc.make_triangle(p0, p4, p1); - lcc.make_triangle(p1, p4, p2); - lcc.make_triangle(p2, p4, p3); - lcc.make_triangle(p3, p4, p0); - - // This creates separate faces. For a proper pyramid, you'd need - // to sew these faces together using the sew operations of the LCC -} - -// Helper to determine cell topology -template -VTK_Cell_Type get_vtk_cell_type(const LCC& lcc, - typename LCC::Dart_const_descriptor dart) -{ - // Count vertices and faces to determine cell type - std::size_t num_vertices = 0; - std::size_t num_faces = 0; - - for (auto it = lcc.template one_dart_per_incident_cell<0,3>(dart).begin(), - itend = lcc.template one_dart_per_incident_cell<0,3>(dart).end(); - it != itend; ++it) { - ++num_vertices; - } - - for (auto it = lcc.template one_dart_per_incident_cell<2,3>(dart).begin(), - itend = lcc.template one_dart_per_incident_cell<2,3>(dart).end(); - it != itend; ++it) { - ++num_faces; - } - - // Simple heuristic based on vertex/face count - if (num_vertices == 4 && num_faces == 4) return VTK_TETRA; - if (num_vertices == 8 && num_faces == 6) return VTK_HEXAHEDRON; - if (num_vertices == 5 && num_faces == 5) return VTK_PYRAMID; - if (num_vertices == 6 && num_faces == 5) return VTK_WEDGE; - if (num_vertices == 10 && num_faces == 7) return VTK_PENTAGONAL_PRISM; - if (num_vertices == 12 && num_faces == 8) return VTK_HEXAGONAL_PRISM; - - return VTK_POLYHEDRON; // Default to generic polyhedron -} - -template -bool read_vtk_ascii(std::istream& is, - LCC& alcc, - std::vector* vertex_scalars, - std::vector* volume_scalars) -{ - static_assert(LCC::dimension == 3 && LCC::ambient_dimension == 3, - "read_vtk() only supports 3D Linear_cell_complexes (3,3)"); - - using Point = typename LCC::Point; - using FT = typename LCC::FT; - - alcc.clear(); - - std::string line, tmp; - std::size_t npoints, ncells; - - // Skip to POINTS section - while (std::getline(is, line)) { - if (line.find("POINTS") != std::string::npos) break; - } - if (is.eof()) { - std::cerr << "[ERROR] read_vtk: POINTS section not found" << std::endl; - return false; - } - - std::stringstream ss(line); - std::getline(ss, tmp, ' '); // skip "POINTS" - ss >> npoints; - - // Read points - std::vector points(npoints); - FT x, y, z; - for (std::size_t i = 0; i < npoints; ++i) { - if (!(is >> x >> y >> z)) { - std::cerr << "[ERROR] read_vtk: failed to read point " << i << std::endl; - return false; - } - points[i] = alcc.create_vertex_attribute(Point(x, y, z)); - } - - // Skip to CELLS section - while (std::getline(is, line)) { - if (line.find("CELLS") != std::string::npos) break; - } - if (is.eof()) { - std::cerr << "[ERROR] read_vtk: CELLS section not found" << std::endl; - return false; - } - - ss = std::stringstream(line); - std::getline(ss, tmp, ' '); // skip "CELLS" - ss >> ncells; - - // Read connectivity - std::vector> faces(ncells); - std::size_t points_per_cell; - for (std::size_t i = 0; i < ncells; ++i) { - if (!(is >> points_per_cell)) { - std::cerr << "[ERROR] read_vtk: failed to read cell " << i << std::endl; - return false; - } - faces[i].resize(points_per_cell); - for (std::size_t j = 0; j < points_per_cell; ++j) { - if (!(is >> faces[i][j])) { - std::cerr << "[ERROR] read_vtk: failed to read cell " << i - << " vertex " << j << std::endl; - return false; - } - } - } - - // Skip to CELL_TYPES section - while (std::getline(is, line)) { - if (line.find("CELL_TYPES") != std::string::npos) break; - } - if (is.eof()) { - std::cerr << "[ERROR] read_vtk: CELL_TYPES section not found" << std::endl; - return false; - } - - // Create cells based on types - std::size_t cell_type; - for (std::size_t i = 0; i < ncells; ++i) { - if (!(is >> cell_type)) { - std::cerr << "[ERROR] read_vtk: failed to read cell type " << i << std::endl; - return false; - } - - const auto& cell_vertices = faces[i]; - - switch (cell_type) { - case VTK_TETRA: - if (cell_vertices.size() == 4) { - alcc.make_tetrahedron(points[cell_vertices[0]], points[cell_vertices[1]], - points[cell_vertices[2]], points[cell_vertices[3]]); - } - break; - - case VTK_VOXEL: - if (cell_vertices.size() == 8) { - // VTK voxel has different vertex ordering than standard hexahedron - alcc.make_hexahedron(points[cell_vertices[0]], points[cell_vertices[1]], - points[cell_vertices[3]], points[cell_vertices[2]], - points[cell_vertices[4]], points[cell_vertices[5]], - points[cell_vertices[7]], points[cell_vertices[6]]); - } - break; - - case VTK_HEXAHEDRON: - if (cell_vertices.size() == 8) { - alcc.make_hexahedron(points[cell_vertices[0]], points[cell_vertices[1]], - points[cell_vertices[2]], points[cell_vertices[3]], - points[cell_vertices[4]], points[cell_vertices[5]], - points[cell_vertices[6]], points[cell_vertices[7]]); - } - break; - - case VTK_WEDGE: - if (cell_vertices.size() == 6) { - // Use helper function to create wedge - create_wedge(alcc, points[cell_vertices[0]], points[cell_vertices[1]], - points[cell_vertices[2]], points[cell_vertices[3]], - points[cell_vertices[4]], points[cell_vertices[5]]); - } - break; - - case VTK_PYRAMID: - if (cell_vertices.size() == 5) { - // Use helper function to create pyramid - create_pyramid(alcc, points[cell_vertices[0]], points[cell_vertices[1]], - points[cell_vertices[2]], points[cell_vertices[3]], - points[cell_vertices[4]]); - } - break; - - case VTK_POLYHEDRON: - // For generic polyhedron, we'd need more complex construction - // This is a simplified version in practice, VTK polyhedron format - // includes face connectivity information that we're not parsing here - std::cerr << "[WARNING] read_vtk: VTK_POLYHEDRON not fully supported yet" << std::endl; - break; - - default: - std::cerr << "[ERROR] read_vtk: unsupported cell type " << cell_type << std::endl; - break; - } - } - - // Clean up unused vertex attributes - for (auto itv = alcc.vertex_attributes().begin(); - itv != alcc.vertex_attributes().end(); ) { - if (alcc.template dart_of_attribute<0>(itv) == alcc.null_descriptor) { - alcc.erase_vertex_attribute(itv); - } else { - ++itv; - } - } - - // Try to read scalar data if requested - if (vertex_scalars != nullptr) { - vertex_scalars->clear(); - // Look for POINT_DATA section - while (std::getline(is, line)) { - if (line.find("POINT_DATA") != std::string::npos) { - std::size_t ndata; - ss = std::stringstream(line); - std::getline(ss, tmp, ' '); // skip "POINT_DATA" - ss >> ndata; - - // Skip SCALARS and LOOKUP_TABLE lines - std::getline(is, line); // SCALARS line - std::getline(is, line); // LOOKUP_TABLE line - - vertex_scalars->resize(ndata); - for (std::size_t i = 0; i < ndata; ++i) { - if (!(is >> (*vertex_scalars)[i])) { - std::cerr << "[WARNING] read_vtk: failed to read vertex scalar " << i << std::endl; - vertex_scalars->clear(); - break; - } - } - break; - } - } - } - - if (volume_scalars != nullptr) { - volume_scalars->clear(); - // Reset stream or continue from current position - while (std::getline(is, line)) { - if (line.find("CELL_DATA") != std::string::npos) { - std::size_t ndata; - ss = std::stringstream(line); - std::getline(ss, tmp, ' '); // skip "CELL_DATA" - ss >> ndata; - - // Skip SCALARS and LOOKUP_TABLE lines - std::getline(is, line); // SCALARS line - std::getline(is, line); // LOOKUP_TABLE line - - volume_scalars->resize(ndata); - for (std::size_t i = 0; i < ndata; ++i) { - if (!(is >> (*volume_scalars)[i])) { - std::cerr << "[WARNING] read_vtk: failed to read volume scalar " << i << std::endl; - volume_scalars->clear(); - break; - } - } - break; - } - } - } - - return true; -} - -template -bool write_vtk_ascii(std::ostream& os, - const LCC& alcc, - const std::vector* vertex_scalars, - const std::vector* volume_scalars) -{ - static_assert(LCC::dimension == 3 && LCC::ambient_dimension == 3, - "write_vtk() only supports 3D Linear_cell_complexes (3,3)"); - - // Write VTK header - os << "# vtk DataFile Version 2.0\n"; - os << "CGAL Linear_cell_complex\n"; - os << "ASCII\n"; - os << "DATASET UNSTRUCTURED_GRID\n\n"; - - // Build vertex index map - std::unordered_map vertex_index; - std::size_t nbpts = 0; - - for (auto itv = alcc.vertex_attributes().begin(), - itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) { - vertex_index[itv] = nbpts++; - } - - // Write points - os << "POINTS " << nbpts << " double\n"; - for (auto itv = alcc.vertex_attributes().begin(), - itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) { - const auto& p = itv->point(); - os << p.x() << " " << p.y() << " " << p.z() << "\n"; - } - os << "\n"; - - // Count cells and build connectivity - std::size_t nbcells = 0; - std::size_t total_size = 0; - std::ostringstream cell_stream; - std::ostringstream type_stream; - - for (auto itvol = alcc.template one_dart_per_cell<3>().begin(), - itvolend = alcc.template one_dart_per_cell<3>().end(); - itvol != itvolend; ++itvol) { - - ++nbcells; - VTK_Cell_Type cell_type = get_vtk_cell_type(alcc, itvol); - type_stream << static_cast(cell_type) << "\n"; - - if (cell_type == VTK_POLYHEDRON) { - // Generic polyhedron format write as face-vertex connectivity - std::vector> faces; - std::size_t cell_size = 1; // Start with 1 for number of faces - - for (auto itface = alcc.template one_dart_per_incident_cell<2,3>(itvol).begin(), - itfaceend = alcc.template one_dart_per_incident_cell<2,3>(itvol).end(); - itface != itfaceend; ++itface) { - - faces.push_back(std::vector()); - auto& face = faces.back(); - - for (auto itvert = alcc.template darts_of_orbit<1>(itface).begin(), - itvertend = alcc.template darts_of_orbit<1>(itface).end(); - itvert != itvertend; ++itvert) { - face.push_back(vertex_index[alcc.vertex_attribute(itvert)]); - } - cell_size += face.size() + 1; // +1 for face size - } - - cell_stream << cell_size << " " << faces.size(); - for (const auto& face : faces) { - cell_stream << " " << face.size(); - for (auto v : face) { - cell_stream << " " << v; - } - } - cell_stream << "\n"; - total_size += cell_size + 1; // +1 for cell size - - } else { - // Standard cell types write vertex connectivity directly - std::vector vertices; - - for (auto itvert = alcc.template one_dart_per_incident_cell<0,3>(itvol).begin(), - itvertend = alcc.template one_dart_per_incident_cell<0,3>(itvol).end(); - itvert != itvertend; ++itvert) { - vertices.push_back(vertex_index[alcc.vertex_attribute(itvert)]); - } - - cell_stream << vertices.size(); - for (auto v : vertices) { - cell_stream << " " << v; - } - cell_stream << "\n"; - total_size += vertices.size() + 1; - } - } - - // Write cells section - os << "CELLS " << nbcells << " " << total_size << "\n"; - os << cell_stream.str(); - os << "\n"; - - // Write cell types - os << "CELL_TYPES " << nbcells << "\n"; - os << type_stream.str(); - os << "\n"; - - // Write vertex scalars if provided - if (vertex_scalars != nullptr) { - if (vertex_scalars->size() != nbpts) { - std::cerr << "[ERROR] write_vtk: vertex_scalars size (" << vertex_scalars->size() - << ") does not match number of vertices (" << nbpts << ")" << std::endl; - return false; - } - - os << "POINT_DATA " << nbpts << "\n"; - os << "SCALARS vertex_scalars float 1\n"; - os << "LOOKUP_TABLE default\n"; - for (float val : *vertex_scalars) { - os << val << "\n"; - } - os << "\n"; - } - - // Write volume scalars if provided - if (volume_scalars != nullptr) { - if (volume_scalars->size() != nbcells) { - std::cerr << "[ERROR] write_vtk: volume_scalars size (" << volume_scalars->size() - << ") does not match number of cells (" << nbcells << ")" << std::endl; - return false; - } - - os << "CELL_DATA " << nbcells << "\n"; - os << "SCALARS volume_scalars float 1\n"; - os << "LOOKUP_TABLE default\n"; - for (float val : *volume_scalars) { - os << val << "\n"; - } - } - - return true; -} - -} // namespace internal - -// Public interface implementation - -template -bool read_vtk(LCC& alcc, - const char* filename, - std::vector* vertex_scalars, - std::vector* volume_scalars) -{ - CGAL_assertion(filename != nullptr); - - std::ifstream file(filename); - if (!file.is_open()) { - std::cerr << "[ERROR] read_vtk: cannot open file " << filename << std::endl; - return false; - } - - return internal::read_vtk_ascii(file, alcc, vertex_scalars, volume_scalars); -} - -template -bool write_vtk(const LCC& alcc, - const char* filename, - const std::vector* vertex_scalars, - const std::vector* volume_scalars) -{ - CGAL_assertion(filename != nullptr); - - std::ofstream file(filename); - if (!file.is_open()) { - std::cerr << "[ERROR] write_vtk: cannot open file " << filename << std::endl; - return false; - } - - return internal::write_vtk_ascii(file, alcc, vertex_scalars, volume_scalars); -} - -} // namespace CGAL - -#endif // CGAL_LINEAR_CELL_COMPLEX_VTK_IO_IMPL_H \ No newline at end of file diff --git a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp index fb6d9ab10fb..9530c5b3ed8 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp +++ b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp @@ -1,48 +1,45 @@ #include #include - -#include -#include #include -#include +#include +#include +#include typedef CGAL::Linear_cell_complex_for_combinatorial_map<3, 3> LCC; -typedef LCC::Point Point; -int main() -{ - LCC lcc_out; +int main() { + LCC lcc1, lcc2; + std::vector v_scalars1, vol_scalars1; + std::vector v_scalars2, vol_scalars2; - // Create a hexahedron - auto d = lcc_out.make_hexahedron( - lcc_out.create_vertex_attribute(Point(0, 0, 0)), - lcc_out.create_vertex_attribute(Point(1, 0, 0)), - lcc_out.create_vertex_attribute(Point(1, 1, 0)), - lcc_out.create_vertex_attribute(Point(0, 1, 0)), - lcc_out.create_vertex_attribute(Point(0, 0, 1)), - lcc_out.create_vertex_attribute(Point(1, 0, 1)), - lcc_out.create_vertex_attribute(Point(1, 1, 1)), - lcc_out.create_vertex_attribute(Point(0, 1, 1)) - ); + const std::string input_file = "data/beam-with-mixed-cells.vtk"; + assert(CGAL::read_lcc_from_vtk(lcc1, input_file.c_str(), &v_scalars1, &vol_scalars1)); - std::vector v_scalars = {1,2,3,4,5,6,7,8}; - std::vector vol_scalars = {42.0f}; + // Build index maps + std::unordered_map vertex_indices; + std::size_t idx = 0; + for(auto itv = lcc1.vertex_attributes().begin(), itvend = lcc1.vertex_attributes().end(); itv != itvend; ++itv) + vertex_indices[itv] = idx++; + std::unordered_map volume_indices; + idx = 0; + for(auto itvol = lcc1.one_dart_per_cell<3>().begin(), itvolend = lcc1.one_dart_per_cell<3>().end(); itvol != itvolend; + ++itvol) + volume_indices[itvol] = idx++; - const char* fname = "tmp_test_lcc_vtk.vtk"; + const char* tmp_file = "tmp_test_lcc_vtk.vtk"; + assert(CGAL::write_lcc_to_vtk( + lcc1, tmp_file, + [&v_scalars1, &vertex_indices](const LCC& lcc, LCC::Dart_const_descriptor d) { + return v_scalars1[vertex_indices.at(lcc.attribute<0>(d))]; + }, + [&vol_scalars1, &volume_indices](const LCC& lcc, LCC::Dart_const_descriptor d) { + return vol_scalars1[volume_indices.at(d)]; + })); + assert(CGAL::read_lcc_from_vtk(lcc2, tmp_file, &v_scalars2, &vol_scalars2)); - assert(CGAL::write_vtk(lcc_out, fname, &v_scalars, &vol_scalars)); + assert(lcc1.is_isomorphic_to(lcc2, false, true, true)); - LCC lcc_in; - std::vector v_scalars_in, vol_scalars_in; - - assert(CGAL::read_vtk(lcc_in, fname, &v_scalars_in, &vol_scalars_in)); - - assert(lcc_in.number_of_vertex_attributes() == lcc_out.number_of_vertex_attributes()); - assert(lcc_in.template number_of_cells<3>() == lcc_out.template number_of_cells<3>()); - assert(v_scalars_in.size() == v_scalars.size()); - assert(vol_scalars_in.size() == vol_scalars.size()); - - std::remove(fname); + std::remove(tmp_file); return EXIT_SUCCESS; } \ No newline at end of file diff --git a/Linear_cell_complex/test/Linear_cell_complex/data/beam-with-mixed-cells.vtk b/Linear_cell_complex/test/Linear_cell_complex/data/beam-with-mixed-cells.vtk new file mode 100644 index 00000000000..3197599a238 --- /dev/null +++ b/Linear_cell_complex/test/Linear_cell_complex/data/beam-with-mixed-cells.vtk @@ -0,0 +1,11 @@ +# vtk DataFile Version 2.0 +CGAL Linear_cell_complex +ASCII +DATASET UNSTRUCTURED_GRID + +POINTS 0 double + +CELLS 0 0 + +CELL_TYPES 0 + From e0634c4ab1a6e6d8e4d56511c1ad4f8d8696ef80 Mon Sep 17 00:00:00 2001 From: Yliess Bellargui Date: Wed, 6 Aug 2025 22:34:33 +0200 Subject: [PATCH 03/30] Add VTK I/O support for Linear_cell_complex --- .../Testing/Temporary/CTestCostData.txt | 1 + .../Testing/Temporary/LastTest.log | 3 + .../linear_cell_complex_3_vtk_io.cpp | 6 +- .../IO/VTK.h} | 63 +- .../Linear_cell_complex_vtk_io_test.cpp | 8 +- .../data/mixed-linear-bending-pdisttosurf.vtk | 673 ++++++++++++++++++ .../File_formats/Supported_file_formats.txt | 25 + Testing/Temporary/CTestCostData.txt | 1 + Testing/Temporary/LastTest.log | 3 + 9 files changed, 745 insertions(+), 38 deletions(-) create mode 100644 Linear_cell_complex/Testing/Temporary/CTestCostData.txt create mode 100644 Linear_cell_complex/Testing/Temporary/LastTest.log rename Linear_cell_complex/include/CGAL/{Linear_cell_complex_vtk_io.h => Linear_cell_complex/IO/VTK.h} (89%) create mode 100644 Linear_cell_complex/test/Linear_cell_complex/data/mixed-linear-bending-pdisttosurf.vtk create mode 100644 Testing/Temporary/CTestCostData.txt create mode 100644 Testing/Temporary/LastTest.log diff --git a/Linear_cell_complex/Testing/Temporary/CTestCostData.txt b/Linear_cell_complex/Testing/Temporary/CTestCostData.txt new file mode 100644 index 00000000000..ed97d539c09 --- /dev/null +++ b/Linear_cell_complex/Testing/Temporary/CTestCostData.txt @@ -0,0 +1 @@ +--- diff --git a/Linear_cell_complex/Testing/Temporary/LastTest.log b/Linear_cell_complex/Testing/Temporary/LastTest.log new file mode 100644 index 00000000000..7016d17c7c2 --- /dev/null +++ b/Linear_cell_complex/Testing/Temporary/LastTest.log @@ -0,0 +1,3 @@ +Start testing: Jul 25 15:46 CEST +---------------------------------------------------------- +End testing: Jul 25 15:46 CEST diff --git a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp index 2f383fa24d5..6c080d0508f 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp @@ -6,11 +6,11 @@ \cgal function `CGAL::load_combinatorial_map()`. It computes for each 3-cell (volume) the number of incident vertices (0-cells), stores these values in a `std::vector`, and writes the result to a `.vtk` file with - `CGAL::write_lcc_to_vtk()`, using the computed values as scalars for each volume. + `CGAL::IO::write_VTK()`, using the computed values as scalars for each volume. */ #include -#include +#include #include #include #include @@ -24,6 +24,6 @@ int main() std::vector v; for(auto it = lcc.template one_dart_per_cell<3>().begin(), itend = lcc.template one_dart_per_cell<3>().end(); it != itend; ++it) v.push_back(std::distance(lcc.template one_dart_per_incident_cell<0,3>(lcc.dart_descriptor(*it)).begin(), lcc.template one_dart_per_incident_cell<0,3>(lcc.dart_descriptor(*it)).end())); - CGAL::write_lcc_to_vtk(lcc, "data/beam-with-mixed-cells.vtk", nullptr, &v); + CGAL::IO::write_VTK(lcc, "data/beam-with-mixed-cells.vtk", nullptr, &v); return EXIT_SUCCESS; } \ No newline at end of file diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h similarity index 89% rename from Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io.h rename to Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h index dcdc5658994..7cb0d8dd660 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_vtk_io.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h @@ -9,10 +9,9 @@ // // Author(s) : Guillaume Damiand -#ifndef CGAL_LINEAR_CELL_COMPLEX_VTK_IO_H -#define CGAL_LINEAR_CELL_COMPLEX_VTK_IO_H 1 - -#include "Linear_cell_complex_incremental_builder_3.h" +#ifndef CGAL_LCC_IO_VTK_H +#define CGAL_LCC_IO_VTK_H 1 +#include #include #include #include @@ -22,8 +21,9 @@ #include namespace CGAL { +namespace IO { -/** \file Linear_cell_complex_vtk_io.h +/** \file VTK.h * Functions to import/export 3D Linear_cell_complex from/to VTK legacy ASCII format. * * Only supports: @@ -60,7 +60,7 @@ namespace CGAL { * \return `true` if loading was successful, `false` otherwise */ template -bool read_lcc_from_vtk(LCC& alcc, +bool read_VTK(LCC& alcc, const char* filename, std::vector* vertex_scalars = nullptr, std::vector* volume_scalars = nullptr); @@ -79,17 +79,17 @@ bool read_lcc_from_vtk(LCC& alcc, * \return `true` if writing was successful, `false` otherwise */ template -bool write_lcc_to_vtk(const LCC& alcc, +bool write_VTK(const LCC& alcc, const char* filename, const std::vector* vertex_scalars = nullptr, const std::vector* volume_scalars = nullptr); // Advanced versions with functors template -bool read_lcc_from_vtk(LCC& alcc, const char* filename, VertexScalarReader vertex_reader, CellScalarReader cell_reader); +bool read_VTK(LCC& alcc, const char* filename, VertexScalarReader vertex_reader, CellScalarReader cell_reader); template -bool write_lcc_to_vtk(const LCC& alcc, const char* filename, PointFunctor ptval, CellFunctor cellval); +bool write_VTK(const LCC& alcc, const char* filename, PointFunctor ptval, CellFunctor cellval); // ============================================================================ // Implementation details @@ -175,7 +175,7 @@ bool read_scalar_by_vtk_type(std::istream& is, const std::string& vtk_type, std: f(i, v); } } else { - std::cerr << "[ERROR] read_lcc_from_vtk: unsupported scalar type: " << vtk_type << std::endl; + std::cerr << "[ERROR] read_VTK: unsupported scalar type: " << vtk_type << std::endl; return false; } return true; @@ -274,7 +274,7 @@ template inline VTK_Cell_Type get_vtk_cell_type(co template bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader vertex_reader, CellScalarReader cell_reader) { static_assert(LCC::dimension == 3 && LCC::ambient_dimension == 3, - "read_lcc_from_vtk() only supports 3D Linear_cell_complexes (3,3)"); + "read_VTK() only supports 3D Linear_cell_complexes (3,3)"); using Point = typename LCC::Point; using FT = typename LCC::FT; @@ -292,7 +292,7 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver break; } if(is.eof()) { - std::cerr << "[ERROR] read_lcc_from_vtk: POINTS section not found" << std::endl; + std::cerr << "[ERROR] read_VTK: POINTS section not found" << std::endl; return false; } @@ -305,7 +305,7 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver for(std::size_t i = 0; i < npoints; ++i) { FT x, y, z; if(!(is >> x >> y >> z)) { - std::cerr << "[ERROR] read_lcc_from_vtk: failed to read point " << i << std::endl; + std::cerr << "[ERROR] read_VTK: failed to read point " << i << std::endl; return false; } points[i] = ib.add_vertex(Point(x, y, z)); @@ -317,7 +317,7 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver break; } if(is.eof()) { - std::cerr << "[ERROR] read_lcc_from_vtk: CELLS section not found" << std::endl; + std::cerr << "[ERROR] read_VTK: CELLS section not found" << std::endl; return false; } @@ -330,13 +330,13 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver std::size_t points_per_cell; for(std::size_t i = 0; i < ncells; ++i) { if(!(is >> points_per_cell)) { - std::cerr << "[ERROR] read_lcc_from_vtk: failed to read cell " << i << std::endl; + std::cerr << "[ERROR] read_VTK: failed to read cell " << i << std::endl; return false; } faces[i].resize(points_per_cell); for(std::size_t j = 0; j < points_per_cell; ++j) { if(!(is >> faces[i][j])) { - std::cerr << "[ERROR] read_lcc_from_vtk: failed to read cell " << i << " vertex " << j << std::endl; + std::cerr << "[ERROR] read_VTK: failed to read cell " << i << " vertex " << j << std::endl; return false; } } @@ -348,7 +348,7 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver break; } if(is.eof()) { - std::cerr << "[ERROR] read_lcc_from_vtk: CELL_TYPES section not found" << std::endl; + std::cerr << "[ERROR] read_VTK: CELL_TYPES section not found" << std::endl; return false; } @@ -356,7 +356,7 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver std::size_t cell_type; for(std::size_t i = 0; i < ncells; ++i) { if(!(is >> cell_type)) { - std::cerr << "[ERROR] read_lcc_from_vtk: failed to read cell type " << i << std::endl; + std::cerr << "[ERROR] read_VTK: failed to read cell type " << i << std::endl; return false; } const auto& v = faces[i]; @@ -393,7 +393,7 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver make_generic_cell_with_builder(ib, v); break; default: - std::cerr << "[ERROR] read_lcc_from_vtk: type " << cell_type << " unknown." << std::endl; + std::cerr << "[ERROR] read_VTK: type " << cell_type << " unknown." << std::endl; } } @@ -422,7 +422,7 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver std::getline(is, line); // LOOKUP_TABLE line if(!read_scalar_by_vtk_type(is, vtk_type, ndata, vertex_reader)) { - std::cerr << "[ERROR] read_lcc_from_vtk: failed to read POINT_DATA" << std::endl; + std::cerr << "[ERROR] read_VTK: failed to read POINT_DATA" << std::endl; } break; } @@ -444,7 +444,7 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver std::getline(is, line); // LOOKUP_TABLE line if(!read_scalar_by_vtk_type(is, vtk_type, ndata, cell_reader)) { - std::cerr << "[ERROR] read_lcc_from_vtk: failed to read CELL_DATA" << std::endl; + std::cerr << "[ERROR] read_VTK: failed to read CELL_DATA" << std::endl; } break; } @@ -456,7 +456,7 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver template bool write_lcc_to_vtk_ascii(std::ostream& os, const LCC& alcc, PointFunctor ptval, CellFunctor cellval) { static_assert(LCC::dimension == 3 && LCC::ambient_dimension == 3, - "write_lcc_to_vtk() only supports 3D Linear_cell_complexes (3,3)"); + "write_VTK() only supports 3D Linear_cell_complexes (3,3)"); // Write VTK header os << "# vtk DataFile Version 2.0\n"; @@ -590,22 +590,22 @@ bool write_lcc_to_vtk_ascii(std::ostream& os, const LCC& alcc, PointFunctor ptva // Functor-based versions template -inline bool read_lcc_from_vtk(LCC& alcc, const char* filename, VertexScalarReader vertex_reader, CellScalarReader cell_reader) { +inline bool read_VTK(LCC& alcc, const char* filename, VertexScalarReader vertex_reader, CellScalarReader cell_reader) { CGAL_assertion(filename != nullptr); std::ifstream file(filename); if(!file.is_open()) { - std::cerr << "[ERROR] read_lcc_from_vtk: cannot open file " << filename << std::endl; + std::cerr << "[ERROR] read_VTK: cannot open file " << filename << std::endl; return false; } return internal::read_lcc_from_vtk_ascii(file, alcc, vertex_reader, cell_reader); } template -inline bool write_lcc_to_vtk(const LCC& alcc, const char* filename, PointFunctor ptval, CellFunctor cellval) { +inline bool write_VTK(const LCC& alcc, const char* filename, PointFunctor ptval, CellFunctor cellval) { CGAL_assertion(filename != nullptr); std::ofstream file(filename); if(!file.is_open()) { - std::cerr << "[ERROR] write_lcc_to_vtk: cannot open file " << filename << std::endl; + std::cerr << "[ERROR] write_VTK: cannot open file " << filename << std::endl; return false; } return internal::write_lcc_to_vtk_ascii(file, alcc, ptval, cellval); @@ -613,7 +613,7 @@ inline bool write_lcc_to_vtk(const LCC& alcc, const char* filename, PointFunctor // Vector-based versions (convenience wrappers) template -inline bool read_lcc_from_vtk(LCC& alcc, +inline bool read_VTK(LCC& alcc, const char* filename, std::vector* vertex_scalars, std::vector* volume_scalars) { @@ -631,11 +631,11 @@ inline bool read_lcc_from_vtk(LCC& alcc, (*volume_scalars)[i] = val; } }; - return read_lcc_from_vtk(alcc, filename, v_writer, c_writer); + return read_VTK(alcc, filename, v_writer, c_writer); } template -inline bool write_lcc_to_vtk(const LCC& alcc, +inline bool write_VTK(const LCC& alcc, const char* filename, const std::vector* vertex_scalars, const std::vector* volume_scalars) { @@ -651,7 +651,7 @@ inline bool write_lcc_to_vtk(const LCC& alcc, itvol != itvolend; ++itvol) volume_indices[itvol] = idx++; - return write_lcc_to_vtk( + return write_VTK( alcc, filename, [vertex_scalars, &vertex_indices](const LCC& lcc, typename LCC::Dart_const_descriptor d) -> ScalarType { if(vertex_scalars) @@ -665,6 +665,7 @@ inline bool write_lcc_to_vtk(const LCC& alcc, }); } +} // namespace IO } // namespace CGAL -#endif // CGAL_LINEAR_CELL_COMPLEX_VTK_IO_H \ No newline at end of file +#endif // CGAL_LCC_IO_VTK_H \ No newline at end of file diff --git a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp index 9530c5b3ed8..93aa2a27d7d 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp +++ b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp @@ -1,5 +1,5 @@ #include -#include +#include #include #include #include @@ -13,7 +13,7 @@ int main() { std::vector v_scalars2, vol_scalars2; const std::string input_file = "data/beam-with-mixed-cells.vtk"; - assert(CGAL::read_lcc_from_vtk(lcc1, input_file.c_str(), &v_scalars1, &vol_scalars1)); + assert(CGAL::IO::read_VTK(lcc1, input_file.c_str(), &v_scalars1, &vol_scalars1)); // Build index maps std::unordered_map vertex_indices; @@ -27,7 +27,7 @@ int main() { volume_indices[itvol] = idx++; const char* tmp_file = "tmp_test_lcc_vtk.vtk"; - assert(CGAL::write_lcc_to_vtk( + assert(CGAL::IO::write_VTK( lcc1, tmp_file, [&v_scalars1, &vertex_indices](const LCC& lcc, LCC::Dart_const_descriptor d) { return v_scalars1[vertex_indices.at(lcc.attribute<0>(d))]; @@ -35,7 +35,7 @@ int main() { [&vol_scalars1, &volume_indices](const LCC& lcc, LCC::Dart_const_descriptor d) { return vol_scalars1[volume_indices.at(d)]; })); - assert(CGAL::read_lcc_from_vtk(lcc2, tmp_file, &v_scalars2, &vol_scalars2)); + assert(CGAL::IO::read_VTK(lcc2, tmp_file, &v_scalars2, &vol_scalars2)); assert(lcc1.is_isomorphic_to(lcc2, false, true, true)); diff --git a/Linear_cell_complex/test/Linear_cell_complex/data/mixed-linear-bending-pdisttosurf.vtk b/Linear_cell_complex/test/Linear_cell_complex/data/mixed-linear-bending-pdisttosurf.vtk new file mode 100644 index 00000000000..1aaee160410 --- /dev/null +++ b/Linear_cell_complex/test/Linear_cell_complex/data/mixed-linear-bending-pdisttosurf.vtk @@ -0,0 +1,673 @@ +# vtk DataFile Version 2.0 +3D Mesh +ASCII +DATASET UNSTRUCTURED_GRID +POINTS 329 double + 0.117844 -0.279767 1.08011 + 0.102602 -0.267148 1.0493 + 0.199542 -0.280426 1.08011 + 0.199629 -0.318181 1.17014 + -0.000927929 -0.355862 1.26093 + 0.199648 -0.350348 1.24569 + 0.199633 -0.356614 1.26021 + -0.00154631 -0.287035 1.10025 + -0.00215992 -0.206748 0.900091 + 0.0388902 -0.279312 1.08045 + 0.000544925 -0.0928771 1.15542 + 2.50809e-05 -0.0188471 0.969227 + 0.000474716 -0.170576 1.33869 + -0.00146544 -0.279058 1.08055 + 0.000479773 -0.171026 1.33974 + 0.000485021 -0.169846 1.34024 + 0.00242347 0.0925284 1.22939 + 0.0019677 0.0120239 1.41809 + 0.172282 0.0908555 1.229 + 0.199499 -0.248694 1.00169 + 0.300049 -0.280533 1.07979 + 0.300115 -0.318195 1.16993 + 0.249878 -0.318145 1.16996 + 0.199635 -0.337341 1.21516 + 0.206796 -0.356616 1.26016 + 0.295316 -0.436999 1.44063 + 0.199577 -0.436486 1.44076 + -0.000760644 -0.435756 1.44174 + 0.399954 -0.437395 1.44057 + 0.24981 -0.3568 1.26009 + 0.400384 -0.172678 1.33876 + 0.400382 -0.407585 1.67199 + 0.400493 -0.254203 1.52166 + 0.399931 -0.519595 1.62103 + 0.400645 -0.327928 1.68306 + 0.400672 -0.337427 1.70374 + 0.299787 -0.519236 1.62121 + 0.383854 -0.519535 1.62104 + 0.199675 -0.518866 1.62155 + 0.149622 -0.518632 1.6217 + 0.0995653 -0.518389 1.62185 + -0.000243934 -0.472347 1.64297 + -0.000583228 -0.517902 1.62227 + 0.201493 -0.0711814 1.60324 + 0.00188744 -0.070056 1.60395 + 0.000544026 -0.252589 1.5226 + 0.400317 -0.133017 1.24684 + 0.400392 -0.264876 1.2997 + 0.400408 -0.225684 1.20865 + 0.400602 -0.318037 1.16996 + 0.400347 -0.357052 1.26002 + 0.300056 -0.337493 1.21498 + 0.300003 -0.356956 1.26002 + 0.400533 -0.28056 1.07992 + 0.400422 -0.187233 1.11759 + 0.400133 -0.0938909 1.15437 + 0.40079 -0.208152 0.899168 + 0.400809 -0.209803 0.903426 + 0.199315 -0.208531 0.899399 + 0.400103 -0.0748807 1.16204 + 0.400183 -0.0870121 1.13757 + 0.400219 -0.0201366 0.968839 + 0.399881 0.0905685 1.22888 + 0.399382 0.16705 1.03746 + 0.200823 0.166672 1.03792 + 0.20111 0.0906915 1.22885 + 0.400612 -0.114445 0.934523 + 0.40086 -0.0800494 0.84256 + 0.400264 0.0477057 0.78096 + 0.40027 0.0147103 0.875096 + 0.398348 0.238354 0.840656 + 0.00269146 0.238014 0.843979 + 0.00216973 0.191139 0.827757 + 0.200532 0.23675 0.841985 + 0.0521965 0.237337 0.842936 + 0.00272124 0.233613 0.857286 + 0.0840499 0.166764 1.03739 + 0.260256 0.0108216 1.41731 + 0.20115 0.0647793 1.29135 + 0.400182 0.0275115 1.37849 + 0.324831 0.0107867 1.41726 + 0.40032 0.0108929 1.41698 + 0.201324 0.0109127 1.41755 + 0.00191039 -0.0600546 1.58165 + 0.201357 -0.0165888 1.48028 + 0.272863 -0.000829879 1.44391 + 0.400923 -0.071409 1.60247 + 0.300127 -0.208542 0.899147 + 0.401235 -0.175248 0.808826 + 0.401662 -0.143242 0.718871 + 0.401097 -0.0478292 0.75012 + 0.19971 -0.143604 0.718933 + 0.19969 -0.17567 0.808894 + 0.0283583 -0.207283 0.89991 + 0.30118 -0.0877158 0.537365 + 0.351889 -0.0873609 0.53745 + 0.300728 -0.143835 0.718393 + 0.199689 -0.0877262 0.537407 + 0.402562 -0.0868125 0.537503 + 0.402114 -0.0382943 0.551213 + -0.0020446 -0.141708 0.718591 + -0.00269365 -0.0860023 0.538517 + 0.000183889 0.0489514 0.780824 + 0.000247973 0.0798914 0.685923 + 0.000202365 0.0943941 0.638085 + 0.300438 -0.175116 0.808842 + 0.200906 0.268159 0.741093 + 0.0524026 0.253778 0.792639 + 0.101689 0.237029 0.842233 + 0.101918 0.253301 0.792086 + 0.101966 0.269168 0.741793 + 0.0526198 0.269721 0.742081 + 0.00260275 0.223187 0.727961 + 0.00326241 0.270322 0.742419 + 0.00310344 0.254327 0.792944 + 0.00246661 0.207321 0.777861 + 0.102035 0.29907 0.639701 + 0.102128 0.284481 0.691026 + 0.00157259 0.143916 0.811832 + 0.00104317 0.127786 0.69998 + 0.00179243 0.175586 0.71399 + 0.00168674 0.160053 0.76307 + 0.00107696 0.156684 0.602456 + 0.000130298 0.108517 0.590352 + 0.00188155 0.190522 0.664651 + 0.00194231 0.204652 0.61499 + 0.00276869 0.252557 0.627444 + 0.00382961 0.350429 0.4326 + 0.0035181 0.300465 0.639444 + 0.200646 0.298876 0.639228 + 0.00275257 0.238259 0.677952 + 0.00344385 0.285621 0.691231 + 0.0527601 0.284901 0.691146 + -0.00190717 0.0575125 0.377389 + 0.000180886 0.15652 0.396133 + -0.00339568 -0.0414656 0.356774 + 0.0980358 -0.0429848 0.357157 + 0.199853 -0.0435406 0.356622 + 0.398688 0.299111 0.640174 + 0.400455 0.107893 0.589549 + 0.400385 0.132823 0.493018 + 0.0527602 0.299652 0.639716 + 0.102433 0.38313 0.219416 + 0.0533349 0.383721 0.219678 + 0.200897 0.348681 0.43234 + 0.200827 0.382963 0.219265 + 0.00433835 0.384608 0.22039 + 0.00338989 0.335954 0.214058 + -0.000370419 0.188791 0.198294 + -0.000206422 0.174387 0.297141 + -0.00243614 0.0756297 0.283252 + 0.199981 -0.0642111 0.446502 + 0.301523 -0.064166 0.447224 + 0.30139 -0.0759116 0.492248 + 0.352154 -0.0754694 0.492307 + 0.402405 -0.0258558 0.505331 + 0.401601 0.0103101 0.564154 + 0.401744 0.0231251 0.517531 + 0.401876 0.0463011 0.424084 + 0.401835 0.0351821 0.470929 + 0.402445 -0.0140065 0.459403 + 0.40363 -0.0423327 0.358053 + 0.402015 0.0567642 0.37727 + 0.40313 -0.0633716 0.447853 + 0.402942 -0.0748896 0.492563 + 0.301801 -0.0265415 0.267373 + 0.403739 -0.0255785 0.267783 + 0.402245 0.0748334 0.283635 + 0.401288 0.124291 0.290658 + 0.400357 0.155088 0.395707 + 0.401144 0.105879 0.386532 + 0.401076 0.095459 0.434267 + 0.398163 0.349739 0.431794 + 0.400289 0.173691 0.29771 + 0.400229 0.18135 0.248745 + 0.4 0 0 + 0.40013 0.188796 0.199689 + 0.4 0.4 0 + 0.2 0.4 0 + 0.398307 0.382932 0.217345 + 0.4 0.2 0 + 0.2 0.3 0 + 0.200877 0.391862 0.109846 + 0.101717 0.39294 0.109963 + 0.102296 0.388469 0.16457 + 0.1 0.4 0 + 0 0.4 0 + 0.00365088 0.39415 0.11046 + 0.0530706 0.389057 0.164822 + 0.00329423 0.341401 0.160892 + 0.00211108 0.2922 0.15649 + 0.00220697 0.28694 0.208571 + 0.00169669 0.296249 0.10425 + 0.0525666 0.393497 0.110224 + 0.004162 0.389947 0.165372 + 0.00277329 0.345255 0.107351 + 0 0.2 0 + 0 0.3 0 + 0.1 0.2 0 + 0.1 0.3 0 + -0.000168421 0.196766 0.099037 + 0.2 0.2 0 + 0.2 0 0 + 0 0 0 + -0.00452584 -0.0117977 0.178804 + 0.199603 -0.0140204 0.179504 + 0.0975679 -0.0129059 0.178402 + -0.00252732 0.0886471 0.188673 + 0.301744 -0.0137264 0.178935 + -0.00405547 -0.0248316 0.268009 + 0.0977914 -0.0264536 0.267714 + 0.1997 -0.0269309 0.267538 + 0.301705 -0.0434898 0.357138 + 0.403994 -0.0129122 0.179474 + 0.402289 0.0820212 0.236389 + 0.401307 0.132016 0.242604 + 0.402333 0.0881122 0.189148 + 0.401264 0.138416 0.194761 + 0.352278 -0.063763 0.447341 + 0.400405 0.144302 0.444605 + 0.401121 0.0840927 0.481954 + 0.00109902 0.142651 0.651466 + 0.000361117 0.0252134 0.848926 + 0.00211826 0.167263 1.03771 + -0.00195643 -0.18374 0.837242 + 0.348856 -0.071558 1.60281 + 0.401204 -0.120985 1.71123 + 0.400298 -0.428543 1.66247 + 0.399912 -0.561253 1.71133 + 0.399944 -0.534704 1.65381 + 0.40032 -0.449405 1.70777 + 0.400353 -0.470333 1.75308 + 0.199758 -0.560466 1.71188 + 0.199706 -0.539641 1.66671 + 0.299841 -0.560871 1.71157 + 0.199785 -0.581381 1.75711 + 0.14971 -0.560257 1.71205 + 0.0997128 -0.580916 1.75744 + 0.14975 -0.581153 1.75727 + 0.149791 -0.602095 1.80254 + -0.000119459 -0.51404 1.73348 + 0.000316862 -0.510481 1.84493 + 0.000260852 -0.489509 1.79962 + 0.099758 -0.601856 1.8027 + -0.000293695 -0.601345 1.80305 + -8.58753e-05 -0.685243 1.98431 + 0.000940823 -0.419563 1.88664 + 0.199817 -0.602323 1.80238 + 0.199941 -0.686263 1.98368 + 0.000628583 -0.465022 1.86579 + 0.000576246 -0.444031 1.82044 + 0.299872 -0.602745 1.80207 + 0.400874 -0.421394 1.8854 + 0.0996621 -0.560019 1.71221 + 0.000199501 -0.468559 1.75432 + 9.47383e-05 -0.42681 1.66369 + 0.149657 -0.539404 1.66685 + 0.000777942 -0.335713 1.7049 + 0.4003 -0.431368 1.66863 + 0.400565 -0.424845 1.77386 + 0.400773 -0.379354 1.79461 + 0.400404 -0.512295 1.84367 + 0.399917 -0.603156 1.80178 + 0.400525 -0.403883 1.7285 + 0.400723 -0.35838 1.74919 + 0.401525 -0.15549 1.78625 + 0.201768 -0.15481 1.78684 + 0.201999 -0.238871 1.96943 + 0.400483 -0.382979 1.68311 + 0.00212019 -0.153593 1.78742 + 0.000848636 -0.37756 1.79583 + 0.000896682 -0.398555 1.84124 + 0.000141364 -0.447654 1.70901 + 0.0495583 -0.538916 1.66719 + 0.0996116 -0.539166 1.667 + 0.049618 -0.559769 1.71239 + -0.000429724 -0.559505 1.71255 + -0.000504198 -0.53867 1.66739 + 0.0495004 -0.518154 1.62204 + -0.000183961 -0.493162 1.68824 + 0.00218844 -0.237889 1.97012 + 0.00110128 -0.503659 2.06819 + 0.401815 -0.239647 1.96879 + 0.401633 -0.41483 2.10875 + 0.25224 -0.323407 2.15119 + 0.302214 -0.323635 2.15103 + 0.202269 -0.32317 2.15135 + 0.400108 -0.771222 2.16451 + 0.399977 -0.687206 1.98302 + 0.401091 -0.505625 2.06689 + 7.32968e-05 -0.76922 2.16581 + 0.200086 -0.770259 2.16513 + 0.00247162 -0.406053 2.33354 + 0.20245 -0.407172 2.33293 + 0.00235272 -0.322045 2.15194 + 0.0012577 -0.587647 2.2497 + 0.201258 -0.588709 2.24906 + 0.201849 -0.497933 2.29098 + 0.301264 -0.589211 2.24874 + 0.301561 -0.543815 2.26969 + 0.202314 -0.344199 2.19675 + 0.252295 -0.344437 2.1966 + 0.402167 -0.324067 2.15066 + 0.302279 -0.344672 2.19643 + 0.202369 -0.365205 2.24215 + 0.252351 -0.365448 2.24199 + 0.301856 -0.498427 2.29065 + 0.302337 -0.36569 2.24183 + 0.401415 -0.481276 2.1332 + 0.401361 -0.460223 2.08782 + 0.401697 -0.435882 2.15415 + 0.401465 -0.50231 2.17859 + 0.401754 -0.456916 2.19953 + 0.401179 -0.547708 2.15764 + 0.401136 -0.526673 2.11227 + 0.351563 -0.544054 2.26953 + 0.401561 -0.544301 2.26936 + 0.351266 -0.589458 2.24857 + 0.401264 -0.589706 2.24841 + 0.401223 -0.568713 2.20302 + 0.401514 -0.523316 2.22397 + 0.401806 -0.477924 2.24492 + 0.401859 -0.498903 2.29032 + 0.351858 -0.498664 2.29049 + 0.402439 -0.408127 2.33225 + 0.402325 -0.366153 2.24148 + 0.302445 -0.407663 2.3326 + 0.000523569 -0.423062 1.77509 + 0.249858 -0.337423 1.21504 + +CELLS 1 1547 + 1546 297 4 323 315 316 322 4 315 323 306 299 3 316 315 317 4 322 316 320 321 5 323 322 324 326 306 5 299 306 297 296 298 4 315 299 298 317 3 316 317 318 3 320 316 319 4 321 320 311 312 5 322 321 312 325 324 4 326 324 325 307 4 306 326 293 297 5 296 297 293 292 295 6 298 296 291 287 318 317 3 316 318 319 3 320 319 311 4 312 311 308 310 5 325 312 310 283 302 5 307 325 302 285 303 5 326 307 305 304 293 6 292 293 304 300 286 294 4 295 292 294 281 4 296 295 290 291 4 287 291 248 288 7 318 287 288 289 314 313 319 3 311 319 313 3 308 311 314 4 310 308 309 283 6 302 283 309 289 252 282 6 285 302 282 267 286 284 4 303 285 284 301 3 307 303 301 3 305 307 301 4 304 305 301 300 4 286 300 301 284 4 294 286 267 280 4 281 294 280 246 4 295 281 245 290 4 291 290 245 248 5 288 248 247 251 262 5 289 288 262 261 252 4 314 289 309 308 3 313 314 311 6 282 252 260 264 35 265 4 267 282 265 266 4 280 267 266 269 6 246 280 269 257 270 271 6 281 246 249 241 244 245 6 248 245 244 243 239 247 5 251 247 235 232 234 4 262 251 234 228 4 261 262 228 231 5 252 261 231 259 260 4 264 260 259 263 3 35 264 268 4 265 35 34 226 5 266 265 226 225 43 4 269 266 43 44 4 257 269 44 45 6 270 257 255 272 254 327 4 271 270 327 250 4 246 271 250 249 4 241 249 250 242 6 244 241 242 254 240 276 6 243 244 276 275 253 237 4 239 243 237 238 4 247 239 238 235 3 232 235 238 5 234 232 233 38 36 5 228 234 36 37 229 5 231 228 229 258 230 4 259 231 230 263 3 264 263 268 4 35 268 31 34 4 226 34 32 86 3 225 226 86 4 43 225 85 84 4 44 43 84 83 5 45 44 83 15 14 6 257 45 27 42 41 255 4 272 255 41 279 3 254 272 240 3 327 254 242 3 250 327 242 4 276 240 279 277 4 275 276 277 273 4 253 275 273 274 4 237 253 236 238 3 232 238 236 3 233 232 256 4 38 233 256 39 5 36 38 26 25 37 3 229 37 33 4 258 229 33 227 5 230 258 31 268 263 6 34 31 227 33 28 32 4 86 32 30 81 5 225 86 81 80 85 4 84 85 77 82 4 83 84 82 17 3 15 83 17 3 14 15 12 4 45 14 4 27 7 42 27 26 38 39 40 278 3 41 42 279 3 272 279 240 3 277 279 42 3 273 277 42 4 274 273 278 40 3 253 274 256 3 236 253 256 3 232 236 256 4 39 256 274 40 4 25 26 6 24 4 37 25 28 33 3 258 227 31 5 32 28 50 47 30 6 81 30 46 55 59 79 3 80 81 79 3 85 80 77 3 82 77 78 5 17 82 78 18 16 5 15 17 16 10 12 4 14 12 7 4 4 27 4 6 26 3 42 278 273 3 24 6 5 6 25 24 29 52 50 28 4 47 50 49 48 4 30 47 48 46 4 55 46 48 54 3 59 55 60 3 79 59 62 6 80 79 62 65 78 77 3 18 78 65 4 16 18 76 223 4 10 16 223 11 4 12 10 13 7 6 4 7 9 0 5 6 5 24 5 23 328 29 4 52 29 328 51 5 50 52 51 21 49 4 48 49 53 54 5 55 54 53 57 60 5 59 60 61 63 62 4 65 62 63 64 4 18 65 64 76 3 223 76 75 4 11 223 75 222 4 10 11 8 13 3 7 13 9 3 0 9 1 5 5 0 2 3 23 4 328 23 3 22 4 51 328 22 21 4 49 21 20 53 5 57 53 20 2 19 5 60 57 56 66 61 5 63 61 69 68 70 4 64 63 70 73 7 76 64 73 108 74 71 75 6 222 75 71 72 118 102 4 11 222 224 8 5 13 8 93 1 9 4 0 1 19 2 5 3 2 20 21 22 5 57 19 58 87 56 4 66 56 88 67 4 61 66 67 69 4 68 69 67 90 4 70 68 139 138 5 73 70 138 129 106 5 108 73 106 110 109 3 74 108 107 4 71 74 107 114 4 72 71 114 115 3 118 72 121 6 102 118 121 120 119 103 4 222 102 100 224 3 8 224 93 4 1 93 58 19 4 87 58 92 105 4 56 87 105 88 4 67 88 89 90 7 68 90 89 98 99 156 139 6 138 139 140 219 169 172 4 129 138 172 144 5 106 129 116 117 110 4 109 110 111 107 3 108 109 107 3 114 107 113 4 115 114 113 112 3 72 115 121 3 120 121 112 4 119 120 124 221 3 103 119 221 6 102 103 104 123 101 100 6 224 100 91 92 58 93 4 105 92 91 96 4 88 105 96 89 7 98 89 96 91 97 94 95 4 99 98 164 155 4 156 99 155 157 6 139 156 157 159 220 140 4 219 140 220 171 4 169 219 171 170 6 172 169 173 174 176 179 4 144 172 179 145 6 129 144 127 128 141 116 3 117 116 141 4 110 117 132 111 3 107 111 113 4 112 113 131 130 3 115 112 121 4 120 112 130 124 4 221 124 125 122 3 103 221 104 3 123 104 221 5 101 123 134 133 135 4 100 101 97 91 5 94 97 151 152 153 4 95 94 153 154 4 98 95 154 164 3 155 164 160 4 157 155 160 159 3 220 159 158 3 171 220 158 4 170 171 158 162 6 169 170 162 167 168 173 4 174 173 168 215 4 176 174 215 217 4 179 176 180 177 5 145 179 177 178 182 6 144 145 142 143 146 127 7 128 127 134 123 122 125 126 4 141 128 131 132 3 117 141 132 4 111 132 131 113 4 130 131 128 126 4 124 130 126 125 3 221 122 123 4 133 134 149 150 4 135 133 150 209 6 101 135 136 137 151 97 4 152 151 137 212 4 153 152 218 154 3 164 154 218 3 160 164 163 6 159 160 163 161 162 158 4 167 162 161 166 4 168 167 214 215 3 217 215 216 6 176 217 216 213 175 180 5 177 180 201 181 178 4 182 178 185 183 5 145 182 183 184 142 4 143 142 184 188 4 146 143 188 194 7 127 146 147 191 148 149 134 4 150 149 148 207 4 209 150 207 204 4 135 209 210 136 4 137 136 210 211 4 212 137 211 165 5 152 212 161 163 218 3 164 218 163 4 166 161 212 165 5 167 166 213 216 214 3 215 214 216 5 175 213 208 205 202 4 180 175 202 201 3 181 201 199 4 178 181 199 185 5 183 185 186 187 193 4 184 183 193 188 3 194 188 193 4 146 194 189 147 3 191 147 189 5 148 191 190 192 200 6 207 148 200 196 203 204 4 209 204 206 210 4 211 210 206 205 4 165 211 205 208 4 166 165 208 213 5 202 205 206 204 203 5 201 202 203 196 198 3 199 201 198 4 185 199 197 186 5 187 186 197 192 195 3 193 187 194 4 189 194 187 195 3 191 189 190 3 192 190 189 4 200 192 197 196 4 198 196 197 199 3 195 192 189 + +CELL_TYPES 1 +42 + +POINT_DATA 329 +SCALARS point_scalars double 1 +LOOKUP_TABLE default +0.0503917 +0.0480462 +0.0499558 +0.0566911 +0.000144382 +0.0628173 +0.0640013 +0.00031906 +0.000205429 +0.0401827 +1.41767e-05 +0.000476538 +1.73141e-05 +0.000173554 +1.21196e-05 +1.53109e-05 +0.0498591 +0.0633972 +0.0491366 +0.0441774 +0.0494894 +0.0563909 +0.0565916 +0.0602589 +0.0639741 +0.0781994 +0.0788069 +0.000340948 +0.000476081 +0.0637372 +0.000860448 +0.000468595 +0.000881924 +0.00026105 +0.000928775 +0.000942533 +0.0933495 +0.0163379 +0.0938929 +0.094154 +0.0943966 +0.000172461 +0.000399915 +0.0775362 +0.0784259 +0.000140227 +0.000820352 +0.000217754 +0.000123796 +0.000426391 +0.000444997 +0.0598629 +0.0634493 +0.00077471 +2.10181e-06 +0.000648282 +0.00119965 +0.00116172 +0.0373993 +0.000815669 +0.000698641 +0.000696644 +0.0479083 +0.0357407 +0.0368486 +0.0489412 +0.000180313 +0.00016587 +0.000622551 +0.00069821 +0.0252151 +0.0260588 +0.000903361 +0.0258808 +0.0257998 +0.0268293 +0.0362597 +0.0625819 +0.0534203 +0.0589244 +0.0623263 +0.0619034 +0.0628381 +0.0765923 +0.0676214 +0.0645432 +0.0765533 +0.0369696 +0.00117282 +0.00119319 +0.000200345 +0.026314 +0.0310078 +0.030317 +0.0160818 +0.0157949 +0.0254805 +0.0166178 +0.00134614 +0.000814031 +0.000780609 +0.00117767 +0.000203148 +4.89587e-05 +4.0115e-05 +0.0311313 +0.0200568 +0.0231719 +0.0258049 +0.0231147 +0.0207622 +0.0207603 +0.000744842 +0.0205794 +0.0229841 +0.00074022 +0.0163578 +0.0185522 +0.000587527 +0.000242338 +0.00051509 +0.000548244 +0.000222277 +6.00408e-05 +0.000499105 +0.000508293 +0.000859084 +0.0084048 +0.0159518 +0.016571 +0.000734989 +0.0181256 +0.0183296 +0.000802595 +0.000283824 +0.00174947 +0.00908411 +0.00907525 +0.0151767 +0.000621912 +0.000401872 +0.0162179 +0.00365011 +0.00333626 +0.00924303 +0.0041346 +0.00339447 +0.00107905 +0.000112057 +0.000103234 +0.000715712 +0.0122542 +0.011904 +0.0135812 +0.0133327 +0.000764953 +0.000337335 +0.000378101 +0.000647721 +0.000479761 +0.000975296 +0.0015286 +0.000719625 +0.00138314 +0.00126603 +0.00577133 +0.0021258 +0.000929894 +0.000501117 +0.000210979 +0.000330614 +0.000244773 +0.00822404 +3.91472e-05 +0.000192554 +0 +0.000346637 +0 +0 +0.00443775 +0 +0 +0.00101559 +0.00164473 +0.00236899 +0 +0 +0.00186486 +0.00211237 +0.00100422 +0.000568392 +0.000585369 +0.000720964 +0.00150947 +0.00241028 +0.00107704 +0 +0 +0 +0 +0.000403133 +0 +0 +0 +0.00189315 +0.00413625 +0.00435596 +0.00102836 +0.00363171 +0.00178087 +0.00591789 +0.00612707 +0.00859204 +0.00231504 +0.00110684 +0.000631002 +0.0012392 +0.000800718 +0.0115979 +0.000342542 +5.53965e-05 +0.000197516 +7.57995e-05 +0.035986 +0.000278494 +0.076753 +0.0852908 +0.000329723 +0.000202603 +0.000218396 +0.000358205 +0.000395405 +0.101565 +0.0977211 +0.100273 +0.105412 +0.101822 +0.0997898 +0.105681 +0.109555 +9.20035e-05 +0.0002628 +0.000205006 +0.0998105 +0.000241805 +8.72492e-05 +0.000773111 +0.109289 +0.124896 +0.000519259 +0.00045051 +0.100187 +0.00102432 +0.0997694 +0.00014476 +4.95748e-05 +0.0979816 +0.000490398 +0.000333099 +0.000689941 +0.000983 +0.000445488 +0.000142652 +0.000662899 +0.000963357 +0.0914326 +0.0925388 +0.108082 +0.000631874 +0.0936272 +0.000621649 +0.000700599 +9.01655e-05 +0.0497008 +0.0982251 +0.0497248 +0.000323344 +0.000362224 +0.0496844 +0.000136778 +0.109159 +0.00103522 +0.107001 +0.022873 +0.123333 +0.123049 +0.12362 +0.00186182 +2.80118e-05 +0.00114266 +0.00201791 +0.00193495 +0.140482 +0.139221 +0.12485 +0.00125447 +0.0135609 +0.0395375 +0.0135921 +0.0108986 +0.127514 +0.127231 +0.122487 +0.126938 +0.131415 +0.131125 +0.0389415 +0.130836 +0.00145666 +0.00142698 +0.0267525 +0.00148643 +0.0306218 +0.0011962 +0.00116897 +0.0111871 +0.00155375 +0.0136078 +0.00125381 +0.00122616 +0.00151987 +0.0345086 +0.0384067 +0.0386557 +0.13807 +0.130271 +0.138627 +0.000383886 +0.0600847 diff --git a/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt b/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt index 53a1a22b2cf..b11507d338c 100644 --- a/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt +++ b/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt @@ -22,6 +22,7 @@ each specific format. - \ref IOStreamMedit - \ref IOStreamTetgen - \ref IOStreamWKT +- \ref IOStreamVTKLCC \section IOStreamOFF Object File Format (OFF) @@ -504,6 +505,30 @@ The following \cgal data structures can be exported into the `.VTU` file format: - `CGAL::Mesh_complex_3_in_triangulation_3`, using \link CGAL::IO::output_to_vtu() `CGAL::IO::output_to_vtu()` \endlink - `CGAL::Constrained_Delaunay_triangulation_2`, using the function \link CGAL::IO::write_VTU `CGAL::IO::write_VTU()` \endlink +\section IOStreamVTKLCC VTK Legacy File Format for Linear Cell Complex + +The VTK legacy format, using file extension `.vtk`, is an \ascii format used to store 3D volumetric meshes. +This specific implementation supports Linear Cell Complex structures with various 3D cell types including +tetrahedra, hexahedra, prisms, pyramids, and generic polyhedra. Optional scalar data can be associated +with both vertices and volumes. + + + + + + + + + + + + + + + + + +
VTK Legacy File Format for Linear Cell Complex
Input3D Volumetric Mesh`Linear_cell_complex_for_combinatorial_map<3,3>`CGAL::IO::read_VTK()
Output3D Volumetric Mesh`Linear_cell_complex_for_combinatorial_map<3,3>`CGAL::IO::write_VTK()
\section IOStreamAvizo Avizo File Format diff --git a/Testing/Temporary/CTestCostData.txt b/Testing/Temporary/CTestCostData.txt new file mode 100644 index 00000000000..ed97d539c09 --- /dev/null +++ b/Testing/Temporary/CTestCostData.txt @@ -0,0 +1 @@ +--- diff --git a/Testing/Temporary/LastTest.log b/Testing/Temporary/LastTest.log new file mode 100644 index 00000000000..7016d17c7c2 --- /dev/null +++ b/Testing/Temporary/LastTest.log @@ -0,0 +1,3 @@ +Start testing: Jul 25 15:46 CEST +---------------------------------------------------------- +End testing: Jul 25 15:46 CEST From 464c591b5a9b4a10b7de75efe95d0eb0cd668749 Mon Sep 17 00:00:00 2001 From: ybellargui Date: Mon, 11 Aug 2025 14:52:05 +0200 Subject: [PATCH 04/30] Add VTK I/O support for Linear_cell_complex with dual scalar types --- .../linear_cell_complex_3_vtk_io.cpp | 30 ++++++++++-- .../include/CGAL/Linear_cell_complex/IO/VTK.h | 46 ++++++++++--------- .../Linear_cell_complex_vtk_io_test.cpp | 10 ++-- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp index 6c080d0508f..d1f8483fac9 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp @@ -20,10 +20,30 @@ typedef CGAL::Linear_cell_complex_for_combinatorial_map<3> LCC; int main() { - LCC lcc; CGAL::load_combinatorial_map("data/beam-with-mixed-cells.3map", lcc); - std::vector v; - for(auto it = lcc.template one_dart_per_cell<3>().begin(), itend = lcc.template one_dart_per_cell<3>().end(); it != itend; ++it) - v.push_back(std::distance(lcc.template one_dart_per_incident_cell<0,3>(lcc.dart_descriptor(*it)).begin(), lcc.template one_dart_per_incident_cell<0,3>(lcc.dart_descriptor(*it)).end())); - CGAL::IO::write_VTK(lcc, "data/beam-with-mixed-cells.vtk", nullptr, &v); + LCC lcc; + CGAL::load_combinatorial_map("data/beam-with-mixed-cells.3map", lcc); + + // Compute per-volume vertex count + std::vector volume_scalars; + for(auto it = lcc.template one_dart_per_cell<3>().begin(), + itend = lcc.template one_dart_per_cell<3>().end(); + it != itend; ++it) + { + volume_scalars.push_back( + std::distance( + lcc.template one_dart_per_incident_cell<0,3>(lcc.dart_descriptor(*it)).begin(), + lcc.template one_dart_per_incident_cell<0,3>(lcc.dart_descriptor(*it)).end() + ) + ); + } + + // Write to VTK with explicit template parameters + CGAL::IO::write_VTK( + lcc, + "data/beam-with-mixed-cells.vtk", + nullptr, + &volume_scalars + ); + return EXIT_SUCCESS; } \ No newline at end of file diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h index 7cb0d8dd660..11d3afcb46e 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h @@ -51,6 +51,8 @@ namespace IO { * \ingroup PkgLinearCellComplexExamples * * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> + * \tparam VertexScalarType Type for vertex scalar data (default: float) + * \tparam VolumeScalarType Type for volume scalar data (default: float) * \param alcc The Linear_cell_complex to populate (will be cleared first) * \param filename Path to the VTK file * \param vertex_scalars Optional output vector to store per-vertex scalar values. @@ -59,17 +61,19 @@ namespace IO { * If provided, will be resized to match number of volumes. * \return `true` if loading was successful, `false` otherwise */ -template +template bool read_VTK(LCC& alcc, const char* filename, - std::vector* vertex_scalars = nullptr, - std::vector* volume_scalars = nullptr); + std::vector* vertex_scalars = nullptr, + std::vector* volume_scalars = nullptr); /** * \brief Write a 3D Linear_cell_complex to a VTK legacy ASCII file. * \ingroup PkgLinearCellComplexExamples * * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> + * \tparam VertexScalarType Type for vertex scalar data (default: float) + * \tparam VolumeScalarType Type for volume scalar data (default: float) * \param alcc The Linear_cell_complex to export * \param filename Path to the output VTK file * \param vertex_scalars Optional per-vertex scalar data. If provided, must have @@ -78,11 +82,11 @@ bool read_VTK(LCC& alcc, * same size as number of 3-cells in the LCC. * \return `true` if writing was successful, `false` otherwise */ -template +template bool write_VTK(const LCC& alcc, const char* filename, - const std::vector* vertex_scalars = nullptr, - const std::vector* volume_scalars = nullptr); + const std::vector* vertex_scalars = nullptr, + const std::vector* volume_scalars = nullptr); // Advanced versions with functors template @@ -612,33 +616,33 @@ inline bool write_VTK(const LCC& alcc, const char* filename, PointFunctor ptval, } // Vector-based versions (convenience wrappers) -template +template inline bool read_VTK(LCC& alcc, const char* filename, - std::vector* vertex_scalars, - std::vector* volume_scalars) { - auto v_writer = [&](std::size_t i, ScalarType val) { + std::vector* vertex_scalars, + std::vector* volume_scalars) { + auto v_writer = [&](std::size_t i, auto val) { if(vertex_scalars) { if(vertex_scalars->size() <= i) vertex_scalars->resize(i + 1); - (*vertex_scalars)[i] = val; + (*vertex_scalars)[i] = static_cast(val); } }; - auto c_writer = [&](std::size_t i, ScalarType val) { + auto c_writer = [&](std::size_t i, auto val) { if(volume_scalars) { if(volume_scalars->size() <= i) volume_scalars->resize(i + 1); - (*volume_scalars)[i] = val; + (*volume_scalars)[i] = static_cast(val); } }; return read_VTK(alcc, filename, v_writer, c_writer); } -template +template inline bool write_VTK(const LCC& alcc, const char* filename, - const std::vector* vertex_scalars, - const std::vector* volume_scalars) { + const std::vector* vertex_scalars, + const std::vector* volume_scalars) { // Build index maps std::unordered_map vertex_indices; std::size_t idx = 0; @@ -653,15 +657,15 @@ inline bool write_VTK(const LCC& alcc, return write_VTK( alcc, filename, - [vertex_scalars, &vertex_indices](const LCC& lcc, typename LCC::Dart_const_descriptor d) -> ScalarType { + [vertex_scalars, &vertex_indices](const LCC& lcc, typename LCC::Dart_const_descriptor d) -> VertexScalarType { if(vertex_scalars) - return (*vertex_scalars)[vertex_indices.at(lcc.attribute<0>(d))]; - return ScalarType(); + return (*vertex_scalars)[vertex_indices.at(lcc.template attribute<0>(d))]; + return VertexScalarType(); }, - [volume_scalars, &volume_indices](const LCC& lcc, typename LCC::Dart_const_descriptor d) -> ScalarType { + [volume_scalars, &volume_indices](const LCC& lcc, typename LCC::Dart_const_descriptor d) -> VolumeScalarType { if(volume_scalars) return (*volume_scalars)[volume_indices.at(d)]; - return ScalarType(); + return VolumeScalarType(); }); } diff --git a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp index 93aa2a27d7d..0eec196cd0d 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp +++ b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include typedef CGAL::Linear_cell_complex_for_combinatorial_map<3, 3> LCC; @@ -13,13 +14,14 @@ int main() { std::vector v_scalars2, vol_scalars2; const std::string input_file = "data/beam-with-mixed-cells.vtk"; + assert(CGAL::IO::read_VTK(lcc1, input_file.c_str(), &v_scalars1, &vol_scalars1)); - // Build index maps std::unordered_map vertex_indices; std::size_t idx = 0; for(auto itv = lcc1.vertex_attributes().begin(), itvend = lcc1.vertex_attributes().end(); itv != itvend; ++itv) vertex_indices[itv] = idx++; + std::unordered_map volume_indices; idx = 0; for(auto itvol = lcc1.one_dart_per_cell<3>().begin(), itvolend = lcc1.one_dart_per_cell<3>().end(); itvol != itvolend; @@ -27,14 +29,16 @@ int main() { volume_indices[itvol] = idx++; const char* tmp_file = "tmp_test_lcc_vtk.vtk"; + assert(CGAL::IO::write_VTK( lcc1, tmp_file, - [&v_scalars1, &vertex_indices](const LCC& lcc, LCC::Dart_const_descriptor d) { + [&v_scalars1, &vertex_indices](const LCC& lcc, LCC::Dart_const_descriptor d) -> float { return v_scalars1[vertex_indices.at(lcc.attribute<0>(d))]; }, - [&vol_scalars1, &volume_indices](const LCC& lcc, LCC::Dart_const_descriptor d) { + [&vol_scalars1, &volume_indices](const LCC& lcc, LCC::Dart_const_descriptor d) -> float { return vol_scalars1[volume_indices.at(d)]; })); + assert(CGAL::IO::read_VTK(lcc2, tmp_file, &v_scalars2, &vol_scalars2)); assert(lcc1.is_isomorphic_to(lcc2, false, true, true)); From cc19bd4a80735e95570c7506514dd90bbe76f62e Mon Sep 17 00:00:00 2001 From: ybellargui Date: Fri, 15 Aug 2025 13:58:24 +0200 Subject: [PATCH 05/30] Refine VTK I/O example and test --- .../linear_cell_complex_3_vtk_io.cpp | 18 ++--- .../Linear_cell_complex_vtk_io_test.cpp | 74 ++++++++++++------- 2 files changed, 55 insertions(+), 37 deletions(-) diff --git a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp index d1f8483fac9..710442385de 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp @@ -25,17 +25,17 @@ int main() // Compute per-volume vertex count std::vector volume_scalars; - for(auto it = lcc.template one_dart_per_cell<3>().begin(), - itend = lcc.template one_dart_per_cell<3>().end(); - it != itend; ++it) + for(auto it = lcc.template one_dart_per_cell<3>().begin(), + itend = lcc.template one_dart_per_cell<3>().end(); it != itend; ++it) { - volume_scalars.push_back( - std::distance( - lcc.template one_dart_per_incident_cell<0,3>(lcc.dart_descriptor(*it)).begin(), - lcc.template one_dart_per_incident_cell<0,3>(lcc.dart_descriptor(*it)).end() - ) - ); + auto d = lcc.dart_descriptor(*it); + std::size_t nbv = lcc.template one_dart_per_incident_cell<0,3>(d).size(); + volume_scalars.push_back(nbv); } + + if(!CGAL::IO::write_VTK(lcc, + "data/beam-with-mixed-cells.vtk", nullptr, &volume_scalars)) + return EXIT_FAILURE; // Write to VTK with explicit template parameters CGAL::IO::write_VTK( diff --git a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp index 0eec196cd0d..6587b9e928b 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp +++ b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp @@ -1,8 +1,6 @@ #include #include #include -#include -#include #include #include @@ -10,40 +8,60 @@ typedef CGAL::Linear_cell_complex_for_combinatorial_map<3, 3> LCC; int main() { LCC lcc1, lcc2; - std::vector v_scalars1, vol_scalars1; - std::vector v_scalars2, vol_scalars2; + std::vector vertex_scalars1, vertex_scalars2; + std::vector volume_scalars1, volume_scalars2; + + const char* filename = "data/beam-with-mixed-cells.vtk"; - const std::string input_file = "data/beam-with-mixed-cells.vtk"; - assert(CGAL::IO::read_VTK(lcc1, input_file.c_str(), &v_scalars1, &vol_scalars1)); + bool ok_read1 = CGAL::IO::read_VTK(lcc1, filename, + &vertex_scalars1, &volume_scalars1); + assert(ok_read1); - std::unordered_map vertex_indices; - std::size_t idx = 0; + + std::size_t nb_vertices = 0; for(auto itv = lcc1.vertex_attributes().begin(), itvend = lcc1.vertex_attributes().end(); itv != itvend; ++itv) - vertex_indices[itv] = idx++; - - std::unordered_map volume_indices; - idx = 0; - for(auto itvol = lcc1.one_dart_per_cell<3>().begin(), itvolend = lcc1.one_dart_per_cell<3>().end(); itvol != itvolend; - ++itvol) - volume_indices[itvol] = idx++; + ++nb_vertices; + if(vertex_scalars1.size() != nb_vertices) { + vertex_scalars1.resize(nb_vertices); + for(std::size_t i=0;i(i); + } - const char* tmp_file = "tmp_test_lcc_vtk.vtk"; - assert(CGAL::IO::write_VTK( - lcc1, tmp_file, - [&v_scalars1, &vertex_indices](const LCC& lcc, LCC::Dart_const_descriptor d) -> float { - return v_scalars1[vertex_indices.at(lcc.attribute<0>(d))]; - }, - [&vol_scalars1, &volume_indices](const LCC& lcc, LCC::Dart_const_descriptor d) -> float { - return vol_scalars1[volume_indices.at(d)]; - })); + std::size_t nb_volumes = 0; + for(auto itvol = lcc1.one_dart_per_cell<3>().begin(), + itvolend = lcc1.one_dart_per_cell<3>().end(); itvol != itvolend; ++itvol) + ++nb_volumes; + + if(volume_scalars1.size() != nb_volumes) { + volume_scalars1.clear(); + volume_scalars1.reserve(nb_volumes); + for(auto itvol = lcc1.one_dart_per_cell<3>().begin(), + itvolend = lcc1.one_dart_per_cell<3>().end(); itvol != itvolend; ++itvol) { + auto d = lcc1.dart_descriptor(*itvol); + std::size_t nbv = lcc1.template one_dart_per_incident_cell<0,3>(d).size(); + volume_scalars1.push_back(nbv); + } + } + - assert(CGAL::IO::read_VTK(lcc2, tmp_file, &v_scalars2, &vol_scalars2)); + bool ok_write = CGAL::IO::write_VTK(lcc1, filename, + &vertex_scalars1, &volume_scalars1); + assert(ok_write); + + + bool ok_read2 = CGAL::IO::read_VTK(lcc2, filename, + &vertex_scalars2, &volume_scalars2); + assert(ok_read2); assert(lcc1.is_isomorphic_to(lcc2, false, true, true)); - - std::remove(tmp_file); + assert(vertex_scalars1.size() == vertex_scalars2.size()); + assert(volume_scalars1.size() == volume_scalars2.size()); + for(std::size_t i=0;i Date: Wed, 3 Sep 2025 12:46:19 +0200 Subject: [PATCH 06/30] Add prisms and pyramids creation --- .../include/CGAL/Combinatorial_map.h | 176 ++++++++++++++++++ .../include/CGAL/Linear_cell_complex_base.h | 141 +++++++++++++- 2 files changed, 310 insertions(+), 7 deletions(-) diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map.h b/Combinatorial_map/include/CGAL/Combinatorial_map.h index 59f88e34970..336b317f566 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map.h @@ -4019,6 +4019,182 @@ namespace CGAL { return make_combinatorial_hexahedron(d1, d2, d3, d4, d5, d6); } + /** Test if a volume is a combinatorial prism. + * @param adart an intial dart + * @return true iff the volume containing adart is a combinatorial prism. + */ + bool is_volume_combinatorial_prism(Dart_const_descriptor d1) const + { + Dart_const_descriptor d2=beta(d1, 2); + Dart_const_descriptor d3=beta(d1, 1, 2); + Dart_const_descriptor d4=beta(d1, 0, 2); + Dart_const_descriptor d5=beta(d2, 1, 1, 2); + + if ( d1==null_dart_descriptor || d2==null_dart_descriptor || + d3==null_dart_descriptor || d4==null_dart_descriptor || + d5==null_dart_descriptor ) { return false; } + + if (!is_face_combinatorial_polygon(d1, 3) || + !is_face_combinatorial_polygon(d2, 4) || + !is_face_combinatorial_polygon(d3, 4) || + !is_face_combinatorial_polygon(d4, 4) || + !is_face_combinatorial_polygon(d5, 3)) { return false; } + + // TODO do better with marks. + if (belong_to_same_cell<2,1>(d1, d2) || + belong_to_same_cell<2,1>(d1, d3) || + belong_to_same_cell<2,1>(d1, d4) || + belong_to_same_cell<2,1>(d1, d5) || + belong_to_same_cell<2,1>(d2, d3) || + belong_to_same_cell<2,1>(d2, d4) || + belong_to_same_cell<2,1>(d2, d5) || + belong_to_same_cell<2,1>(d3, d4) || + belong_to_same_cell<2,1>(d3, d5) || + belong_to_same_cell<2,1>(d4, d5)) + { return false; } + + if (beta(d2,0,2) !=beta(d3,1) || + beta(d2,1,2) !=beta(d4,0) || + beta(d3,0,2) !=beta(d4,1) || + beta(d3,1,1,2)!=beta(d5,0) || + beta(d4,1,1,2)!=beta(d5,1)) { return false; } + + return true; + } + + /** Create a combinatorial prism from 2 triangles and 3 squares. + * @param d1 a dart onto a first triangle. + * @param d2 a dart onto a first square. + * @param d3 a dart onto a second square. + * @param d4 a dart onto a thirth square. + * @param d5 a dart onto a second triangle. + * @return a new dart. + */ + Dart_descriptor make_combinatorial_prism(Dart_descriptor d1, + Dart_descriptor d2, + Dart_descriptor d3, + Dart_descriptor d4, + Dart_descriptor d5) + { + // 2-link for first triangle + basic_link_beta_for_involution(d1, d2, 2); + basic_link_beta_for_involution(beta(d1, 1), d3, 2); + basic_link_beta_for_involution(beta(d1, 0), d4, 2); + + // 2-link for quandrangles between them + basic_link_beta_for_involution(beta(d2, 0), beta(d3, 1), 2); + basic_link_beta_for_involution(beta(d2, 1), beta(d4, 0), 2); + basic_link_beta_for_involution(beta(d3, 0), beta(d4, 1), 2); + + // 2-link for second triangle + basic_link_beta_for_involution(beta(d2, 1, 1), d5, 2); + basic_link_beta_for_involution(beta(d3, 1, 1), beta(d5, 0), 2); + basic_link_beta_for_involution(beta(d4, 1, 1), beta(d5, 1), 2); + + return d1; + } + + /** Create a new combinatorial prism. + * @return a new dart. + */ + Dart_descriptor make_combinatorial_prism() + { + Dart_descriptor d1 = make_combinatorial_polygon(3); + Dart_descriptor d2 = make_combinatorial_polygon(4); + Dart_descriptor d3 = make_combinatorial_polygon(4); + Dart_descriptor d4 = make_combinatorial_polygon(4); + Dart_descriptor d5 = make_combinatorial_polygon(3); + + return make_combinatorial_prism( d1, d2, d3, d4, d5); + } + + /** Test if a volume is a combinatorial pyramid. + * @param adart an intial dart + * @return true iff the volume containing adart is a combinatorial pyramid. + */ + bool is_volume_combinatorial_pyramid(Dart_const_descriptor d1) const + { + Dart_const_descriptor d2=beta(d1, 2); + Dart_const_descriptor d3=beta(d1, 0, 2); + Dart_const_descriptor d4=beta(d1, 1, 1, 2); + Dart_const_descriptor d5=beta(d1, 1, 2); + + if (d1==null_dart_descriptor || d2==null_dart_descriptor || + d3==null_dart_descriptor || d4==null_dart_descriptor || + d5==null_dart_descriptor) { return false; } + + if (!is_face_combinatorial_polygon(d1, 4) || + !is_face_combinatorial_polygon(d2, 3) || + !is_face_combinatorial_polygon(d3, 3) || + !is_face_combinatorial_polygon(d4, 3) || + !is_face_combinatorial_polygon(d5, 3)) { return false; } + + // TODO do better with marks. + if (belong_to_same_cell<2,1>(d1, d2) || + belong_to_same_cell<2,1>(d1, d3) || + belong_to_same_cell<2,1>(d1, d4) || + belong_to_same_cell<2,1>(d1, d5) || + belong_to_same_cell<2,1>(d2, d3) || + belong_to_same_cell<2,1>(d2, d4) || + belong_to_same_cell<2,1>(d2, d5) || + belong_to_same_cell<2,1>(d3, d4) || + belong_to_same_cell<2,1>(d3, d5) || + belong_to_same_cell<2,1>(d4, d5)) + { return false; } + + if (beta(d2,1,2)!=beta(d3,0) || + beta(d2,0,2)!=beta(d5,1) || + beta(d5,0,2)!=beta(d4,1) || + beta(d4,0,2)!=beta(d3,1)) { return false; } + + return true; + } + + /** Create a combinatorial pyramid from 1 square and 4 triangles. + * @param d1 a dart onto the square. + * @param d2 a dart onto a first triangle. + * @param d3 a dart onto a second triangle. + * @param d4 a dart onto a thirth triangle. + * @param d5 a dart onto a fourth triangle. + * @return a new dart. + */ + Dart_descriptor make_combinatorial_pyramid(Dart_descriptor d1, + Dart_descriptor d2, + Dart_descriptor d3, + Dart_descriptor d4, + Dart_descriptor d5) + { + // 2-link for the square + basic_link_beta_for_involution(d1, d2, 2); + basic_link_beta_for_involution(beta(d1, 1), d5, 2); + basic_link_beta_for_involution(beta(d1, 1, 1), d4, 2); + basic_link_beta_for_involution(beta(d1, 0), d3, 2); + + // 2-link for first triangle + basic_link_beta_for_involution(beta(d2, 1), beta(d3, 0), 2); + basic_link_beta_for_involution(beta(d2, 0), beta(d5, 1), 2); + + // 2-link for triangles between them + basic_link_beta_for_involution(beta(d5, 0), beta(d4, 1), 2); + basic_link_beta_for_involution(beta(d4, 0), beta(d3, 1), 2); + + return d1; + } + + /** Create a new combinatorial pyramid. + * @return a new dart. + */ + Dart_descriptor make_combinatorial_pyramid() + { + Dart_descriptor d1=make_combinatorial_polygon(4); + Dart_descriptor d2=make_combinatorial_polygon(3); + Dart_descriptor d3=make_combinatorial_polygon(3); + Dart_descriptor d4=make_combinatorial_polygon(3); + Dart_descriptor d5=make_combinatorial_polygon(3); + + return make_combinatorial_pyramid(d1, d2, d3, d4, d5); + } + /** Test if an i-cell can be removed. * An i-cell can be removed if i==dimension or i==dimension-1, * or if there are at most two (i+1)-cell incident to it. diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h index b1943bca3c4..7b9dcec4f5e 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h @@ -660,13 +660,13 @@ namespace CGAL { * h0,h5 and to the facet (h0,h5,h6,h1). */ Dart_descriptor make_hexahedron(Vertex_attribute_descriptor h0, - Vertex_attribute_descriptor h1, - Vertex_attribute_descriptor h2, - Vertex_attribute_descriptor h3, - Vertex_attribute_descriptor h4, - Vertex_attribute_descriptor h5, - Vertex_attribute_descriptor h6, - Vertex_attribute_descriptor h7) + Vertex_attribute_descriptor h1, + Vertex_attribute_descriptor h2, + Vertex_attribute_descriptor h3, + Vertex_attribute_descriptor h4, + Vertex_attribute_descriptor h5, + Vertex_attribute_descriptor h6, + Vertex_attribute_descriptor h7) { Dart_descriptor d1 = make_quadrangle(h0, h5, h6, h1); Dart_descriptor d2 = make_quadrangle(h1, h6, h7, h2); @@ -717,6 +717,133 @@ namespace CGAL { create_vertex_attribute(p7)); } + /** Create an prism given 6 Vertex_attribute_descriptor. + * (6 vertices, 9 edges and 5 facets) + * \verbatim + * 3---4 + * |\ /| + * 0-5-1 + * \|/ + * 2 + * \endverbatim + * @param h0 the first vertex handle. + * @param h1 the second vertex handle. + * @param h2 the third vertex handle. + * @param h3 the fourth vertex handle. + * @param h4 the fifth vertex handle. + * @param h5 the sixth vertex handle. + * @return the dart of the new prism incident to h0 and to + * the facet (h0,h1,h2). + */ + Dart_descriptor make_prism(Vertex_attribute_descriptor h0, + Vertex_attribute_descriptor h1, + Vertex_attribute_descriptor h2, + Vertex_attribute_descriptor h3, + Vertex_attribute_descriptor h4, + Vertex_attribute_descriptor h5) + { + Dart_descriptor d1=make_triangle(h0, h1, h2); + Dart_descriptor d2=make_quadrangle(h1, h0, h3, h4); + Dart_descriptor d3=make_quadrangle(h2, h1, h4, h5); + Dart_descriptor d4=make_quadrangle(h0, h2, h5, h3); + Dart_descriptor d5=make_triangle(h4, h3, h5); + + return make_combinatorial_prism(d1, d2, d3, d4, d5); + } + + /** Create an prism given 6 points. + * \verbatim + * 3---4 + * |\ /| + * 0-5-1 + * \|/ + * 2 + * \endverbatim + * @param p0 the first point. + * @param p1 the second point. + * @param p2 the third point. + * @param p3 the fourth point. + * @param p4 the fifth point. + * @param p5 the sixth point. + * @return the dart of the new prism incident to p0 and to + * the facet (p0,p1,p2). + */ + Dart_descriptor make_prism(const Point& p0, + const Point& p1, + const Point& p2, + const Point& p3, + const Point& p4, + const Point& p5) + { + return make_prism(create_vertex_attribute(p0), + create_vertex_attribute(p1), + create_vertex_attribute(p2), + create_vertex_attribute(p3), + create_vertex_attribute(p4), + create_vertex_attribute(p5)); + } + + /** Create an pyramid given 5 Vertex_attribute_descriptor. + * (5 vertices, 8 edges and 5 facets) + * \verbatim + * 4 + * /|\ + * 0-|-1 + * | | | + * 3---2 + * \endverbatim + * @param h0 the first vertex handle. + * @param h1 the second vertex handle. + * @param h2 the third vertex handle. + * @param h3 the fourth vertex handle. + * @param h4 the fifth vertex handle. + * @return the dart of the new pyramid incident to h0 and to + * the facet (h0,h1,h2,h3). + */ + Dart_descriptor make_pyramid(Vertex_attribute_descriptor h0, + Vertex_attribute_descriptor h1, + Vertex_attribute_descriptor h2, + Vertex_attribute_descriptor h3, + Vertex_attribute_descriptor h4) + { + Dart_descriptor d1=make_quadrangle(h0, h1, h2, h3); + Dart_descriptor d2=make_triangle(h1, h0, h4); + Dart_descriptor d3=make_triangle(h0, h3, h4); + Dart_descriptor d4=make_triangle(h3, h2, h4); + Dart_descriptor d5=make_triangle(h2, h1, h4); + + return make_combinatorial_pyramid(d1, d2, d3, d4, d5); + } + + /** Create an pyramid given 5 points. + * \verbatim + * 4 + * /|\ + * 0-|-1 + * | | | + * 3---2 + * \endverbatim + * @param p0 the first point. + * @param p1 the second point. + * @param p2 the third point. + * @param p3 the fourth point. + * @param p4 the fifth point. + * @return the dart of the new pyramid incident to p0 and to + * the facet (p0,p1,p2,p3). + */ + Dart_descriptor make_pyramid(const Point& p0, + const Point& p1, + const Point& p2, + const Point& p3, + const Point& p4) + { + return make_pyramid(create_vertex_attribute(p0), + create_vertex_attribute(p1), + create_vertex_attribute(p2), + create_vertex_attribute(p3), + create_vertex_attribute(p4)); + } + /** Compute the barycenter of a given cell. * @param adart a dart incident to the cell. * @param adim the dimension of the cell. From 707375e7805df9186bcd71abff99172dce709249 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Sun, 7 Sep 2025 09:34:49 +0200 Subject: [PATCH 07/30] Add method to test some volume topology. --- .../include/CGAL/Combinatorial_map.h | 179 ++++++++++++++++++ 1 file changed, 179 insertions(+) diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map.h b/Combinatorial_map/include/CGAL/Combinatorial_map.h index 336b317f566..e4839b37d4b 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map.h @@ -4195,6 +4195,185 @@ namespace CGAL { return make_combinatorial_pyramid(d1, d2, d3, d4, d5); } + /** Test if a volume is a combinatorial pentagonal prism. + * @param adart an initial dart + * @return true iff the volume containing adart is a combinatorial pentagonal prism. + */ + bool is_volume_combinatorial_pentagonal_prism(Dart_const_descriptor d1) const + { + Dart_const_descriptor d2=beta(d1, 2); + Dart_const_descriptor d3=beta(d1, 1, 2); + Dart_const_descriptor d4=beta(d1, 1, 1, 2); + Dart_const_descriptor d5=beta(d1, 0, 0, 2); + Dart_const_descriptor d6=beta(d1, 0, 2); + Dart_const_descriptor d7=beta(d2, 1, 1, 2); + + if (d1==null_dart_descriptor || d2==null_dart_descriptor || + d3==null_dart_descriptor || d4==null_dart_descriptor || + d5==null_dart_descriptor || d6==null_dart_descriptor || + d7==null_dart_descriptor) + { return false; } + + if (!is_face_combinatorial_polygon(d1, 5) || + !is_face_combinatorial_polygon(d2, 4) || + !is_face_combinatorial_polygon(d3, 4) || + !is_face_combinatorial_polygon(d4, 4) || + !is_face_combinatorial_polygon(d5, 4) || + !is_face_combinatorial_polygon(d6, 4) || + !is_face_combinatorial_polygon(d7, 5)) { return false; } + + // TODO do better with marks. + if (belong_to_same_cell<2,1>(d1, d2) || + belong_to_same_cell<2,1>(d1, d3) || + belong_to_same_cell<2,1>(d1, d4) || + belong_to_same_cell<2,1>(d1, d5) || + belong_to_same_cell<2,1>(d1, d6) || + belong_to_same_cell<2,1>(d1, d7) || + belong_to_same_cell<2,1>(d2, d3) || + belong_to_same_cell<2,1>(d2, d4) || + belong_to_same_cell<2,1>(d2, d5) || + belong_to_same_cell<2,1>(d2, d6) || + belong_to_same_cell<2,1>(d2, d7) || + belong_to_same_cell<2,1>(d3, d4) || + belong_to_same_cell<2,1>(d3, d5) || + belong_to_same_cell<2,1>(d3, d6) || + belong_to_same_cell<2,1>(d3, d7) || + belong_to_same_cell<2,1>(d4, d5) || + belong_to_same_cell<2,1>(d4, d6) || + belong_to_same_cell<2,1>(d4, d7) || + belong_to_same_cell<2,1>(d5, d6) || + belong_to_same_cell<2,1>(d5, d7) || + belong_to_same_cell<2,1>(d6, d7)) + { return false; } + + if (beta(d2,0,2) !=beta(d3,1) || + beta(d3,0,2) !=beta(d4,1) || + beta(d4,0,2) !=beta(d5,1) || + beta(d5,0,2) !=beta(d6,1) || + beta(d6,0,2) !=beta(d2,1) || + beta(d3,1,1,2)!=beta(d7,0) || + beta(d4,1,1,2)!=beta(d7,0,0) || + beta(d5,1,1,2)!=beta(d7,1,1) || + beta(d6,1,1,2)!=beta(d7,1)) { return false; } + + return true; + + } + + /** Test if a volume is a combinatorial hexagonal prism. + * @param adart an initial dart + * @return true iff the volume containing adart is a combinatorial hexagonal prism. + */ + bool is_volume_combinatorial_hexagonal_prism(Dart_const_descriptor d1) const + { + Dart_const_descriptor d2=beta(d1, 2); + Dart_const_descriptor d3=beta(d1, 1, 2); + Dart_const_descriptor d4=beta(d1, 1, 1, 2); + Dart_const_descriptor d5=beta(d1, 1, 1, 1, 2); + Dart_const_descriptor d6=beta(d1, 0, 0, 2); + Dart_const_descriptor d7=beta(d1, 0, 2); + Dart_const_descriptor d8=beta(d2, 1, 1, 2); + + if (d1==null_dart_descriptor || d2==null_dart_descriptor || + d3==null_dart_descriptor || d4==null_dart_descriptor || + d5==null_dart_descriptor || d6==null_dart_descriptor || + d7==null_dart_descriptor || d8==null_dart_descriptor) + { return false; } + + if (!is_face_combinatorial_polygon(d1, 6) || + !is_face_combinatorial_polygon(d2, 4) || + !is_face_combinatorial_polygon(d3, 4) || + !is_face_combinatorial_polygon(d4, 4) || + !is_face_combinatorial_polygon(d5, 4) || + !is_face_combinatorial_polygon(d6, 4) || + !is_face_combinatorial_polygon(d7, 4) || + !is_face_combinatorial_polygon(d8, 6)) { return false; } + + // TODO do better with marks. + if (belong_to_same_cell<2,1>(d1, d2) || + belong_to_same_cell<2,1>(d1, d3) || + belong_to_same_cell<2,1>(d1, d4) || + belong_to_same_cell<2,1>(d1, d5) || + belong_to_same_cell<2,1>(d1, d6) || + belong_to_same_cell<2,1>(d1, d7) || + belong_to_same_cell<2,1>(d1, d8) || + belong_to_same_cell<2,1>(d2, d3) || + belong_to_same_cell<2,1>(d2, d4) || + belong_to_same_cell<2,1>(d2, d5) || + belong_to_same_cell<2,1>(d2, d6) || + belong_to_same_cell<2,1>(d2, d7) || + belong_to_same_cell<2,1>(d2, d8) || + belong_to_same_cell<2,1>(d3, d4) || + belong_to_same_cell<2,1>(d3, d5) || + belong_to_same_cell<2,1>(d3, d6) || + belong_to_same_cell<2,1>(d3, d7) || + belong_to_same_cell<2,1>(d3, d8) || + belong_to_same_cell<2,1>(d4, d5) || + belong_to_same_cell<2,1>(d4, d6) || + belong_to_same_cell<2,1>(d4, d7) || + belong_to_same_cell<2,1>(d4, d8) || + belong_to_same_cell<2,1>(d5, d6) || + belong_to_same_cell<2,1>(d5, d7) || + belong_to_same_cell<2,1>(d5, d8) || + belong_to_same_cell<2,1>(d6, d7) || + belong_to_same_cell<2,1>(d6, d8) || + belong_to_same_cell<2,1>(d7, d8)) + { return false; } + + if (beta(d2,0,2) !=beta(d3,1) || + beta(d3,0,2) !=beta(d4,1) || + beta(d4,0,2) !=beta(d5,1) || + beta(d5,0,2) !=beta(d6,1) || + beta(d6,0,2) !=beta(d7,1) || + beta(d7,0,2) !=beta(d2,1) || + beta(d3,1,1,2)!=beta(d8,0) || + beta(d4,1,1,2)!=beta(d8,0,0) || + beta(d5,1,1,2)!=beta(d8,0,0,0) || + beta(d6,1,1,2)!=beta(d8,1,1) || + beta(d7,1,1,2)!=beta(d8,1)) { return false; } + + return true; + } + + /** Test if a volume is a combinatorial tetrahedron10. + * @param adart an initial dart + * @return true iff the volume containing adart is a combinatorial tetrahedron. + */ + bool is_volume_combinatorial_tetrahedron10(Dart_const_descriptor d1) const + { + Dart_const_descriptor d2=beta(d1, 2,0); + Dart_const_descriptor d3=beta(d2, 0,2); + Dart_const_descriptor d4=beta(d2, 1,1,1,2); + + if(d1==null_dart_descriptor || d2==null_dart_descriptor || + d3==null_dart_descriptor || d4==null_dart_descriptor) + { return false; } + + if(!is_face_combinatorial_polygon(d1, 6) || + !is_face_combinatorial_polygon(d2, 6) || + !is_face_combinatorial_polygon(d3, 6) || + !is_face_combinatorial_polygon(d4, 6)) { return false; } + + if(beta(d1, 1,2)!=beta(d1, 2,0) || + beta(d2, 1,2)!=beta(d2, 2,0) || + beta(d3, 1,2)!=beta(d3, 2,0) || + beta(d4, 1,2)!=beta(d4, 2,0)) { return false; } + + // TODO do better with marks (?). + if(belong_to_same_cell<2,1>(d1, d2) || + belong_to_same_cell<2,1>(d1, d3) || + belong_to_same_cell<2,1>(d1, d4) || + belong_to_same_cell<2,1>(d2, d3) || + belong_to_same_cell<2,1>(d2, d4) || + belong_to_same_cell<2,1>(d3, d4)) { return false; } + + if(beta(d1,1,1,2)!=beta(d3,0) || + beta(d1,0,2)!=beta(d4,1,1) || + beta(d4,0,2)!=beta(d3,1,1)) { return false; } + + return true; + } + /** Test if an i-cell can be removed. * An i-cell can be removed if i==dimension or i==dimension-1, * or if there are at most two (i+1)-cell incident to it. From 3382ac0d1807690e9cb193eeff38c7a90dfe7c30 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Sun, 7 Sep 2025 09:50:04 +0200 Subject: [PATCH 08/30] Example for LCC write vtk --- .../linear_cell_complex_3_vtk_io.cpp | 42 +++++++------------ 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp index 710442385de..794f1aaa62a 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp @@ -2,10 +2,10 @@ \ingroup PkgLinearCellComplexExamples \brief Minimal example: read a `.3map` file, compute per-volume vertex count, and write to VTK. - This example loads a 3D linear cell complex from a `.3map` file using - \cgal function `CGAL::load_combinatorial_map()`. It computes for each - 3-cell (volume) the number of incident vertices (0-cells), stores these values - in a `std::vector`, and writes the result to a `.vtk` file with + This example loads a 3D linear cell complex from a `.3map` file using + \cgal function `CGAL::load_combinatorial_map()`. It computes for each + 3-cell (volume) the number of incident vertices (0-cells), stores these values + in a `std::vector`, and writes the result to a `.vtk` file with `CGAL::IO::write_VTK()`, using the computed values as scalars for each volume. */ @@ -13,37 +13,25 @@ #include #include #include -#include #include -typedef CGAL::Linear_cell_complex_for_combinatorial_map<3> LCC; - int main() { - LCC lcc; - CGAL::load_combinatorial_map("data/beam-with-mixed-cells.3map", lcc); - + CGAL::Linear_cell_complex_for_combinatorial_map<3> lcc; + CGAL::load_combinatorial_map("data/beam-with-mixed-cells.3map", lcc); + // Compute per-volume vertex count std::vector volume_scalars; - for(auto it = lcc.template one_dart_per_cell<3>().begin(), - itend = lcc.template one_dart_per_cell<3>().end(); it != itend; ++it) + for(auto it=lcc.template one_dart_per_cell<3>().begin(), + itend=lcc.template one_dart_per_cell<3>().end(); it!=itend; ++it) { - auto d = lcc.dart_descriptor(*it); - std::size_t nbv = lcc.template one_dart_per_incident_cell<0,3>(d).size(); + std::size_t nbv=lcc.template one_dart_per_incident_cell<0,3>(it).size(); volume_scalars.push_back(nbv); } - if(!CGAL::IO::write_VTK(lcc, - "data/beam-with-mixed-cells.vtk", nullptr, &volume_scalars)) - return EXIT_FAILURE; - - // Write to VTK with explicit template parameters - CGAL::IO::write_VTK( - lcc, - "data/beam-with-mixed-cells.vtk", - nullptr, - &volume_scalars - ); - + if(!CGAL::IO::write_VTK(lcc, "beam-with-mixed-cells.vtk", nullptr, + &volume_scalars)) + { return EXIT_FAILURE; } + return EXIT_SUCCESS; -} \ No newline at end of file +} From f25a684c95cefea794a5515633592b6ba7cdd7c6 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Sun, 7 Sep 2025 09:55:49 +0200 Subject: [PATCH 09/30] Read / write vtk for lcc --- .../include/CGAL/Linear_cell_complex/IO/VTK.h | 997 +++++++++--------- 1 file changed, 519 insertions(+), 478 deletions(-) diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h index 11d3afcb46e..0a70ee38e22 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h @@ -11,8 +11,11 @@ #ifndef CGAL_LCC_IO_VTK_H #define CGAL_LCC_IO_VTK_H 1 + #include #include +#include + #include #include #include @@ -24,7 +27,8 @@ namespace CGAL { namespace IO { /** \file VTK.h - * Functions to import/export 3D Linear_cell_complex from/to VTK legacy ASCII format. + * Functions to import/export 3D Linear_cell_complex from/to VTK legacy ASCII + * format. * * Only supports: * - Linear_cell_complex_for_combinatorial_map<3,3> @@ -47,7 +51,8 @@ namespace IO { // ============================================================================ /** - * \brief Read a VTK legacy ASCII file and load it into a 3D Linear_cell_complex. + * \brief Read a VTK legacy ASCII file and load it into a 3D + * Linear_cell_complex. * \ingroup PkgLinearCellComplexExamples * * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> @@ -61,11 +66,12 @@ namespace IO { * If provided, will be resized to match number of volumes. * \return `true` if loading was successful, `false` otherwise */ -template +template bool read_VTK(LCC& alcc, const char* filename, - std::vector* vertex_scalars = nullptr, - std::vector* volume_scalars = nullptr); + std::vector* vertex_scalars, + std::vector* volume_scalars); /** * \brief Write a 3D Linear_cell_complex to a VTK legacy ASCII file. @@ -82,208 +88,205 @@ bool read_VTK(LCC& alcc, * same size as number of 3-cells in the LCC. * \return `true` if writing was successful, `false` otherwise */ -template +template bool write_VTK(const LCC& alcc, const char* filename, - const std::vector* vertex_scalars = nullptr, - const std::vector* volume_scalars = nullptr); - -// Advanced versions with functors -template -bool read_VTK(LCC& alcc, const char* filename, VertexScalarReader vertex_reader, CellScalarReader cell_reader); + const std::vector* vertex_scalars, + const std::vector* volume_scalars); +// "Advanced" versions with functors template -bool write_VTK(const LCC& alcc, const char* filename, PointFunctor ptval, CellFunctor cellval); +bool write_VTK_with_fct(const LCC& alcc, const char* filename, + PointFunctor ptval, CellFunctor cellval); // ============================================================================ // Implementation details // ============================================================================ -namespace internal { +namespace internal +{ + ///////////////////////////////////////////////////////////////////////////// + // VTK type name mapping + // bit, unsigned_char, char, unsigned_short, short, unsigned_int, int, + // unsigned_long, long, float, double. + template + struct gettype + { static std::string name() { return "unknown"; }}; + template<> + struct gettype + { static std::string name() { return "bit"; }}; + template<> + struct gettype + { static std::string name() { return "unsigned_char"; }}; + template<> + struct gettype + { static std::string name() { return "char"; }}; + template<> + struct gettype + { static std::string name() { return "unsigned_short"; }}; + template<> + struct gettype + { static std::string name() { return "short"; }}; + template<> + struct gettype + { static std::string name() { return "unsigned_int"; }}; + template<> + struct gettype + { static std::string name() { return "int"; }}; + template<> + struct gettype + { static std::string name() { return "unsigned_long"; }}; + template<> + struct gettype + { static std::string name() { return "long"; }}; + template<> + struct gettype + { static std::string name() { return "float"; }}; + template<> + struct gettype + { static std::string name() { return "double"; }}; + ///////////////////////////////////////////////////////////////////////////// + // VTK cell type constants + enum VTK_Cell_Type + { + VTK_TETRA = 10, + VTK_VOXEL = 11, + VTK_HEXAHEDRON = 12, + VTK_WEDGE = 13, // Prism + VTK_PYRAMID = 14, + VTK_PENTAGONAL_PRISM = 15, + VTK_HEXAGONAL_PRISM = 16, + VTK_POLYHEDRON = 42 // Generic cell + }; + ///////////////////////////////////////////////////////////////////////////// + /// Write cell_data. + template + struct Write_cell_data + { + /// nb is the number of cells, + /// fct is a function having 3 parameters: a lcc, a dart_descriptor, + /// an the index of the cell. + template + static void run(std::ofstream& fo, LCC& lcc, std::size_t nb, FCT fct) + { + fo<<"CELL_DATA "<::name() + <<" 1"<().begin(), + itvolend=lcc.template one_dart_per_cell<3>().end(); + itvol!=itvolend; ++itvol, ++i) + { fo< + struct Write_cell_data + { + template + static void run(std::ofstream&, LCC&, std::size_t, std::nullptr_t) + {} + }; + ///////////////////////////////////////////////////////////////////////////// + /// Write point_data. + template + struct Write_point_data + { + /// nb is the number of cells, + /// fct is a function having 3 parameters: a lcc, a dart_descriptor, + /// an the index of the cell. + template + static void run(std::ofstream& fo, LCC& lcc, std::size_t nb, FCT fct) + { + fo<<"POINT_DATA "<::name() + <<" 1"<(itv), i)< + struct Write_point_data + { + template + static void run(std::ofstream&, LCC&, std::size_t, std::nullptr_t) + {} + }; + ///////////////////////////////////////////////////////////////////////////// + // Read data, stored values as T. + template + bool read_data(std::istream& fi, std::string& line, std::vector& data) + { + std::string txt, data_type; + std::size_t nb; + std::istringstream inputline(line); + inputline>>txt>>nb; // "CELL_DATA xxx" + fi>>txt>>txt; // "SCALARS cell_scalars " + fi>>data_type>>txt; // type for data + fi>>txt>>txt; // "LOOKUP_TABLE default" + if(!fi.good()) + { return false; } + data.clear(); + data.reserve(nb); + for(std::size_t i=0; i>txt)) + { return false; } -// Helper: read a scalar of the right type from stream -template -bool read_scalar_by_vtk_type(std::istream& is, const std::string& vtk_type, std::size_t n, Functor f) { - if(vtk_type == "float") { - for(std::size_t i = 0; i < n; ++i) { - float v; - if(!(is >> v)) - return false; - f(i, v); + std::stringstream ss{txt}; + T t; + ss>>t; + + data.push_back(t); } - } else if(vtk_type == "double") { - for(std::size_t i = 0; i < n; ++i) { - double v; - if(!(is >> v)) - return false; - f(i, v); - } - } else if(vtk_type == "int") { - for(std::size_t i = 0; i < n; ++i) { - int v; - if(!(is >> v)) - return false; - f(i, v); - } - } else if(vtk_type == "unsigned_int") { - for(std::size_t i = 0; i < n; ++i) { - unsigned int v; - if(!(is >> v)) - return false; - f(i, v); - } - } else if(vtk_type == "short") { - for(std::size_t i = 0; i < n; ++i) { - short int v; - if(!(is >> v)) - return false; - f(i, v); - } - } else if(vtk_type == "unsigned_short") { - for(std::size_t i = 0; i < n; ++i) { - unsigned short int v; - if(!(is >> v)) - return false; - f(i, v); - } - } else if(vtk_type == "char") { - for(std::size_t i = 0; i < n; ++i) { - char v; - int tmp; - if(!(is >> tmp)) - return false; - v = static_cast(tmp); - f(i, v); - } - } else if(vtk_type == "unsigned_char") { - for(std::size_t i = 0; i < n; ++i) { - unsigned char v; - int tmp; - if(!(is >> tmp)) - return false; - v = static_cast(tmp); - f(i, v); - } - } else if(vtk_type == "long") { - for(std::size_t i = 0; i < n; ++i) { - long int v; - if(!(is >> v)) - return false; - f(i, v); - } - } else if(vtk_type == "unsigned_long") { - for(std::size_t i = 0; i < n; ++i) { - unsigned long int v; - if(!(is >> v)) - return false; - f(i, v); - } - } else { - std::cerr << "[ERROR] read_VTK: unsupported scalar type: " << vtk_type << std::endl; - return false; + return true; } - return true; -} - -// VTK type name mapping -template struct gettype + ///////////////////////////////////////////////////////////////////////////// + // Helper: detect VTK cell type from a 3-cell + template + VTK_Cell_Type get_vtk_cell_type(const LCC& lcc, + typename LCC::Dart_const_descriptor itvol, + typename LCC::Dart_const_descriptor& sd) + { + using namespace CGAL::CMap::Element_topo; + cell_topo vol_type=get_cell_topo<3>(lcc, itvol, sd); + switch(vol_type) + { + case TETRAHEDRON: return VTK_TETRA; + case PYRAMID: return VTK_PYRAMID; + case PRISM: return VTK_WEDGE; + case HEXAHEDRON: return VTK_HEXAHEDRON; + // case PENTAGONAL_PRISM: return VTK_PENTAGONAL_PRISM; + // case HEXAGONAL_PRISM: return VTK_HEXAGONAL_PRISM; + // 24 QUADRATIC_TETRA + // 25 QUADRATIC_HEXAHEDRON + // 26 QUADRATIC_WEDGE + // 27 QUADRATIC_PYRAMID + default: break; + } + return VTK_POLYHEDRON; + } + ///////////////////////////////////////////////////////////////////////////// +template +bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, + std::vector* vertex_scalars=nullptr, + std::vector* cell_scalars=nullptr) { - static std::string name() { return "unknown"; } -}; -template <> struct gettype -{ - static std::string name() { return "bit"; } -}; -template <> struct gettype -{ - static std::string name() { return "unsigned_char"; } -}; -template <> struct gettype -{ - static std::string name() { return "char"; } -}; -template <> struct gettype -{ - static std::string name() { return "unsigned_short"; } -}; -template <> struct gettype -{ - static std::string name() { return "short"; } -}; -template <> struct gettype -{ - static std::string name() { return "unsigned_int"; } -}; -template <> struct gettype -{ - static std::string name() { return "int"; } -}; -template <> struct gettype -{ - static std::string name() { return "unsigned_long"; } -}; -template <> struct gettype -{ - static std::string name() { return "long"; } -}; -template <> struct gettype -{ - static std::string name() { return "float"; } -}; -template <> struct gettype -{ - static std::string name() { return "double"; } -}; - -// VTK cell type constants -enum VTK_Cell_Type { - VTK_TETRA = 10, - VTK_VOXEL = 11, - VTK_HEXAHEDRON = 12, - VTK_WEDGE = 13, - VTK_PYRAMID = 14, - VTK_PENTAGONAL_PRISM = 15, - VTK_HEXAGONAL_PRISM = 16, - VTK_POLYHEDRON = 42 -}; - -// Helper: detect VTK cell type from a 3-cell -template inline VTK_Cell_Type get_vtk_cell_type(const LCC& lcc, Dart itvol) { - // Heuristic: count number of vertices and faces - std::size_t nbv = 0, nbf = 0; - for(auto itv = lcc.template one_dart_per_incident_cell<0, 3>(itvol).begin(), - itvend = lcc.template one_dart_per_incident_cell<0, 3>(itvol).end(); - itv != itvend; ++itv) - ++nbv; - for(auto itf = lcc.template one_dart_per_incident_cell<2, 3>(itvol).begin(), - itfend = lcc.template one_dart_per_incident_cell<2, 3>(itvol).end(); - itf != itfend; ++itf) - ++nbf; - - if(nbv == 4 && nbf == 4) - return VTK_TETRA; - if(nbv == 5 && nbf == 5) - return VTK_PYRAMID; - if(nbv == 6 && nbf == 5) - return VTK_WEDGE; - if(nbv == 8 && nbf == 6) - return VTK_HEXAHEDRON; - if(nbv == 10 && nbf == 7) - return VTK_PENTAGONAL_PRISM; - if(nbv == 12 && nbf == 8) - return VTK_HEXAGONAL_PRISM; - return VTK_POLYHEDRON; -} - -template -bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader vertex_reader, CellScalarReader cell_reader) { - static_assert(LCC::dimension == 3 && LCC::ambient_dimension == 3, + static_assert(LCC::dimension==3 && LCC::ambient_dimension==3, "read_VTK() only supports 3D Linear_cell_complexes (3,3)"); - using Point = typename LCC::Point; - using FT = typename LCC::FT; - - alcc.clear(); + using Point=typename LCC::Point; + using FT=typename LCC::FT; Linear_cell_complex_incremental_builder_3 ib(alcc); @@ -291,297 +294,295 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, VertexScalarReader ver std::size_t npoints, ncells; // Skip to POINTS section - while(std::getline(is, line)) { - if(line.find("POINTS") != std::string::npos) - break; - } - if(is.eof()) { - std::cerr << "[ERROR] read_VTK: POINTS section not found" << std::endl; + while(std::getline(is, line) && line.find("POINTS")==std::string::npos) + {} + if(is.eof()) + { + std::cerr<<"[ERROR] read_VTK: POINTS section not found"<> npoints; + ss>>npoints; // Read points std::vector points(npoints); - for(std::size_t i = 0; i < npoints; ++i) { + for(std::size_t i=0; i> x >> y >> z)) { - std::cerr << "[ERROR] read_VTK: failed to read point " << i << std::endl; + if(!(is>>x>>y>>z)) + { + std::cerr<<"[ERROR] read_VTK: failed to read point "<> ncells; + ss>>ncells; // Read connectivity std::vector> faces(ncells); std::size_t points_per_cell; - for(std::size_t i = 0; i < ncells; ++i) { - if(!(is >> points_per_cell)) { - std::cerr << "[ERROR] read_VTK: failed to read cell " << i << std::endl; + for(std::size_t i=0; i>points_per_cell)) + { + std::cerr<<"[ERROR] read_VTK: failed to read cell "<> faces[i][j])) { - std::cerr << "[ERROR] read_VTK: failed to read cell " << i << " vertex " << j << std::endl; + for(std::size_t j=0; j>faces[i][j])) + { + std::cerr<<"[ERROR] read_VTK: failed to read cell "<> cell_type)) { - std::cerr << "[ERROR] read_VTK: failed to read cell type " << i << std::endl; + for(std::size_t i = 0; i>cell_type)) + { + std::cerr<<"[ERROR] read_VTK: failed to read cell type "<(itv) == alcc.null_descriptor) { - alcc.erase_vertex_attribute(itv); - } else { - ++itv; - } + for(auto itv=alcc.vertex_attributes().begin(); + itv!=alcc.vertex_attributes().end(); ++itv) + { + if(alcc.template dart_of_attribute<0>(itv)==alcc.null_descriptor) + { alcc.erase_vertex_attribute(itv); } } - // Read POINT_DATA scalars if present - while(std::getline(is, line)) { - if(line.find("POINT_DATA") != std::string::npos) { - std::size_t ndata; - ss = std::stringstream(line); - std::getline(ss, tmp, ' '); // skip "POINT_DATA" - ss >> ndata; - - std::getline(is, line); // SCALARS line - std::stringstream scalars_line(line); - std::string scalars, name, vtk_type; - scalars_line >> scalars >> name >> vtk_type; - - std::getline(is, line); // LOOKUP_TABLE line - - if(!read_scalar_by_vtk_type(is, vtk_type, ndata, vertex_reader)) { - std::cerr << "[ERROR] read_VTK: failed to read POINT_DATA" << std::endl; + while(std::getline(is, line)) + { + // Read POINT_DATA scalars if present + if(vertex_scalars!=nullptr && line.find("POINT_DATA")!=std::string::npos) + { + if(!read_data(is, line, *vertex_scalars)) + { + std::cerr<<"[ERROR] read_VTK: error when reading POINT_DATA." + <> ndata; - - std::getline(is, line); // SCALARS line - std::stringstream scalars_line(line); - std::string scalars, name, vtk_type; - scalars_line >> scalars >> name >> vtk_type; - - std::getline(is, line); // LOOKUP_TABLE line - - if(!read_scalar_by_vtk_type(is, vtk_type, ndata, cell_reader)) { - std::cerr << "[ERROR] read_VTK: failed to read CELL_DATA" << std::endl; + // Read CELL_DATA scalars if present + else if(cell_scalars!=nullptr && line.find("CELL_DATA")!=std::string::npos) + { + if(!read_data(is, line, *cell_scalars)) + { + std::cerr<<"[ERROR] read_VTK: error when reading CELL_DATA." + < -bool write_lcc_to_vtk_ascii(std::ostream& os, const LCC& alcc, PointFunctor ptval, CellFunctor cellval) { - static_assert(LCC::dimension == 3 && LCC::ambient_dimension == 3, +///////////////////////////////////////////////////////////////////////////// +template +bool write_lcc_topo_to_vtk_ascii(std::ostream& os, const LCC& alcc, + std::size_t& nbpts, std::size_t& nbcells) +{ + static_assert(LCC::dimension==3 && LCC::ambient_dimension==3, "write_VTK() only supports 3D Linear_cell_complexes (3,3)"); // Write VTK header - os << "# vtk DataFile Version 2.0\n"; - os << "CGAL Linear_cell_complex\n"; - os << "ASCII\n"; - os << "DATASET UNSTRUCTURED_GRID\n\n"; + os<<"# vtk DataFile Version 2.0\n"; + os<<"CGAL Linear_cell_complex\n"; + os<<"ASCII\n"; + os<<"DATASET UNSTRUCTURED_GRID\n\n"; - // Build vertex index map - std::unordered_map vertex_index; - std::size_t nbpts = 0; - - for(auto itv = alcc.vertex_attributes().begin(), itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) { - vertex_index[itv] = nbpts++; + // Build vertex index map and write points + std::unordered_map + index; + nbpts=0; + os<<"POINTS "<point()<point(); - os << p.x() << " " << p.y() << " " << p.z() << "\n"; - } - os << "\n"; + os<().begin(), itvolend = alcc.template one_dart_per_cell<3>().end(); - itvol != itvolend; ++itvol) - { - ++nbcells; - VTK_Cell_Type cell_type = get_vtk_cell_type(alcc, itvol); - type_stream << static_cast(cell_type) << "\n"; - - if(cell_type == VTK_POLYHEDRON) { - // Generic polyhedron format write as face-vertex connectivity - std::vector> faces; - std::size_t cell_size = 1; // Start with 1 for number of faces - - for(auto itface = alcc.template one_dart_per_incident_cell<2, 3>(itvol).begin(), - itfaceend = alcc.template one_dart_per_incident_cell<2, 3>(itvol).end(); - itface != itfaceend; ++itface) - { - faces.push_back(std::vector()); - auto& face = faces.back(); - - for(auto itvert = alcc.template darts_of_orbit<1>(itface).begin(), - itvertend = alcc.template darts_of_orbit<1>(itface).end(); - itvert != itvertend; ++itvert) - { - face.push_back(vertex_index[alcc.vertex_attribute(itvert)]); - } - cell_size += face.size() + 1; // +1 for face size - } - - cell_stream << cell_size << " " << faces.size(); - for(const auto& face : faces) { - cell_stream << " " << face.size(); - for(auto v : face) { - cell_stream << " " << v; - } - } - cell_stream << "\n"; - total_size += cell_size + 1; // +1 for cell size - - } else { - // Standard cell types write vertex connectivity directly - std::vector vertices; - - for(auto itvert = alcc.template one_dart_per_incident_cell<0, 3>(itvol).begin(), - itvertend = alcc.template one_dart_per_incident_cell<0, 3>(itvol).end(); - itvert != itvertend; ++itvert) - { - vertices.push_back(vertex_index[alcc.vertex_attribute(itvert)]); - } - - cell_stream << vertices.size(); - for(auto v : vertices) { - cell_stream << " " << v; - } - cell_stream << "\n"; - total_size += vertices.size() + 1; - } - } + nbcells=0; + std::size_t total_size=0; + std::ostringstream cell_stream, type_stream; + typename LCC::Dart_const_descriptor sd; // Write cells section - os << "CELLS " << nbcells << " " << total_size << "\n"; - os << cell_stream.str(); - os << "\n"; + for(typename LCC::template One_dart_per_cell_range<3>::const_iterator + itvol=alcc.template one_dart_per_cell<3>().begin(), + itvolend=alcc.template one_dart_per_cell<3>().end(); + itvol!=itvolend; ++itvol) + { + ++nbcells; + ++total_size; // for the number of vertices + VTK_Cell_Type cell_type=get_vtk_cell_type(alcc, itvol, sd); + type_stream<(cell_type)<(sd))]<<" " + <(sd))]<<" " + <(sd))]<(sd))]<<" " + <(sd))]<<" " + <(sd))]<<" " + <(sd))]<(sd))]<<" " + <(sd))]<<" "; + // Move to the up face + typename LCC::Dart_const_descriptor d2=alcc.template beta<2, 1, 1, 2>(sd); + cell_stream<(d2))]<<" " + <(d2))]<(sd); + } + typename LCC::Dart_const_descriptor d2=alcc.template beta<2, 1, 1, 2, 1>(sd); + // Darts associated with particles 4, 5, 6, 7 + for(unsigned int i = 0; i < 4; i++) + { + cell_stream<(d2); + } + cell_stream<> faces; + std::size_t cell_size=1; // Start with 1 for number of faces + ++total_size; // for the same reason + for(auto itface=alcc.template one_dart_per_incident_cell<2, 3, 2>(itvol).begin(), + itfaceend=alcc.template one_dart_per_incident_cell<2, 3, 2>(itvol).end(); + itface!=itfaceend; ++itface) + { + faces.push_back(std::vector()); + typename LCC::Dart_const_descriptor curdh=itface; + do + { + faces.back().push_back(index[alcc.vertex_attribute(curdh)]); + curdh=alcc.template beta<1>(curdh); + } + while(curdh!=itface); + cell_size+=faces.back().size()+1; // +1 for the number of vertices in the face + } + cell_stream<) { - os << "POINT_DATA " << nbpts << "\n"; - os << "SCALARS vertex_scalars " << gettype::name() << " 1\n"; - os << "LOOKUP_TABLE default\n"; - for(auto itv = alcc.vertex_attributes().begin(), itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) { - auto dart = alcc.template dart_of_attribute<0>(itv); - CGAL_assertion(dart != alcc.null_dart_descriptor); - os << ptval(alcc, dart) << "\n"; - } - } - - // Write cell scalars if cellval is not nullptr/pointer - if constexpr(!std::is_same_v && !std::is_pointer_v) { - os << "CELL_DATA " << nbcells << "\n"; - os << "SCALARS volume_scalars " << gettype::name() << " 1\n"; - os << "LOOKUP_TABLE default\n"; - for(auto itvol = alcc.template one_dart_per_cell<3>().begin(), - itvolend = alcc.template one_dart_per_cell<3>().end(); - itvol != itvolend; ++itvol) - { - os << cellval(alcc, itvol) << "\n"; - } - } + os<<"CELL_TYPES "< -inline bool read_VTK(LCC& alcc, const char* filename, VertexScalarReader vertex_reader, CellScalarReader cell_reader) { - CGAL_assertion(filename != nullptr); - std::ifstream file(filename); - if(!file.is_open()) { - std::cerr << "[ERROR] read_VTK: cannot open file " << filename << std::endl; - return false; - } - return internal::read_lcc_from_vtk_ascii(file, alcc, vertex_reader, cell_reader); -} - -template -inline bool write_VTK(const LCC& alcc, const char* filename, PointFunctor ptval, CellFunctor cellval) { - CGAL_assertion(filename != nullptr); - std::ofstream file(filename); - if(!file.is_open()) { - std::cerr << "[ERROR] write_VTK: cannot open file " << filename << std::endl; - return false; - } - return internal::write_lcc_to_vtk_ascii(file, alcc, ptval, cellval); -} - -// Vector-based versions (convenience wrappers) +//////////////////////////////////////////////////////////////////////////////////// template -inline bool read_VTK(LCC& alcc, +bool read_VTK(LCC& alcc, const char* filename, std::vector* vertex_scalars, - std::vector* volume_scalars) { - auto v_writer = [&](std::size_t i, auto val) { - if(vertex_scalars) { - if(vertex_scalars->size() <= i) - vertex_scalars->resize(i + 1); - (*vertex_scalars)[i] = static_cast(val); - } - }; - auto c_writer = [&](std::size_t i, auto val) { - if(volume_scalars) { - if(volume_scalars->size() <= i) - volume_scalars->resize(i + 1); - (*volume_scalars)[i] = static_cast(val); - } - }; - return read_VTK(alcc, filename, v_writer, c_writer); + std::vector* volume_scalars) +{ + CGAL_assertion(filename!=nullptr); + std::ifstream file(filename); + if(!file.is_open()) + { + std::cerr<<"[ERROR] read_VTK: cannot open file "< +bool read_VTK(LCC& alcc, + const char* filename) +{ return read_VTK + (alcc, filename, nullptr, nullptr); } + +template +bool read_VTK(LCC& alcc, + const char* filename, + std::vector* vertex_scalars) +{ return read_VTK + (alcc, filename, vertex_scalars, nullptr); } + +template +bool read_VTK(LCC& alcc, + const char* filename, + std::nullptr_t, + std::vector* volume_scalars) +{ return read_VTK + (alcc, filename, nullptr, volume_scalars); } +//////////////////////////////////////////////////////////////////////////////////// +template +inline bool write_VTK_with_fct(const LCC& alcc, const char* filename, + PointFunctor pointfct, CellFunctor cellfct) +{ + CGAL_assertion(filename!=nullptr); + std::ofstream file(filename); + if(!file.good()) + { + std::cerr<<"[ERROR] write_VTK: cannot open file "<:: + run(file, alcc, nbpts, pointfct); } + if(cellfct) + { internal::Write_cell_data:: + run(file, alcc, nbcells, cellfct); } + } + file.close(); + return true; +} +//////////////////////////////////////////////////////////////////////////////////// template -inline bool write_VTK(const LCC& alcc, - const char* filename, +bool write_VTK(const LCC& alcc, const char* filename, const std::vector* vertex_scalars, - const std::vector* volume_scalars) { - // Build index maps - std::unordered_map vertex_indices; - std::size_t idx = 0; - for(auto itv = alcc.vertex_attributes().begin(), itvend = alcc.vertex_attributes().end(); itv != itvend; ++itv) - vertex_indices[itv] = idx++; + const std::vector* volume_scalars) +{ + std::function vertexfct; + std::function cellfct; + if(vertex_scalars!=nullptr) + { + vertexfct=[&vertex_scalars](const LCC&, typename LCC::Dart_const_descriptor, + std::size_t i) -> VertexScalarType + { return (*vertex_scalars)[i]; }; + } - std::unordered_map volume_indices; - idx = 0; - for(auto itvol = alcc.template one_dart_per_cell<3>().begin(), itvolend = alcc.template one_dart_per_cell<3>().end(); - itvol != itvolend; ++itvol) - volume_indices[itvol] = idx++; + if(volume_scalars!=nullptr) + { + cellfct=[&volume_scalars](const LCC&, typename LCC::Dart_const_descriptor, + std::size_t i) -> VolumeScalarType + { return (*volume_scalars)[i]; }; + } - return write_VTK( - alcc, filename, - [vertex_scalars, &vertex_indices](const LCC& lcc, typename LCC::Dart_const_descriptor d) -> VertexScalarType { - if(vertex_scalars) - return (*vertex_scalars)[vertex_indices.at(lcc.template attribute<0>(d))]; - return VertexScalarType(); - }, - [volume_scalars, &volume_indices](const LCC& lcc, typename LCC::Dart_const_descriptor d) -> VolumeScalarType { - if(volume_scalars) - return (*volume_scalars)[volume_indices.at(d)]; - return VolumeScalarType(); - }); + return write_VTK_with_fct(alcc, filename, vertexfct, cellfct); } +template +bool write_VTK(const LCC& alcc, const char* filename) +{ + return write_VTK(alcc, filename, nullptr, nullptr); +} + +template +bool write_VTK(const LCC& alcc, const char* filename, + const std::vector* vertex_scalars) +{ + return write_VTK(alcc, filename, vertex_scalars, + nullptr); +} + +template +bool write_VTK(const LCC& alcc, const char* filename, + std::nullptr_t, + const std::vector* volume_scalars) +{ + return write_VTK(alcc, filename, nullptr, + volume_scalars); +} +//////////////////////////////////////////////////////////////////////////////////// + } // namespace IO } // namespace CGAL -#endif // CGAL_LCC_IO_VTK_H \ No newline at end of file +#endif // CGAL_LCC_IO_VTK_H From 8ebeb1389677ae07696aaeb832eb46d236e4095a Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Sun, 7 Sep 2025 09:57:36 +0200 Subject: [PATCH 10/30] Creation of prisms and pyramids are now members of cmap and lcc --- .../LCC_3_incremental_builder_test.cpp | 98 ------------------- 1 file changed, 98 deletions(-) diff --git a/Linear_cell_complex/test/Linear_cell_complex/LCC_3_incremental_builder_test.cpp b/Linear_cell_complex/test/Linear_cell_complex/LCC_3_incremental_builder_test.cpp index 03d6bf55922..32e4336bc03 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/LCC_3_incremental_builder_test.cpp +++ b/Linear_cell_complex/test/Linear_cell_complex/LCC_3_incremental_builder_test.cpp @@ -5,104 +5,6 @@ #include "Linear_cell_complex_3_test.h" -/////////////////////////////////////////////////////////////////////////////// -/* 3 - * /|\ - * 0-|-2 - * \|/ - * 1 - */ -template -void make_tetrahedron_with_builder(IncrementalBuilder& ib, - std::size_t i0, - std::size_t i1, - std::size_t i2, - std::size_t i3) -{ - ib.begin_surface(); - ib.add_facet({i0,i1,i2}); - ib.add_facet({i1,i0,i3}); - ib.add_facet({i2,i1,i3}); - ib.add_facet({i0,i2,i3}); - ib.end_surface(); -} -/////////////////////////////////////////////////////////////////////////////// -/* 4 - * /|\ - * 0-|-3 - * | | | - * 1---2 - */ -template -void make_pyramid_with_builder(IncrementalBuilder& ib, - std::size_t i0, - std::size_t i1, - std::size_t i2, - std::size_t i3, - std::size_t i4) -{ - ib.begin_surface(); - ib.add_facet({i0,i1,i2,i3}); - ib.add_facet({i1,i0,i4}); - ib.add_facet({i2,i1,i4}); - ib.add_facet({i3,i2,i4}); - ib.add_facet({i0,i3,i4}); - ib.end_surface(); -} -/////////////////////////////////////////////////////////////////////////////// -/* 3 - * /|\ - * 4---5 - * | | | - * | 0 | - * |/ \| - * 1---2 - */ -template -void make_prism_with_builder(IncrementalBuilder& ib, - std::size_t i0, - std::size_t i1, - std::size_t i2, - std::size_t i3, - std::size_t i4, - std::size_t i5) -{ - ib.begin_surface(); - ib.add_facet({i0,i1,i2}); - ib.add_facet({i1,i0,i3,i4}); - ib.add_facet({i2,i1,i4,i5}); - ib.add_facet({i0,i2,i5,i3}); - ib.add_facet({i5,i4,i3}); - ib.end_surface(); -} -/////////////////////////////////////////////////////////////////////////////// -/* 7----6 - * /| /| - * 4----5 | - * | 3--|-2 - * |/ |/ - * 0----1 - */ -template -void make_hexahedron_with_builder(IncrementalBuilder& ib, - std::size_t i0, - std::size_t i1, - std::size_t i2, - std::size_t i3, - std::size_t i4, - std::size_t i5, - std::size_t i6, - std::size_t i7) -{ - ib.begin_surface(); - ib.add_facet({i0,i1,i2,i3}); - ib.add_facet({i1,i0,i4,i5}); - ib.add_facet({i2,i1,i5,i6}); - ib.add_facet({i3,i2,i6,i7}); - ib.add_facet({i0,i3,i7,i4}); - ib.add_facet({i7,i6,i5,i4}); - ib.end_surface(); -} /////////////////////////////////////////////////////////////////////////////// template bool test_ib(const char* filename) From 876db072d83b5eac741fade7dff3d44f45aaeda0 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Sun, 7 Sep 2025 10:02:14 +0200 Subject: [PATCH 11/30] LCC: compute topology of volumes --- Combinatorial_map/include/CGAL/Element_topo.h | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 Combinatorial_map/include/CGAL/Element_topo.h diff --git a/Combinatorial_map/include/CGAL/Element_topo.h b/Combinatorial_map/include/CGAL/Element_topo.h new file mode 100644 index 00000000000..4ef5d0c1776 --- /dev/null +++ b/Combinatorial_map/include/CGAL/Element_topo.h @@ -0,0 +1,208 @@ +// Copyright (c) 2025 CNRS and LIRIS' Establishments (France). +// All rights reserved. +// +// This file is part of CGAL (www.cgal.org) +// +// $URL$ +// $Id$ +// SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-Commercial +// +// Author(s) : Guillaume Damiand +// +//////////////////////////////////////////////////////////////////////////////// +#ifndef CMAP_ELEMENT_TOPO_H +#define CMAP_ELEMENT_TOPO_H + +#include + +namespace CGAL { + namespace CMap { + namespace Element_topo { + +enum cell_topo + { + SQUARE=0, + TRIANGLE=1, + HEXAHEDRON=2, + TETRAHEDRON=3, + PRISM=4, + PYRAMID=5, + GENERIC_2D=6, + GENERIC_3D=7, + EDGE=8, + TETRAHEDRON10=9, + PENTAGONAL_PRISM=10, + HEXAGONAL_PRISM=11, + NO_TYPE=-1 + }; + +inline +std::string topo_name(cell_topo t) +{ + switch(t) + { + case SQUARE: return "SQUARE"; + case TRIANGLE: return "TRIANGLE"; + case HEXAHEDRON: return "HEXAHEDRON"; + case TETRAHEDRON: return "TETRAHEDRON"; + case PRISM: return "PRISM"; + case PYRAMID: return "PYRAMID"; + case GENERIC_2D: return "GENERIC_2D"; + case GENERIC_3D: return "GENERIC_3D"; + case EDGE: return "EDGE"; + case TETRAHEDRON10: return "TETRAHEDRON10"; + case PENTAGONAL_PRISM: return "PENTAGONAL_PRISM"; + case HEXAGONAL_PRISM: return "HEXAGONAL_PRISM"; + case NO_TYPE: return "NO_TYPE"; + } + return "UNKNOWN"; +} + +inline +cell_topo topo_from_name(const std::string& t) +{ + if (t=="SQUARE") return SQUARE; + if (t=="TRIANGLE") return TRIANGLE; + if (t=="HEXAHEDRON") return HEXAHEDRON; + if (t=="TETRAHEDRON") return TETRAHEDRON; + if (t=="PRISM") return PRISM; + if (t=="PYRAMID") return PYRAMID; + if (t=="GENERIC_2D") return GENERIC_2D; + if (t=="GENERIC_3D") return GENERIC_3D; + if (t=="EDGE") return EDGE; + if (t=="TETRAHEDRON10") return TETRAHEDRON10; + if (t=="PENTAGONAL_PRISM") return PENTAGONAL_PRISM; + if (t=="HEXAGONAL_PRISM") return HEXAGONAL_PRISM; + if (t=="NO_TYPE") return NO_TYPE; + return NO_TYPE; +} + +/** + * @brief To get the type of dimD cell of the CMap of cmapdim dimension. + */ +template +struct Get_cell_topo +{ + static cell_topo run(CMap&, typename CMap::Dart_descriptor dh, + typename CMap::Dart_descriptor& starting_dart) + { + starting_dart=dh; + return NO_TYPE; + } +}; + +/** + * @brief To get the type associated of an edge. For now only one type. + */ +template +struct Get_cell_topo +{ + static cell_topo run(CMap&, typename CMap::Dart_descriptor it, + typename CMap::Dart_descriptor& starting_dart) + { + starting_dart=it; + return EDGE; + } +}; + +/** + * @brief To get the type of 2D cell of the CMap of cmapdim dimension. + */ +template +struct Get_cell_topo +{ + static cell_topo run(CMap& cmap, typename CMap::Dart_descriptor it, + typename CMap::Dart_descriptor& starting_dart) + { + starting_dart=it; + + if (cmap.is_face_combinatorial_polygon(it, 3)) + { return TRIANGLE; } + + else if (cmap.is_face_combinatorial_polygon(it, 4)) + { return SQUARE; } + + return GENERIC_2D; + } +}; + +/** + * @brief To get the type of 3D cell of the CMap of dimension 3. + */ +template +struct Get_cell_topo +{ + static cell_topo run(CMap& cmap, typename CMap::Dart_descriptor it, + typename CMap::Dart_descriptor& starting_dart) + { + starting_dart=it; + + if (cmap.is_volume_combinatorial_tetrahedron(it)) + { return TETRAHEDRON; } + + else if (cmap.is_volume_combinatorial_hexahedron(it)) + { return HEXAHEDRON; } + + else if(cmap.is_volume_combinatorial_tetrahedron10(it)) + { return TETRAHEDRON10; } + + // For non symetric object, we need to test all darts + for (auto itv=cmap.template darts_of_cell<3>(it).begin(), + itvend=cmap.template darts_of_cell<3>(it).end(); itv!=itvend; ++itv) + { + starting_dart=itv; + + if (cmap.is_volume_combinatorial_prism(itv)) + { return PRISM; } + + else if (cmap.is_volume_combinatorial_pentagonal_prism(itv)) + { return PENTAGONAL_PRISM; } + + else if (cmap.is_volume_combinatorial_pyramid(itv)) + { return PYRAMID; } + + else if (cmap.is_volume_combinatorial_hexagonal_prism(itv)) + { return HEXAGONAL_PRISM; } + + } + + return GENERIC_3D; + } +}; + +template +cell_topo get_cell_topo(CMap& cmap, typename CMap::Dart_descriptor it, + typename CMap::Dart_descriptor& starting_dart) +{ return Get_cell_topo::run(cmap, it, starting_dart); } + +template +cell_topo get_cell_topo(CMap& cmap, typename CMap::Dart_descriptor it) +{ + typename CMap::Dart_descriptor dummy; + return get_cell_topo(cmap, it, dummy); +} + +template +cell_topo get_cell_topo(const CMap& cmap, typename CMap::Dart_const_descriptor it, + typename CMap::Dart_const_descriptor& starting_dart) +{ + typename CMap::Dart_descriptor it2=const_cast(cmap).dart_descriptor + (cmap.darts().index(it)); + typename CMap::Dart_descriptor sd2; + cell_topo res=Get_cell_topo::run(const_cast(cmap), + it2, sd2); + starting_dart=sd2; + return res; +} + +template +cell_topo get_cell_topo(const CMap& cmap, typename CMap::Dart_const_descriptor it) +{ + typename CMap::Dart_descriptor it2=it; + return Get_cell_topo::run(const_cast(cmap), it2); +} + +} } } // namespace CGAL::CMap::Element_topo + +#endif // CMAP_ELEMENT_TOPO_H From 5a3dbda022a442eb8457ac6f70e9ec82b8a9db58 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Mon, 8 Sep 2025 12:30:48 +0200 Subject: [PATCH 12/30] Test for read write vtk + data files --- .../include/CGAL/Linear_cell_complex/IO/VTK.h | 5 + .../Linear_cell_complex_vtk_io_test.cpp | 225 +- .../data/2generic_cell.vtk | 35 + .../test/Linear_cell_complex/data/2hexa.vtk | 26 + .../test/Linear_cell_complex/data/2prism.vtk | 30 + .../Linear_cell_complex/data/2pyramid.vtk | 21 + .../test/Linear_cell_complex/data/2tetra.vtk | 33 + .../data/beam-with-mixed-cells.vtk | 1958 ++++++++++++++++- 8 files changed, 2283 insertions(+), 50 deletions(-) create mode 100644 Linear_cell_complex/test/Linear_cell_complex/data/2generic_cell.vtk create mode 100644 Linear_cell_complex/test/Linear_cell_complex/data/2hexa.vtk create mode 100644 Linear_cell_complex/test/Linear_cell_complex/data/2prism.vtk create mode 100644 Linear_cell_complex/test/Linear_cell_complex/data/2pyramid.vtk create mode 100644 Linear_cell_complex/test/Linear_cell_complex/data/2tetra.vtk diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h index 0a70ee38e22..2805f904d8d 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h @@ -423,6 +423,11 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, { alcc.erase_vertex_attribute(itv); } } + if(vertex_scalars!=nullptr) + { vertex_scalars->clear(); } + if(cell_scalars!=nullptr) + { cell_scalars->clear(); } + while(std::getline(is, line)) { // Read POINT_DATA scalars if present diff --git a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp index 6587b9e928b..10f825f0435 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp +++ b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp @@ -6,62 +6,197 @@ typedef CGAL::Linear_cell_complex_for_combinatorial_map<3, 3> LCC; -int main() { +bool test_file(const char* filename) +{ LCC lcc1, lcc2; std::vector vertex_scalars1, vertex_scalars2; std::vector volume_scalars1, volume_scalars2; - const char* filename = "data/beam-with-mixed-cells.vtk"; - - - bool ok_read1 = CGAL::IO::read_VTK(lcc1, filename, - &vertex_scalars1, &volume_scalars1); - assert(ok_read1); - - - std::size_t nb_vertices = 0; - for(auto itv = lcc1.vertex_attributes().begin(), itvend = lcc1.vertex_attributes().end(); itv != itvend; ++itv) - ++nb_vertices; - if(vertex_scalars1.size() != nb_vertices) { - vertex_scalars1.resize(nb_vertices); - for(std::size_t i=0;i(i); + bool res=CGAL::IO::read_VTK(lcc1, filename); + if(!res) + { + std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK in test_file"<().begin(), - itvolend = lcc1.one_dart_per_cell<3>().end(); itvol != itvolend; ++itvol) - ++nb_volumes; + std::size_t nb_vertices=lcc1.number_of_vertex_attributes(); + vertex_scalars1.resize(nb_vertices); + for(std::size_t i=0;i(i); } - if(volume_scalars1.size() != nb_volumes) { - volume_scalars1.clear(); - volume_scalars1.reserve(nb_volumes); - for(auto itvol = lcc1.one_dart_per_cell<3>().begin(), - itvolend = lcc1.one_dart_per_cell<3>().end(); itvol != itvolend; ++itvol) { - auto d = lcc1.dart_descriptor(*itvol); - std::size_t nbv = lcc1.template one_dart_per_incident_cell<0,3>(d).size(); - volume_scalars1.push_back(nbv); - } + std::size_t nb_volumes=0; + for(auto itvol=lcc1.one_dart_per_cell<3>().begin(), + itvolend=lcc1.one_dart_per_cell<3>().end(); itvol!=itvolend; ++itvol) + { ++nb_volumes; } + + volume_scalars1.reserve(nb_volumes); + for(auto itvol=lcc1.one_dart_per_cell<3>().begin(), + itvolend=lcc1.one_dart_per_cell<3>().end(); itvol!=itvolend; ++itvol) + { + std::size_t nbv=lcc1.template one_dart_per_incident_cell<0,3>(itvol).size(); + volume_scalars1.push_back(nbv); } - - bool ok_write = CGAL::IO::write_VTK(lcc1, filename, - &vertex_scalars1, &volume_scalars1); - assert(ok_write); + res=CGAL::IO::write_VTK(lcc1, "output.vtk", + &vertex_scalars1, &volume_scalars1); + if(!res) + { + std::cerr<<"[ERROR] LCC_vtk_io_test error write_VTK in test_file"<(lcc2, filename, - &vertex_scalars2, &volume_scalars2); - assert(ok_read2); + res=CGAL::IO::read_VTK(lcc2, "output.vtk", + &vertex_scalars2, &volume_scalars2); + if(!res) + { + std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK 2 in test_file"< vertex_scalars; + std::vector volume_scalars; + + /// Read the last file generated by test_file("data/beam-with-mixed-cells.vtk") + /// i.e. beam-with-mixed-cells.vtk with point and cells scalars. + if(!CGAL::IO::read_VTK(lcc, "output.vtk", + &vertex_scalars, &volume_scalars) || + vertex_scalars.size()!=719 || volume_scalars.size()!=615) + { + std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK in test_different_scalars"< Date: Mon, 8 Sep 2025 13:06:42 +0200 Subject: [PATCH 13/30] Cleanup --- Linear_cell_complex/Testing/Temporary/CTestCostData.txt | 1 - Linear_cell_complex/Testing/Temporary/LastTest.log | 3 --- Testing/Temporary/CTestCostData.txt | 1 - Testing/Temporary/LastTest.log | 3 --- 4 files changed, 8 deletions(-) delete mode 100644 Linear_cell_complex/Testing/Temporary/CTestCostData.txt delete mode 100644 Linear_cell_complex/Testing/Temporary/LastTest.log delete mode 100644 Testing/Temporary/CTestCostData.txt delete mode 100644 Testing/Temporary/LastTest.log diff --git a/Linear_cell_complex/Testing/Temporary/CTestCostData.txt b/Linear_cell_complex/Testing/Temporary/CTestCostData.txt deleted file mode 100644 index ed97d539c09..00000000000 --- a/Linear_cell_complex/Testing/Temporary/CTestCostData.txt +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/Linear_cell_complex/Testing/Temporary/LastTest.log b/Linear_cell_complex/Testing/Temporary/LastTest.log deleted file mode 100644 index 7016d17c7c2..00000000000 --- a/Linear_cell_complex/Testing/Temporary/LastTest.log +++ /dev/null @@ -1,3 +0,0 @@ -Start testing: Jul 25 15:46 CEST ----------------------------------------------------------- -End testing: Jul 25 15:46 CEST diff --git a/Testing/Temporary/CTestCostData.txt b/Testing/Temporary/CTestCostData.txt deleted file mode 100644 index ed97d539c09..00000000000 --- a/Testing/Temporary/CTestCostData.txt +++ /dev/null @@ -1 +0,0 @@ ---- diff --git a/Testing/Temporary/LastTest.log b/Testing/Temporary/LastTest.log deleted file mode 100644 index 7016d17c7c2..00000000000 --- a/Testing/Temporary/LastTest.log +++ /dev/null @@ -1,3 +0,0 @@ -Start testing: Jul 25 15:46 CEST ----------------------------------------------------------- -End testing: Jul 25 15:46 CEST From 1a03f8c6e10e234970f73de06e7b87c64fdc9888 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Thu, 9 Oct 2025 17:32:55 +0200 Subject: [PATCH 14/30] update following Mael review --- .../include/CGAL/Combinatorial_map.h | 16 ++++++++-------- .../include/CGAL/Linear_cell_complex/IO/VTK.h | 2 +- .../include/CGAL/Linear_cell_complex_base.h | 8 ++++---- .../Linear_cell_complex_incremental_builder_3.h | 17 +++++++++-------- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map.h b/Combinatorial_map/include/CGAL/Combinatorial_map.h index e4839b37d4b..1502b7bff7b 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map.h @@ -3860,7 +3860,7 @@ namespace CGAL { } /** Test if a volume is a combinatorial tetrahedron. - * @param adart an initial dart + * @param d1 an initial dart * @return true iff the volume containing adart is a combinatorial tetrahedron. */ bool is_volume_combinatorial_tetrahedron(Dart_const_descriptor d1) const @@ -3953,7 +3953,7 @@ namespace CGAL { } /** Test if a volume is a combinatorial hexahedron. - * @param adart an initial dart + * @param d1 an initial dart * @return true iff the volume containing adart is a combinatorial hexahedron. */ bool is_volume_combinatorial_hexahedron(Dart_const_descriptor d1) const @@ -4020,7 +4020,7 @@ namespace CGAL { } /** Test if a volume is a combinatorial prism. - * @param adart an intial dart + * @param d1 an initial dart * @return true iff the volume containing adart is a combinatorial prism. */ bool is_volume_combinatorial_prism(Dart_const_descriptor d1) const @@ -4109,7 +4109,7 @@ namespace CGAL { } /** Test if a volume is a combinatorial pyramid. - * @param adart an intial dart + * @param d1 an intial dart * @return true iff the volume containing adart is a combinatorial pyramid. */ bool is_volume_combinatorial_pyramid(Dart_const_descriptor d1) const @@ -4196,7 +4196,7 @@ namespace CGAL { } /** Test if a volume is a combinatorial pentagonal prism. - * @param adart an initial dart + * @param d1 an initial dart * @return true iff the volume containing adart is a combinatorial pentagonal prism. */ bool is_volume_combinatorial_pentagonal_prism(Dart_const_descriptor d1) const @@ -4261,7 +4261,7 @@ namespace CGAL { } /** Test if a volume is a combinatorial hexagonal prism. - * @param adart an initial dart + * @param d1 an initial dart * @return true iff the volume containing adart is a combinatorial hexagonal prism. */ bool is_volume_combinatorial_hexagonal_prism(Dart_const_descriptor d1) const @@ -4336,8 +4336,8 @@ namespace CGAL { } /** Test if a volume is a combinatorial tetrahedron10. - * @param adart an initial dart - * @return true iff the volume containing adart is a combinatorial tetrahedron. + * @param d1 an initial dart + * @return true iff the volume containing adart is a combinatorial tetrahedron10. */ bool is_volume_combinatorial_tetrahedron10(Dart_const_descriptor d1) const { diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h index 2805f904d8d..cbdeaaa0ef9 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h @@ -10,7 +10,7 @@ // Author(s) : Guillaume Damiand #ifndef CGAL_LCC_IO_VTK_H -#define CGAL_LCC_IO_VTK_H 1 +#define CGAL_LCC_IO_VTK_H #include #include diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h index 7b9dcec4f5e..f62d36ff41d 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h @@ -717,7 +717,7 @@ namespace CGAL { create_vertex_attribute(p7)); } - /** Create an prism given 6 Vertex_attribute_descriptor. + /** Create a prism given 6 Vertex_attribute_descriptor. * (6 vertices, 9 edges and 5 facets) * \verbatim * 3---4 @@ -751,7 +751,7 @@ namespace CGAL { return make_combinatorial_prism(d1, d2, d3, d4, d5); } - /** Create an prism given 6 points. + /** Create a prism given 6 points. * \verbatim * 3---4 * |\ /| @@ -783,7 +783,7 @@ namespace CGAL { create_vertex_attribute(p5)); } - /** Create an pyramid given 5 Vertex_attribute_descriptor. + /** Create a pyramid given 5 Vertex_attribute_descriptor. * (5 vertices, 8 edges and 5 facets) * \verbatim * 4 @@ -815,7 +815,7 @@ namespace CGAL { return make_combinatorial_pyramid(d1, d2, d3, d4, d5); } - /** Create an pyramid given 5 points. + /** Create a pyramid given 5 points. * \verbatim * 4 * /|\ diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_incremental_builder_3.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_incremental_builder_3.h index 1fadfead366..d88208ad181 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_incremental_builder_3.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_incremental_builder_3.h @@ -261,7 +261,8 @@ public: prev_dart =lcc.null_descriptor; } -void add_vertex_to_facet(size_type i, std::vector* tabdarts = nullptr) { + void add_vertex_to_facet(size_type i, std::vector* tabdarts = nullptr) + { CGAL_assertion(i::run(lcc, vertex_map[i], prev_dart); @@ -326,13 +327,13 @@ void add_vertex_to_facet(size_type i, std::vector* tabdarts = nullptr) { } DH add_facet(std::initializer_list l, std::vector* tabdarts = nullptr) -{ - if(tabdarts != nullptr) { tabdarts->reserve(tabdarts->size() + l.size()); } - begin_facet(); - for (size_type i:l) - { add_vertex_to_facet(i, tabdarts); } - return end_facet(); -} + { + if(tabdarts != nullptr) { tabdarts->reserve(tabdarts->size() + l.size()); } + begin_facet(); + for (size_type i:l) + { add_vertex_to_facet(i, tabdarts); } + return end_facet(); + } void begin_surface() { From cd248c2638f6d5e10b836f153d19cfa7504471ff Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Thu, 9 Oct 2025 18:40:47 +0200 Subject: [PATCH 15/30] Change order of parameters for lcc read/write vtk --- .../linear_cell_complex_3_vtk_io.cpp | 13 +----- .../include/CGAL/Linear_cell_complex/IO/VTK.h | 41 +++++++++---------- .../Linear_cell_complex_vtk_io_test.cpp | 26 ++++++------ 3 files changed, 33 insertions(+), 47 deletions(-) diff --git a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp index 794f1aaa62a..d1c040ac29c 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp @@ -1,14 +1,3 @@ -/*! - \ingroup PkgLinearCellComplexExamples - \brief Minimal example: read a `.3map` file, compute per-volume vertex count, and write to VTK. - - This example loads a 3D linear cell complex from a `.3map` file using - \cgal function `CGAL::load_combinatorial_map()`. It computes for each - 3-cell (volume) the number of incident vertices (0-cells), stores these values - in a `std::vector`, and writes the result to a `.vtk` file with - `CGAL::IO::write_VTK()`, using the computed values as scalars for each volume. -*/ - #include #include #include @@ -29,7 +18,7 @@ int main() volume_scalars.push_back(nbv); } - if(!CGAL::IO::write_VTK(lcc, "beam-with-mixed-cells.vtk", nullptr, + if(!CGAL::IO::write_VTK("beam-with-mixed-cells.vtk", lcc, nullptr, &volume_scalars)) { return EXIT_FAILURE; } diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h index cbdeaaa0ef9..2bcf5fe9973 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h @@ -26,7 +26,7 @@ namespace CGAL { namespace IO { -/** \file VTK.h +/* * Functions to import/export 3D Linear_cell_complex from/to VTK legacy ASCII * format. * @@ -50,10 +50,8 @@ namespace IO { // Declarations // ============================================================================ -/** - * \brief Read a VTK legacy ASCII file and load it into a 3D - * Linear_cell_complex. - * \ingroup PkgLinearCellComplexExamples +/* + * Read a VTK legacy ASCII file and load it into a 3D Linear_cell_complex. * * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> * \tparam VertexScalarType Type for vertex scalar data (default: float) @@ -68,14 +66,13 @@ namespace IO { */ template -bool read_VTK(LCC& alcc, - const char* filename, +bool read_VTK(const char* filename, + LCC& alcc, std::vector* vertex_scalars, std::vector* volume_scalars); -/** - * \brief Write a 3D Linear_cell_complex to a VTK legacy ASCII file. - * \ingroup PkgLinearCellComplexExamples +/* + * Write a 3D Linear_cell_complex to a VTK legacy ASCII file. * * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> * \tparam VertexScalarType Type for vertex scalar data (default: float) @@ -90,14 +87,14 @@ bool read_VTK(LCC& alcc, */ template -bool write_VTK(const LCC& alcc, - const char* filename, +bool write_VTK(const char* filename, + const LCC& alcc, const std::vector* vertex_scalars, const std::vector* volume_scalars); // "Advanced" versions with functors template -bool write_VTK_with_fct(const LCC& alcc, const char* filename, +bool write_VTK_with_fct(const char* filename, const LCC& alcc, PointFunctor ptval, CellFunctor cellval); // ============================================================================ @@ -638,7 +635,7 @@ bool read_VTK(LCC& alcc, (alcc, filename, nullptr, volume_scalars); } //////////////////////////////////////////////////////////////////////////////////// template -inline bool write_VTK_with_fct(const LCC& alcc, const char* filename, +inline bool write_VTK_with_fct(const char* filename, const LCC& alcc, PointFunctor pointfct, CellFunctor cellfct) { CGAL_assertion(filename!=nullptr); @@ -664,7 +661,7 @@ inline bool write_VTK_with_fct(const LCC& alcc, const char* filename, } //////////////////////////////////////////////////////////////////////////////////// template -bool write_VTK(const LCC& alcc, const char* filename, +bool write_VTK(const char* filename, const LCC& alcc, const std::vector* vertex_scalars, const std::vector* volume_scalars) { @@ -688,27 +685,27 @@ bool write_VTK(const LCC& alcc, const char* filename, { return (*volume_scalars)[i]; }; } - return write_VTK_with_fct(alcc, filename, vertexfct, cellfct); + return write_VTK_with_fct(filename, alcc, vertexfct, cellfct); } template -bool write_VTK(const LCC& alcc, const char* filename) +bool write_VTK(const char* filename, const LCC& alcc) { return write_VTK(alcc, filename, nullptr, nullptr); } template -bool write_VTK(const LCC& alcc, const char* filename, - const std::vector* vertex_scalars) +bool write_VTK(const char* filename, const LCC& alcc, + const std::vector* vertex_scalars) { return write_VTK(alcc, filename, vertex_scalars, nullptr); } template -bool write_VTK(const LCC& alcc, const char* filename, - std::nullptr_t, - const std::vector* volume_scalars) +bool write_VTK(const char* filename, const LCC& alcc, + std::nullptr_t, + const std::vector* volume_scalars) { return write_VTK(alcc, filename, nullptr, volume_scalars); diff --git a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp index 10f825f0435..179961092f5 100644 --- a/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp +++ b/Linear_cell_complex/test/Linear_cell_complex/Linear_cell_complex_vtk_io_test.cpp @@ -12,7 +12,7 @@ bool test_file(const char* filename) std::vector vertex_scalars1, vertex_scalars2; std::vector volume_scalars1, volume_scalars2; - bool res=CGAL::IO::read_VTK(lcc1, filename); + bool res=CGAL::IO::read_VTK(filename, lcc1); if(!res) { std::cerr<<"[ERROR] LCC_vtk_io_test error read_VTK in test_file"< Date: Thu, 9 Oct 2025 18:47:58 +0200 Subject: [PATCH 16/30] add example in lcc for write_vtk; add groups --- .../doc/Linear_cell_complex/Linear_cell_complex.txt | 7 +++++++ .../doc/Linear_cell_complex/PackageDescription.txt | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt b/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt index d58e0f6e2e5..6dc799dae2b 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt @@ -288,6 +288,13 @@ The following example shows the use of \link GenericMap::insert_cell_1_between_t Result of the run of the linear_cell_complex_3_insert program. A window shows the 3D cube where one face has a hole. \cgalFigureEnd +\subsection Linear_cell_complexWriteVTK Write a Linear Cell Complex in a VTK File +\anchor ssecLCCWriteVtK + +This example loads a 3D linear cell complex from a `.3map` file using \cgal function `CGAL::load_combinatorial_map()`. It computes for each 3-cell (volume) the number of incident vertices (0-cells), stores these values in a `std::vector`, and writes the result to a `.vtk` file with `CGAL::IO::write_VTK()`, using the computed values as scalars for each volume. + +\cgalExample{Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp} + \section Linear_cell_complexDesign Design and Implementation History This package was developed by Guillaume Damiand, with the help of Andreas Fabri, Sébastien Loriot and Laurent Rineau. Monique Teillaud and Bernd Gärtner contributed to the manual. diff --git a/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt b/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt index caf7173fbee..8c078b6159c 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt @@ -23,6 +23,14 @@ /// \defgroup PkgDrawLinearCellComplex Draw a Linear Cell Complex /// \ingroup PkgLinearCellComplexRef +/// \defgroup PkgLinearCellComplexRefIO IO Functions for LCC +/// \ingroup PkgLinearCellComplexRef + +/*! High-level operations. +\cgalInclude{CGAL/Linear_cell_complex/IO/VTK.h} +*/ +/// \defgroup PkgLinearCellComplexRefIOVTK VTK IO Functions for LCC +/// \ingroup PkgLinearCellComplexRefIO /*! \addtogroup PkgLinearCellComplexRef @@ -74,4 +82,8 @@ - \link PkgDrawLinearCellComplex CGAL::draw() \endlink - \link PkgDrawLinearCellComplex CGAL::add_in_graphics_scene() \endlink +\cgalCRPSubsection{IO Functions for LCC} +- `CGAL::IO::Read_VTK()` +- `CGAL::IO::Write_VTK()` + */ From ed6eb76670ea2605c52992ba9565de6a00781d39 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Thu, 9 Oct 2025 18:53:22 +0200 Subject: [PATCH 17/30] spaces --- Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h index 2bcf5fe9973..115d2e2a416 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h @@ -94,7 +94,7 @@ bool write_VTK(const char* filename, // "Advanced" versions with functors template -bool write_VTK_with_fct(const char* filename, const LCC& alcc, +bool write_VTK_with_fct(const char* filename, const LCC& alcc, PointFunctor ptval, CellFunctor cellval); // ============================================================================ From 8c8431679630ec9becc2898ab14a66c266e03af0 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Thu, 9 Oct 2025 18:57:19 +0200 Subject: [PATCH 18/30] doc for lcc vtk io --- .../CGAL/Linear_cell_complex/IO/VTK.h | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h diff --git a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h new file mode 100644 index 00000000000..6f7b4ae2c67 --- /dev/null +++ b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h @@ -0,0 +1,68 @@ +namespace CGAL { +namespace IO { + +/** \file VTK.h + * Functions to import/export 3D Linear_cell_complex from/to VTK legacy ASCII + * format. + * + * Only supports: + * - Linear_cell_complex_for_combinatorial_map<3,3> + * - VTK legacy ASCII format (.vtk files) + * - Optional scalar fields for vertices and volumes + * + * Supported VTK cell types: + * - VTK_TETRA (10): Tetrahedron + * - VTK_VOXEL (11): Voxel (special hexahedron ordering) + * - VTK_HEXAHEDRON (12): Hexahedron + * - VTK_WEDGE (13): Prism/Wedge + * - VTK_PYRAMID (14): Pyramid + * - VTK_PENTAGONAL_PRISM (15): Pentagonal prism + * - VTK_HEXAGONAL_PRISM (16): Hexagonal prism + * - VTK_POLYHEDRON (42): Generic polyhedron + */ + +/** + * \brief Read a VTK legacy ASCII file and load it into a 3D + * Linear_cell_complex. + * \ingroup PkgLinearCellComplexRefIOVTK + * + * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> + * \tparam VertexScalarType Type for vertex scalar data (default: float) + * \tparam VolumeScalarType Type for volume scalar data (default: float) + * \param filename Path to the VTK file + * \param alcc The Linear_cell_complex to populate (will be cleared first) + * \param vertex_scalars Optional output vector to store per-vertex scalar values. + * If provided, will be resized to match number of vertices. + * \param volume_scalars Optional output vector to store per-volume scalar values. + * If provided, will be resized to match number of volumes. + * \return `true` if loading was successful, `false` otherwise + */ +template +bool read_VTK(const char* filename, + LCC& alcc, + std::vector* vertex_scalars, + std::vector* volume_scalars); + +/** + * \brief Write a 3D Linear_cell_complex to a VTK legacy ASCII file. + * \ingroup PkgLinearCellComplexRefIOVTK + * + * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> + * \tparam VertexScalarType Type for vertex scalar data (default: float) + * \tparam VolumeScalarType Type for volume scalar data (default: float) + * \param filename Path to the output VTK file + * \param alcc The Linear_cell_complex to export + * \param vertex_scalars Optional per-vertex scalar data. If provided, must have + * same size as number of vertex attributes in the LCC. + * \param volume_scalars Optional per-volume scalar data. If provided, must have + * same size as number of 3-cells in the LCC. + * \return `true` if writing was successful, `false` otherwise + */ +template +bool write_VTK(const char* filename, + const LCC& alcc, + const std::vector* vertex_scalars, + const std::vector* volume_scalars); + +} // namespace IO +} // namespace CGAL From ce1c890cb0ec71294a56f23199e9aa0a55b25ed4 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Fri, 10 Oct 2025 09:42:43 +0200 Subject: [PATCH 19/30] order of parameter for lcc vtk functions --- .../linear_cell_complex_3_vtk_io.cpp | 33 +++++++++++-------- .../include/CGAL/Linear_cell_complex/IO/VTK.h | 31 ++++++++--------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp index d1c040ac29c..8bd7b39e38d 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp @@ -1,26 +1,31 @@ #include #include -#include #include #include int main() { CGAL::Linear_cell_complex_for_combinatorial_map<3> lcc; - CGAL::load_combinatorial_map("data/beam-with-mixed-cells.3map", lcc); + std::ifstream is("data/beam-with-mixed-cells.3map"); + if(!is) + { + std::cout<<"Error opening data/beam-with-mixed-cells.3map."< volume_scalars; - for(auto it=lcc.template one_dart_per_cell<3>().begin(), - itend=lcc.template one_dart_per_cell<3>().end(); it!=itend; ++it) - { - std::size_t nbv=lcc.template one_dart_per_incident_cell<0,3>(it).size(); - volume_scalars.push_back(nbv); - } + is>>lcc; + // Compute per-volume vertex count + std::vector volume_scalars; + for(auto it=lcc.template one_dart_per_cell<3>().begin(), + itend=lcc.template one_dart_per_cell<3>().end(); it!=itend; ++it) + { + std::size_t nbv=lcc.template one_dart_per_incident_cell<0,3>(it).size(); + volume_scalars.push_back(nbv); + } - if(!CGAL::IO::write_VTK("beam-with-mixed-cells.vtk", lcc, nullptr, - &volume_scalars)) - { return EXIT_FAILURE; } + if(!CGAL::IO::write_VTK("beam-with-mixed-cells.vtk", lcc, nullptr, + &volume_scalars)) + { std::cout<<"Error for write_VTK."< -bool read_VTK(LCC& alcc, - const char* filename, +bool read_VTK(const char* filename, LCC& alcc, std::vector* vertex_scalars, std::vector* volume_scalars) { @@ -614,25 +613,21 @@ bool read_VTK(LCC& alcc, } template -bool read_VTK(LCC& alcc, - const char* filename) -{ return read_VTK - (alcc, filename, nullptr, nullptr); } +bool read_VTK(const char* filename, LCC& alcc) +{ return read_VTK(filename, alcc, nullptr, nullptr); } template -bool read_VTK(LCC& alcc, - const char* filename, - std::vector* vertex_scalars) +bool read_VTK(const char* filename, LCC& alcc, + std::vector* vertex_scalars) { return read_VTK - (alcc, filename, vertex_scalars, nullptr); } + (filename, alcc, vertex_scalars, nullptr); } template -bool read_VTK(LCC& alcc, - const char* filename, - std::nullptr_t, - std::vector* volume_scalars) +bool read_VTK(const char* filename, LCC& alcc, + std::nullptr_t, + std::vector* volume_scalars) { return read_VTK - (alcc, filename, nullptr, volume_scalars); } + (filename, alcc, nullptr, volume_scalars); } //////////////////////////////////////////////////////////////////////////////////// template inline bool write_VTK_with_fct(const char* filename, const LCC& alcc, @@ -691,14 +686,14 @@ bool write_VTK(const char* filename, const LCC& alcc, template bool write_VTK(const char* filename, const LCC& alcc) { - return write_VTK(alcc, filename, nullptr, nullptr); + return write_VTK(filename, alcc, nullptr, nullptr); } template bool write_VTK(const char* filename, const LCC& alcc, const std::vector* vertex_scalars) { - return write_VTK(alcc, filename, vertex_scalars, + return write_VTK(filename, alcc, vertex_scalars, nullptr); } @@ -707,7 +702,7 @@ bool write_VTK(const char* filename, const LCC& alcc, std::nullptr_t, const std::vector* volume_scalars) { - return write_VTK(alcc, filename, nullptr, + return write_VTK(filename, alcc, nullptr, volume_scalars); } //////////////////////////////////////////////////////////////////////////////////// From e1ec2fd1d242bf4fc566cb8ea565899fa585275e Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Fri, 10 Oct 2025 09:55:12 +0200 Subject: [PATCH 20/30] Document cmap read/write; and lcc read/write vtk --- .../doc/Combinatorial_map/Concepts/GenericMap.h | 14 ++++++++++++-- .../Combinatorial_map/PackageDescription.txt | 7 +++++++ .../Linear_cell_complex/Linear_cell_complex.txt | 7 ++++++- .../Linear_cell_complex/PackageDescription.txt | 6 ++++-- .../Linear_cell_complex/fig/lcc-export-vtk.png | Bin 0 -> 91005 bytes 5 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 Linear_cell_complex/doc/Linear_cell_complex/fig/lcc-export-vtk.png diff --git a/Combinatorial_map/doc/Combinatorial_map/Concepts/GenericMap.h b/Combinatorial_map/doc/Combinatorial_map/Concepts/GenericMap.h index b7f985acac0..fbe5315f6d3 100644 --- a/Combinatorial_map/doc/Combinatorial_map/Concepts/GenericMap.h +++ b/Combinatorial_map/doc/Combinatorial_map/Concepts/GenericMap.h @@ -1068,8 +1068,18 @@ If \link GenericMap::are_attributes_automatically_managed `are_attributes_automa template size_type remove_cell(Dart_descriptor d); +/*! +\ingroup PkgCombinatorialMapsRefIO + Writes `amap` in `os`, using our own internal file format in XML. Writes both the topology of the combinatorial map and its enabled attributes. + */ +friend std::ostream& operator<< (std::ostream& os, const GenericMap& amap); + +/*! + \ingroup PkgCombinatorialMapsRefIO + Reads `amap` from `is`, using our own internal file format in XML. Reads both the topology of the combinatorial map and its enabled attributes which are present in `is`. Note that if `amap` is not empty before the reading, the new map is added in the previous one. + */ +friend std::ifstream& operator>> (std::ifstream& is, GenericMap& amap); + /// @} }; /* end GenericMap */ - - diff --git a/Combinatorial_map/doc/Combinatorial_map/PackageDescription.txt b/Combinatorial_map/doc/Combinatorial_map/PackageDescription.txt index 5016a763697..45081261ce8 100644 --- a/Combinatorial_map/doc/Combinatorial_map/PackageDescription.txt +++ b/Combinatorial_map/doc/Combinatorial_map/PackageDescription.txt @@ -6,6 +6,9 @@ /// \defgroup PkgCombinatorialMapsClasses Classes /// \ingroup PkgCombinatorialMapsRef +/// \defgroup PkgCombinatorialMapsRefIO IO Functions for CMap +/// \ingroup PkgCombinatorialMapsRef + /*! \addtogroup PkgCombinatorialMapsRef \cgalPkgDescriptionBegin{Combinatorial Maps,PkgCombinatorialMaps} @@ -36,5 +39,9 @@ - `CGAL::Cell_attribute_with_id` - `CGAL::Generic_map_min_items` +\cgalCRPSubsection{IO Functions for CMap} +- \link PkgCombinatorialMapsRefIO `std::ostream& operator<< (std::ostream& os, const GenericMap& amap)` \endlink +- \link PkgCombinatorialMapsRefIO `std::ifstream& operator>> (std::ifstream& is, GenericMap& amap)` \endlink + */ diff --git a/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt b/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt index 6dc799dae2b..d0dc1a2b351 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt @@ -291,10 +291,15 @@ Result of the run of the linear_cell_complex_3_insert program. A window shows th \subsection Linear_cell_complexWriteVTK Write a Linear Cell Complex in a VTK File \anchor ssecLCCWriteVtK -This example loads a 3D linear cell complex from a `.3map` file using \cgal function `CGAL::load_combinatorial_map()`. It computes for each 3-cell (volume) the number of incident vertices (0-cells), stores these values in a `std::vector`, and writes the result to a `.vtk` file with `CGAL::IO::write_VTK()`, using the computed values as scalars for each volume. +This example loads a 3D linear cell complex from a `.3map` file (using the `operator>>`). It computes for each 3-cell (volume) the number of incident vertices (0-cells), stores these values in a `std::vector`, and writes the result to a `.vtk` file with `CGAL::IO::write_VTK()`, using the computed values as scalars for each volume. \cgalExample{Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp} +\cgalFigureBegin{fig_lcc_export_vtk,lcc-export-vtk.png} +Visualization of the VTK file generated by the linear_cell_complex_3_vtk_io program, using Paraview. Each volume is colored depending on its number of vertices. +\cgalFigureEnd + + \section Linear_cell_complexDesign Design and Implementation History This package was developed by Guillaume Damiand, with the help of Andreas Fabri, Sébastien Loriot and Laurent Rineau. Monique Teillaud and Bernd Gärtner contributed to the manual. diff --git a/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt b/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt index 8c078b6159c..03983e5a810 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/PackageDescription.txt @@ -83,7 +83,9 @@ - \link PkgDrawLinearCellComplex CGAL::add_in_graphics_scene() \endlink \cgalCRPSubsection{IO Functions for LCC} -- `CGAL::IO::Read_VTK()` -- `CGAL::IO::Write_VTK()` +- \link PkgCombinatorialMapsRefIO `std::ostream& operator<< (std::ostream& os, const GenericMap& amap)` \endlink +- \link PkgCombinatorialMapsRefIO `std::ifstream& operator>> (std::ifstream& is, GenericMap& amap)` \endlink +- \link PkgLinearCellComplexRefIOVTK `CGAL::IO::Read_VTK()` \endlink +- \link PkgLinearCellComplexRefIOVTK `CGAL::IO::Write_VTK()` \endlink */ diff --git a/Linear_cell_complex/doc/Linear_cell_complex/fig/lcc-export-vtk.png b/Linear_cell_complex/doc/Linear_cell_complex/fig/lcc-export-vtk.png new file mode 100644 index 0000000000000000000000000000000000000000..02f534c839559cd46d6f00f5470b5c6e23422be2 GIT binary patch literal 91005 zcmce-V`HSz5;dBM?POw4Y$p@j&cwED+qP}nwrwX9O>8H(bIy6+dw;>rmrg(ZG$|}Ix5;2JG$uE8v&VE+gKUVI2hO)8Cg4++BjZ;^zZ;~BLBWg(B4ST(agr0K*`L? z2*}yUnwEfpp1{Vyk(Pjwo{@!so`aK#fs=(5!{8|e2#5ekT!>%EHS>JSEpgMt>-g>I zPQ&7&Tzg4feQVuCt@#%*-L1cs6mo4}b{mQyfkCF9Uq%AZ9&$g13^J)EyI{YwEUBPx zEjzdrBszH@;>Io*4qd&Gh1ms7nZ{PtcFMZ1@=vLDTIp ziR<;GU}1a4&e9D(S*E6PQvau%SFZ_=YLBotGwIt zYq+THxZFQ2$vLXf`Jk-$Q?(x_inj;2maj^Ed+E~ihPLtj(Vb6SSBGahUz{qMc3`|O zW3tZ|JD*nBKA&#rH0sPWADs`&8mIsM?K|YW;ZXgl)ZJ*d^88DTulM!&;kgH+lgf3a znDdH?|F$~vd~U)k>EiO#crW~4d#A~mRXx014zAT(tk5o3X^d=ld6-#PWN>{}*?2|t zJV*5878D$yZG80MzyC;+3a0Zql}s41?tU@0ZaYNhd8~`cdhq`Ir_!^3VdL{V1OdOe zy4w2oIh)%1DBmXXx|e?PdF^+hzIfzkVH*a*>A<_IO+~QS0`6 z5zhnP{Z~r?OnO$Czfg z?&=Q!RwB-sNsuYgsoT2x`nr4ZO-PV`R`zC_x?YyD$!pbIt%jD^Dt5UlQ zYk|4#Y1_l?D9z;ix4aziej0Q?Hq~@hd*l6fJ~zrcY7Gts2Zw;rS$X)cn_UY!N{?1k zi^I&)$#Ai;u=Wq|zu3QjxXvFxj?1GAo1@1Kn`3~()43kkX1tS)CX%JSzq+5gVmhw6 zGiJOl9TG;8X*7lbi)`Hwr&6uc2g_i!;;iyEuhLnbIiQ}{C&I!7U=gswK@K~4u#6Ne zJiMc14ePylN!q=HocF&JGjF>PyrX>q5NqvDR1?WG2jAfag8vMpZovZxrTMkBZ+i@Q zJ#CGgoScYTnM|b*;ks=0bvgwt`-)utx+Gtj5cRao4Qu{A> zw|i+rbsfqj#>+BggbR9lax!eX)0UV2T=sl@D*h2$-`IG0>-qAC#^WBZRBHfg{d_%p z8D{J5i(=az#sA#HpWoh=K?J2%t=&zGahafLsWq9w1H_@r{LOK;hqb-De{(Y{CnqO8 zYyds1&JCv?hCas6B}o4NetGd$BWQ+CT}s!ZIN7RxmgdlNmhMaf=W!TWHbIg^oo*j60Iq}aza*c>Rl0BMEt*B+IE>G}@@ zdOpv3j6FRw=jP_dHtcrZkJ#2)?TCSBXlOilLGX8%HEa&^Lh$xa<_avgJJSGJ#Ophm zW#jZa1I%*!GUJnt;B_L%^{}Xj!(kuzcGZ)kVciz=`?58lrTd|(WNXHvx-Gb+>%wZ& zb^wm+c{jk(*}2|m0{t8N-d9iFG0V%#Ox|$+i*@4k0c(Ywf1S`=P?~WkTm@0RNL77Z;aWyEB#d>yG#Mvg0b7%Veos*>a~l z>pPV`bslry-{04|KbUtv57F6=;JS3``v5Y?QE@BjXrdQ)7YZy-J-^542=cR4D@ z{NJx0jC7fU6Nd5kodK-g^Z56Uo~>=Ha>bvUFj-H3m(By+gyTUwDb|c4CCaSDM;M)F zV4qtuAN%SK>OnIKbZ&`X_&W$UoxT#kauseUQamM$a`fx^PfWvbe{-ImVH%VAVB$t50^)v=hTYI1Adkr0D)g7*{ zrzJ0d@-benT;cjRPP7$pjT}9q^KI)2e0R4mAW&}?X-lowh#D3M^8+H2tq^qF=n1_D1QXYe-!!Y`R0*!W96bIJQa`^%UzT9 z)MUd1=ZXCyOlW3+#TN8qydRt?Ut$03Qb@0>3ndRPb0v&MncvVTuHhvJrzQvr8-iX6 zD|%fmeLY!pd)&SCO&1jYMQ)Z7Zx2;Fi^aU#PTJH&aoZ$rekXq01O-?k^OAa{=Bik8 zbFd++AZZR^ifr5r*_f;++IRhNrCCs_~iYKAI=1H#>e zakcZhABI||JF~dB_-nf+tXhH^uEXYbjvw7NZO#xdtS@TbwJww1nX9x18ykJp8mN1UZti6J(>uXe=xgSQZV`TJ#lI z;pX#XL3syH-$=X}w*CKBL2{Y-fPLXB0>~hLKHy>eN_r>8bZ244VFvDQP%!`&VdI27 zNIKqF%aCP8t^)Q?xgPcYg1Z!$;msIj4mvd57hwSzE_4$=ScWQ9u#-O#IGClrfCMq= z+8#6>INJPuoFOj-G|7!pe7HSDIVhG4v=Ejw&vASPtWfNXNm-d)S=E%?nvrDN`|Y1U zRp}q@+A`mm)bveU9^nPgX^VEuOs>QErxm=d{cUxO3s0v=V zRI5t0m@DYQQp0r^OSA>8B;>P#a9x~!qPVgB%u))@k$N3M41w~a^F~pfW*?fYS{>m< z6UX(2;>1o)r+06l-(Is@FE)#gdRZrv23cU1O=kk3XJ#H8;r+DZd7X=q2~NJ)Xh|3| zZ2kItQ)@7W15`>9{MXr#lk@YxHlIf})1oUw!uvX(hhW~*EL9gUglZ?|~SjIAro$iT! z!~vpRzz6{#oZ>&hiPsHBE%Ojp^wZ%j(j_d_T|?7_;3_f%!6lJ8qRphxW?AM(?hu@> zYk1wV?M)9}7}6>S`h%J(wH79oRcKOrzZ11)Z*h^n!*x%$mBhtQZ;J`F(~;|IdKX!QRY8Y7WoG@I$8=8&r5%IOaY#zlfd{U z9=v*!J_Ng3OW^K(ZPKQyq^jz(l3V8+TAAx$b*_9PTVxP<%{4aJ^9L?2E)EOQY<12T z>X%(l+SF%5B`--eo+j z>8mLTK?oyq<6n^Nwi8GzC-Lf3d;?6{>svXH5`5F>iC_BmQ?>PLpi;dBf8RiFAhkw7 zWIIEu$?82Xf6CJTEyAq9aOI!ON5cDW$=DK=xVi&FOrn9Z;K6Xr zT^$c&+x%@mt3H^}`MjMFkfu!m+5K*90j(FE&inpPH9!~C^D<@gJSxi555fD)f7y1N zP4S>LX^FtQInCDn0)yvq57adxaiWS6ywn0HuS)B{aPpcT+CRwUFv!88Eq2`)x__bw zr@Pu483yU$4A`05ZZVfN1~AC4DWUw7_tpCY5@+UbhN+6Kn(SwVsmhA-Hf)MBLXgC0 zs>TUZwRfs>@we?*l01n77s3_eS=AI3I*LD#KTzD4Kahw>0I47>bS@AhkmQ;)Kn^_z z%hMcE3^86F$*XV-QBhDVI<*m6Ojb##m>5==-1!U@WPMj{OKNRYanUI?cpzNu7c0%V zk-S%UQUg)+&v2cJpEWL!>u20wOE?HzzunP5gnfvv7j10`rc6_dkkg*Mg^Gvu<^)n$ zDt_7?DkHlBU=zB)K+{)zhVZqJxIXjt^?4e({;{O(V-Oy3iK8A+I7ymHE7u2T>P4IBwFsdYb5 zTB8^V4KhW9(zpO7xc0C9ia;ewByEmDO=t}Kr_mLx^KCod0bH=*V3uqX{n-BbS`pk{ z0^KYu(i(|Wp-77eBphgR1yCh=@-q_Q`N(+VNK~+_LOy@SCB4)o0@MOh|5))relbuX zJ}D_KyU8KqFgDCU`)5Na+py8{Sf2SpGJiR4Bo;~nr|>*IGR|&9z7`q#zkxwOw`Hk2 zYIc#zQ$MIOXfjbmfU>QDICA=ql%gTBi3b=Uz==hu2uFtRaB!vP6vY(pQRPt;RZ?`v z;z2EzsgH)SR{%(rOl2Zti{eHB5Iy5)KxeRp|4FB4&U-A$%Pz@{w7?7x%EKs2GfJuqi zjw%*cq9n>d3J7NzW`h1I?;(*hMZGZ;9wiwh;30$*PT2WX8aqf^n9aM;=HQ?HFBH7zWcR<4kXNkO$9lXlMYXaD6A zRjU9qf3=SpWzs@?UzvLR(6_xEbVaKrHp5zdpxx=t$cYt@8EjM+P%L>Eo0Nx+Ja0Tq z%E$yVE3u5d$BrPJQG{9H95j!pZAX{bc2g!u6reVhfH#`UL7J4L%H#?as1K5;lqB%v zQIT8;{jN|(&|W)6D1J&iW)3$}D~y3QMUhT5Xqn%ty?VsxriNQa30QF38QfN!k%ke6 zvY5hkmxKvOqgqfN0*An(LcN1ZkcBzj@B z?=lJba~Vmj=SihA%tyu+i^coP$PqBO;RawN_yVDXl3636gGm|fpMo2&B&u#N${KJ^ z6UeG;P`LR_G7NUl>;+%gt3DF0-H6KGVPJ}Lz&d;{hoa&v+l zy2T(6b7cf}7uWPQ2eynHJWF?s>u(%FhVpoY^G+E_4!)?!i%FxVGyOX7YOkWNS< z+}s;6Ri26rucN;L>SxT_kP&Cn>gHDVVTz8r!R+*q7b6l}tt-U_g$eJD(0^VmWvug^&K3o7u+9(0K$Qb}FCkH^1U^%vmA&hA1S~t`x15g{E^qF`+LfE#f8ANEXno`w7w(BV*j&M+)9%IpN4He^SFpHE_}mH(Di9B7vb%8sYaK z1D%Ft2v+mUub2ifLV70j-i7u5yJqS^R-lDL5+#il*_+P~R_&w3L9S$TFTpXMUdH~A zaydPn6MqeJ`?KPpIwMeqik3B?1fH_^7|#mR*;Xc2g(4TOd({f_e4l86aqVzUx5$9U zo=Qn%=Jw1GXeSgYyMB|Zbw-HlZ(tf1&2y(v6P_%jrt6_)x$YDTiW88} zXyE~b^7Zq)3s9l&zr2sBAA~yNlm;e=-~WH~ zmsdv{8-^8t&VneZa4VL(A3uK_?3`gZCW2-GTP;)$t4(XGFOpl0kC3J>uUNLXAV1JQ zH&y4U{KlDYkP`{_pElU7tu*$HdcdtLhZ_B@Tdwj|Qi`Y!`vM*UjqVqHLUVjdy)vgf zE+0-!P2A7m<*$k|Oo)|(wPGM2Agf5KFCHL5F%+)G>O^tZ37!oCQd?0oD44L6MjhvD zW+i=FOr?cRlRh(F^rHC3WP0!PV09E1v<#%MHD%@6m(Fi=Ja7OHv0AN9tR3+ zHrn{_=+hTTPu5-d;{7}WMBnF9%d`mFAa?K3)JAzyTFyC9()jG`-})o_6t}xGiWGvR za@q{b4Pz%KrXo3Tlso|xa6&!QJr&?^FzGrBMGS;f&iRqPF5zKOH2TP8G~MM1JRORl zV1!yR)1aht=hy^56aaf$AGQH(`6cx2fo&i1M1zb681pEN6^+K(c z**xqUrD$lDB}ygp%nGc>co!Vn3L4!mkyH-cgFI=Sp2NS7fojAjf zVDRPYG#`tT_RlZ&R)f05*<`tzsevu zMHlHZuLG0MJwU8!MzY#$4?lH(L1y5u3Zt$u&p4^J_ZvQTigenGb<+wLG0I?o2lDeF zKBL0moi<9k>4&P8{oPXr_9q~PCGICUy5`TIm +tgaS7ML-q}?~Q@t0;x*i17pKH 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 Date: Fri, 10 Oct 2025 10:22:11 +0200 Subject: [PATCH 21/30] doc for read/write_vtk lcc in stream support --- .../File_formats/Supported_file_formats.txt | 8 ++++---- Stream_support/doc/Stream_support/dependencies | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt b/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt index b11507d338c..e7c81b16d76 100644 --- a/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt +++ b/Stream_support/doc/Stream_support/File_formats/Supported_file_formats.txt @@ -519,14 +519,14 @@ with both vertices and volumes. Input 3D Volumetric Mesh - `Linear_cell_complex_for_combinatorial_map<3,3>` - CGAL::IO::read_VTK() + `CGAL::Linear_cell_complex_for_combinatorial_map<3,3>` + \link PkgLinearCellComplexRefIOVTK `CGAL::IO::read_VTK()` \endlink Output 3D Volumetric Mesh - `Linear_cell_complex_for_combinatorial_map<3,3>` - CGAL::IO::write_VTK() + `CGAL::Linear_cell_complex_for_combinatorial_map<3,3>` + \link PkgLinearCellComplexRefIOVTK `CGAL::IO::Write_VTK()` \endlink diff --git a/Stream_support/doc/Stream_support/dependencies b/Stream_support/doc/Stream_support/dependencies index 55201690c3c..6c6839848e6 100644 --- a/Stream_support/doc/Stream_support/dependencies +++ b/Stream_support/doc/Stream_support/dependencies @@ -3,6 +3,7 @@ Arrangement_on_surface_2 BGL Constrained_triangulation_3 Kernel_23 +Linear_cell_complex Manual Mesh_2 Mesh_3 From f6425d7773b417be91f56c951a5a591dd49dce9f Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Sat, 11 Oct 2025 14:57:17 +0200 Subject: [PATCH 22/30] write error message only once --- .../include/CGAL/Linear_cell_complex/IO/VTK.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h index a5700661597..ab829bf5b8d 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex/IO/VTK.h @@ -22,6 +22,7 @@ #include #include #include +#include namespace CGAL { namespace IO { @@ -361,6 +362,7 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, // Create cells based on types std::size_t cell_type; + std::set error_types; for(std::size_t i = 0; i>cell_type)) @@ -408,7 +410,11 @@ bool read_lcc_from_vtk_ascii(std::istream& is, LCC& alcc, make_generic_cell_with_builder(ib, v); break; default: - std::cerr<<"[ERROR] read_VTK: type "< Date: Wed, 5 Nov 2025 20:29:40 +0100 Subject: [PATCH 23/30] formatting --- .../Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp index 8bd7b39e38d..87f1fe88bfe 100644 --- a/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp +++ b/Linear_cell_complex/examples/Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp @@ -25,7 +25,10 @@ int main() if(!CGAL::IO::write_VTK("beam-with-mixed-cells.vtk", lcc, nullptr, &volume_scalars)) - { std::cout<<"Error for write_VTK."< Date: Wed, 5 Nov 2025 20:37:36 +0100 Subject: [PATCH 24/30] update comments --- .../include/CGAL/Combinatorial_map.h | 86 +++++++++---------- .../include/CGAL/Linear_cell_complex_base.h | 30 +++---- 2 files changed, 58 insertions(+), 58 deletions(-) diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map.h b/Combinatorial_map/include/CGAL/Combinatorial_map.h index 1502b7bff7b..a35053846aa 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map.h @@ -255,7 +255,7 @@ namespace CGAL { } } - // Create an mapping between darts of the two maps (originals->copies). + // Creates a mapping between darts of the two maps (originals->copies). // (here we cannot use CGAL::Unique_hash_map because it does not provide // iterators... std::unordered_map local_dartmap; @@ -585,7 +585,7 @@ namespace CGAL { bool copy_perforated_darts=false, size_type mark_perforated=INVALID_MARK) { - // Create an mapping between darts of the two maps (originals->copies). + // Creates a mapping between darts of the two maps (originals->copies). // (here we cannot use CGAL::Unique_hash_map because it does not provide // iterators... std::unordered_map @@ -661,7 +661,7 @@ namespace CGAL { return is; } - /** Create a new dart and add it to the map. + /** Creates a new dart and add it to the map. * The marks of the darts are initialized with mmask_marks, i.e. the dart * is unmarked for all the marks. * @return a Dart_descriptor on the new dart. @@ -968,7 +968,7 @@ namespace CGAL { size_type number_of_used_marks() const { return mnb_used_marks; } - /** Test if a given mark is reserved. + /** Tests if a given mark is reserved. * @return true iff the mark is reserved (i.e. in used). */ bool is_reserved(size_type amark) const @@ -997,14 +997,14 @@ namespace CGAL { return number_of_darts() - number_of_marked_darts(amark); } - /** Test if all the darts are unmarked for a given mark. + /** Tests if all the darts are unmarked for a given mark. * @param amark the mark index. * @return true iff all the darts are unmarked for amark. */ bool is_whole_map_unmarked(size_type amark) const { return number_of_marked_darts(amark) == 0; } - /** Test if all the darts are marked for a given mark. + /** Tests if all the darts are marked for a given mark. * @param amark the mark index. * @return true iff all the darts are marked for amark. */ @@ -1071,7 +1071,7 @@ namespace CGAL { mmask_marks.flip(amark); } - /** Test if a given dart is marked for a given mark. + /** Tests if a given dart is marked for a given mark. * @param adart the dart to test. * @param amark the given mark. * @return true iff adart is marked for the mark amark. @@ -1239,7 +1239,7 @@ namespace CGAL { std::size_t orient(size_type amark) const { negate_mark(amark); return number_of_darts(); } - /** Test if this map is without boundary for a given dimension. + /** Tests if this map is without boundary for a given dimension. * @param i the dimension. * @return true iff all the darts are not i-free. * @pre 1<=i<=n @@ -1253,7 +1253,7 @@ namespace CGAL { return true; } - /** Test if this map is without boundary for all the dimensions. + /** Tests if this map is without boundary for all the dimensions. * @return true iff all the darts are non free. */ bool is_without_boundary() const @@ -1334,7 +1334,7 @@ namespace CGAL { return res; } - /** Test if the map is valid. + /** Tests if the map is valid. * @return true iff the map is valid. */ bool is_valid(bool show_errors=true) const @@ -1579,7 +1579,7 @@ namespace CGAL { return os; } - /// Create a new attribute. + /// Creates a new attribute. /// @return a descriptor on the new attribute. template typename Attribute_descriptor::type create_attribute(const Args&... args) @@ -1988,7 +1988,7 @@ namespace CGAL { else unlink_beta_for_involution(adart, i); } - /** Test if it is possible to sew by betai the two given darts + /** Tests if it is possible to sew by betai the two given darts * @param adart1 the first dart. * @param adart2 the second dart. * @return true iff \em adart1 can be i-sewn with \em adart2. @@ -3439,7 +3439,7 @@ namespace CGAL { } - /** Test if the connected component of cmap containing dart dh1 is + /** Tests if the connected component of cmap containing dart dh1 is * isomorphic to the connected component of map2 containing dart dh2, * starting from dh1 and dh2. * @param dh1 initial dart for this map @@ -3648,7 +3648,7 @@ namespace CGAL { return match; } - /** Test if this cmap is isomorphic to map2. + /** Tests if this cmap is isomorphic to map2. * @pre cmap is connected. * @param map2 the second combinatorial map * @param testDartInfo Boolean to test the equality of dart info (true) @@ -3687,7 +3687,7 @@ namespace CGAL { return false; } - /** Test if the attributes of this map are automatically updated. + /** Tests if the attributes of this map are automatically updated. * @return true iff the boolean automatic_attributes_management is set to true. */ bool are_attributes_automatically_managed() const @@ -3710,13 +3710,13 @@ namespace CGAL { void set_automatic_attributes_management_without_correction(bool newval) { this->automatic_attributes_management = newval; } - /** Create an half-edge. + /** Creates an half-edge. * @return a dart of the new half-edge. */ Dart_descriptor make_half_edge() { return create_dart(); } - /** Create an edge. + /** Creates an edge. * if closed==true, the edge has no 2-free dart. * (note that for CMap there is no difference between true and false, but * this is not the case for GMap) @@ -3730,7 +3730,7 @@ namespace CGAL { return d1; } - /** Create an edge given 2 Attribute_descriptor<0>. + /** Creates an edge given 2 Attribute_descriptor<0>. * Note that this function can be used only if 0-attributes are non void * @param h0 the first vertex descriptor. * @param h1 the second vertex descriptor. @@ -3751,7 +3751,7 @@ namespace CGAL { return d1; } - /** Create a combinatorial polygon of length alg + /** Creates a combinatorial polygon of length alg * (a cycle of alg darts beta1 links together). * @return a new dart. */ @@ -3772,7 +3772,7 @@ namespace CGAL { return start; } - /** Test if a face is a combinatorial polygon of length alg + /** Tests if a face is a combinatorial polygon of length alg * (a cycle of alg darts beta1 links together). * @param adart an initial dart * @return true iff the face containing adart is a polygon of length alg. @@ -3794,7 +3794,7 @@ namespace CGAL { return (nb==alg); } - /** Create a triangle given 3 Attribute_descriptor<0>. + /** Creates a triangle given 3 Attribute_descriptor<0>. * @param h0 the first descriptor. * @param h1 the second descriptor. * @param h2 the third descriptor. @@ -3814,7 +3814,7 @@ namespace CGAL { return d1; } - /** Create a quadrangle given 4 Vertex_attribute_descriptor. + /** Creates a quadrangle given 4 Vertex_attribute_descriptor. * @param h0 the first vertex descriptor. * @param h1 the second vertex descriptor. * @param h2 the third vertex descriptor. @@ -3837,7 +3837,7 @@ namespace CGAL { return d1; } - /** Create a combinatorial tetrahedron from 4 triangles. + /** Creates a combinatorial tetrahedron from 4 triangles. * @param d1 a dart onto a first triangle. * @param d2 a dart onto a second triangle. * @param d3 a dart onto a third triangle. @@ -3859,7 +3859,7 @@ namespace CGAL { return d1; } - /** Test if a volume is a combinatorial tetrahedron. + /** Tests if a volume is a combinatorial tetrahedron. * @param d1 an initial dart * @return true iff the volume containing adart is a combinatorial tetrahedron. */ @@ -3892,7 +3892,7 @@ namespace CGAL { return true; } - /** Create a new combinatorial tetrahedron. + /** Creates a new combinatorial tetrahedron. * @return a new dart. */ Dart_descriptor make_combinatorial_tetrahedron() @@ -3905,7 +3905,7 @@ namespace CGAL { return make_combinatorial_tetrahedron(d1, d2, d3, d4); } - /** Create a combinatorial hexahedron from 6 quadrilaterals. + /** Creates a combinatorial hexahedron from 6 quadrilaterals. * @param d1 a dart onto a first quadrilateral. * @param d2 a dart onto a second quadrilateral. * @param d3 a dart onto a third quadrilateral. @@ -3952,7 +3952,7 @@ namespace CGAL { return d1; } - /** Test if a volume is a combinatorial hexahedron. + /** Tests if a volume is a combinatorial hexahedron. * @param d1 an initial dart * @return true iff the volume containing adart is a combinatorial hexahedron. */ @@ -4004,7 +4004,7 @@ namespace CGAL { return true; } - /** Create a new combinatorial hexahedron. + /** Creates a new combinatorial hexahedron. * @return a new dart. */ Dart_descriptor make_combinatorial_hexahedron() @@ -4019,9 +4019,9 @@ namespace CGAL { return make_combinatorial_hexahedron(d1, d2, d3, d4, d5, d6); } - /** Test if a volume is a combinatorial prism. + /** Tests if a volume is a combinatorial prism. * @param d1 an initial dart - * @return true iff the volume containing adart is a combinatorial prism. + * @return true iff the volume containing d1 is a combinatorial prism. */ bool is_volume_combinatorial_prism(Dart_const_descriptor d1) const { @@ -4062,7 +4062,7 @@ namespace CGAL { return true; } - /** Create a combinatorial prism from 2 triangles and 3 squares. + /** Creates a combinatorial prism from 2 triangles and 3 squares. * @param d1 a dart onto a first triangle. * @param d2 a dart onto a first square. * @param d3 a dart onto a second square. @@ -4094,7 +4094,7 @@ namespace CGAL { return d1; } - /** Create a new combinatorial prism. + /** Creates a new combinatorial prism. * @return a new dart. */ Dart_descriptor make_combinatorial_prism() @@ -4108,7 +4108,7 @@ namespace CGAL { return make_combinatorial_prism( d1, d2, d3, d4, d5); } - /** Test if a volume is a combinatorial pyramid. + /** Tests if a volume is a combinatorial pyramid. * @param d1 an intial dart * @return true iff the volume containing adart is a combinatorial pyramid. */ @@ -4150,7 +4150,7 @@ namespace CGAL { return true; } - /** Create a combinatorial pyramid from 1 square and 4 triangles. + /** Creates a combinatorial pyramid from 1 square and 4 triangles. * @param d1 a dart onto the square. * @param d2 a dart onto a first triangle. * @param d3 a dart onto a second triangle. @@ -4181,7 +4181,7 @@ namespace CGAL { return d1; } - /** Create a new combinatorial pyramid. + /** Creates a new combinatorial pyramid. * @return a new dart. */ Dart_descriptor make_combinatorial_pyramid() @@ -4195,7 +4195,7 @@ namespace CGAL { return make_combinatorial_pyramid(d1, d2, d3, d4, d5); } - /** Test if a volume is a combinatorial pentagonal prism. + /** Tests if a volume is a combinatorial pentagonal prism. * @param d1 an initial dart * @return true iff the volume containing adart is a combinatorial pentagonal prism. */ @@ -4260,7 +4260,7 @@ namespace CGAL { } - /** Test if a volume is a combinatorial hexagonal prism. + /** Tests if a volume is a combinatorial hexagonal prism. * @param d1 an initial dart * @return true iff the volume containing adart is a combinatorial hexagonal prism. */ @@ -4335,7 +4335,7 @@ namespace CGAL { return true; } - /** Test if a volume is a combinatorial tetrahedron10. + /** Tests if a volume is a combinatorial tetrahedron10. * @param d1 an initial dart * @return true iff the volume containing adart is a combinatorial tetrahedron10. */ @@ -4374,7 +4374,7 @@ namespace CGAL { return true; } - /** Test if an i-cell can be removed. + /** Tests if an i-cell can be removed. * An i-cell can be removed if i==dimension or i==dimension-1, * or if there are at most two (i+1)-cell incident to it. * @param adart a dart of the i-cell. @@ -4396,7 +4396,7 @@ namespace CGAL { run(*this,adart,update_attributes); } - /** Test if an i-cell can be contracted. + /** Tests if an i-cell can be contracted. * An i-cell can be contracted if i==1 * or if there are at most two (i-1)-cell incident to it. * @param adart a dart of the i-cell. @@ -4762,7 +4762,7 @@ namespace CGAL { return this->template beta<0>(adart1); } - /** Test if an edge can be inserted onto a 2-cell between two given darts. + /** Tests if an edge can be inserted onto a 2-cell between two given darts. * @param adart1 a first dart. * @param adart2 a second dart. * @return true iff an edge can be inserted between adart1 and adart2. @@ -4798,7 +4798,7 @@ namespace CGAL { return generic_insert_cell_1(adart1, adart2, false, update_attributes); } - /** Test if an edge can be inserted between two different 2-cells + /** Tests if an edge can be inserted between two different 2-cells * between two given darts. * @param adart1 a first dart. * @param adart2 a second dart. @@ -4982,7 +4982,7 @@ namespace CGAL { return this->template beta<0>(adart1); } - /** Test if a 2-cell can be inserted onto a given 3-cell along + /** Tests if a 2-cell can be inserted onto a given 3-cell along * a path of edges. * @param afirst iterator on the beginning of the path. * @param alast iterator on the end of the path. diff --git a/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h b/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h index f62d36ff41d..fc4af01a588 100644 --- a/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h +++ b/Linear_cell_complex/include/CGAL/Linear_cell_complex_base.h @@ -213,7 +213,7 @@ namespace CGAL { return *this; } - /** Create a vertex attribute. + /** Creates a vertex attribute. * @return an handle on the new attribute. */ template @@ -221,7 +221,7 @@ namespace CGAL { { return Base::template create_attribute<0>(args...); } /** - * Create a new dart associated with an handle through an attribute. + * Creates a new dart associated with an handle through an attribute. * @param ahandle the point handle to associated with the dart. * @return a Dart_descriptor on the new dart. */ @@ -232,7 +232,7 @@ namespace CGAL { return res; } - /** Create a new dart associated with a point. + /** Creates a new dart associated with a point. * @param apoint the point to associated with the dart. * @return a Dart_descriptor on the new dart. */ @@ -307,7 +307,7 @@ namespace CGAL { return point_of_vertex_attribute(this->template attribute<0>(adart)); } - /** Test if the lcc is valid. + /** Tests if the lcc is valid. * A Linear_cell_complex is valid if it is a valid Combinatorial_map with * an attribute associated to each dart. * @return true iff the map is valid. @@ -550,7 +550,7 @@ namespace CGAL { return res; } - /** Create a segment given 2 points. + /** Creates a segment given 2 points. * @param p0 the first point. * @param p1 the second point. * if closed==true, the edge has no 2-free dart. @@ -564,7 +564,7 @@ namespace CGAL { closed); } - /** Create a triangle given 3 points. + /** Creates a triangle given 3 points. * @param p0 the first point. * @param p1 the second point. * @param p2 the third point. @@ -579,7 +579,7 @@ namespace CGAL { create_vertex_attribute(p2)); } - /** Create a quadrangle given 4 points. + /** Creates a quadrangle given 4 points. * @param p0 the first point. * @param p1 the second point. * @param p2 the third point. @@ -598,7 +598,7 @@ namespace CGAL { } - /** Create a tetrahedron given 4 Vertex_attribute_descriptor. + /** Creates a tetrahedron given 4 Vertex_attribute_descriptor. * @param h0 the first vertex handle. * @param h1 the second vertex handle. * @param h2 the third vertex handle. @@ -619,7 +619,7 @@ namespace CGAL { return this->make_combinatorial_tetrahedron(d1, d2, d3, d4); } - /** Create a tetrahedron given 4 points. + /** Creates a tetrahedron given 4 points. * @param p0 the first point. * @param p1 the second point. * @param p2 the third point. @@ -638,7 +638,7 @@ namespace CGAL { create_vertex_attribute(p3)); } - /** Create an hexahedron given 8 Vertex_attribute_descriptor. + /** Creates an hexahedron given 8 Vertex_attribute_descriptor. * (8 vertices, 12 edges and 6 facets) * \verbatim * 4----7 @@ -678,7 +678,7 @@ namespace CGAL { return this->make_combinatorial_hexahedron(d1, d2, d3, d4, d5, d6); } - /** Create an hexahedron given 8 points. + /** Creates an hexahedron given 8 points. * \verbatim * 4----7 * /| /| @@ -717,7 +717,7 @@ namespace CGAL { create_vertex_attribute(p7)); } - /** Create a prism given 6 Vertex_attribute_descriptor. + /** Creates a prism given 6 Vertex_attribute_descriptor. * (6 vertices, 9 edges and 5 facets) * \verbatim * 3---4 @@ -751,7 +751,7 @@ namespace CGAL { return make_combinatorial_prism(d1, d2, d3, d4, d5); } - /** Create a prism given 6 points. + /** Creates a prism given 6 points. * \verbatim * 3---4 * |\ /| @@ -783,7 +783,7 @@ namespace CGAL { create_vertex_attribute(p5)); } - /** Create a pyramid given 5 Vertex_attribute_descriptor. + /** Creates a pyramid given 5 Vertex_attribute_descriptor. * (5 vertices, 8 edges and 5 facets) * \verbatim * 4 @@ -815,7 +815,7 @@ namespace CGAL { return make_combinatorial_pyramid(d1, d2, d3, d4, d5); } - /** Create a pyramid given 5 points. + /** Creates a pyramid given 5 points. * \verbatim * 4 * /|\ From 459fcf3c3f76bdcc9a90f03186117e4cb68ecae9 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Wed, 5 Nov 2025 20:46:02 +0100 Subject: [PATCH 25/30] adart -> d1 --- Combinatorial_map/include/CGAL/Combinatorial_map.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map.h b/Combinatorial_map/include/CGAL/Combinatorial_map.h index a35053846aa..44d653e2c83 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map.h @@ -3861,7 +3861,7 @@ namespace CGAL { /** Tests if a volume is a combinatorial tetrahedron. * @param d1 an initial dart - * @return true iff the volume containing adart is a combinatorial tetrahedron. + * @return true iff the volume containing d1 is a combinatorial tetrahedron. */ bool is_volume_combinatorial_tetrahedron(Dart_const_descriptor d1) const { @@ -3954,7 +3954,7 @@ namespace CGAL { /** Tests if a volume is a combinatorial hexahedron. * @param d1 an initial dart - * @return true iff the volume containing adart is a combinatorial hexahedron. + * @return true iff the volume containing d1 is a combinatorial hexahedron. */ bool is_volume_combinatorial_hexahedron(Dart_const_descriptor d1) const { @@ -4110,7 +4110,7 @@ namespace CGAL { /** Tests if a volume is a combinatorial pyramid. * @param d1 an intial dart - * @return true iff the volume containing adart is a combinatorial pyramid. + * @return true iff the volume containing d1 is a combinatorial pyramid. */ bool is_volume_combinatorial_pyramid(Dart_const_descriptor d1) const { @@ -4197,7 +4197,7 @@ namespace CGAL { /** Tests if a volume is a combinatorial pentagonal prism. * @param d1 an initial dart - * @return true iff the volume containing adart is a combinatorial pentagonal prism. + * @return true iff the volume containing d1 is a combinatorial pentagonal prism. */ bool is_volume_combinatorial_pentagonal_prism(Dart_const_descriptor d1) const { @@ -4262,7 +4262,7 @@ namespace CGAL { /** Tests if a volume is a combinatorial hexagonal prism. * @param d1 an initial dart - * @return true iff the volume containing adart is a combinatorial hexagonal prism. + * @return true iff the volume containing d1 is a combinatorial hexagonal prism. */ bool is_volume_combinatorial_hexagonal_prism(Dart_const_descriptor d1) const { @@ -4337,7 +4337,7 @@ namespace CGAL { /** Tests if a volume is a combinatorial tetrahedron10. * @param d1 an initial dart - * @return true iff the volume containing adart is a combinatorial tetrahedron10. + * @return true iff the volume containing d1 is a combinatorial tetrahedron10. */ bool is_volume_combinatorial_tetrahedron10(Dart_const_descriptor d1) const { From 828d57a41957daa7ce478d57a6f7e04da2dbc077 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Thu, 6 Nov 2025 09:45:20 +0100 Subject: [PATCH 26/30] Update Combinatorial_map/include/CGAL/Combinatorial_map.h Co-authored-by: Andreas Fabri --- Combinatorial_map/include/CGAL/Combinatorial_map.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Combinatorial_map/include/CGAL/Combinatorial_map.h b/Combinatorial_map/include/CGAL/Combinatorial_map.h index fe661377baa..a14c628f2ac 100644 --- a/Combinatorial_map/include/CGAL/Combinatorial_map.h +++ b/Combinatorial_map/include/CGAL/Combinatorial_map.h @@ -3710,7 +3710,7 @@ namespace CGAL { void set_automatic_attributes_management_without_correction(bool newval) { this->automatic_attributes_management = newval; } - /** Creates a half-edge. + /** Creates a halfedge. * @return a dart of the new half-edge. */ Dart_descriptor make_half_edge() From 546d0b2871cc6a12394e8f18850e56d644b6a48e Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Thu, 6 Nov 2025 18:14:22 +0100 Subject: [PATCH 27/30] verbs --- .../doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h index 6f7b4ae2c67..bf7f5fd4818 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h @@ -22,7 +22,7 @@ namespace IO { */ /** - * \brief Read a VTK legacy ASCII file and load it into a 3D + * \brief Reads a VTK legacy ASCII file and load it into a 3D * Linear_cell_complex. * \ingroup PkgLinearCellComplexRefIOVTK * @@ -44,7 +44,7 @@ bool read_VTK(const char* filename, std::vector* volume_scalars); /** - * \brief Write a 3D Linear_cell_complex to a VTK legacy ASCII file. + * \brief Writes a 3D Linear_cell_complex to a VTK legacy ASCII file. * \ingroup PkgLinearCellComplexRefIOVTK * * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> From 76552ccca132b5d77c7c573580eb26faf7af8c68 Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Thu, 6 Nov 2025 18:16:43 +0100 Subject: [PATCH 28/30] class name --- .../doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h index bf7f5fd4818..48755d80425 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h @@ -26,7 +26,7 @@ namespace IO { * Linear_cell_complex. * \ingroup PkgLinearCellComplexRefIOVTK * - * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> + * \tparam LCC must be a `CGAL::Linear_cell_complex_for_combinatorial_map<3,3>` * \tparam VertexScalarType Type for vertex scalar data (default: float) * \tparam VolumeScalarType Type for volume scalar data (default: float) * \param filename Path to the VTK file @@ -47,7 +47,7 @@ bool read_VTK(const char* filename, * \brief Writes a 3D Linear_cell_complex to a VTK legacy ASCII file. * \ingroup PkgLinearCellComplexRefIOVTK * - * \tparam LCC must be a Linear_cell_complex_for_combinatorial_map<3,3> + * \tparam LCC must be a `CGAL::Linear_cell_complex_for_combinatorial_map<3,3>` * \tparam VertexScalarType Type for vertex scalar data (default: float) * \tparam VolumeScalarType Type for volume scalar data (default: float) * \param filename Path to the output VTK file From eb14bf2a1727dcbc2e221d98ca447dfe6793b756 Mon Sep 17 00:00:00 2001 From: Sebastien Loriot Date: Thu, 20 Nov 2025 13:23:26 +0100 Subject: [PATCH 29/30] backticks and rephrasing Co-authored-by: Mael --- Combinatorial_map/include/CGAL/Element_topo.h | 2 +- .../Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h | 8 ++++---- .../doc/Linear_cell_complex/Linear_cell_complex.txt | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Combinatorial_map/include/CGAL/Element_topo.h b/Combinatorial_map/include/CGAL/Element_topo.h index 4ef5d0c1776..f37a18c6278 100644 --- a/Combinatorial_map/include/CGAL/Element_topo.h +++ b/Combinatorial_map/include/CGAL/Element_topo.h @@ -78,7 +78,7 @@ cell_topo topo_from_name(const std::string& t) } /** - * @brief To get the type of dimD cell of the CMap of cmapdim dimension. + * @brief To get the type of `dimD` cell of the `CMap` of `cmapdim` dimension. */ template diff --git a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h index 48755d80425..07f6dd4327c 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h @@ -6,7 +6,7 @@ namespace IO { * format. * * Only supports: - * - Linear_cell_complex_for_combinatorial_map<3,3> + * - `CGAL::Linear_cell_complex_for_combinatorial_map<3,3>` * - VTK legacy ASCII format (.vtk files) * - Optional scalar fields for vertices and volumes * @@ -23,14 +23,14 @@ namespace IO { /** * \brief Reads a VTK legacy ASCII file and load it into a 3D - * Linear_cell_complex. + * linear cell complex. * \ingroup PkgLinearCellComplexRefIOVTK * * \tparam LCC must be a `CGAL::Linear_cell_complex_for_combinatorial_map<3,3>` * \tparam VertexScalarType Type for vertex scalar data (default: float) * \tparam VolumeScalarType Type for volume scalar data (default: float) * \param filename Path to the VTK file - * \param alcc The Linear_cell_complex to populate (will be cleared first) + * \param alcc The linear cell complex to populate (will be cleared first) * \param vertex_scalars Optional output vector to store per-vertex scalar values. * If provided, will be resized to match number of vertices. * \param volume_scalars Optional output vector to store per-volume scalar values. @@ -51,7 +51,7 @@ bool read_VTK(const char* filename, * \tparam VertexScalarType Type for vertex scalar data (default: float) * \tparam VolumeScalarType Type for volume scalar data (default: float) * \param filename Path to the output VTK file - * \param alcc The Linear_cell_complex to export + * \param alcc The linear cell complex to export * \param vertex_scalars Optional per-vertex scalar data. If provided, must have * same size as number of vertex attributes in the LCC. * \param volume_scalars Optional per-volume scalar data. If provided, must have diff --git a/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt b/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt index 0a04ceb347d..94672f31b71 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt +++ b/Linear_cell_complex/doc/Linear_cell_complex/Linear_cell_complex.txt @@ -289,15 +289,15 @@ The following example shows the use of \link GenericMap::insert_cell_1_between_t Result of the run of the linear_cell_complex_3_insert program. A window shows the 3D cube where one face has a hole. \cgalFigureEnd -\subsection Linear_cell_complexWriteVTK Write a Linear Cell Complex in a VTK File +\subsection Linear_cell_complexWriteVTK Writing a Linear Cell Complex to a VTK File \anchor ssecLCCWriteVtK -This example loads a 3D linear cell complex from a `.3map` file (using the `operator>>`). It computes for each 3-cell (volume) the number of incident vertices (0-cells), stores these values in a `std::vector`, and writes the result to a `.vtk` file with `CGAL::IO::write_VTK()`, using the computed values as scalars for each volume. +This example loads a 3D linear cell complex from a `.3map` file (using the `operator>>`). It computes for each 3-cell (volume) the number of incident vertices (0-cells), stores these values in a `std::vector`, and writes the result to a `.vtk` file using `CGAL::IO::write_VTK()`, with the computed values as scalars for each volume. \cgalExample{Linear_cell_complex/linear_cell_complex_3_vtk_io.cpp} \cgalFigureBegin{fig_lcc_export_vtk,lcc-export-vtk.png} -Visualization of the VTK file generated by the linear_cell_complex_3_vtk_io program, using Paraview. Each volume is colored depending on its number of vertices. +Visualization of the VTK file generated by the `linear_cell_complex_3_vtk_io` program, using Paraview. Each volume is colored depending on its number of vertices. \cgalFigureEnd From fdf06fe9690af570d74b8d6c2f14b98e4487acec Mon Sep 17 00:00:00 2001 From: Guillaume Damiand Date: Fri, 21 Nov 2025 15:01:14 +0100 Subject: [PATCH 30/30] add default parameter --- .../Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h index 07f6dd4327c..8be086ed211 100644 --- a/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h +++ b/Linear_cell_complex/doc/Linear_cell_complex/CGAL/Linear_cell_complex/IO/VTK.h @@ -40,8 +40,8 @@ namespace IO { template bool read_VTK(const char* filename, LCC& alcc, - std::vector* vertex_scalars, - std::vector* volume_scalars); + std::vector* vertex_scalars=nullptr, + std::vector* volume_scalars=nullptr); /** * \brief Writes a 3D Linear_cell_complex to a VTK legacy ASCII file. @@ -61,8 +61,8 @@ bool read_VTK(const char* filename, template bool write_VTK(const char* filename, const LCC& alcc, - const std::vector* vertex_scalars, - const std::vector* volume_scalars); + const std::vector* vertex_scalars=nullptr, + const std::vector* volume_scalars=nullptr); } // namespace IO } // namespace CGAL