From 93a59fcd7745d04c2318cef8cb16ffb9f44132f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mael=20Rouxel-Labb=C3=A9?= Date: Fri, 6 Jan 2023 16:34:49 +0100 Subject: [PATCH] 4 --> 2 spaces indentation and "typedef" --> "using" --- .../Concepts/IsosurfacingDomain.h | 241 +- .../Concepts/IsosurfacingDomainWithGradient.h | 41 +- .../Isosurfacing_3/all_cartesian_cube.cpp | 123 +- .../dual_contouring_cartesian_grid.cpp | 78 +- .../dual_contouring_implicit_iwp.cpp | 81 +- .../dual_contouring_mesh_offset.cpp | 111 +- .../Isosurfacing_3/dual_contouring_octree.cpp | 132 +- .../marching_cubes_cartesian_grid_sphere.cpp | 65 +- .../marching_cubes_implicit_sphere.cpp | 52 +- .../marching_cubes_inrimage.cpp | 57 +- .../marching_cubes_signed_mesh_offset.cpp | 146 +- .../include/CGAL/Cartesian_grid_3.h | 420 ++-- .../include/CGAL/Dual_contouring_3.h | 70 +- .../CGAL/Explicit_cartesian_grid_domain.h | 63 +- .../CGAL/Explicit_cartesian_grid_gradient.h | 148 +- .../include/CGAL/Finite_difference_gradient.h | 90 +- .../CGAL/Implicit_cartesian_grid_domain.h | 78 +- .../include/CGAL/Implicit_octree_domain.h | 63 +- .../Isosurfacing_3/internal/Base_domain.h | 179 +- .../internal/Cartesian_grid_geometry.h | 50 +- .../CGAL/Isosurfacing_3/internal/Cell_type.h | 19 +- .../internal/Dual_contouring_internal.h | 539 ++--- .../Isosurfacing_3/internal/Grid_topology.h | 343 +-- .../Implicit_function_with_geometry.h | 50 +- .../internal/Marching_cubes_3_internal.h | 264 ++- .../Isosurfacing_3/internal/Octree_geometry.h | 38 +- .../Isosurfacing_3/internal/Octree_topology.h | 180 +- .../CGAL/Isosurfacing_3/internal/Tables.h | 1149 +++++----- .../Isosurfacing_3/internal/Tmc_internal.h | 1932 +++++++++-------- .../include/CGAL/Marching_cubes_3.h | 44 +- Isosurfacing_3/include/CGAL/Octree_wrapper.h | 953 ++++---- Isosurfacing_3/include/CGAL/Zero_gradient.h | 40 +- .../Isosurfacing_3/long_description.txt | 6 +- Isosurfacing_3/test/Isosurfacing_3/Timer.h | 4 +- .../Isosurfacing_3/test_dual_contouring.cpp | 110 +- .../Isosurfacing_3/test_marching_cubes.cpp | 120 +- .../test/Isosurfacing_3/test_util.h | 75 +- 37 files changed, 4355 insertions(+), 3799 deletions(-) diff --git a/Isosurfacing_3/doc/Isosurfacing_3/Concepts/IsosurfacingDomain.h b/Isosurfacing_3/doc/Isosurfacing_3/Concepts/IsosurfacingDomain.h index b584fca3ff7..6d337669492 100644 --- a/Isosurfacing_3/doc/Isosurfacing_3/Concepts/IsosurfacingDomain.h +++ b/Isosurfacing_3/doc/Isosurfacing_3/Concepts/IsosurfacingDomain.h @@ -1,5 +1,6 @@ /*! \ingroup PkgIsosurfacing3Concepts + \cgalConcept The concept `IsosurfacingDomain` describes the set of requirements to be @@ -7,171 +8,169 @@ fulfilled by any class used as input data for any isosurfacing algorithms. \cgalHasModel `CGAL::Isosurfacing::Explicit_cartesian_grid_domain` \cgalHasModel `CGAL::Isosurfacing::Implicit_cartesian_grid_domain` - */ - -class IsosurfacingDomain { +class IsosurfacingDomain +{ public: - /// \name Types - /// @{ + /// \name Types + /// @{ - /*! - Traits type model of \cgal %Kernel - */ - typedef unspecified_type Geom_traits; + /*! + Traits type model of \cgal %Kernel + */ + typedef unspecified_type Geom_traits; - /*! - The scalar type. - */ - typedef unspecified_type FT; + /*! + The scalar type. + */ + typedef unspecified_type FT; - /*! - The point type. - */ - typedef unspecified_type Point; + /*! + The point type. + */ + typedef unspecified_type Point; - /*! - A descriptor to uniquely identify a vertex. - */ - typedef unspecified_type Vertex_descriptor; + /*! + A descriptor to uniquely identify a vertex. + */ + typedef unspecified_type Vertex_descriptor; - /*! - A descriptor to uniquely identify an edge. - */ - typedef unspecified_type Edge_descriptor; + /*! + A descriptor to uniquely identify an edge. + */ + typedef unspecified_type Edge_descriptor; - /*! - A descriptor to uniquely identify a cell. - */ - typedef unspecified_type Cell_descriptor; + /*! + A descriptor to uniquely identify a cell. + */ + typedef unspecified_type Cell_descriptor; - /*! - A container for the two vertices of an edge. - Must be a model of the concept `RandomAccessContainer` with size 2 whose value type is `Vertex_descriptor`. - */ - typedef unspecified_type Vertices_incident_to_edge; + /*! + A container for the two vertices of an edge. + Must be a model of the concept `RandomAccessContainer` with size 2 whose value type is `Vertex_descriptor`. + */ + typedef unspecified_type Vertices_incident_to_edge; - /*! - A container for the cells incident to an edge. - Must be a model of the concept `Container` whose value type is `Cell_descriptor`. - */ - typedef unspecified_type Cells_incident_to_edge; + /*! + A container for the cells incident to an edge. + Must be a model of the concept `Container` whose value type is `Cell_descriptor`. + */ + typedef unspecified_type Cells_incident_to_edge; - /*! - A container for the vertices of a cell. - Must be a model of the concept `Container` whose value type is `Vertex_descriptor`. - */ - typedef unspecified_type Cell_vertices; + /*! + A container for the vertices of a cell. + Must be a model of the concept `Container` whose value type is `Vertex_descriptor`. + */ + typedef unspecified_type Cell_vertices; - /*! - A container for the edges of a cell. - Must be a model of the concept `Container` whose value type is `Edge_descriptor`. - */ - typedef unspecified_type Cell_edges; + /*! + A container for the edges of a cell. + Must be a model of the concept `Container` whose value type is `Edge_descriptor`. + */ + typedef unspecified_type Cell_edges; - /// @} + /// @} - /// \name Operations - /// The following member functions must exist. - /// @{ + /// \name Operations + /// The following member functions must exist. + /// @{ - /*! - Get the position of a vertex in 3D space + /*! + Get the position of a vertex in 3D space - \param v the descriptor of the vertex + \param v the descriptor of the vertex - \return the position of the vertex as a point - */ - Point position(const Vertex_descriptor& v) const; + \return the position of the vertex as a point + */ + Point position(const Vertex_descriptor& v) const; - /*! - Get the value of the function at a vertex + /*! + Get the value of the function at a vertex - \param v the descriptor of the vertex + \param v the descriptor of the vertex - \return the value of the function - */ - FT value(const Vertex_descriptor& v) const; + \return the value of the function + */ + FT value(const Vertex_descriptor& v) const; - /*! - Get the two vertices incident to an edge + /*! + Get the two vertices incident to an edge - \param e the descriptor of the edge + \param e the descriptor of the edge - \return a collection of the two vertex descriptors - */ - Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const; + \return a collection of the two vertex descriptors + */ + Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const; - /*! - Get all cells incident to an edge + /*! + Get all cells incident to an edge - \param e the descriptor of the edge + \param e the descriptor of the edge - \return a collection of cell descriptors - */ - Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const; + \return a collection of cell descriptors + */ + Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const; - /*! - Get all vertices of the a cell + /*! + Get all vertices of the a cell - \param c the descriptor of the cell + \param c the descriptor of the cell - \return a collection of vertex descriptors - */ - Cell_vertices cell_vertices(const Cell_descriptor& c) const; + \return a collection of vertex descriptors + */ + Cell_vertices cell_vertices(const Cell_descriptor& c) const; - /*! - Get all edges of the cell c + /*! + Get all edges of the cell c - \param c the descriptor of the cell + \param c the descriptor of the cell - \return a collection of edge descriptors - */ - Cell_edges cell_edges(const Cell_descriptor& c) const; + \return a collection of edge descriptors + */ + Cell_edges cell_edges(const Cell_descriptor& c) const; - /*! - Iterate over all vertices and call a functor on each one + /*! + Iterate over all vertices and call a functor on each one - /tparam Concurrency_tag decides if the vertices are iterated sequentially or in parallel. - Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`. - Only the sequential version has to be implemented. The parallel version is optional. + /tparam Concurrency_tag decides if the vertices are iterated sequentially or in parallel. + Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`. + Only the sequential version has to be implemented. The parallel version is optional. - /tparam Functor must implement `void operator()(const Vertex_descriptor& vertex)` + /tparam Functor must implement `void operator()(const Vertex_descriptor& vertex)` - \param f the functor called with every vertex - */ - template - void iterate_vertices(Functor& f) const; + \param f the functor called with every vertex + */ + template + void iterate_vertices(Functor& f) const; - /*! - Iterate over all edges and call the functor f on each one + /*! + Iterate over all edges and call the functor f on each one - /tparam Concurrency_tag decides if the edges are iterated sequentially or in parallel. - Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`. - Only the sequential version has to be implemented. The parallel version is optional. + /tparam Concurrency_tag decides if the edges are iterated sequentially or in parallel. + Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`. + Only the sequential version has to be implemented. The parallel version is optional. - /tparam Functor must implement `void operator()(const Edge_descriptor& edge)`. + /tparam Functor must implement `void operator()(const Edge_descriptor& edge)`. - \param f the functor called with every edge - */ - template - void iterate_edges(Functor& f) const; + \param f the functor called with every edge + */ + template + void iterate_edges(Functor& f) const; - /*! - Iterate sequentially over all cells and call the functor f on each one + /*! + Iterate sequentially over all cells and call the functor f on each one - /tparam Concurrency_tag decides if the cells are iterated sequentially or in parallel. - Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`. - Only the sequential version has to be implemented. The parallel version is optional. + /tparam Concurrency_tag decides if the cells are iterated sequentially or in parallel. + Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`. + Only the sequential version has to be implemented. The parallel version is optional. - /tparam Functor must implement `void operator()(const Cell_descriptor& cell)`. + /tparam Functor must implement `void operator()(const Cell_descriptor& cell)`. - \param f the functor called with every cell - */ - template - void iterate_cells(Functor& f) const; + \param f the functor called with every cell + */ + template + void iterate_cells(Functor& f) const; - - /// @} + /// @} }; diff --git a/Isosurfacing_3/doc/Isosurfacing_3/Concepts/IsosurfacingDomainWithGradient.h b/Isosurfacing_3/doc/Isosurfacing_3/Concepts/IsosurfacingDomainWithGradient.h index 2d3e105efd5..ac6b98d99b6 100644 --- a/Isosurfacing_3/doc/Isosurfacing_3/Concepts/IsosurfacingDomainWithGradient.h +++ b/Isosurfacing_3/doc/Isosurfacing_3/Concepts/IsosurfacingDomainWithGradient.h @@ -1,5 +1,6 @@ /*! \ingroup PkgIsosurfacing3Concepts + \cgalConcept The concept `IsosurfacingDomainWithGradient` describes the set of requirements to be @@ -7,33 +8,33 @@ fulfilled by any class used as input data for some isosurfacing algorithms. \cgalHasModel `CGAL::Isosurfacing::Explicit_cartesian_grid_domain` \cgalHasModel `CGAL::Isosurfacing::Implicit_cartesian_grid_domain` - */ - -class IsosurfacingDomainWithGradient : public IsosurfacingDomain { +class IsosurfacingDomainWithGradient + : public IsosurfacingDomain +{ public: - /// \name Types - /// @{ + /// \name Types + /// @{ - /*! - The vector type. - */ - typedef unspecified_type Vector; + /*! + The vector type. + */ + typedef unspecified_type Vector; - /// @} + /// @} - /// \name Operations - /// The following member function must exist. - /// @{ + /// \name Operations + /// The following member function must exist. + /// @{ - /*! - Get the gradient at a position + /*! + Get the gradient at a position - \param p the point at which the gradient is evaluated + \param p the point at which the gradient is evaluated - \return the gradient vector - */ - Vector gradient(const Point& p) const; + \return the gradient vector + */ + Vector gradient(const Point& p) const; - /// @} + /// @} }; diff --git a/Isosurfacing_3/examples/Isosurfacing_3/all_cartesian_cube.cpp b/Isosurfacing_3/examples/Isosurfacing_3/all_cartesian_cube.cpp index b3b8487ec38..46c12a9b24e 100644 --- a/Isosurfacing_3/examples/Isosurfacing_3/all_cartesian_cube.cpp +++ b/Isosurfacing_3/examples/Isosurfacing_3/all_cartesian_cube.cpp @@ -1,82 +1,87 @@ +#include + #include #include #include #include -#include + #include -typedef CGAL::Simple_cartesian Kernel; -typedef typename Kernel::FT FT; -typedef typename Kernel::Point_3 Point; -typedef typename Kernel::Vector_3 Vector; +using Kernel = CGAL::Simple_cartesian; +using FT = typename Kernel::FT; +using Point = typename Kernel::Point_3; +using Vector = typename Kernel::Vector_3; -typedef CGAL::Cartesian_grid_3 Grid; +using Grid = CGAL::Cartesian_grid_3; -typedef std::vector Point_range; -typedef std::vector> Polygon_range; +using Point_range = std::vector; +using Polygon_range = std::vector >; // return 1.0 if value has positive sign, and -1.0 otherwise -FT sign(FT value) { - return (value > 0.0) - (value < 0.0); +FT sign(FT value) +{ + return (value > 0.0) - (value < 0.0); } -int main() { - // create a cartesian grid with 7^3 grid points and the bounding box [-1, 1]^3 - const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0); - std::shared_ptr grid = std::make_shared(7, 7, 7, bbox); +int main() +{ + // create a cartesian grid with 7^3 grid points and the bounding box [-1, 1]^3 + const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0); + std::shared_ptr grid = std::make_shared(7, 7, 7, bbox); - // calculate the value at all grid points - for (std::size_t x = 0; x < grid->xdim(); x++) { - for (std::size_t y = 0; y < grid->ydim(); y++) { - for (std::size_t z = 0; z < grid->zdim(); z++) { + // calculate the value at all grid points + for(std::size_t x=0; xxdim(); ++x) { + for(std::size_t y=0; yydim(); ++y) { + for(std::size_t z=0; zzdim(); ++z) + { + const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin(); + const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin(); + const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin(); - const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin(); - const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin(); - const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin(); - - // manhattan distance to the origin - grid->value(x, y, z) = std::max({std::abs(pos_x), std::abs(pos_y), std::abs(pos_z)}); - } - } + // manhattan distance to the origin + grid->value(x, y, z) = std::max({std::abs(pos_x), std::abs(pos_y), std::abs(pos_z)}); + } } + } - // compute function gradient - auto cube_gradient = [](const Point& p) { - // the normal depends on the side of the cube - const FT max_value = std::max({std::abs(p.x()), std::abs(p.y()), std::abs(p.z())}); + // compute function gradient + auto cube_gradient = [](const Point& p) + { + // the normal depends on the side of the cube + const FT max_value = std::max({std::abs(p.x()), std::abs(p.y()), std::abs(p.z())}); - Vector g(0.0, 0.0, 0.0); - if (max_value == std::abs(p.x())) { - g += Vector(sign(p.x()), 0.0, 0.0); - } - if (max_value == std::abs(p.y())) { - g += Vector(0.0, sign(p.y()), 0.0); - } - if (max_value == std::abs(p.z())) { - g += Vector(0.0, 0.0, sign(p.z())); - } - const FT length_sq = g.squared_length(); - if (length_sq > 0.00001) { - g /= CGAL::approximate_sqrt(length_sq); - } - return g; - }; + Vector g(0.0, 0.0, 0.0); + if(max_value == std::abs(p.x())) + g += Vector(sign(p.x()), 0.0, 0.); - // create domain from given grid and gradient - auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid, cube_gradient); + if(max_value == std::abs(p.y())) + g += Vector(0.0, sign(p.y()), 0.0); - // containers for output indexed surface meshes - Point_range points_mc, points_dc; - Polygon_range polygons_mc, polygons_dc; + if(max_value == std::abs(p.z())) + g += Vector(0.0, 0.0, sign(p.z())); - // run topologically correct marching cubes and dual contouring with given isovalue - const FT isovalue = 0.88; - CGAL::Isosurfacing::marching_cubes(domain, isovalue, points_mc, polygons_mc, true); - CGAL::Isosurfacing::dual_contouring(domain, isovalue, points_dc, polygons_dc); + const FT length_sq = g.squared_length(); + if(length_sq > 0.00001) + g /= CGAL::approximate_sqrt(length_sq); - // save output indexed meshes to files, in the OFF format - CGAL::IO::write_OFF("result_mc.off", points_mc, polygons_mc); - CGAL::IO::write_OFF("result_dc.off", points_dc, polygons_dc); + return g; + }; - return 0; + // create domain from given grid and gradient + auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid, cube_gradient); + + // containers for output indexed surface meshes + Point_range points_mc, points_dc; + Polygon_range polygons_mc, polygons_dc; + + // run topologically correct marching cubes and dual contouring with given isovalue + const FT isovalue = 0.88; + CGAL::Isosurfacing::marching_cubes(domain, isovalue, points_mc, polygons_mc, true); + CGAL::Isosurfacing::dual_contouring(domain, isovalue, points_dc, polygons_dc); + + // save output indexed meshes to files, in the OFF format + CGAL::IO::write_OFF("result_mc.off", points_mc, polygons_mc); + CGAL::IO::write_OFF("result_dc.off", points_dc, polygons_dc); + + return 0; } diff --git a/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_cartesian_grid.cpp b/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_cartesian_grid.cpp index 89d69ed6386..3a83249456e 100644 --- a/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_cartesian_grid.cpp +++ b/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_cartesian_grid.cpp @@ -1,58 +1,60 @@ +#include + #include #include #include #include -#include + #include -typedef CGAL::Simple_cartesian Kernel; -typedef typename Kernel::FT FT; -typedef typename Kernel::Point_3 Point; -typedef typename Kernel::Vector_3 Vector; +using Kernel = CGAL::Simple_cartesian; +using FT = typename Kernel::FT; +using Point = typename Kernel::Point_3; +using Vector = typename Kernel::Vector_3; -typedef CGAL::Cartesian_grid_3 Grid; +using Grid = CGAL::Cartesian_grid_3; -typedef std::vector Point_range; -typedef std::vector> Polygon_range; +using Point_range = std::vector; +using Polygon_range = std::vector >; -int main() { +int main() +{ + // create bounding box and grid + const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0); + std::shared_ptr grid = std::make_shared(30, 30, 30, bbox); - // create bounding box and grid - const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0); - std::shared_ptr grid = std::make_shared(30, 30, 30, bbox); + // compute field values and gradients + for(std::size_t x=0; xxdim(); ++x) { + for(std::size_t y=0; yydim(); ++y) { + for(std::size_t z=0; zzdim(); ++z) + { + const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin(); + const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin(); + const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin(); - // compute field values and gradients - for (std::size_t x = 0; x < grid->xdim(); x++) { - for (std::size_t y = 0; y < grid->ydim(); y++) { - for (std::size_t z = 0; z < grid->zdim(); z++) { + const Vector direction(pos_x, pos_y, pos_z); + const FT distance = CGAL::approximate_sqrt(direction.squared_length()); - const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin(); - const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin(); - const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin(); - - const Vector direction(pos_x, pos_y, pos_z); - const FT distance = CGAL::approximate_sqrt(direction.squared_length()); - - grid->value(x, y, z) = distance; - grid->gradient(x, y, z) = direction / distance; // TODO: check division / 0 - } - } + grid->value(x, y, z) = distance; + grid->gradient(x, y, z) = direction / distance; // @todo check division / 0 + } } + } - // gradient field - CGAL::Isosurfacing::Explicit_cartesian_grid_gradient gradient(grid); + // gradient field + CGAL::Isosurfacing::Explicit_cartesian_grid_gradient gradient(grid); - // create domain from scalar and gradient fields - auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid, gradient); + // create domain from scalar and gradient fields + auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid, gradient); - Point_range points; - Polygon_range polygons; + Point_range points; + Polygon_range polygons; - // run dual contouring isosurfacing - CGAL::Isosurfacing::dual_contouring(domain, 0.8, points, polygons); + // run dual contouring isosurfacing + CGAL::Isosurfacing::dual_contouring(domain, 0.8, points, polygons); - // write output indexed surface mesh to file, in OFF format - CGAL::IO::write_OFF("result.off", points, polygons); + // write output indexed surface mesh to file, in OFF format + CGAL::IO::write_OFF("result.off", points, polygons); - return 0; + return 0; } diff --git a/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_implicit_iwp.cpp b/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_implicit_iwp.cpp index 1cb31a3937f..e5c5821064b 100644 --- a/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_implicit_iwp.cpp +++ b/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_implicit_iwp.cpp @@ -1,56 +1,59 @@ +#include + #include #include #include -#include + #include -typedef CGAL::Simple_cartesian Kernel; -typedef typename Kernel::FT FT; -typedef typename Kernel::Vector_3 Vector; -typedef typename Kernel::Point_3 Point; +using Kernel = CGAL::Simple_cartesian; +using FT = typename Kernel::FT; +using Vector = typename Kernel::Vector_3; +using Point = typename Kernel::Point_3; -typedef std::vector Point_range; -typedef std::vector> Polygon_range; +using Point_range = std::vector; +using Polygon_range = std::vector >; +int main() +{ + const FT alpha = 5.01; -int main() { - const FT alpha = 5.01; + auto iwp_value = [alpha](const Point& point) + { + const FT x = alpha * (point.x() + 1) * CGAL_PI; + const FT y = alpha * (point.y() + 1) * CGAL_PI; + const FT z = alpha * (point.z() + 1) * CGAL_PI; + return cos(x) * cos(y) + cos(y) * cos(z) + cos(z) * cos(x) - cos(x) * cos(y) * cos(z); // isovalue = 0 + }; - auto iwp_value = [alpha](const Point& point) { - const FT x = alpha * (point.x() + 1) * CGAL_PI; - const FT y = alpha * (point.y() + 1) * CGAL_PI; - const FT z = alpha * (point.z() + 1) * CGAL_PI; - return cos(x) * cos(y) + cos(y) * cos(z) + cos(z) * cos(x) - cos(x) * cos(y) * cos(z); // isovalue = 0 - }; + auto iwp_gradient = [alpha](const Point& point) + { + const FT x = alpha * (point.x() + 1) * CGAL_PI; + const FT y = alpha * (point.y() + 1) * CGAL_PI; + const FT z = alpha * (point.z() + 1) * CGAL_PI; - auto iwp_gradient = [alpha](const Point& point) { - const FT x = alpha * (point.x() + 1) * CGAL_PI; - const FT y = alpha * (point.y() + 1) * CGAL_PI; - const FT z = alpha * (point.z() + 1) * CGAL_PI; + const FT gx = CGAL_PI * alpha * sin(x) * (cos(y) * (cos(z) - 1.0) - cos(z)); + const FT gy = CGAL_PI * alpha * sin(y) * (cos(x) * (cos(z) - 1.0) - cos(z)); + const FT gz = CGAL_PI * alpha * sin(z) * (cos(x) * (cos(y) - 1.0) - cos(y)); + return Vector(gx, gy, gz); + }; - const FT gx = CGAL_PI * alpha * sin(x) * (cos(y) * (cos(z) - 1.0) - cos(z)); - const FT gy = CGAL_PI * alpha * sin(y) * (cos(x) * (cos(z) - 1.0) - cos(z)); - const FT gz = CGAL_PI * alpha * sin(z) * (cos(x) * (cos(y) - 1.0) - cos(y)); - return Vector(gx, gy, gz); - }; + const CGAL::Bbox_3 bbox{-1.0, -1.0, -1.0, 1.0, 1.0, 1.0}; + const FT spacing = 0.5; + const Vector vec_spacing(spacing, spacing, spacing); - const CGAL::Bbox_3 bbox{-1.0, -1.0, -1.0, 1.0, 1.0, 1.0}; - const FT spacing = 0.5; - const Vector vec_spacing(spacing, spacing, spacing); + // create a domain with given bounding box and grid spacing + auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain(bbox, vec_spacing, iwp_value, iwp_gradient); - // create a domain with given bounding box and grid spacing - auto domain = - CGAL::Isosurfacing::create_implicit_cartesian_grid_domain(bbox, vec_spacing, iwp_value, iwp_gradient); + // prepare collections for the result + Point_range points; + Polygon_range polygons; - // prepare collections for the result - Point_range points; - Polygon_range polygons; + // run marching cubes with an isovalue of 0.0 + CGAL::Isosurfacing::dual_contouring(domain, 0.0, points, polygons); - // run marching cubes with an isovalue of 0.0 - CGAL::Isosurfacing::dual_contouring(domain, 0.0, points, polygons); + // save the result in the OFF format + CGAL::IO::write_OFF("result.off", points, polygons); - // save the result in the OFF format - CGAL::IO::write_OFF("result.off", points, polygons); - - return 0; + return 0; } diff --git a/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_mesh_offset.cpp b/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_mesh_offset.cpp index 4cbe13aa78a..8cd2715479f 100644 --- a/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_mesh_offset.cpp +++ b/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_mesh_offset.cpp @@ -1,76 +1,83 @@ +#include +#include + +#include +#include + #include #include #include #include -#include -#include #include -#include -#include + #include #include -typedef CGAL::Simple_cartesian Kernel; -typedef typename Kernel::FT FT; -typedef typename Kernel::Point_3 Point; -typedef typename Kernel::Vector_3 Vector; +using Kernel = CGAL::Simple_cartesian; +using FT = typename Kernel::FT; +using Point = typename Kernel::Point_3; +using Vector = typename Kernel::Vector_3; -typedef CGAL::Surface_mesh Mesh; +using Mesh = CGAL::Surface_mesh; -typedef CGAL::AABB_face_graph_triangle_primitive Primitive; -typedef CGAL::AABB_traits Traits; -typedef CGAL::AABB_tree Tree; +using Primitive = CGAL::AABB_face_graph_triangle_primitive; +using Traits = CGAL::AABB_traits; +using Tree = CGAL::AABB_tree; -typedef std::vector Point_range; -typedef std::vector > Polygon_range; +using Point_range = std::vector; +using Polygon_range = std::vector >; -int main() { - const std::string input_name = CGAL::data_file_path("meshes/cross.off"); - const Vector grid_spacing(0.1, 0.1, 0.1); - const FT offset_value = 0.2; +int main() +{ + const std::string input_name = CGAL::data_file_path("meshes/cross.off"); + const Vector grid_spacing(0.1, 0.1, 0.1); + const FT offset_value = 0.2; - Mesh mesh_input; - if (!CGAL::IO::read_OFF(input_name, mesh_input)) { - std::cerr << "Could not read input mesh" << std::endl; - exit(-1); - } + Mesh mesh_input; + if(!CGAL::IO::read_OFF(input_name, mesh_input)) + { + std::cerr << "Could not read input mesh" << std::endl; + exit(-1); + } - // compute bounding box - CGAL::Bbox_3 aabb_grid = CGAL::Polygon_mesh_processing::bbox(mesh_input); - Vector aabb_increase_vec = Vector(offset_value + 0.01, offset_value + 0.01, offset_value + 0.01); - aabb_grid += (Point(aabb_grid.xmax(), aabb_grid.ymax(), aabb_grid.zmax()) + aabb_increase_vec).bbox(); - aabb_grid += (Point(aabb_grid.xmin(), aabb_grid.ymin(), aabb_grid.zmin()) - aabb_increase_vec).bbox(); + // compute bounding box + CGAL::Bbox_3 aabb_grid = CGAL::Polygon_mesh_processing::bbox(mesh_input); + Vector aabb_increase_vec = Vector(offset_value + 0.01, offset_value + 0.01, offset_value + 0.01); + aabb_grid += (Point(aabb_grid.xmax(), aabb_grid.ymax(), aabb_grid.zmax()) + aabb_increase_vec).bbox(); + aabb_grid += (Point(aabb_grid.xmin(), aabb_grid.ymin(), aabb_grid.zmin()) - aabb_increase_vec).bbox(); - // construct AABB tree - Tree tree(mesh_input.faces_begin(), mesh_input.faces_end(), mesh_input); + // construct AABB tree + Tree tree(mesh_input.faces_begin(), mesh_input.faces_end(), mesh_input); - CGAL::Side_of_triangle_mesh::type> sotm(mesh_input); + CGAL::Side_of_triangle_mesh::type> sotm(mesh_input); - // functors for addressing distance and normal queries - auto mesh_distance = [&tree](const Point& p) { - const Point& x = tree.closest_point(p); - return std::sqrt((p - x).squared_length()); - }; + // functors for addressing distance and normal queries + auto mesh_distance = [&tree](const Point& p) + { + const Point& x = tree.closest_point(p); + return std::sqrt((p - x).squared_length()); + }; - auto mesh_normal = [&tree](const Point& p) { - const Point& x = tree.closest_point(p); - const Vector n = p - x; // TODO: address case where norm = zero - return n / std::sqrt(n.squared_length()); // normalize output vector - }; + auto mesh_normal = [&tree](const Point& p) + { + const Point& x = tree.closest_point(p); + const Vector n = p - x; // @todo address case where norm = zero + return n / std::sqrt(n.squared_length()); // normalize output vector + }; - // create a domain with given bounding box and grid spacing - auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain(aabb_grid, grid_spacing, - mesh_distance, mesh_normal); - // containers for output indexed surface mesh - Point_range points; - Polygon_range polygons; + // create a domain with given bounding box and grid spacing + auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain(aabb_grid, grid_spacing, + mesh_distance, mesh_normal); + // containers for output indexed surface mesh + Point_range points; + Polygon_range polygons; - // run dual contouring - CGAL::Isosurfacing::dual_contouring(domain, offset_value, points, polygons); + // run dual contouring + CGAL::Isosurfacing::dual_contouring(domain, offset_value, points, polygons); - // save output indexed mesh to a file, in the OFF format - CGAL::IO::write_OFF("result.off", points, polygons); + // save output indexed mesh to a file, in the OFF format + CGAL::IO::write_OFF("result.off", points, polygons); - return 0; + return 0; } diff --git a/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_octree.cpp b/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_octree.cpp index 0562d8e3a10..858e558377d 100644 --- a/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_octree.cpp +++ b/Isosurfacing_3/examples/Isosurfacing_3/dual_contouring_octree.cpp @@ -1,88 +1,100 @@ +#include + #include #include #include -#include + #include -#include #include +#include -typedef CGAL::Simple_cartesian Kernel; -typedef typename Kernel::FT FT; -typedef typename Kernel::Vector_3 Vector; -typedef typename Kernel::Point_3 Point; +using Kernel = CGAL::Simple_cartesian; +using FT = typename Kernel::FT; +using Vector = typename Kernel::Vector_3; +using Point = typename Kernel::Point_3; -typedef std::vector Point_range; -typedef std::vector> Polygon_range; +using Point_range = std::vector; +using Polygon_range = std::vector >; -typedef CGAL::Isosurfacing::Octree_wrapper Octree_wrapper_; +using Octree_wrapper_ = CGAL::Isosurfacing::Octree_wrapper; -struct Refine_one_eighth { - std::size_t min_depth_; - std::size_t max_depth_; +struct Refine_one_eighth +{ + std::size_t min_depth_; + std::size_t max_depth_; - std::size_t octree_dim_; + std::size_t octree_dim_; - Octree_wrapper_::Uniform_coords uniform_coordinates(const Octree_wrapper_::Octree::Node& node) const { - auto coords = node.global_coordinates(); - const std::size_t depth_factor = std::size_t(1) << (max_depth_ - node.depth()); - for (int i = 0; i < Octree_wrapper_::Octree::Node::Dimension::value; ++i) { - coords[i] *= (uint32_t)depth_factor; - } + Octree_wrapper_::Uniform_coords uniform_coordinates(const Octree_wrapper_::Octree::Node& node) const + { + auto coords = node.global_coordinates(); + const std::size_t depth_factor = std::size_t(1) << (max_depth_ - node.depth()); + for(int i=0; i < Octree_wrapper_::Octree::Node::Dimension::value; ++i) + coords[i] *= uint32_t(depth_factor); - return coords; - } + return coords; + } - Refine_one_eighth(std::size_t min_depth, std::size_t max_depth) : min_depth_(min_depth), max_depth_(max_depth) { - octree_dim_ = std::size_t(1) << max_depth_; - } + Refine_one_eighth(std::size_t min_depth, + std::size_t max_depth) + : min_depth_(min_depth), + max_depth_(max_depth) + { + octree_dim_ = std::size_t(1) << max_depth_; + } - bool operator()(const Octree_wrapper_::Octree::Node& n) const { - // n.depth() - if (n.depth() < min_depth_) { - return true; - } - if (n.depth() == max_depth_) { - return false; - } + bool operator()(const Octree_wrapper_::Octree::Node& n) const + { + // n.depth() + if(n.depth() < min_depth_) + return true; - auto leaf_coords = uniform_coordinates(n); + if(n.depth() == max_depth_) + return false; - if (leaf_coords[0] >= octree_dim_ / 2) { - return false; - } - if (leaf_coords[1] >= octree_dim_ / 2) { - return false; - } - if (leaf_coords[2] >= octree_dim_ / 2) { - // return false; - } - return true; - } + auto leaf_coords = uniform_coordinates(n); + + if(leaf_coords[0] >= octree_dim_ / 2) + return false; + + if(leaf_coords[1] >= octree_dim_ / 2) + return false; + + // if(leaf_coords[2] >= octree_dim_ / 2) + // return false; + + return true; + } }; -int main() { - const CGAL::Bbox_3 bbox(-1, -1, -1, 1, 1, 1); - std::shared_ptr octree_wrap = std::make_shared(bbox); +int main() +{ + const CGAL::Bbox_3 bbox(-1., -1., -1., 1., 1., 1.); + std::shared_ptr octree_wrap = std::make_shared(bbox); - Refine_one_eighth split_predicate(3, 4); - octree_wrap->refine(split_predicate); + Refine_one_eighth split_predicate(3, 4); + octree_wrap->refine(split_predicate); - auto sphere_function = [&](const Point& p) { return std::sqrt(p.x() * p.x() + p.y() * p.y() + p.z() * p.z()); }; + auto sphere_function = [&](const Point& p) + { + return std::sqrt(p.x() * p.x() + p.y() * p.y() + p.z() * p.z()); + }; - auto sphere_gradient = [&](const Point& p) { - const Vector g = p - CGAL::ORIGIN; - return g / std::sqrt(g.squared_length()); - }; + auto sphere_gradient = [&](const Point& p) + { + const Vector g = p - CGAL::ORIGIN; + return g / std::sqrt(g.squared_length()); + }; - auto domain = CGAL::Isosurfacing::create_implicit_octree_domain(octree_wrap, sphere_function, sphere_gradient); + auto domain = CGAL::Isosurfacing::create_implicit_octree_domain(octree_wrap, sphere_function, sphere_gradient); - Point_range points; - Polygon_range polygons; + Point_range points; + Polygon_range polygons; - CGAL::Isosurfacing::dual_contouring(domain, 0.8, points, polygons); + CGAL::Isosurfacing::dual_contouring(domain, 0.8, points, polygons); - CGAL::IO::write_OFF("result.off", points, polygons); + CGAL::IO::write_OFF("result.off", points, polygons); - return 0; + return 0; } diff --git a/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_cartesian_grid_sphere.cpp b/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_cartesian_grid_sphere.cpp index 0700506ca12..280a1508023 100644 --- a/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_cartesian_grid_sphere.cpp +++ b/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_cartesian_grid_sphere.cpp @@ -5,47 +5,48 @@ #include #include -typedef CGAL::Simple_cartesian Kernel; -typedef typename Kernel::FT FT; -typedef typename Kernel::Point_3 Point; +using Kernel = CGAL::Simple_cartesian; +using FT = typename Kernel::FT; +using Point = typename Kernel::Point_3; -typedef CGAL::Cartesian_grid_3 Grid; +using Grid = CGAL::Cartesian_grid_3; -typedef std::vector Point_range; -typedef std::vector> Polygon_range; +using Point_range = std::vector; +using Polygon_range = std::vector >; -int main() { - // create a cartesian grid with 100^3 grid points and the bounding box [-1, 1]^3 - const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0); - std::shared_ptr grid = std::make_shared(50, 50, 50, bbox); +int main() +{ + // create a cartesian grid with 100^3 grid points and the bounding box [-1, 1]^3 + const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0); + std::shared_ptr grid = std::make_shared(50, 50, 50, bbox); - // compute and store function values at all grid points - for (std::size_t x = 0; x < grid->xdim(); x++) { - for (std::size_t y = 0; y < grid->ydim(); y++) { - for (std::size_t z = 0; z < grid->zdim(); z++) { + // compute and store function values at all grid points + for(std::size_t x=0; xxdim(); ++x) { + for(std::size_t y=0; yydim(); ++y) { + for(std::size_t z=0; zzdim(); ++z) + { + const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin(); + const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin(); + const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin(); - const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin(); - const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin(); - const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin(); - - // Euclidean distance to the origin - grid->value(x, y, z) = std::sqrt(pos_x * pos_x + pos_y * pos_y + pos_z * pos_z); - } - } + // Euclidean distance to the origin + grid->value(x, y, z) = std::sqrt(pos_x * pos_x + pos_y * pos_y + pos_z * pos_z); + } } + } - // create a domain from the grid - auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid); + // create a domain from the grid + auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid); - // prepare collections for the result - Point_range points; - Polygon_range polygons; + // prepare collections for the result + Point_range points; + Polygon_range polygons; - // run marching cubes with an isovalue of 0.8 - CGAL::Isosurfacing::marching_cubes(domain, 0.8, points, polygons); + // run marching cubes with an isovalue of 0.8 + CGAL::Isosurfacing::marching_cubes(domain, 0.8, points, polygons); - // save output indexed surface mesh to file, in the OFF format - CGAL::IO::write_OFF("result.off", points, polygons); + // save output indexed surface mesh to file, in the OFF format + CGAL::IO::write_OFF("result.off", points, polygons); - return 0; + return 0; } diff --git a/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_implicit_sphere.cpp b/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_implicit_sphere.cpp index 86b036a7346..e90acf5a9fd 100644 --- a/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_implicit_sphere.cpp +++ b/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_implicit_sphere.cpp @@ -1,37 +1,43 @@ +#include + #include #include #include -#include + #include -typedef CGAL::Simple_cartesian Kernel; -typedef typename Kernel::FT FT; -typedef typename Kernel::Vector_3 Vector; -typedef typename Kernel::Point_3 Point; +using Kernel = CGAL::Simple_cartesian; +using FT = typename Kernel::FT; +using Vector = typename Kernel::Vector_3; +using Point = typename Kernel::Point_3; -typedef std::vector Point_range; -typedef std::vector > Polygon_range; +using Point_range = std::vector; +using Polygon_range = std::vector >; -int main() { - const CGAL::Bbox_3 bbox{-1.0, -1.0, -1.0, 1.0, 1.0, 1.0}; - const FT spacing = 0.04; - const Vector vec_spacing(spacing, spacing, spacing); +int main() +{ + const CGAL::Bbox_3 bbox { -1.0, -1.0, -1.0, 1.0, 1.0, 1.0 }; + const FT spacing = 0.04; + const Vector vec_spacing(spacing, spacing, spacing); - // Euclidean distance function to the origin - auto sphere_function = [&](const Point& p) { return std::sqrt(p.x() * p.x() + p.y() * p.y() + p.z() * p.z()); }; + // Euclidean distance function to the origin + auto sphere_function = [&](const Point& p) + { + return std::sqrt(p.x() * p.x() + p.y() * p.y() + p.z() * p.z()); + }; - // create a domain with given bounding box and grid spacing - auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain(bbox, vec_spacing, sphere_function); + // create a domain with given bounding box and grid spacing + auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain(bbox, vec_spacing, sphere_function); - // prepare collections for the output indexed mesh - Point_range points; - Polygon_range polygons; + // prepare collections for the output indexed mesh + Point_range points; + Polygon_range polygons; - // execute marching cubes with an isovalue of 0.8 - CGAL::Isosurfacing::marching_cubes(domain, 0.8, points, polygons); + // execute marching cubes with an isovalue of 0.8 + CGAL::Isosurfacing::marching_cubes(domain, 0.8, points, polygons); - // save ouput indexed mesh to a file, in the OFF format - CGAL::IO::write_OFF("result.off", points, polygons); + // save ouput indexed mesh to a file, in the OFF format + CGAL::IO::write_OFF("result.off", points, polygons); - return 0; + return 0; } diff --git a/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_inrimage.cpp b/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_inrimage.cpp index 7dc7fdd5182..dee94271ff1 100644 --- a/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_inrimage.cpp +++ b/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_inrimage.cpp @@ -1,42 +1,45 @@ +#include + #include #include #include -#include + #include -typedef CGAL::Simple_cartesian Kernel; -typedef typename Kernel::Point_3 Point; -typedef CGAL::Cartesian_grid_3 Grid; +using Kernel = CGAL::Simple_cartesian; +using Point = typename Kernel::Point_3; +using Grid = CGAL::Cartesian_grid_3; -typedef std::vector Point_range; -typedef std::vector> Polygon_range; +using Point_range = std::vector; +using Polygon_range = std::vector >; -int main() { +int main() +{ + const std::string fname = CGAL::data_file_path("images/skull_2.9.inr"); - const std::string fname = CGAL::data_file_path("images/skull_2.9.inr"); + // load volumetric image from a file + CGAL::Image_3 image; + if(!image.read(fname)) + { + std::cerr << "Error: Cannot read image file " << fname << std::endl; + return EXIT_FAILURE; + } - // load volumetric image from a file - CGAL::Image_3 image; - if (!image.read(fname)) { - std::cerr << "Error: Cannot read image file " << fname << std::endl; - return EXIT_FAILURE; - } + // convert image to a cartesian grid + std::shared_ptr grid = std::make_shared(image); - // convert image to a cartesian grid - std::shared_ptr grid = std::make_shared(image); + // create a domain from the grid + auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid); - // create a domain from the grid - auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid); + // prepare collections for the output indexed mesh + Point_range points; + Polygon_range polygons; - // prepare collections for the output indexed mesh - Point_range points; - Polygon_range polygons; + // execute marching cubes with an isovalue of 2.9 + CGAL::Isosurfacing::marching_cubes(domain, 2.9, points, polygons); - // execute marching cubes with an isovalue of 2.9 - CGAL::Isosurfacing::marching_cubes(domain, 2.9, points, polygons); + // save output indexed mesh to a file, in the OFF format + CGAL::IO::write_OFF("result.off", points, polygons); - // save output indexed mesh to a file, in the OFF format - CGAL::IO::write_OFF("result.off", points, polygons); - - return 0; + return 0; } diff --git a/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_signed_mesh_offset.cpp b/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_signed_mesh_offset.cpp index 3c71e681fff..ad63f02e17e 100644 --- a/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_signed_mesh_offset.cpp +++ b/Isosurfacing_3/examples/Isosurfacing_3/marching_cubes_signed_mesh_offset.cpp @@ -1,3 +1,6 @@ +#include +#include + #include #include #include @@ -5,95 +8,96 @@ #include #include #include -#include -#include + #include #include -typedef CGAL::Simple_cartesian Kernel; -typedef typename Kernel::FT FT; -typedef typename Kernel::Point_3 Point; -typedef typename Kernel::Vector_3 Vector; +using Kernel = CGAL::Simple_cartesian; +using FT = typename Kernel::FT; +using Point = typename Kernel::Point_3; +using Vector = typename Kernel::Vector_3; -typedef CGAL::Cartesian_grid_3 Grid; +using Grid = CGAL::Cartesian_grid_3; -typedef CGAL::Surface_mesh Mesh; +using Mesh = CGAL::Surface_mesh; -typedef CGAL::AABB_face_graph_triangle_primitive Primitive; -typedef CGAL::AABB_traits Traits; -typedef CGAL::AABB_tree Tree; - -typedef std::vector Point_range; -typedef std::vector> Polygon_range; +using Primitive = CGAL::AABB_face_graph_triangle_primitive; +using Traits = CGAL::AABB_traits; +using Tree = CGAL::AABB_tree; +using Point_range = std::vector; +using Polygon_range = std::vector >; // computes the Euclidean distance from query point p to the mesh // via the AABB tree data structure -inline Kernel::FT distance_to_mesh(const Tree& tree, const Point& p) { - const Point& x = tree.closest_point(p); - return std::sqrt((p - x).squared_length()); +inline Kernel::FT distance_to_mesh(const Tree& tree, + const Point& p) +{ + const Point& x = tree.closest_point(p); + return std::sqrt((p - x).squared_length()); } -int main() { - const std::string input_name = CGAL::data_file_path("meshes/cross.off"); - const int n_voxels = 20; - const FT offset_value = 0.2; +int main() +{ + const std::string input_name = CGAL::data_file_path("meshes/cross.off"); + const int n_voxels = 20; + const FT offset_value = 0.2; - // load input mesh - Mesh mesh_input; - if (!CGAL::IO::read_OFF(input_name, mesh_input)) { - std::cerr << "Could not read input mesh" << std::endl; - exit(-1); + // load input mesh + Mesh mesh_input; + if(!CGAL::IO::read_OFF(input_name, mesh_input)) + { + std::cerr << "Could not read input mesh" << std::endl; + exit(-1); + } + + // compute loose bounding box of the mesh + CGAL::Bbox_3 aabb_grid = CGAL::Polygon_mesh_processing::bbox(mesh_input); + const FT loose_offset = offset_value + 0.01; + Vector aabb_increase_vec = Vector(loose_offset, loose_offset, loose_offset); + aabb_grid += (Point(aabb_grid.xmax(), aabb_grid.ymax(), aabb_grid.zmax()) + aabb_increase_vec).bbox(); + aabb_grid += (Point(aabb_grid.xmin(), aabb_grid.ymin(), aabb_grid.zmin()) - aabb_increase_vec).bbox(); + + // construct AABB tree and functor to address inside/outside point queries + Tree tree(mesh_input.faces_begin(), mesh_input.faces_end(), mesh_input); + CGAL::Side_of_triangle_mesh::type> sotm(mesh_input); + + // create grid + std::shared_ptr grid = std::make_shared(n_voxels, n_voxels, n_voxels, aabb_grid); + + for(std::size_t z=0; zzdim(); ++z) { + for(std::size_t y=0; yydim(); ++y) { + for(std::size_t x=0; xxdim(); ++x) + { + const FT pos_x = x * grid->get_spacing()[0] + grid->get_bbox().xmin(); + const FT pos_y = y * grid->get_spacing()[1] + grid->get_bbox().ymin(); + const FT pos_z = z * grid->get_spacing()[2] + grid->get_bbox().zmin(); + const Point p(pos_x, pos_y, pos_z); + + // compute unsigned distance to input mesh + grid->value(x, y, z) = distance_to_mesh(tree, p); + + // sign distance so that it is negative inside the mesh + const bool is_inside = (sotm(p) == CGAL::ON_BOUNDED_SIDE); + if(is_inside) + grid->value(x, y, z) *= -1.0; + } } + } - // compute loose bounding box of the mesh - CGAL::Bbox_3 aabb_grid = CGAL::Polygon_mesh_processing::bbox(mesh_input); - const FT loose_offset = offset_value + 0.01; - Vector aabb_increase_vec = Vector(loose_offset, loose_offset, loose_offset); - aabb_grid += (Point(aabb_grid.xmax(), aabb_grid.ymax(), aabb_grid.zmax()) + aabb_increase_vec).bbox(); - aabb_grid += (Point(aabb_grid.xmin(), aabb_grid.ymin(), aabb_grid.zmin()) - aabb_increase_vec).bbox(); + // create domain from the grid + auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid); - // construct AABB tree and functor to address inside/outside point queries - Tree tree(mesh_input.faces_begin(), mesh_input.faces_end(), mesh_input); - CGAL::Side_of_triangle_mesh::type> sotm(mesh_input); + // containers for output indexed triangle soup + Point_range points; + Polygon_range polygons; - // create grid - std::shared_ptr grid = std::make_shared(n_voxels, n_voxels, n_voxels, aabb_grid); + // execute marching cubes with an isovalue equating offset + CGAL::Isosurfacing::marching_cubes(domain, offset_value, points, polygons); - for (std::size_t z = 0; z < grid->zdim(); z++) { - for (std::size_t y = 0; y < grid->ydim(); y++) { - for (std::size_t x = 0; x < grid->xdim(); x++) { + // save output indexed triangle soup to a file, in the OFF format + CGAL::IO::write_OFF("output.off", points, polygons); - const FT pos_x = x * grid->get_spacing()[0] + grid->get_bbox().xmin(); - const FT pos_y = y * grid->get_spacing()[1] + grid->get_bbox().ymin(); - const FT pos_z = z * grid->get_spacing()[2] + grid->get_bbox().zmin(); - const Point p(pos_x, pos_y, pos_z); - - // compute unsigned distance to input mesh - grid->value(x, y, z) = distance_to_mesh(tree, p); - - // sign distance so that it is negative inside the mesh - const bool is_inside = (sotm(p) == CGAL::ON_BOUNDED_SIDE); - if (is_inside) { - grid->value(x, y, z) *= -1.0; - } - } - } - } - - // create domain from the grid - auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid); - - // containers for output indexed triangle soup - Point_range points; - Polygon_range polygons; - - // execute marching cubes with an isovalue equating offset - CGAL::Isosurfacing::marching_cubes(domain, offset_value, points, polygons); - - // save output indexed triangle soup to a file, in the OFF format - CGAL::IO::write_OFF("output.off", points, polygons); - - return 0; + return 0; } diff --git a/Isosurfacing_3/include/CGAL/Cartesian_grid_3.h b/Isosurfacing_3/include/CGAL/Cartesian_grid_3.h index a212e0ed5b1..0df6f02a714 100644 --- a/Isosurfacing_3/include/CGAL/Cartesian_grid_3.h +++ b/Isosurfacing_3/include/CGAL/Cartesian_grid_3.h @@ -31,244 +31,268 @@ namespace CGAL { * * \tparam GeomTraits the traits type */ -template -class Cartesian_grid_3 { +template +class Cartesian_grid_3 +{ public: - typedef GeomTraits Geom_traits; - typedef typename Geom_traits::FT FT; - typedef typename Geom_traits::Vector_3 Vector; + using Geom_traits = GeomTraits; + using FT = typename Geom_traits::FT; + using Vector = typename Geom_traits::Vector_3; - typedef Isosurfacing::internal::Grid_topology::Vertex_descriptor VertexDescriptor; + using VertexDescriptor = Isosurfacing::internal::Grid_topology::Vertex_descriptor; public: - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Create a grid with `xdim * ydim * zdim` grid points. - * The grid covers the space described by a bounding box. - * - * \param xdim the number of grid points in x direction - * \param ydim the number of grid points in y direction - * \param zdim the number of grid points in z direction - * \param bbox the bounding box - */ - Cartesian_grid_3(const std::size_t xdim, const std::size_t ydim, const std::size_t zdim, const Bbox_3& bbox) - : sizes{xdim, ydim, zdim}, bbox(bbox) { + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Create a grid with `xdim * ydim * zdim` grid points. + * The grid covers the space described by a bounding box. + * + * \param xdim the number of grid points in x direction + * \param ydim the number of grid points in y direction + * \param zdim the number of grid points in z direction + * \param bbox the bounding box + */ + Cartesian_grid_3(const std::size_t xdim, + const std::size_t ydim, + const std::size_t zdim, + const Bbox_3& bbox) + : sizes{xdim, ydim, zdim}, + bbox(bbox) + { + // pre-allocate memory + values.resize(xdim * ydim * zdim); + gradients.resize(xdim * ydim * zdim); - // pre-allocate memory - values.resize(xdim * ydim * zdim); - gradients.resize(xdim * ydim * zdim); + // calculate grid spacing + const FT d_x = bbox.x_span() / (xdim - 1); + const FT d_y = bbox.y_span() / (ydim - 1); + const FT d_z = bbox.z_span() / (zdim - 1); + spacing = Vector(d_x, d_y, d_z); + } - // calculate grid spacing - const FT d_x = bbox.x_span() / (xdim - 1); - const FT d_y = bbox.y_span() / (ydim - 1); - const FT d_z = bbox.z_span() / (zdim - 1); - spacing = Vector(d_x, d_y, d_z); - } + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Create a grid from an `Image_3`. + * The dimensions and bounding box are read from the image. + * The values stored in the image must be of type `Geom_traits::FT` or implicitly convertible to it. + * + * \param image the image providing the data + */ + Cartesian_grid_3(const Image_3& image) + { + from_image(image); + } - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Create a grid from an `Image_3`. - * The dimensions and bounding box are read from the image. - * The values stored in the image must be of type `Geom_traits::FT` or implicitly convertible to it. - * - * \param image the image providing the data - */ - Cartesian_grid_3(const Image_3& image) { - from_image(image); - } + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Get the value stored in the grid at the grid point described by the vertex. + * + * \param v the vertex descriptor of the vertex + * + * \return the stored value + */ + FT operator()(const VertexDescriptor& v) const + { + return values[linear_index(v[0], v[1], v[2])]; + } - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Get the value stored in the grid at the grid point described by the vertex. - * - * \param v the vertex descriptor of the vertex - * - * \return the stored value - */ - FT operator()(const VertexDescriptor& v) const { - return values[linear_index(v[0], v[1], v[2])]; - } + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Get the value stored in the grid at the given indices. + * + * \param x the index in x direction + * \param y the index in y direction + * \param z the index in z direction + * + * \return the stored value + */ + FT value(const std::size_t x, + const std::size_t y, + const std::size_t z) const + { + return values[linear_index(x, y, z)]; + } - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Get the value stored in the grid at the given indices. - * - * \param x the index in x direction - * \param y the index in y direction - * \param z the index in z direction - * - * \return the stored value - */ - FT value(const std::size_t x, const std::size_t y, const std::size_t z) const { - return values[linear_index(x, y, z)]; - } + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Get a reference to the value stored in the grid at the given indices. + * Can be used to set values of the grid. + * + * \param x the index in x direction + * \param y the index in y direction + * \param z the index in z direction + * + * \return a reference to the stored value + */ + FT& value(const std::size_t x, + const std::size_t y, + const std::size_t z) + { + return values[linear_index(x, y, z)]; + } - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Get a reference to the value stored in the grid at the given indices. - * Can be used to set values of the grid. - * - * \param x the index in x direction - * \param y the index in y direction - * \param z the index in z direction - * - * \return a reference to the stored value - */ - FT& value(const std::size_t x, const std::size_t y, const std::size_t z) { - return values[linear_index(x, y, z)]; - } + Vector gradient(const std::size_t x, + const std::size_t y, + const std::size_t z) const + { + return gradients[linear_index(x, y, z)]; + } - Vector gradient(const std::size_t x, const std::size_t y, const std::size_t z) const { - return gradients[linear_index(x, y, z)]; - } + Vector& gradient(const std::size_t x, + const std::size_t y, + const std::size_t z) + { + return gradients[linear_index(x, y, z)]; + } - Vector& gradient(const std::size_t x, const std::size_t y, const std::size_t z) { - return gradients[linear_index(x, y, z)]; - } + /** + * \ingroup PkgIsosurfacing3Ref + * + * \return the number of grid points in x direction + */ + std::size_t xdim() const + { + return sizes[0]; + } - /** - * \ingroup PkgIsosurfacing3Ref - * - * \return the number of grid points in x direction - */ - std::size_t xdim() const { - return sizes[0]; - } + /** + * \ingroup PkgIsosurfacing3Ref + * + * \return the number of grid points in y direction + */ + std::size_t ydim() const + { + return sizes[1]; + } - /** - * \ingroup PkgIsosurfacing3Ref - * - * \return the number of grid points in y direction - */ - std::size_t ydim() const { - return sizes[1]; - } + /** + * \ingroup PkgIsosurfacing3Ref + * + * \return the number of grid points in z direction + */ + std::size_t zdim() const + { + return sizes[2]; + } - /** - * \ingroup PkgIsosurfacing3Ref - * - * \return the number of grid points in z direction - */ - std::size_t zdim() const { - return sizes[2]; - } + const Bbox_3& get_bbox() const + { + return bbox; + } - const Bbox_3& get_bbox() const { - return bbox; - } - - const Vector& get_spacing() const { - return spacing; - } + const Vector& get_spacing() const + { + return spacing; + } private: - std::size_t linear_index(const std::size_t x, const std::size_t y, const std::size_t z) const { - // convert x, y, z into a linear index to access the vector - return (z * ydim() + y) * xdim() + x; - } + std::size_t linear_index(const std::size_t x, + const std::size_t y, + const std::size_t z) const + { + // convert x, y, z into a linear index to access the vector + return (z * ydim() + y) * xdim() + x; + } - void from_image(const Image_3& image); - Image_3 to_image() const; + void from_image(const Image_3& image); + Image_3 to_image() const; private: - std::vector values; - std::vector gradients; + std::vector values; + std::vector gradients; - std::array sizes; + std::array sizes; - Bbox_3 bbox; - Vector spacing; + Bbox_3 bbox; + Vector spacing; }; template -void Cartesian_grid_3::from_image(const Image_3& image) { - // compute bounding box - const FT max_x = image.tx() + (image.xdim() - 1) * image.vx(); - const FT max_y = image.ty() + (image.ydim() - 1) * image.vy(); - const FT max_z = image.tz() + (image.zdim() - 1) * image.vz(); - bbox = Bbox_3(image.tx(), image.ty(), image.tz(), max_x, max_y, max_z); +void +Cartesian_grid_3:: +from_image(const Image_3& image) +{ + // compute bounding box + const FT max_x = image.tx() + (image.xdim() - 1) * image.vx(); + const FT max_y = image.ty() + (image.ydim() - 1) * image.vy(); + const FT max_z = image.tz() + (image.zdim() - 1) * image.vz(); + bbox = Bbox_3(image.tx(), image.ty(), image.tz(), max_x, max_y, max_z); - // get spacing - spacing = Vector(image.vx(), image.vy(), image.vz()); + // get spacing + spacing = Vector(image.vx(), image.vy(), image.vz()); - // get sizes - sizes[0] = image.xdim(); - sizes[1] = image.ydim(); - sizes[2] = image.zdim(); + // get sizes + sizes[0] = image.xdim(); + sizes[1] = image.ydim(); + sizes[2] = image.zdim(); - // pre-allocate - values.resize(xdim() * ydim() * zdim()); - gradients.resize(xdim() * ydim() * zdim()); + // pre-allocate + values.resize(xdim() * ydim() * zdim()); + gradients.resize(xdim() * ydim() * zdim()); - // copy values - for (std::size_t x = 0; x < sizes[0]; x++) { - for (std::size_t y = 0; y < sizes[1]; y++) { - for (std::size_t z = 0; z < sizes[2]; z++) { - - value(x, y, z) = image.value(x, y, z); - } - } - } + // copy values + for(std::size_t x=0; x -Image_3 Cartesian_grid_3::to_image() const { - // select the number type - WORD_KIND wordkind; - if (std::is_floating_point::value) - wordkind = WK_FLOAT; - else - wordkind = WK_FIXED; +Image_3 +Cartesian_grid_3:: +to_image() const +{ + // select the number type + WORD_KIND wordkind; + if(std::is_floating_point::value) + wordkind = WK_FLOAT; + else + wordkind = WK_FIXED; - // select signed or unsigned - SIGN sign; - if (std::is_signed::value) - sign = SGN_SIGNED; - else - sign = SGN_UNSIGNED; + // select signed or unsigned + SIGN sign; + if(std::is_signed::value) + sign = SGN_SIGNED; + else + sign = SGN_UNSIGNED; - // get spacing - const double vx = spacing()[0]; - const double vy = spacing()[1]; - const double vz = spacing()[2]; + // get spacing + const double vx = spacing()[0]; + const double vy = spacing()[1]; + const double vz = spacing()[2]; - // create image - _image* im = _createImage(xdim(), ydim(), zdim(), - 1, // vectorial dimension - vx, vy, vz, // voxel size - sizeof(FT), // image word size in bytes - wordkind, // image word kind WK_FIXED, WK_FLOAT, WK_UNKNOWN - sign); // image word sign + // create image + _image* im = _createImage(xdim(), ydim(), zdim(), + 1, // vectorial dimension + vx, vy, vz, // voxel size + sizeof(FT), // image word size in bytes + wordkind, // image word kind WK_FIXED, WK_FLOAT, WK_UNKNOWN + sign); // image word sign - // error handling - if (im == nullptr || im->data == nullptr) { - throw std::bad_alloc(); // TODO: idk? - } + // error handling + if(im == nullptr || im->data == nullptr) + throw std::bad_alloc(); // @todo idk? - // set min coordinates - im->tx = bbox.xmin(); - im->ty = bbox.ymin(); - im->tz = bbox.zmin(); + // set min coordinates + im->tx = bbox.xmin(); + im->ty = bbox.ymin(); + im->tz = bbox.zmin(); - // copy data - FT* data = (FT*)im->data; - for (std::size_t x = 0; x < xdim(); x++) { - for (std::size_t y = 0; y < ydim(); y++) { - for (std::size_t z = 0; z < zdim(); z++) { + // copy data + FT* data = (FT*)im->data; + for(std::size_t x=0; x> -void dual_contouring(const Domain_& domain, const typename Domain_::FT isovalue, PointRange& points, - PolygonRange& polygons, const Positioning& positioning = Positioning()) { +template > +void dual_contouring(const Domain_& domain, + const typename Domain_::FT isovalue, + PointRange& points, + PolygonRange& polygons, + const Positioning& positioning = Positioning()) +{ + // create vertices in each relevant cell + internal::Dual_contouring_vertex_positioning pos_func(domain, isovalue, positioning); + domain.template iterate_cells(pos_func); - // create vertices in each relevant cell - internal::Dual_contouring_vertex_positioning pos_func(domain, isovalue, positioning); - domain.template iterate_cells(pos_func); + // connect vertices around an edge to form a face + internal::Dual_contouring_face_generation face_generation(domain, isovalue); + domain.template iterate_edges(face_generation); - // connect vertices around an edge to form a face - internal::Dual_contouring_face_generation face_generation(domain, isovalue); - domain.template iterate_edges(face_generation); + // copy vertices to point range + points.resize(pos_func.points_counter); + for(const auto& vtop : pos_func.map_voxel_to_point) + points[pos_func.map_voxel_to_point_id[vtop.first]] = vtop.second; - // copy vertices to point range - points.resize(pos_func.points_counter); - for (const auto& vtop : pos_func.map_voxel_to_point) { - points[pos_func.map_voxel_to_point_id[vtop.first]] = vtop.second; + // copy faces to polygon range + polygons.reserve(face_generation.faces.size()); + for(const auto& q : face_generation.faces) + { + std::vector vertex_ids; + for(const auto& v_id : q.second) + { + // ignore voxels that are outside the valid region and are not stored in the map + if(pos_func.map_voxel_to_point_id.count(v_id) > 0) + vertex_ids.push_back(pos_func.map_voxel_to_point_id[v_id]); } - // copy faces to polygon range - polygons.reserve(face_generation.faces.size()); - for (const auto& q : face_generation.faces) { - std::vector vertex_ids; - for (const auto& v_id : q.second) { - // ignore voxels that are outside the valid region and are not stored in the map - if (pos_func.map_voxel_to_point_id.count(v_id) > 0) { - vertex_ids.push_back(pos_func.map_voxel_to_point_id[v_id]); - } - } - // ignore degenerated faces - if (vertex_ids.size() > 2) { - polygons.push_back(vertex_ids); - } - } + // ignore degenerated faces + if(vertex_ids.size() > 2) + polygons.push_back(vertex_ids); + } } -} // namespace Isosurfacing -} // namespace CGAL +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_DUAL_CONTOURING_3_H +#endif // CGAL_DUAL_CONTOURING_3_H diff --git a/Isosurfacing_3/include/CGAL/Explicit_cartesian_grid_domain.h b/Isosurfacing_3/include/CGAL/Explicit_cartesian_grid_domain.h index 5e9ac644e85..651da15c40a 100644 --- a/Isosurfacing_3/include/CGAL/Explicit_cartesian_grid_domain.h +++ b/Isosurfacing_3/include/CGAL/Explicit_cartesian_grid_domain.h @@ -30,13 +30,17 @@ namespace Isosurfacing { * `IsosurfacingDomainWithGradient`. * * \tparam GeomTraits the traits type - * \tparam Gradient_ the type of the gradient functor. It must implement `GeomTraits::Vector operator()(const - * GeomTraits::Point& point) const`. + * \tparam Gradient_ the type of the gradient functor. It must implement + * `GeomTraits::Vector operator()(const GeomTraits::Point& point) const`. */ -template +template using Explicit_cartesian_grid_domain = - internal::Base_domain, - Cartesian_grid_3, Gradient_>; + internal::Base_domain, + Cartesian_grid_3, + Gradient_>; /** * \ingroup PkgIsosurfacing3Ref @@ -52,34 +56,37 @@ using Explicit_cartesian_grid_domain = * * \return a new `Explicit_cartesian_grid_domain` */ -template > -Explicit_cartesian_grid_domain create_explicit_cartesian_grid_domain( - const std::shared_ptr> grid, const Gradient_& gradient = Gradient_()) { +template > +Explicit_cartesian_grid_domain +create_explicit_cartesian_grid_domain(const std::shared_ptr > grid, + const Gradient_& gradient = Gradient_()) +{ + using Domain = Explicit_cartesian_grid_domain; - typedef Explicit_cartesian_grid_domain Domain; - typedef typename Domain::Topology Topology; - typedef typename Domain::Geometry Geometry; - typedef typename Domain::Function Function; - typedef typename Domain::Gradient Gradient; + using Topology = typename Domain::Topology ; + using Geometry = typename Domain::Geometry; + using Function = typename Domain::Function; + using Gradient = typename Domain::Gradient; - const std::size_t size_i = grid->xdim(); - const std::size_t size_j = grid->ydim(); - const std::size_t size_k = grid->zdim(); + const std::size_t size_i = grid->xdim(); + const std::size_t size_j = grid->ydim(); + const std::size_t size_k = grid->zdim(); - const Bbox_3& bbox = grid->get_bbox(); - const typename GeomTraits::Vector_3 offset(bbox.xmin(), bbox.ymin(), bbox.zmin()); - const typename GeomTraits::Vector_3 spacing = grid->get_spacing(); + const Bbox_3& bbox = grid->get_bbox(); + const typename GeomTraits::Vector_3 offset(bbox.xmin(), bbox.ymin(), bbox.zmin()); + const typename GeomTraits::Vector_3 spacing = grid->get_spacing(); - // create copies as shared_ptr for safe memory management - const Topology topo = std::make_shared(size_i, size_j, size_k); - const Geometry geom = std::make_shared(offset, spacing); - const Function func = grid; - const Gradient grad = std::make_shared(gradient); + // create copies as shared_ptr for safe memory management + const Topology topo = std::make_shared(size_i, size_j, size_k); + const Geometry geom = std::make_shared(offset, spacing); + const Function func = grid; + const Gradient grad = std::make_shared(gradient); - return Domain(topo, geom, func, grad); + return Domain(topo, geom, func, grad); } -} // namespace Isosurfacing -} // namespace CGAL +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_EXPLICIT_CARTESIAN_GRID_DOMAIN_H +#endif // CGAL_EXPLICIT_CARTESIAN_GRID_DOMAIN_H diff --git a/Isosurfacing_3/include/CGAL/Explicit_cartesian_grid_gradient.h b/Isosurfacing_3/include/CGAL/Explicit_cartesian_grid_gradient.h index 1782fa01a1c..7a9d666be77 100644 --- a/Isosurfacing_3/include/CGAL/Explicit_cartesian_grid_gradient.h +++ b/Isosurfacing_3/include/CGAL/Explicit_cartesian_grid_gradient.h @@ -29,92 +29,96 @@ namespace Isosurfacing { * * \tparam GeomTraits the traits for this gradient. */ -template -class Explicit_cartesian_grid_gradient { +template +class Explicit_cartesian_grid_gradient +{ public: - typedef GeomTraits Geom_traits; - typedef typename Geom_traits::FT FT; - typedef typename Geom_traits::Point_3 Point; - typedef typename Geom_traits::Vector_3 Vector; + using Geom_traits = GeomTraits; + using FT = typename Geom_traits::FT; + using Point = typename Geom_traits::Point_3; + using Vector = typename Geom_traits::Vector_3; - typedef std::shared_ptr> Grid; + using Grid = std::shared_ptr >; public: - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Create a new instance of this gradient. - * - * \param grid the cartesian grid that stores the gradient - */ - Explicit_cartesian_grid_gradient(const Grid& grid) : grid(grid) {} + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Create a new instance of this gradient. + * + * \param grid the cartesian grid that stores the gradient + */ + Explicit_cartesian_grid_gradient(const Grid& grid) + : grid(grid) + { } - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Evaluate the gradient at a point in space. - * - * \param point the point at which the gradient is computed - */ - Vector operator()(const Point& point) const { - // trilinear interpolation of stored gradients + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Evaluate the gradient at a point in space. + * + * \param point the point at which the gradient is computed + */ + Vector operator()(const Point& point) const + { + // trilinear interpolation of stored gradients - const Bbox_3& bbox = grid->get_bbox(); - const Vector& spacing = grid->get_spacing(); + const Bbox_3& bbox = grid->get_bbox(); + const Vector& spacing = grid->get_spacing(); - // calculate min index including border case - std::size_t min_i = (point.x() - bbox.xmin()) / spacing.x(); - std::size_t min_j = (point.y() - bbox.ymin()) / spacing.y(); - std::size_t min_k = (point.z() - bbox.zmin()) / spacing.z(); - if (min_i == grid->xdim() - 1) { - min_i--; - } - if (min_j == grid->ydim() - 1) { - min_j--; - } - if (min_k == grid->zdim() - 1) { - min_k--; - } + // calculate min index including border case + std::size_t min_i = (point.x() - bbox.xmin()) / spacing.x(); + std::size_t min_j = (point.y() - bbox.ymin()) / spacing.y(); + std::size_t min_k = (point.z() - bbox.zmin()) / spacing.z(); + if(min_i == grid->xdim() - 1) + --min_i; - // calculate coordinates of min index - const FT min_x = min_i * spacing.x() + bbox.xmin(); - const FT min_y = min_j * spacing.y() + bbox.ymin(); - const FT min_z = min_k * spacing.z() + bbox.zmin(); + if(min_j == grid->ydim() - 1) + --min_j; - // interpolation factors between 0 and 1 - const FT f_i = (point.x() - min_x) / spacing.x(); - const FT f_j = (point.y() - min_y) / spacing.y(); - const FT f_k = (point.z() - min_z) / spacing.z(); + if(min_k == grid->zdim() - 1) + --min_k; - // read the gradient at all 8 corner points - const Vector g000 = grid->gradient(min_i + 0, min_j + 0, min_k + 0); - const Vector g001 = grid->gradient(min_i + 0, min_j + 0, min_k + 1); - const Vector g010 = grid->gradient(min_i + 0, min_j + 1, min_k + 0); - const Vector g011 = grid->gradient(min_i + 0, min_j + 1, min_k + 1); - const Vector g100 = grid->gradient(min_i + 1, min_j + 0, min_k + 0); - const Vector g101 = grid->gradient(min_i + 1, min_j + 0, min_k + 1); - const Vector g110 = grid->gradient(min_i + 1, min_j + 1, min_k + 0); - const Vector g111 = grid->gradient(min_i + 1, min_j + 1, min_k + 1); - // interpolate along all axes by weighting the corner points - const Vector g0 = g000 * (1 - f_i) * (1 - f_j) * (1 - f_k); - const Vector g1 = g001 * (1 - f_i) * (1 - f_j) * f_k; - const Vector g2 = g010 * (1 - f_i) * f_j * (1 - f_k); - const Vector g3 = g011 * (1 - f_i) * f_j * f_k; - const Vector g4 = g100 * f_i * (1 - f_j) * (1 - f_k); - const Vector g5 = g101 * f_i * (1 - f_j) * f_k; - const Vector g6 = g110 * f_i * f_j * (1 - f_k); - const Vector g7 = g111 * f_i * f_j * f_k; + // calculate coordinates of min index + const FT min_x = min_i * spacing.x() + bbox.xmin(); + const FT min_y = min_j * spacing.y() + bbox.ymin(); + const FT min_z = min_k * spacing.z() + bbox.zmin(); - // add weighted corners - return g0 + g1 + g2 + g3 + g4 + g5 + g6 + g7; - } + // interpolation factors between 0 and 1 + const FT f_i = (point.x() - min_x) / spacing.x(); + const FT f_j = (point.y() - min_y) / spacing.y(); + const FT f_k = (point.z() - min_z) / spacing.z(); + + // read the gradient at all 8 corner points + const Vector g000 = grid->gradient(min_i + 0, min_j + 0, min_k + 0); + const Vector g001 = grid->gradient(min_i + 0, min_j + 0, min_k + 1); + const Vector g010 = grid->gradient(min_i + 0, min_j + 1, min_k + 0); + const Vector g011 = grid->gradient(min_i + 0, min_j + 1, min_k + 1); + const Vector g100 = grid->gradient(min_i + 1, min_j + 0, min_k + 0); + const Vector g101 = grid->gradient(min_i + 1, min_j + 0, min_k + 1); + const Vector g110 = grid->gradient(min_i + 1, min_j + 1, min_k + 0); + const Vector g111 = grid->gradient(min_i + 1, min_j + 1, min_k + 1); + + // interpolate along all axes by weighting the corner points + const Vector g0 = g000 * (1 - f_i) * (1 - f_j) * (1 - f_k); + const Vector g1 = g001 * (1 - f_i) * (1 - f_j) * f_k; + const Vector g2 = g010 * (1 - f_i) * f_j * (1 - f_k); + const Vector g3 = g011 * (1 - f_i) * f_j * f_k; + const Vector g4 = g100 * f_i * (1 - f_j) * (1 - f_k); + const Vector g5 = g101 * f_i * (1 - f_j) * f_k; + const Vector g6 = g110 * f_i * f_j * (1 - f_k); + const Vector g7 = g111 * f_i * f_j * f_k; + + // add weighted corners + return g0 + g1 + g2 + g3 + g4 + g5 + g6 + g7; + } private: - const Grid grid; + const Grid grid; }; -} // namespace Isosurfacing -} // namespace CGAL +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_EXPLICIT_CARTESIAN_GRID_GRADIENT_H +#endif // CGAL_EXPLICIT_CARTESIAN_GRID_GRADIENT_H diff --git a/Isosurfacing_3/include/CGAL/Finite_difference_gradient.h b/Isosurfacing_3/include/CGAL/Finite_difference_gradient.h index b11c22c0340..b125996724b 100644 --- a/Isosurfacing_3/include/CGAL/Finite_difference_gradient.h +++ b/Isosurfacing_3/include/CGAL/Finite_difference_gradient.h @@ -30,56 +30,62 @@ namespace Isosurfacing { * \tparam PointFunction the type of the implicit function. It must implement `GeomTraits::FT operator()(const * GeomTraits::Point& point) const`. */ -template -class Finite_difference_gradient { +template +class Finite_difference_gradient +{ public: - typedef GeomTraits Geom_traits; - typedef typename Geom_traits::FT FT; - typedef typename Geom_traits::Point_3 Point; - typedef typename Geom_traits::Vector_3 Vector; + using Geom_traits = GeomTraits; + using FT = typename Geom_traits::FT; + using Point = typename Geom_traits::Point_3; + using Vector = typename Geom_traits::Vector_3; public: - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Create a new instance of this gradient. - * - * \param point_function the function with a point as argument - * \param delta the distance for calculating the finite differences - */ - Finite_difference_gradient(const PointFunction& point_function, const FT delta = 0.001) - : func(point_function), delta(delta) {} + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Create a new instance of this gradient. + * + * \param point_function the function with a point as argument + * \param delta the distance for calculating the finite differences + */ + Finite_difference_gradient(const PointFunction& point_function, + const FT delta = 0.001) + : func(point_function), + delta(delta) + { } - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Evaluate the gradient at a point in space. - * - * \param point the point at which the gradient is computed - */ - Vector operator()(const Point& point) const { - // compute the gradient by sampling the function with finite differences - // at six points with distance delta around the query point - const Point p0 = point + Vector(delta, 0, 0); - const Point p1 = point - Vector(delta, 0, 0); - const Point p2 = point + Vector(0, delta, 0); - const Point p3 = point - Vector(0, delta, 0); - const Point p4 = point + Vector(0, 0, delta); - const Point p5 = point - Vector(0, 0, delta); + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Evaluate the gradient at a point in space. + * + * \param point the point at which the gradient is computed + */ + Vector operator()(const Point& point) const + { + // compute the gradient by sampling the function with finite differences + // at six points with distance delta around the query point + const Point p0 = point + Vector(delta, 0, 0); + const Point p1 = point - Vector(delta, 0, 0); + const Point p2 = point + Vector(0, delta, 0); + const Point p3 = point - Vector(0, delta, 0); + const Point p4 = point + Vector(0, 0, delta); + const Point p5 = point - Vector(0, 0, delta); - const FT gx = (func(p0) - func(p1)) / (2 * delta); - const FT gy = (func(p2) - func(p3)) / (2 * delta); - const FT gz = (func(p4) - func(p5)) / (2 * delta); + const FT gx = (func(p0) - func(p1)) / (2 * delta); + const FT gy = (func(p2) - func(p3)) / (2 * delta); + const FT gz = (func(p4) - func(p5)) / (2 * delta); - return Vector(gx, gy, gz); - } + return Vector(gx, gy, gz); + } private: - const PointFunction func; - FT delta; + const PointFunction func; + FT delta; }; -} // namespace Isosurfacing -} // namespace CGAL +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_FINITE_DIFFERENCE_GRADIENT_H +#endif // CGAL_FINITE_DIFFERENCE_GRADIENT_H diff --git a/Isosurfacing_3/include/CGAL/Implicit_cartesian_grid_domain.h b/Isosurfacing_3/include/CGAL/Implicit_cartesian_grid_domain.h index 0b0720f3295..b856c67d86e 100644 --- a/Isosurfacing_3/include/CGAL/Implicit_cartesian_grid_domain.h +++ b/Isosurfacing_3/include/CGAL/Implicit_cartesian_grid_domain.h @@ -31,15 +31,22 @@ namespace Isosurfacing { * `IsosurfacingDomainWithGradient`. * * \tparam GeomTraits the traits type - * \tparam PointFunction the type of the implicit function. It must implement `GeomTraits::FT operator()(const - * GeomTraits::Point& point) const`. \tparam Gradient_ the type of the gradient functor. It must implement - * `GeomTraits::Vector operator()(const GeomTraits::Point& point) const`. + * \tparam PointFunction the type of the implicit function. It must implement + * `GeomTraits::FT operator()(const GeomTraits::Point& point) const`. + * \tparam Gradient_ the type of the gradient functor. It must implement + * `GeomTraits::Vector operator()(const GeomTraits::Point& point) const`. */ -template -using Implicit_cartesian_grid_domain = internal::Base_domain< - GeomTraits, internal::Grid_topology, internal::Cartesian_grid_geometry, - internal::Implicit_function_with_geometry, PointFunction>, - Gradient_>; +template +using Implicit_cartesian_grid_domain = + internal::Base_domain, + internal::Implicit_function_with_geometry, + PointFunction>, + Gradient_>; /** * \ingroup PkgIsosurfacing3Ref @@ -61,36 +68,41 @@ using Implicit_cartesian_grid_domain = internal::Base_domain< * * \return a new `Implicit_cartesian_grid_domain` */ -template > -Implicit_cartesian_grid_domain create_implicit_cartesian_grid_domain( - const Bbox_3& bbox, const typename GeomTraits::Vector_3& spacing, const PointFunction& point_function, - const Gradient_& gradient = Gradient_()) { +template > +Implicit_cartesian_grid_domain +create_implicit_cartesian_grid_domain(const Bbox_3& bbox, + const typename GeomTraits::Vector_3& spacing, + const PointFunction& point_function, + const Gradient_& gradient = Gradient_()) +{ + using Domain = Implicit_cartesian_grid_domain; - typedef Implicit_cartesian_grid_domain Domain; - typedef typename Domain::Topology Topology; - typedef typename Domain::Geometry Geometry; - typedef typename Domain::Function Function; - typedef typename Domain::Gradient Gradient; - typedef typename Function::element_type::Point_function Point_function; + using Topology = typename Domain::Topology; + using Geometry = typename Domain::Geometry; + using Function = typename Domain::Function; + using Gradient = typename Domain::Gradient; + using Point_function = typename Function::element_type::Point_function; - // calculate grid dimensions - const std::size_t size_i = std::ceil(bbox.x_span() / spacing.x()) + 1; - const std::size_t size_j = std::ceil(bbox.y_span() / spacing.y()) + 1; - const std::size_t size_k = std::ceil(bbox.z_span() / spacing.z()) + 1; + // calculate grid dimensions + const std::size_t size_i = std::ceil(bbox.x_span() / spacing.x()) + 1; + const std::size_t size_j = std::ceil(bbox.y_span() / spacing.y()) + 1; + const std::size_t size_k = std::ceil(bbox.z_span() / spacing.z()) + 1; - const typename GeomTraits::Vector_3 offset(bbox.xmin(), bbox.ymin(), bbox.zmin()); + const typename GeomTraits::Vector_3 offset(bbox.xmin(), bbox.ymin(), bbox.zmin()); - // create copies as shared_ptr for safe memory management - const Topology topo = std::make_shared(size_i, size_j, size_k); - const Geometry geom = std::make_shared(offset, spacing); - const Point_function point_func = std::make_shared(point_function); - const Function func = std::make_shared(geom, point_func); - const Gradient grad = std::make_shared(gradient); + // create copies as shared_ptr for safe memory management + const Topology topo = std::make_shared(size_i, size_j, size_k); + const Geometry geom = std::make_shared(offset, spacing); + const Point_function point_func = std::make_shared(point_function); + const Function func = std::make_shared(geom, point_func); + const Gradient grad = std::make_shared(gradient); - return Domain(topo, geom, func, grad); + return Domain(topo, geom, func, grad); } -} // namespace Isosurfacing -} // namespace CGAL +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_IMPLICIT_CARTESIAN_GRID_DOMAIN_H +#endif // CGAL_IMPLICIT_CARTESIAN_GRID_DOMAIN_H diff --git a/Isosurfacing_3/include/CGAL/Implicit_octree_domain.h b/Isosurfacing_3/include/CGAL/Implicit_octree_domain.h index fd45031a93f..ecadd4e39cf 100644 --- a/Isosurfacing_3/include/CGAL/Implicit_octree_domain.h +++ b/Isosurfacing_3/include/CGAL/Implicit_octree_domain.h @@ -24,37 +24,46 @@ namespace CGAL { namespace Isosurfacing { +template +using Implicit_octree_domain = + internal::Base_domain, + internal::Octree_geometry, + internal::Implicit_function_with_geometry, + PointFunction>, + Gradient_>; -template -using Implicit_octree_domain = internal::Base_domain< - GeomTraits, internal::Octree_topology, internal::Octree_geometry, - internal::Implicit_function_with_geometry, PointFunction>, - Gradient_>; +template > +Implicit_octree_domain +create_implicit_octree_domain(const std::shared_ptr > octree, + const PointFunction& point_function, + const Gradient_& gradient = Gradient_()) +{ + using Domain = Implicit_octree_domain; -template > -Implicit_octree_domain create_implicit_octree_domain( - const std::shared_ptr> octree, const PointFunction& point_function, - const Gradient_& gradient = Gradient_()) { + using Topology = typename Domain::Topology; + using Geometry = typename Domain::Geometry; + using Function = typename Domain::Function; + using Gradient = typename Domain::Gradient; + using Point_function = typename Function::element_type::Point_function; + using Octree = typename Topology::element_type::Octree; - typedef Implicit_octree_domain Domain; - typedef typename Domain::Topology Topology; - typedef typename Domain::Geometry Geometry; - typedef typename Domain::Function Function; - typedef typename Domain::Gradient Gradient; - typedef typename Function::element_type::Point_function Point_function; - typedef typename Topology::element_type::Octree Octree; + const Octree oct = octree; + const Topology topo = std::make_shared(oct); + const Geometry geom = std::make_shared(oct); + const Point_function point_func = std::make_shared(point_function); + const Function func = std::make_shared(geom, point_func); + const Gradient grad = std::make_shared(gradient); - const Octree oct = octree; - const Topology topo = std::make_shared(oct); - const Geometry geom = std::make_shared(oct); - const Point_function point_func = std::make_shared(point_function); - const Function func = std::make_shared(geom, point_func); - const Gradient grad = std::make_shared(gradient); - - return Domain(topo, geom, func, grad); + return Domain(topo, geom, func, grad); } -} // namespace Isosurfacing -} // namespace CGAL +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_IMPLICIT_OCTREE_DOMAIN_H +#endif // CGAL_IMPLICIT_OCTREE_DOMAIN_H diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Base_domain.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Base_domain.h index c8398ff2c5d..ac0f356f8c3 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Base_domain.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Base_domain.h @@ -9,8 +9,8 @@ // // Author(s) : Julian Stahl -#ifndef CGAL_BASE_DOMAIN_H -#define CGAL_BASE_DOMAIN_H +#ifndef CGAL_ISOSURFACING_3_INTERNAL_BASE_DOMAIN_H +#define CGAL_ISOSURFACING_3_INTERNAL_BASE_DOMAIN_H #include @@ -22,101 +22,124 @@ namespace CGAL { namespace Isosurfacing { namespace internal { -// A wrapper class to puzzle a domain together from different combinations of topology, geometry, function, and -// gradient. -template -class Base_domain { +// A wrapper class to puzzle a domain together from different combinations of topology, +// geometry, function, and gradient. +template +class Base_domain +{ public: - typedef GeomTraits Geom_traits; - typedef typename Geom_traits::FT FT; - typedef typename Geom_traits::Point_3 Point; - typedef typename Geom_traits::Vector_3 Vector; + using Geom_traits = GeomTraits; - typedef std::shared_ptr Topology; - typedef typename Topology_::Vertex_descriptor Vertex_descriptor; - typedef typename Topology_::Edge_descriptor Edge_descriptor; - typedef typename Topology_::Cell_descriptor Cell_descriptor; + using FT = typename Geom_traits::FT; + using Point = typename Geom_traits::Point_3; + using Vector = typename Geom_traits::Vector_3; - static constexpr Cell_type CELL_TYPE = Topology_::CELL_TYPE; - static constexpr std::size_t VERTICES_PER_CELL = Topology_::VERTICES_PER_CELL; - static constexpr std::size_t EDGES_PER_CELL = Topology_::EDGES_PER_CELL; + using Topology = std::shared_ptr; + using Vertex_descriptor = typename Topology_::Vertex_descriptor; + using Edge_descriptor = typename Topology_::Edge_descriptor; + using Cell_descriptor = typename Topology_::Cell_descriptor; - typedef typename Topology_::Vertices_incident_to_edge Vertices_incident_to_edge; - typedef typename Topology_::Cells_incident_to_edge Cells_incident_to_edge; - typedef typename Topology_::Cell_vertices Cell_vertices; - typedef typename Topology_::Cell_edges Cell_edges; + using Vertices_incident_to_edge = typename Topology_::Vertices_incident_to_edge; + using Cells_incident_to_edge = typename Topology_::Cells_incident_to_edge; + using Cell_vertices = typename Topology_::Cell_vertices; + using Cell_edges = typename Topology_::Cell_edges; - typedef std::shared_ptr Geometry; - typedef std::shared_ptr Function; - typedef std::shared_ptr Gradient; + using Geometry = std::shared_ptr; + using Function = std::shared_ptr; + using Gradient = std::shared_ptr; + + static constexpr Cell_type CELL_TYPE = Topology_::CELL_TYPE; + static constexpr std::size_t VERTICES_PER_CELL = Topology_::VERTICES_PER_CELL; + static constexpr std::size_t EDGES_PER_CELL = Topology_::EDGES_PER_CELL; public: - // Create a base_domain from a topology, geometry, input function, and gradient - Base_domain(const Topology& topo, const Geometry& geom, const Function& func, const Gradient& grad) - : topo(topo), geom(geom), func(func), grad(grad) {} + // Create a base_domain from a topology, geometry, input function, and gradient + Base_domain(const Topology& topo, + const Geometry& geom, + const Function& func, + const Gradient& grad) + : topo(topo), + geom(geom), + func(func), + grad(grad) + { } - // Get the position of vertex v - Point position(const Vertex_descriptor& v) const { - return geom->operator()(v); - } + // Get the position of vertex v + Point position(const Vertex_descriptor& v) const + { + return geom->operator()(v); + } - // Get the value of the function at vertex v - FT value(const Vertex_descriptor& v) const { - return func->operator()(v); - } + // Get the value of the function at vertex v + FT value(const Vertex_descriptor& v) const + { + return func->operator()(v); + } - // Get the gradient at vertex v - Vector gradient(const Point& p) const { - return grad->operator()(p); - } + // Get the gradient at vertex v + Vector gradient(const Point& p) const + { + return grad->operator()(p); + } - // Get a container with the two vertices incident to the edge e - Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const { - return topo->edge_vertices(e); - } + // Get a container with the two vertices incident to the edge e + Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const + { + return topo->edge_vertices(e); + } - // Get a container with all cells incident to the edge e - Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const { - return topo->cells_incident_to_edge(e); - } + // Get a container with all cells incident to the edge e + Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const + { + return topo->cells_incident_to_edge(e); + } - // Get a container with all vertices of the cell c - Cell_vertices cell_vertices(const Cell_descriptor& c) const { - return topo->cell_vertices(c); - } + // Get a container with all vertices of the cell c + Cell_vertices cell_vertices(const Cell_descriptor& c) const + { + return topo->cell_vertices(c); + } - // Get a container with all edges of the cell c - Cell_edges cell_edges(const Cell_descriptor& c) const { - return topo->cell_edges(c); - } + // Get a container with all edges of the cell c + Cell_edges cell_edges(const Cell_descriptor& c) const + { + return topo->cell_edges(c); + } - // Iterate over all vertices v calling f(v) on every one - template - void iterate_vertices(Functor& f) const { - topo->iterate_vertices(f, Concurrency_tag()); - } + // Iterate over all vertices v calling f(v) on every one + template + void iterate_vertices(Functor& f) const + { + topo->iterate_vertices(f, Concurrency_tag()); + } - // Iterate over all edges e calling f(e) on every one - template - void iterate_edges(Functor& f) const { - topo->iterate_edges(f, Concurrency_tag()); - } + // Iterate over all edges e calling f(e) on every one + template + void iterate_edges(Functor& f) const + { + topo->iterate_edges(f, Concurrency_tag()); + } - // Iterate over all cells c calling f(c) on every one - template - void iterate_cells(Functor& f) const { - topo->iterate_cells(f, Concurrency_tag()); - } + // Iterate over all cells c calling f(c) on every one + template + void iterate_cells(Functor& f) const + { + topo->iterate_cells(f, Concurrency_tag()); + } private: - const Topology topo; - const Geometry geom; - const Function func; - const Gradient grad; + const Topology topo; + const Geometry geom; + const Function func; + const Gradient grad; }; -} // namespace internal -} // namespace Isosurfacing -} // namespace CGAL +} // namespace internal +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_BASE_DOMAIN_H +#endif // CGAL_ISOSURFACING_3_INTERNAL_BASE_DOMAIN_H diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Cartesian_grid_geometry.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Cartesian_grid_geometry.h index 0601a87292e..dd1d68a0564 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Cartesian_grid_geometry.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Cartesian_grid_geometry.h @@ -9,8 +9,8 @@ // // Author(s) : Julian Stahl -#ifndef CGAL_CARTESIAN_GRID_GEOMETRY_H -#define CGAL_CARTESIAN_GRID_GEOMETRY_H +#ifndef CGAL_ISOSURFACING_3_INTERNAL_CARTESIAN_GRID_GEOMETRY_H +#define CGAL_ISOSURFACING_3_INTERNAL_CARTESIAN_GRID_GEOMETRY_H #include @@ -22,32 +22,40 @@ namespace internal { // Describes the geometry of a regular cartesian grid. Positions are not stored but calculated // from an offset and grid spacing. -template -class Cartesian_grid_geometry { +template +class Cartesian_grid_geometry +{ public: - typedef GeomTraits Geom_traits; - typedef typename Geom_traits::Point_3 Point; - typedef typename Geom_traits::Vector_3 Vector; + using Geom_traits = GeomTraits; + using Point = typename Geom_traits::Point_3; + using Vector = typename Geom_traits::Vector_3; - typedef typename Grid_topology::Vertex_descriptor Vertex_descriptor; + using Vertex_descriptor = typename Grid_topology::Vertex_descriptor; public: - // Create a regular grid geometry where offset is the position of the vertex with index (0, 0, 0) - // and spacing the distance between two connected vertices in each dimension. - Cartesian_grid_geometry(const Vector& offset, const Vector& spacing) : offset(offset), spacing(spacing) {} + // Create a regular grid geometry where offset is the position of the vertex with index (0, 0, 0) + // and spacing the distance between two connected vertices in each dimension. + Cartesian_grid_geometry(const Vector& offset, + const Vector& spacing) + : offset(offset), + spacing(spacing) + { } - // Get the position of vertex v - Point operator()(const Vertex_descriptor& v) const { - return Point(v[0] * spacing[0], v[1] * spacing[1], v[2] * spacing[2]) + offset; - } + // Get the position of vertex v + Point operator()(const Vertex_descriptor& v) const + { + return Point(v[0] * spacing[0], + v[1] * spacing[1], + v[2] * spacing[2]) + offset; + } private: - Vector offset; - Vector spacing; + Vector offset; + Vector spacing; }; -} // namespace internal -} // namespace Isosurfacing -} // namespace CGAL +} // namespace internal +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_CARTESIAN_GRID_GEOMETRY_H +#endif // CGAL_ISOSURFACING_3_INTERNAL_CARTESIAN_GRID_GEOMETRY_H diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Cell_type.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Cell_type.h index bc7eb753307..a3245726483 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Cell_type.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Cell_type.h @@ -9,8 +9,8 @@ // // Author(s) : Julian Stahl -#ifndef CGAL_DOMAIN_CELL_TYPE -#define CGAL_DOMAIN_CELL_TYPE +#ifndef CGAL_ISOSURFACING_3_INTERNAL_DOMAIN_CELL_TYPE +#define CGAL_ISOSURFACING_3_INTERNAL_DOMAIN_CELL_TYPE #include @@ -19,17 +19,16 @@ namespace CGAL { namespace Isosurfacing { - // Was supposed to check if an algorithm can handle a specific domain. Not used right now. -typedef std::size_t Cell_type; +using Cell_type = std::size_t; static constexpr Cell_type ANY_CELL = (std::numeric_limits::max)(); -static constexpr Cell_type POLYHERDAL_CELL = ((Cell_type)1) << 0; -static constexpr Cell_type TETRAHEDRAL_CELL = ((Cell_type)1) << 1; -static constexpr Cell_type CUBICAL_CELL = ((Cell_type)1) << 2; +static constexpr Cell_type POLYHERDAL_CELL = (Cell_type(1) << 0); +static constexpr Cell_type TETRAHEDRAL_CELL = (Cell_type(1) << 1); +static constexpr Cell_type CUBICAL_CELL = (Cell_type(1) << 2); -} // namespace Isosurfacing -} // namespace CGAL +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_DOMAIN_CELL_TYPE \ No newline at end of file +#endif // CGAL_ISOSURFACING_3_INTERNAL_DOMAIN_CELL_TYPE \ No newline at end of file diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Dual_contouring_internal.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Dual_contouring_internal.h index 5630ed6eb7c..c081b476ce7 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Dual_contouring_internal.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Dual_contouring_internal.h @@ -10,16 +10,17 @@ // Author(s) : Daniel Zint // Julian Stahl -#ifndef CGAL_DUAL_CONTOURING_3_INTERNAL_DUAL_CONTOURING_3_H -#define CGAL_DUAL_CONTOURING_3_INTERNAL_DUAL_CONTOURING_3_H +#ifndef CGAL_ISOSURFACING_3_INTERNAL_DUAL_CONTOURING_INTERNAL_H +#define CGAL_ISOSURFACING_3_INTERNAL_DUAL_CONTOURING_INTERNAL_H #include #include -#include #include +#include #include + #include #include #include @@ -30,11 +31,12 @@ namespace Isosurfacing { namespace internal { namespace Positioning { + /** * \ingroup PkgIsosurfacing3Ref * - * \brief Computes the vertex position for a point in Dual Contouring using Quadric Error Metrics and the SVD pseudo - * inverse. + * \brief Computes the vertex position for a point in Dual Contouring + * using Quadric Error Metrics and the SVD pseudo inverse. * * \details * @@ -42,109 +44,120 @@ namespace Positioning { * */ template -class QEM_SVD { +class QEM_SVD +{ public: - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Computes the vertex position for a point in Dual Contouring. - * - * \details - * - * \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`. - * - * \param domain the domain providing input data and its topology - * \param isovalue value of the isosurface - * \param cell the cell within the domain for which the vertex position ins computed - * \param point the point position of the vertex that belongs to that cell - * - * \return true, if the voxel intersects the isosurface - */ - template - bool position(const Domain_& domain, const typename Domain_::FT isovalue, - const typename Domain_::Cell_descriptor& cell, typename Domain_::Point& point) const { - typedef typename Domain_::Point Point; - typedef typename Domain_::Geom_traits::Vector_3 Vector; - typedef typename Domain_::FT FT; + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Computes the vertex position for a point in Dual Contouring. + * + * \details + * + * \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`. + * + * \param domain the domain providing input data and its topology + * \param isovalue value of the isosurface + * \param cell the cell within the domain for which the vertex position ins computed + * \param point the point position of the vertex that belongs to that cell + * + * \return true, if the voxel intersects the isosurface + */ + template + bool position(const Domain_& domain, + const typename Domain_::FT isovalue, + const typename Domain_::Cell_descriptor& cell, + typename Domain_::Point& point) const + { + using Point = typename Domain_::Point; + using Vector = typename Domain_::Geom_traits::Vector_3; + using FT = typename Domain_::FT; - typename Domain_::Cell_vertices vertices = domain.cell_vertices(cell); + typename Domain_::Cell_vertices vertices = domain.cell_vertices(cell); - std::vector pos(vertices.size()); - std::transform(vertices.begin(), vertices.end(), pos.begin(), - [&](const auto& v) { return domain.position(v); }); + std::vector pos(vertices.size()); + std::transform(vertices.begin(), vertices.end(), pos.begin(), + [&](const auto& v) { return domain.position(v); }); - point = CGAL::centroid(pos.begin(), pos.end(), CGAL::Dimension_tag<0>()); // set point to cell center + // set point to cell center + point = CGAL::centroid(pos.begin(), pos.end(), CGAL::Dimension_tag<0>()); - // compute edge intersections - std::vector edge_intersections; - std::vector edge_intersection_normals; + // compute edge intersections + std::vector edge_intersections; + std::vector edge_intersection_normals; - for (const auto& edge : domain.cell_edges(cell)) { - const auto& edge_vertices = domain.edge_vertices(edge); - const auto& v0 = edge_vertices[0]; - const auto& v1 = edge_vertices[1]; + for(const auto& edge : domain.cell_edges(cell)) + { + const auto& edge_vertices = domain.edge_vertices(edge); + const auto& v0 = edge_vertices[0]; + const auto& v1 = edge_vertices[1]; - const auto& val0 = domain.value(v0); - const auto& val1 = domain.value(v1); + const auto& val0 = domain.value(v0); + const auto& val1 = domain.value(v1); - const auto& p0 = domain.position(v0); - const auto& p1 = domain.position(v1); + const auto& p0 = domain.position(v0); + const auto& p1 = domain.position(v1); - if ((val0 <= isovalue) != (val1 <= isovalue)) { // this edge is intersected by the isosurface - const FT u = (val0 - isovalue) / (val0 - val1); - const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN)); - edge_intersections.push_back(p_lerp); - edge_intersection_normals.push_back(domain.gradient(p_lerp)); - } - } - - if (edge_intersections.empty()) { - return false; - } - - // SVD QEM - Eigen::Matrix3d A; - A.setZero(); - Eigen::Vector3d rhs; - rhs.setZero(); - for (std::size_t i = 0; i < edge_intersections.size(); ++i) { - Eigen::Vector3d n_k = {edge_intersection_normals[i].x(), edge_intersection_normals[i].y(), - edge_intersection_normals[i].z()}; - Eigen::Vector3d p_k = {edge_intersections[i].x(), edge_intersections[i].y(), edge_intersections[i].z()}; - double d_k = n_k.transpose() * p_k; - - Eigen::Matrix3d A_k = n_k * n_k.transpose(); - Eigen::Vector3d b_k = d_k * n_k; - A += A_k; - rhs += b_k; - } - - Eigen::JacobiSVD svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV); - // set threshold as in Peter Lindstrom's paper, "Out-of-Core - // Simplification of Large Polygonal Models" - svd.setThreshold(1e-3); - - // Init x hat - Eigen::Vector3d x_hat; - x_hat << point.x(), point.y(), point.z(); - - // Lindstrom formula for QEM new position for singular matrices - Eigen::VectorXd v_svd = x_hat + svd.solve(rhs - A * x_hat); - - point = Point(v_svd[0], v_svd[1], v_svd[2]); - - // bbox - if (use_bbox) { - CGAL::Bbox_3 bbox = pos[0].bbox() + pos[7].bbox(); // TODO remove[0],[7] - - FT x = (std::min)((std::max)(point.x(), bbox.xmin()), bbox.xmax()); - FT y = (std::min)((std::max)(point.y(), bbox.ymin()), bbox.ymax()); - FT z = (std::min)((std::max)(point.z(), bbox.zmin()), bbox.zmax()); - point = Point(x, y, z); - } - - return true; + if((val0 <= isovalue) != (val1 <= isovalue)) + { + // this edge is intersected by the isosurface + const FT u = (val0 - isovalue) / (val0 - val1); + const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN)); + edge_intersections.push_back(p_lerp); + edge_intersection_normals.push_back(domain.gradient(p_lerp)); + } } + + if(edge_intersections.empty()) + return false; + + // SVD QEM + Eigen::Matrix3d A; + A.setZero(); + Eigen::Vector3d rhs; + rhs.setZero(); + for(std::size_t i=0; i svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV); + // set threshold as in Peter Lindstrom's paper, "Out-of-Core Simplification of Large Polygonal Models" + svd.setThreshold(1e-3); + + // Init x hat + Eigen::Vector3d x_hat; + x_hat << point.x(), point.y(), point.z(); + + // Lindstrom formula for QEM new position for singular matrices + Eigen::VectorXd v_svd = x_hat + svd.solve(rhs - A * x_hat); + + point = Point(v_svd[0], v_svd[1], v_svd[2]); + + // bbox + if(use_bbox) + { + CGAL::Bbox_3 bbox = pos[0].bbox() + pos[7].bbox(); // TODO remove[0],[7] + + FT x = (std::min)((std::max)(point.x(), bbox.xmin()), bbox.xmax()); + FT y = (std::min)((std::max)(point.y(), bbox.ymin()), bbox.ymax()); + FT z = (std::min)((std::max)(point.z(), bbox.zmin()), bbox.zmax()); + point = Point(x, y, z); + } + + return true; + } }; /** @@ -152,53 +165,59 @@ public: * * \brief Returns cell center. */ -class Cell_center { +class Cell_center +{ public: - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Computes the vertex position for a point in Dual Contouring. - * - * \details - * - * \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`. - * - * \param domain the domain providing input data and its topology - * \param isovalue value of the isosurface - * \param cell the cell within the domain for which the vertex position ins computed - * \param point the point position of the vertex that belongs to that cell - * - * \return true, if the voxel intersects the isosurface - */ - template - bool position(const Domain_& domain, const typename Domain_::FT isovalue, - const typename Domain_::Cell_descriptor& vh, typename Domain_::Point& point) const { - typedef typename Domain_::Point Point; - typedef typename Domain_::Geom_traits::Vector_3 Vector; - typedef typename Domain_::FT FT; + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Computes the vertex position for a point in Dual Contouring. + * + * \details + * + * \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`. + * + * \param domain the domain providing input data and its topology + * \param isovalue value of the isosurface + * \param cell the cell within the domain for which the vertex position ins computed + * \param point the point position of the vertex that belongs to that cell + * + * \return true, if the voxel intersects the isosurface + */ + template + bool position(const Domain_& domain, + const typename Domain_::FT isovalue, + const typename Domain_::Cell_descriptor& vh, + typename Domain_::Point& point) const + { + using Point = typename Domain_::Point; + using Vector = typename Domain_::Geom_traits::Vector_3; + using FT = typename Domain_::FT; - typename Domain_::Cell_vertices vertices = domain.cell_vertices(vh); + typename Domain_::Cell_vertices vertices = domain.cell_vertices(vh); - std::vector pos(vertices.size()); - std::transform(vertices.begin(), vertices.end(), pos.begin(), - [&](const auto& v) { return domain.position(v); }); + std::vector pos(vertices.size()); + std::transform(vertices.begin(), vertices.end(), pos.begin(), + [&](const auto& v) { return domain.position(v); }); - point = CGAL::centroid(pos.begin(), pos.end(), CGAL::Dimension_tag<0>()); // set point to cell center + // set point to cell center + point = CGAL::centroid(pos.begin(), pos.end(), CGAL::Dimension_tag<0>()); - bool allSmaller = true; - bool allGreater = true; - for (const auto& v : vertices) { - const bool& b = domain.value(v) <= isovalue; - allSmaller = allSmaller && b; - allGreater = allGreater && !b; - } - - if (allSmaller || allGreater) { - return false; - } - - return true; + bool allSmaller = true; + bool allGreater = true; + for(const auto& v : vertices) + { + const bool& b = domain.value(v) <= isovalue; + allSmaller = allSmaller && b; + allGreater = allGreater && !b; } + + if(allSmaller || allGreater) + return false; + + + return true; + } }; /** @@ -206,146 +225,170 @@ public: * * \brief Computes the centroid of all cell edge intersections with the isosurface. */ -class Centroid_of_edge_intersections { +class Centroid_of_edge_intersections +{ public: - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Computes the vertex position for a point in Dual Contouring. - * - * \details - * - * \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`. - * - * \param domain the domain providing input data and its topology - * \param isovalue value of the isosurface - * \param cell the cell within the domain for which the vertex position ins computed - * \param point the point position of the vertex that belongs to that cell - * - * \return true, if the voxel intersects the isosurface - */ - template - bool position(const Domain_& domain, const typename Domain_::FT isovalue, - const typename Domain_::Cell_descriptor& cell, typename Domain_::Point& point) const { - typedef typename Domain_::Point Point; - typedef typename Domain_::Geom_traits::Vector_3 Vector; - typedef typename Domain_::FT FT; + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Computes the vertex position for a point in Dual Contouring. + * + * \details + * + * \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`. + * + * \param domain the domain providing input data and its topology + * \param isovalue value of the isosurface + * \param cell the cell within the domain for which the vertex position ins computed + * \param point the point position of the vertex that belongs to that cell + * + * \return true, if the voxel intersects the isosurface + */ + template + bool position(const Domain_& domain, + const typename Domain_::FT isovalue, + const typename Domain_::Cell_descriptor& cell, + typename Domain_::Point& point) const + { + using Point = typename Domain_::Point; + using Vector = typename Domain_::Geom_traits::Vector_3; + using FT = typename Domain_::FT; - typename Domain_::Cell_vertices vertices = domain.cell_vertices(cell); + typename Domain_::Cell_vertices vertices = domain.cell_vertices(cell); - // compute edge intersections - std::vector edge_intersections; + // compute edge intersections + std::vector edge_intersections; - for (const auto& edge : domain.cell_edges(cell)) { - const auto& edge_vertices = domain.edge_vertices(edge); - const auto& v0 = edge_vertices[0]; - const auto& v1 = edge_vertices[1]; + for(const auto& edge : domain.cell_edges(cell)) + { + const auto& edge_vertices = domain.edge_vertices(edge); + const auto& v0 = edge_vertices[0]; + const auto& v1 = edge_vertices[1]; - const auto& val0 = domain.value(v0); - const auto& val1 = domain.value(v1); + const auto& val0 = domain.value(v0); + const auto& val1 = domain.value(v1); - const auto& p0 = domain.position(v0); - const auto& p1 = domain.position(v1); + const auto& p0 = domain.position(v0); + const auto& p1 = domain.position(v1); - if ((val0 <= isovalue) != (val1 <= isovalue)) { // this edge is intersected by the isosurface - const FT u = (val0 - isovalue) / (val0 - val1); - const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN)); - edge_intersections.push_back(p_lerp); - } - } - - if (edge_intersections.empty()) { - return false; - } - - point = CGAL::centroid(edge_intersections.begin(), edge_intersections.end(), - CGAL::Dimension_tag<0>()); // set point to center of edge intersections - - return true; + if((val0 <= isovalue) != (val1 <= isovalue)) + { + // this edge is intersected by the isosurface + const FT u = (val0 - isovalue) / (val0 - val1); + const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN)); + edge_intersections.push_back(p_lerp); + } } -}; -} // namespace Positioning -template -class Dual_contouring_vertex_positioning { + if(edge_intersections.empty()) + return false; + + point = CGAL::centroid(edge_intersections.begin(), edge_intersections.end(), + CGAL::Dimension_tag<0>()); // set point to center of edge intersections + + return true; + } +}; + +} // namespace Positioning + +template +class Dual_contouring_vertex_positioning +{ private: - typedef Domain_ Domain; - typedef Positioning_ Positioning; + using Domain = Domain_; + using Positioning = Positioning_; - typedef typename Domain::FT FT; - typedef typename Domain::Point Point; - typedef typename Domain::Cell_descriptor Cell_descriptor; + using FT = typename Domain::FT; + using Point = typename Domain::Point; + using Cell_descriptor = typename Domain::Cell_descriptor; public: - Dual_contouring_vertex_positioning(const Domain& domain, FT isovalue, const Positioning& positioning) - : domain(domain), isovalue(isovalue), positioning(positioning), points_counter(0) {} + Dual_contouring_vertex_positioning(const Domain& domain, + const FT isovalue, + const Positioning& positioning) + : domain(domain), + isovalue(isovalue), + positioning(positioning), + points_counter(0) + { } - void operator()(const Cell_descriptor& v) { - // compute dc-vertices - Point p; - if (positioning.position(domain, isovalue, v, p)) { - - std::lock_guard lock(mutex); - map_voxel_to_point[v] = p; - map_voxel_to_point_id[v] = points_counter++; - } + void operator()(const Cell_descriptor& v) + { + // compute dc-vertices + Point p; + if(positioning.position(domain, isovalue, v, p)) + { + std::lock_guard lock(mutex); + map_voxel_to_point[v] = p; + map_voxel_to_point_id[v] = points_counter++; } + } - // private: - const Domain& domain; - FT isovalue; - const Positioning& positioning; + // private: // @todo + const Domain& domain; + FT isovalue; + const Positioning& positioning; - std::map map_voxel_to_point_id; - std::map map_voxel_to_point; - std::size_t points_counter; + std::map map_voxel_to_point_id; + std::map map_voxel_to_point; + std::size_t points_counter; - std::mutex mutex; + std::mutex mutex; }; -template -class Dual_contouring_face_generation { +template +class Dual_contouring_face_generation +{ private: - typedef Domain_ Domain; + using Domain = Domain_; - typedef typename Domain_::FT FT; - typedef typename Domain_::Edge_descriptor Edge_descriptor; - typedef typename Domain_::Cell_descriptor Cell_descriptor; + using FT = typename Domain_::FT; + using Edge_descriptor = typename Domain_::Edge_descriptor; + using Cell_descriptor = typename Domain_::Cell_descriptor; public: - Dual_contouring_face_generation(const Domain& domain, FT isovalue) : domain(domain), isovalue(isovalue) {} + Dual_contouring_face_generation(const Domain& domain, + FT isovalue) + : domain(domain), + isovalue(isovalue) + { } - void operator()(const Edge_descriptor& e) { - // save all faces - const auto& vertices = domain.edge_vertices(e); - const FT s0 = domain.value(vertices[0]); - const FT s1 = domain.value(vertices[1]); + void operator()(const Edge_descriptor& e) + { + // save all faces + const auto& vertices = domain.edge_vertices(e); + const FT s0 = domain.value(vertices[0]); + const FT s1 = domain.value(vertices[1]); - if (s0 <= isovalue && s1 > isovalue) { - const auto& voxels = domain.cells_incident_to_edge(e); + if(s0 <= isovalue && s1 > isovalue) + { + const auto& voxels = domain.cells_incident_to_edge(e); - std::lock_guard lock(mutex); - faces[e].insert(faces[e].begin(), voxels.begin(), voxels.end()); - - } else if (s1 <= isovalue && s0 > isovalue) { - const auto& voxels = domain.cells_incident_to_edge(e); - - std::lock_guard lock(mutex); - faces[e].insert(faces[e].begin(), voxels.rbegin(), voxels.rend()); - } + std::lock_guard lock(mutex); + faces[e].insert(faces[e].begin(), voxels.begin(), voxels.end()); } + else if(s1 <= isovalue && s0 > isovalue) + { + const auto& voxels = domain.cells_incident_to_edge(e); - // private: - std::map> faces; + std::lock_guard lock(mutex); + faces[e].insert(faces[e].begin(), voxels.rbegin(), voxels.rend()); + } + } - const Domain& domain; - FT isovalue; + // private: // @todo + std::map> faces; - std::mutex mutex; + const Domain& domain; + FT isovalue; + + std::mutex mutex; }; -} // namespace internal -} // namespace Isosurfacing -} // namespace CGAL +} // namespace internal +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_DUAL_CONTOURING_3_INTERNAL_DUAL_CONTOURING_3_H +#endif // CGAL_ISOSURFACING_3_INTERNAL_DUAL_CONTOURING_INTERNAL_H diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Grid_topology.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Grid_topology.h index 00ba0def2e0..9ff322cfb5d 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Grid_topology.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Grid_topology.h @@ -9,8 +9,8 @@ // // Author(s) : Julian Stahl -#ifndef CGAL_GRID_TOPOLOGY_H -#define CGAL_GRID_TOPOLOGY_H +#ifndef CGAL_ISOSURFACING_3_INTERNAL_GRID_TOPOLOGY_H +#define CGAL_ISOSURFACING_3_INTERNAL_GRID_TOPOLOGY_H #include @@ -22,197 +22,214 @@ #ifdef CGAL_LINKED_WITH_TBB #include -#endif // CGAL_LINKED_WITH_TBB +#endif // CGAL_LINKED_WITH_TBB namespace CGAL { namespace Isosurfacing { namespace internal { // The topology of a cartesian grid. All elements are created with the help of the cube tables. -class Grid_topology { +class Grid_topology +{ public: - // identify a vertex by its (i, j, k) indices - typedef std::array Vertex_descriptor; - // identify an edge by its starting vertex (i, j, k) and the direction x -> 0, y -> 1, z -> 2 - typedef std::array Edge_descriptor; - // identify a cell by its corner vertex with the smallest (i, j, k) index - typedef std::array Cell_descriptor; + // identify a vertex by its (i, j, k) indices + using Vertex_descriptor = std::array; + // identify an edge by its starting vertex (i, j, k) and the direction x -> 0, y -> 1, z -> 2 + using Edge_descriptor = std::array; + // identify a cell by its corner vertex with the smallest (i, j, k) index + using Cell_descriptor = std::array; - static constexpr Cell_type CELL_TYPE = CUBICAL_CELL; - static constexpr std::size_t VERTICES_PER_CELL = 8; - static constexpr std::size_t EDGES_PER_CELL = 12; + static constexpr Cell_type CELL_TYPE = CUBICAL_CELL; + static constexpr std::size_t VERTICES_PER_CELL = 8; + static constexpr std::size_t EDGES_PER_CELL = 12; - typedef std::array Vertices_incident_to_edge; - typedef std::array Cells_incident_to_edge; - typedef std::array Cell_vertices; - typedef std::array Cell_edges; + using Vertices_incident_to_edge = std::array; + using Cells_incident_to_edge = std::array; + using Cell_vertices = std::array; + using Cell_edges = std::array; public: - // Create the topology of a grid with size_i, size_j, and size_k vertices in the respective dimensions. - Grid_topology(const std::size_t size_i, const std::size_t size_j, const std::size_t size_k) - : size_i(size_i), size_j(size_j), size_k(size_k) {} + // Create the topology of a grid with size_i, size_j, and size_k vertices in the respective dimensions. + Grid_topology(const std::size_t size_i, + const std::size_t size_j, + const std::size_t size_k) + : size_i(size_i), + size_j(size_j), + size_k(size_k) + { } - // Get a container with the two vertices incident to the edge e - Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const { - Vertices_incident_to_edge ev; - ev[0] = {e[0], e[1], e[2]}; // start vertex - ev[1] = {e[0], e[1], e[2]}; // end vertex - ev[1][e[3]] += 1; // one position further in the direction of the edge - return ev; + // Get a container with the two vertices incident to the edge e + Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const + { + Vertices_incident_to_edge ev; + ev[0] = { e[0], e[1], e[2] }; // start vertex + ev[1] = { e[0], e[1], e[2] }; // end vertex + ev[1][e[3]] += 1; // one position further in the direction of the edge + return ev; + } + + // Get a container with all cells incident to the edge e + Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const + { + // lookup the neighbor cells relative to the edge + const int local = internal::Cube_table::edge_store_index[e[3]]; + auto neighbors = internal::Cube_table::edge_to_voxel_neighbor[local]; + + Cells_incident_to_edge cite; + for(std::size_t i=0; i + void iterate_vertices(Functor& f, Sequential_tag) const + { + for(std::size_t i=0; i + void iterate_edges(Functor& f, Sequential_tag) const + { + for(std::size_t i=0; i - void iterate_vertices(Functor& f, Sequential_tag) const { - for (std::size_t i = 0; i < size_i; i++) { - for (std::size_t j = 0; j < size_j; j++) { - for (std::size_t k = 0; k < size_k; k++) { - f({i, j, k}); - } - } - } - } - - // Iterate sequentially over all edges e calling f(e) on every one - template - void iterate_edges(Functor& f, Sequential_tag) const { - for (std::size_t i = 0; i < size_i - 1; i++) { - for (std::size_t j = 0; j < size_j - 1; j++) { - for (std::size_t k = 0; k < size_k - 1; k++) { - // all three edges starting at vertex (i, j, k) - f({i, j, k, 0}); - f({i, j, k, 1}); - f({i, j, k, 2}); - } - } - } - } - - // Iterate sequentially over all cells c calling f(c) on every one - template - void iterate_cells(Functor& f, Sequential_tag) const { - for (std::size_t i = 0; i < size_i - 1; i++) { - for (std::size_t j = 0; j < size_j - 1; j++) { - for (std::size_t k = 0; k < size_k - 1; k++) { - f({i, j, k}); - } - } - } - } + // Iterate sequentially over all cells c calling f(c) on every one + template + void iterate_cells(Functor& f, Sequential_tag) const + { + for(std::size_t i=0; i - void iterate_vertices(Functor& f, Parallel_tag) const { - const std::size_t sj = size_j; - const std::size_t sk = size_k; + // Iterate in parallel over all vertices v calling f(v) on every one + template + void iterate_vertices(Functor& f, Parallel_tag) const + { + const std::size_t sj = size_j; + const std::size_t sk = size_k; - // for now only parallelize outer loop - auto iterator = [&f, sj, sk](const tbb::blocked_range& r) { - for (std::size_t i = r.begin(); i != r.end(); i++) { - for (std::size_t j = 0; j < sj; j++) { - for (std::size_t k = 0; k < sk; k++) { - f({i, j, k}); - } - } - } - }; + // for now only parallelize outer loop + auto iterator = [&f, sj, sk](const tbb::blocked_range& r) + { + for(std::size_t i = r.begin(); i != r.end(); ++i) + for(std::size_t j=0; j(0, size_i), iterator); - } + tbb::parallel_for(tbb::blocked_range(0, size_i), iterator); + } - // Iterate in parallel over all edges e calling f(e) on every one - template - void iterate_edges(Functor& f, Parallel_tag) const { - const std::size_t sj = size_j; - const std::size_t sk = size_k; + // Iterate in parallel over all edges e calling f(e) on every one + template + void iterate_edges(Functor& f, Parallel_tag) const + { + const std::size_t sj = size_j; + const std::size_t sk = size_k; - // for now only parallelize outer loop - auto iterator = [&f, sj, sk](const tbb::blocked_range& r) { - for (std::size_t i = r.begin(); i != r.end(); i++) { - for (std::size_t j = 0; j < sj - 1; j++) { - for (std::size_t k = 0; k < sk - 1; k++) { - f({i, j, k, 0}); - f({i, j, k, 1}); - f({i, j, k, 2}); - } - } - } - }; + // for now only parallelize outer loop + auto iterator = [&f, sj, sk](const tbb::blocked_range& r) + { + for(std::size_t i = r.begin(); i != r.end(); ++i) { + for(std::size_t j=0; j(0, size_i - 1), iterator); - } + tbb::parallel_for(tbb::blocked_range(0, size_i - 1), iterator); + } - // Iterate in parallel over all cells c calling f(c) on every one - template - void iterate_cells(Functor& f, Parallel_tag) const { - const std::size_t sj = size_j; - const std::size_t sk = size_k; + // Iterate in parallel over all cells c calling f(c) on every one + template + void iterate_cells(Functor& f, Parallel_tag) const + { + const std::size_t sj = size_j; + const std::size_t sk = size_k; - // for now only parallelize outer loop - auto iterator = [&f, sj, sk](const tbb::blocked_range& r) { - for (std::size_t i = r.begin(); i != r.end(); i++) { - for (std::size_t j = 0; j < sj - 1; j++) { - for (std::size_t k = 0; k < sk - 1; k++) { - f({i, j, k}); - } - } - } - }; + // for now only parallelize outer loop + auto iterator = [&f, sj, sk](const tbb::blocked_range& r) { + for(std::size_t i = r.begin(); i != r.end(); ++i) + for(std::size_t j=0; j(0, size_i - 1), iterator); - } -#endif // CGAL_LINKED_WITH_TBB + tbb::parallel_for(tbb::blocked_range(0, size_i - 1), iterator); + } +#endif // CGAL_LINKED_WITH_TBB private: - std::size_t size_i; - std::size_t size_j; - std::size_t size_k; + std::size_t size_i; + std::size_t size_j; + std::size_t size_k; }; -} // namespace internal -} // namespace Isosurfacing -} // namespace CGAL +} // namespace internal +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_GRID_TOPOLOGY_H +#endif // CGAL_ISOSURFACING_3_INTERNAL_GRID_TOPOLOGY_H diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Implicit_function_with_geometry.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Implicit_function_with_geometry.h index a6871a4e865..c8f023c8d3a 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Implicit_function_with_geometry.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Implicit_function_with_geometry.h @@ -9,8 +9,8 @@ // // Author(s) : Julian Stahl -#ifndef CGAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H -#define CGAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H +#ifndef CGAL_ISOSURFACING_3_INTERNAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H +#define CGAL_ISOSURFACING_3_INTERNAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H #include @@ -23,32 +23,40 @@ namespace internal { // Wrapper for an implicit function that can only be evaluated at a position and not at a vertex. // Evaluates the geometry to get the vertex position and passes that to the function. // Works for all VertexDescriptor types. -template -class Implicit_function_with_geometry { +template +class Implicit_function_with_geometry +{ public: - typedef GeomTraits Geom_traits; - typedef typename Geom_traits::FT FT; + using Geom_traits = GeomTraits; + using FT = typename Geom_traits::FT; - typedef std::shared_ptr Geometry; - typedef std::shared_ptr Point_function; + using Geometry = std::shared_ptr; + using Point_function = std::shared_ptr; public: - // Create a function that uses the geometry to evaluate the function at vertex positions. - Implicit_function_with_geometry(const Geometry& geom, const Point_function& func) : geom(geom), func(func) {} + // Create a function that uses the geometry to evaluate the function at vertex positions. + Implicit_function_with_geometry(const Geometry& geom, + const Point_function& func) + : geom(geom), + func(func) + { } - // Get the value of the function at vertex v - template - FT operator()(const VertexDescriptor& v) const { - return func->operator()(geom->operator()(v)); - } + // Get the value of the function at vertex v + template + FT operator()(const VertexDescriptor& v) const + { + return func->operator()(geom->operator()(v)); + } private: - const Geometry geom; - const Point_function func; + const Geometry geom; + const Point_function func; }; -} // namespace internal -} // namespace Isosurfacing -} // namespace CGAL +} // namespace internal +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H +#endif // CGAL_ISOSURFACING_3_INTERNAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Marching_cubes_3_internal.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Marching_cubes_3_internal.h index c77c6ff984c..2e60a82f135 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Marching_cubes_3_internal.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Marching_cubes_3_internal.h @@ -38,12 +38,13 @@ // https://github.com/rogrosso/tmc available on 15th of September 2022. // -#ifndef CGAL_MARCHING_CUBES_3_INTERNAL_MARCHING_CUBES_3_H -#define CGAL_MARCHING_CUBES_3_INTERNAL_MARCHING_CUBES_3_H +#ifndef CGAL_ISOSURFACING_3_INTERNAL_MARCHING_CUBES_3_INTERNAL_H +#define CGAL_ISOSURFACING_3_INTERNAL_MARCHING_CUBES_3_INTERNAL_H #include #include + #ifdef CGAL_LINKED_WITH_TBB #include #else @@ -61,164 +62,203 @@ namespace Isosurfacing { namespace internal { // Interpolate linearly between two vertex positions v0, v1 with values d0 and d1 according to the isovalue -template -Point_3 vertex_interpolation(const Point_3& p0, const Point_3& p1, const FT d0, const FT d1, const FT isovalue) { +template +Point_3 vertex_interpolation(const Point_3& p0, + const Point_3& p1, + const FT d0, + const FT d1, + const FT isovalue) +{ + FT mu; - FT mu; + // don't divide by 0 + if(abs(d1 - d0) < 0.000001) // @todo + mu = 0.5; // if both points have the same value, assume isolevel is in the middle + else + mu = (isovalue - d0) / (d1 - d0); - // don't divide by 0 - if (abs(d1 - d0) < 0.000001) { - mu = 0.5; // if both points have the same value, assume isolevel is in the middle - } else { - mu = (isovalue - d0) / (d1 - d0); - } + assert(mu >= 0.0 || mu <= 1.0); - assert(mu >= 0.0 || mu <= 1.0); - - // linear interpolation - return Point_3(p1.x() * mu + p0.x() * (1 - mu), p1.y() * mu + p0.y() * (1 - mu), p1.z() * mu + p0.z() * (1 - mu)); + // linear interpolation + return { p1.x() * mu + p0.x() * (1 - mu), + p1.y() * mu + p0.y() * (1 - mu), + p1.z() * mu + p0.z() * (1 - mu) }; } // Retrieve the corner vertices and their values of a cell and return the lookup index -template -std::size_t get_cell_corners(const Domain_& domain, const typename Domain_::Cell_descriptor& cell, - const typename Domain_::FT isovalue, Corners_& corners, Values_& values) { +template +std::size_t get_cell_corners(const Domain_& domain, + const typename Domain_::Cell_descriptor& cell, + const typename Domain_::FT isovalue, + Corners_& corners, + Values_& values) +{ + using Vertex_descriptor = typename Domain_::Vertex_descriptor; - typedef typename Domain_::Vertex_descriptor Vertex_descriptor; + // collect function values and build index + std::size_t v_id = 0; + std::bitset index = 0; + for(const Vertex_descriptor& v : domain.cell_vertices(cell)) + { + // collect scalar values and computex index + corners[v_id] = domain.position(v); + values[v_id] = domain.value(v); - // collect function values and build index - std::size_t v_id = 0; - std::bitset index = 0; - for (const Vertex_descriptor& v : domain.cell_vertices(cell)) { - // collect scalar values and computex index - corners[v_id] = domain.position(v); - values[v_id] = domain.value(v); + if(values[v_id] >= isovalue) + index.set(v_id); - if (values[v_id] >= isovalue) { - index.set(v_id); - } - // next cell vertex - v_id++; - } + // next cell vertex + ++v_id; + } - return static_cast(index.to_ullong()); + return static_cast(index.to_ullong()); } // Create the vertices on the edges of one cell -template -void mc_construct_vertices(const CellEdges& cell_edges, const FT isovalue, const std::size_t i_case, - const Corners_& corners, const Values_& values, Vertices_& vertices) { +template +void mc_construct_vertices(const CellEdges& cell_edges, + const FT isovalue, + const std::size_t i_case, + const Corners_& corners, + const Values_& values, + Vertices_& vertices) + { + // compute for this case the vertices + std::size_t flag = 1; + std::size_t e_id = 0; - // compute for this case the vertices - std::size_t flag = 1; - std::size_t e_id = 0; + for(const auto& edge : cell_edges) + { + (void)edge; // @todo - for (const auto& edge : cell_edges) { - (void)edge; // TODO + if(flag & Cube_table::intersected_edges[i_case]) + { + // generate vertex here, do not care at this point if vertex already exist - if (flag & Cube_table::intersected_edges[i_case]) { + const int v0 = Cube_table::edge_to_vertex[e_id][0]; + const int v1 = Cube_table::edge_to_vertex[e_id][1]; - // generate vertex here, do not care at this point if vertex already exist - - const int v0 = Cube_table::edge_to_vertex[e_id][0]; - const int v1 = Cube_table::edge_to_vertex[e_id][1]; - - vertices[e_id] = vertex_interpolation(corners[v0], corners[v1], values[v0], values[v1], isovalue); - } - flag <<= 1; - e_id++; + vertices[e_id] = vertex_interpolation(corners[v0], corners[v1], values[v0], values[v1], isovalue); } + + flag <<= 1; + ++e_id; + } } // Connect the vertices of one cell to form triangles -template -void mc_construct_triangles(const int i_case, const Vertices_& vertices, TriangleList& triangles) { - // construct triangles - for (int t = 0; t < 16; t += 3) { +template +void mc_construct_triangles(const int i_case, + const Vertices_& vertices, + TriangleList& triangles) +{ + // construct triangles + for(int t=0; t<16; t+=3) + { + const int t_index = i_case * 16 + t; - const int t_index = i_case * 16 + t; - // if (e_tris_list[t_index] == 0x7f) - if (Cube_table::triangle_cases[t_index] == -1) break; + // if(e_tris_list[t_index] == 0x7f) + if(Cube_table::triangle_cases[t_index] == -1) + break; - const int eg0 = Cube_table::triangle_cases[t_index + 0]; // TODO: move more of this stuff into the table - const int eg1 = Cube_table::triangle_cases[t_index + 1]; - const int eg2 = Cube_table::triangle_cases[t_index + 2]; + const int eg0 = Cube_table::triangle_cases[t_index + 0]; // TODO: move more of this stuff into the table + const int eg1 = Cube_table::triangle_cases[t_index + 1]; + const int eg2 = Cube_table::triangle_cases[t_index + 2]; - // insert new triangle in list - triangles.push_back({vertices[eg0], vertices[eg1], vertices[eg2]}); - } + // insert new triangle in list + triangles.push_back({vertices[eg0], vertices[eg1], vertices[eg2]}); + } } // Convert the triangle list to an indexed face set -template -void to_indexed_face_set(const TriangleList& triangle_list, PointRange& points, PolygonRange& polygons) { - for (auto& triangle : triangle_list) { - const std::size_t id = points.size(); +template +void to_indexed_face_set(const TriangleList& triangle_list, + PointRange& points, + PolygonRange& polygons) +{ + for(auto& triangle : triangle_list) + { + const std::size_t id = points.size(); - points.push_back(triangle[0]); - points.push_back(triangle[1]); - points.push_back(triangle[2]); + points.push_back(triangle[0]); + points.push_back(triangle[1]); + points.push_back(triangle[2]); - // simply use increasing indices - polygons.push_back({id + 2, id + 1, id + 0}); - } + // simply use increasing indices + polygons.push_back({id + 2, id + 1, id + 0}); + } } // Marching Cubes implemented as a functor that runs on every cell of the grid -template -class Marching_cubes_3 { +template +class Marching_cubes_3 +{ private: - typedef Domain_ Domain; - typedef typename Domain::FT FT; - typedef typename Domain::Point Point; - typedef typename Domain::Cell_descriptor Cell_descriptor; + using Domain = Domain_; + using FT = typename Domain::FT; + using Point = typename Domain::Point; + using Cell_descriptor = typename Domain::Cell_descriptor; #ifdef CGAL_LINKED_WITH_TBB - typedef tbb::concurrent_vector> Triangle_list; + using Triangle_list = tbb::concurrent_vector >; #else - typedef std::vector> Triangle_list; + using Triangle_list = std::vector >; #endif public: - // Create a Marching Cubes functor for a domain and iso value - Marching_cubes_3(const Domain& domain, const FT isovalue) : domain(domain), isovalue(isovalue) {} + // Create a Marching Cubes functor for a domain and iso value + Marching_cubes_3(const Domain& domain, + const FT isovalue) + : domain(domain), + isovalue(isovalue) + { } - // Compute one cell - void operator()(const Cell_descriptor& cell) { + // Compute one cell + void operator()(const Cell_descriptor& cell) + { + // @todo: maybe better checks if the domain can be processed? + assert(domain.cell_vertices(cell).size() == 8); + assert(domain.cell_edges(cell).size() == 12); - // TODO: maybe better checks if the domain can be processed? - assert(domain.cell_vertices(cell).size() == 8); - assert(domain.cell_edges(cell).size() == 12); + FT values[8]; + Point corners[8]; + const int i_case = get_cell_corners(domain, cell, isovalue, corners, values); - FT values[8]; - Point corners[8]; - const int i_case = get_cell_corners(domain, cell, isovalue, corners, values); + const int all_bits_set = (1 << (8 + 1)) - 1; // last 8 bits are 1 + if(i_case == 0 || i_case == all_bits_set) + return; // skip empty cells - const int all_bits_set = (1 << (8 + 1)) - 1; // last 8 bits are 1 - if (i_case == 0 || i_case == all_bits_set) { - return; // skip empty cells - } + std::array vertices; + mc_construct_vertices(domain.cell_edges(cell), isovalue, i_case, corners, values, vertices); - std::array vertices; - mc_construct_vertices(domain.cell_edges(cell), isovalue, i_case, corners, values, vertices); + mc_construct_triangles(i_case, vertices, triangle_list); + } - mc_construct_triangles(i_case, vertices, triangle_list); - } - - // Get the created triangle list - const Triangle_list& triangles() const { - return triangle_list; - } + // Get the created triangle list + const Triangle_list& triangles() const + { + return triangle_list; + } private: - const Domain& domain; - FT isovalue; + const Domain& domain; + FT isovalue; - Triangle_list triangle_list; + Triangle_list triangle_list; }; -} // namespace internal -} // namespace Isosurfacing -} // namespace CGAL +} // namespace internal +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_MARCHING_CUBES_3_INTERNAL_MARCHING_CUBES_3_H +#endif // CGAL_ISOSURFACING_3_INTERNAL_MARCHING_CUBES_3_INTERNAL_H diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Octree_geometry.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Octree_geometry.h index 8cd2d8c77cb..a91b58ae495 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Octree_geometry.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Octree_geometry.h @@ -9,8 +9,8 @@ // // Author(s) : Julian Stahl -#ifndef CGAL_OCTREE_GEOMETRY_H -#define CGAL_OCTREE_GEOMETRY_H +#ifndef CGAL_ISOSURFACING_3_INTERNAL_OCTREE_GEOMETRY_H +#define CGAL_ISOSURFACING_3_INTERNAL_OCTREE_GEOMETRY_H #include @@ -23,29 +23,33 @@ namespace CGAL { namespace Isosurfacing { namespace internal { -template -class Octree_geometry { +template +class Octree_geometry +{ public: - typedef GeomTraits Geom_traits; - typedef typename Geom_traits::Point_3 Point; + using Geom_traits = GeomTraits; + using Point = typename Geom_traits::Point_3; - typedef std::shared_ptr> Octree; + using Octree = std::shared_ptr >; - typedef typename Octree_topology::Vertex_descriptor Vertex_descriptor; + using Vertex_descriptor = typename Octree_topology::Vertex_descriptor; public: - Octree_geometry(const Octree& octree) : octree(octree) {} + Octree_geometry(const Octree& octree) + : octree(octree) + { } - Point operator()(const Vertex_descriptor& v) const { - return octree->point(v); - } + Point operator()(const Vertex_descriptor& v) const + { + return octree->point(v); + } private: - const Octree octree; + const Octree octree; }; -} // namespace internal -} // namespace Isosurfacing -} // namespace CGAL +} // namespace internal +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_OCTREE_GEOMETRY_H +#endif // CGAL_ISOSURFACING_3_INTERNAL_OCTREE_GEOMETRY_H diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Octree_topology.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Octree_topology.h index 32e6f80002b..0621122d113 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Octree_topology.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Octree_topology.h @@ -9,8 +9,8 @@ // // Author(s) : Julian Stahl -#ifndef CGAL_OCTREE_TOPOLOGY_H -#define CGAL_OCTREE_TOPOLOGY_H +#ifndef CGAL_ISOSURFACING_3_INTERNAL_OCTREE_TOPOLOGY_H +#define CGAL_ISOSURFACING_3_INTERNAL_OCTREE_TOPOLOGY_H #include @@ -20,118 +20,128 @@ #ifdef CGAL_LINKED_WITH_TBB #include -#endif // CGAL_LINKED_WITH_TBB +#endif // CGAL_LINKED_WITH_TBB namespace CGAL { namespace Isosurfacing { namespace internal { -template // TODO: should not be necessary -class Octree_topology { +template // @todo should not be necessary +class Octree_topology +{ public: - typedef GeomTraits Geom_traits; - typedef Octree_wrapper Octree_; - typedef std::shared_ptr> Octree; - typedef typename Octree_::Vertex_handle Vertex_descriptor; - typedef typename Octree_::Edge_handle Edge_descriptor; - typedef typename Octree_::Voxel_handle Cell_descriptor; + using Geom_traits = GeomTraits; + using Octree_ = Octree_wrapper; + using Octree = std::shared_ptr >; + using Vertex_descriptor = typename Octree_::Vertex_handle; + using Edge_descriptor = typename Octree_::Edge_handle; + using Cell_descriptor = typename Octree_::Voxel_handle; - static constexpr Cell_type CELL_TYPE = CUBICAL_CELL; - static constexpr std::size_t VERTICES_PER_CELL = 8; - static constexpr std::size_t EDGES_PER_CELL = 12; + static constexpr Cell_type CELL_TYPE = CUBICAL_CELL; + static constexpr std::size_t VERTICES_PER_CELL = 8; + static constexpr std::size_t EDGES_PER_CELL = 12; - typedef std::array Vertices_incident_to_edge; - typedef std::array Cells_incident_to_edge; // TODO: not always 4 - typedef std::array Cell_vertices; - typedef std::array Cell_edges; + using Vertices_incident_to_edge = std::array; + using Cells_incident_to_edge = std::array; // @todo: not always 4 + using Cell_vertices = std::array; + using Cell_edges = std::array; public: - Octree_topology(const Octree& octree) : octree(octree) {} + Octree_topology(const Octree& octree) + : octree(octree) + { } - Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const { - return octree->edge_vertices(e); - } + Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const + { + return octree->edge_vertices(e); + } - Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const { - return octree->edge_voxels(e); - } + Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const + { + return octree->edge_voxels(e); + } - Cell_vertices cell_vertices(const Cell_descriptor& c) const { - return octree->voxel_vertices(c); - } + Cell_vertices cell_vertices(const Cell_descriptor& c) const + { + return octree->voxel_vertices(c); + } - Cell_edges cell_edges(const Cell_descriptor& c) const { - return octree->voxel_edges(c); - } + Cell_edges cell_edges(const Cell_descriptor& c) const + { + return octree->voxel_edges(c); + } - template - void iterate_vertices(Functor& f, Sequential_tag) const { - for (const Vertex_descriptor& v : octree->leaf_vertices()) { - f(v); - } - } + template + void iterate_vertices(Functor& f, Sequential_tag) const + { + for(const Vertex_descriptor& v : octree->leaf_vertices()) + f(v); + } - template - void iterate_edges(Functor& f, Sequential_tag) const { - for (const Edge_descriptor& e : octree->leaf_edges()) { - f(e); - } - } + template + void iterate_edges(Functor& f, Sequential_tag) const + { + for(const Edge_descriptor& e : octree->leaf_edges()) + f(e); + } - template - void iterate_cells(Functor& f, Sequential_tag) const { - for (const Cell_descriptor& v : octree->leaf_voxels()) { - f(v); - } - } + template + void iterate_cells(Functor& f, Sequential_tag) const + { + for(const Cell_descriptor& v : octree->leaf_voxels()) + f(v); + } #ifdef CGAL_LINKED_WITH_TBB - template - void iterate_vertices(Functor& f, Parallel_tag) const { - const auto& vertices = octree->leaf_vertices(); + template + void iterate_vertices(Functor& f, Parallel_tag) const + { + const auto& vertices = octree->leaf_vertices(); - auto iterator = [&](const tbb::blocked_range& r) { - for (std::size_t i = r.begin(); i != r.end(); i++) { - f(vertices[i]); - } - }; + auto iterator = [&](const tbb::blocked_range& r) + { + for(std::size_t i = r.begin(); i != r.end(); ++i) + f(vertices[i]); + }; - tbb::parallel_for(tbb::blocked_range(0, vertices.size()), iterator); - } + tbb::parallel_for(tbb::blocked_range(0, vertices.size()), iterator); + } - template - void iterate_edges(Functor& f, Parallel_tag) const { - const auto& edges = octree->leaf_edges(); + template + void iterate_edges(Functor& f, Parallel_tag) const + { + const auto& edges = octree->leaf_edges(); - auto iterator = [&](const tbb::blocked_range& r) { - for (std::size_t i = r.begin(); i != r.end(); i++) { - f(edges[i]); - } - }; + auto iterator = [&](const tbb::blocked_range& r) + { + for(std::size_t i = r.begin(); i != r.end(); ++i) + f(edges[i]); + }; - tbb::parallel_for(tbb::blocked_range(0, edges.size()), iterator); - } + tbb::parallel_for(tbb::blocked_range(0, edges.size()), iterator); + } - template - void iterate_cells(Functor& f, Parallel_tag) const { - const auto& cells = octree->leaf_voxels(); + template + void iterate_cells(Functor& f, Parallel_tag) const + { + const auto& cells = octree->leaf_voxels(); - auto iterator = [&](const tbb::blocked_range& r) { - for (std::size_t i = r.begin(); i != r.end(); i++) { - f(cells[i]); - } - }; + auto iterator = [&](const tbb::blocked_range& r) + { + for(std::size_t i = r.begin(); i != r.end(); ++i) + f(cells[i]); + }; - tbb::parallel_for(tbb::blocked_range(0, cells.size()), iterator); - } -#endif // CGAL_LINKED_WITH_TBB + tbb::parallel_for(tbb::blocked_range(0, cells.size()), iterator); + } +#endif // CGAL_LINKED_WITH_TBB private: - const Octree octree; + const Octree octree; }; -} // namespace internal -} // namespace Isosurfacing -} // namespace CGAL +} // namespace internal +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_OCTREE_TOPOLOGY_H +#endif // CGAL_ISOSURFACING_3_INTERNAL_OCTREE_TOPOLOGY_H diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Tables.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Tables.h index 089a1bcb117..7606811c523 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Tables.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Tables.h @@ -38,8 +38,8 @@ // https://github.com/rogrosso/tmc available on 15th of September 2022. // -#ifndef CGAL_MARCHING_CUBES_3_INTERNAL_TABLES_H -#define CGAL_MARCHING_CUBES_3_INTERNAL_TABLES_H +#ifndef CGAL_ISOSURFACING_3_INTERNAL_TABLES_H +#define CGAL_ISOSURFACING_3_INTERNAL_TABLES_H #include @@ -74,19 +74,20 @@ constexpr int N_EDGES = 12; // This table iterates around an edge of a voxel in positive direction, starting from the given voxel (0,0,0). The // iteration is described in coordinates relative to the given voxel. The last number is the local edge index. -constexpr int edge_to_voxel_neighbor[N_EDGES][4][4] = { - {{0, 0, 0, 0}, {0, -1, 0, 2}, {0, -1, -1, 6}, {0, 0, -1, 4}}, // e0 - {{0, 0, 0, 1}, {1, 0, 0, 3}, {1, 0, -1, 7}, {0, 0, -1, 5}}, // e1 - {{0, 0, 0, 2}, {0, 0, -1, 6}, {0, 1, -1, 4}, {0, 1, 0, 0}}, // e2 - {{0, 0, 0, 3}, {0, 0, -1, 7}, {-1, 0, -1, 5}, {-1, 0, 0, 1}}, // e3 - {{0, 0, 0, 4}, {0, 0, 1, 0}, {0, -1, 1, 2}, {0, -1, 0, 6}}, // e4 - {{0, 0, 0, 5}, {0, 0, 1, 1}, {1, 0, 1, 3}, {1, 0, 0, 7}}, // e5 - {{0, 0, 0, 6}, {0, 1, 0, 4}, {0, 1, 1, 0}, {0, 0, 1, 2}}, // e6 - {{0, 0, 0, 7}, {-1, 0, 0, 5}, {-1, 0, 1, 1}, {0, 0, 1, 3}}, // e7 - {{0, 0, 0, 8}, {-1, 0, 0, 9}, {-1, -1, 0, 10}, {0, -1, 0, 11}}, // e8 - {{0, 0, 0, 9}, {0, -1, 0, 10}, {1, -1, 0, 11}, {1, 0, 0, 8}}, // e9 - {{0, 0, 0, 10}, {1, 0, 0, 11}, {1, 1, 0, 8}, {0, 1, 0, 9}}, // e10 - {{0, 0, 0, 11}, {0, 1, 0, 8}, {-1, 1, 0, 9}, {-1, 0, 0, 10}} // e11 +constexpr int edge_to_voxel_neighbor[N_EDGES][4][4] = +{ + {{0, 0, 0, 0}, {0, -1, 0, 2}, {0, -1, -1, 6}, {0, 0, -1, 4}}, // e0 + {{0, 0, 0, 1}, {1, 0, 0, 3}, {1, 0, -1, 7}, {0, 0, -1, 5}}, // e1 + {{0, 0, 0, 2}, {0, 0, -1, 6}, {0, 1, -1, 4}, {0, 1, 0, 0}}, // e2 + {{0, 0, 0, 3}, {0, 0, -1, 7}, {-1, 0, -1, 5}, {-1, 0, 0, 1}}, // e3 + {{0, 0, 0, 4}, {0, 0, 1, 0}, {0, -1, 1, 2}, {0, -1, 0, 6}}, // e4 + {{0, 0, 0, 5}, {0, 0, 1, 1}, {1, 0, 1, 3}, {1, 0, 0, 7}}, // e5 + {{0, 0, 0, 6}, {0, 1, 0, 4}, {0, 1, 1, 0}, {0, 0, 1, 2}}, // e6 + {{0, 0, 0, 7}, {-1, 0, 0, 5}, {-1, 0, 1, 1}, {0, 0, 1, 3}}, // e7 + {{0, 0, 0, 8}, {-1, 0, 0, 9}, {-1, -1, 0, 10}, {0, -1, 0, 11}}, // e8 + {{0, 0, 0, 9}, {0, -1, 0, 10}, {1, -1, 0, 11}, {1, 0, 0, 8}}, // e9 + {{0, 0, 0, 10}, {1, 0, 0, 11}, {1, 1, 0, 8}, {0, 1, 0, 9}}, // e10 + {{0, 0, 0, 11}, {0, 1, 0, 8}, {-1, 1, 0, 9}, {-1, 0, 0, 10}} // e11 }; /* The global edge index consists of the lexicographical index of the v0 vertex of a voxel, and an index that @@ -96,31 +97,33 @@ constexpr int edge_to_voxel_neighbor[N_EDGES][4][4] = { constexpr int edge_store_index[3] = {0, 3, 8}; // The local vertex indices of an edge. The indices are sorted by axis direction. -constexpr int edge_to_vertex[N_EDGES][2] = { - {0, 1}, // e0 - {1, 3}, // e1 - {2, 3}, // e2 - {0, 2}, // e3 - {4, 5}, // e4 - {5, 7}, // e5 - {6, 7}, // e6 - {4, 6}, // e7 - {0, 4}, // e8 - {1, 5}, // e9 - {3, 7}, // e10 - {2, 6} // e11 +constexpr int edge_to_vertex[N_EDGES][2] = +{ + {0, 1}, // e0 + {1, 3}, // e1 + {2, 3}, // e2 + {0, 2}, // e3 + {4, 5}, // e4 + {5, 7}, // e5 + {6, 7}, // e6 + {4, 6}, // e7 + {0, 4}, // e8 + {1, 5}, // e9 + {3, 7}, // e10 + {2, 6} // e11 }; // The local vertex coordinates within a voxel. -constexpr int local_vertex_position[N_VERTICES][3] = { - {0, 0, 0}, // v0 - {1, 0, 0}, // v1 - {0, 1, 0}, // v2 - {1, 1, 0}, // v3 - {0, 0, 1}, // v4 - {1, 0, 1}, // v5 - {0, 1, 1}, // v6 - {1, 1, 1} // v7 +constexpr int local_vertex_position[N_VERTICES][3] = +{ + {0, 0, 0}, // v0 + {1, 0, 0}, // v1 + {0, 1, 0}, // v2 + {1, 1, 0}, // v3 + {0, 0, 1}, // v4 + {1, 0, 1}, // v5 + {0, 1, 1}, // v6 + {1, 1, 1} // v7 }; // edges are uniquely characterized by the two end vertices, which have a unique vertex id @@ -137,546 +140,550 @@ constexpr int global_edge_id[][4] = {{0, 0, 0, 0}, {1, 0, 0, 1}, {0, 1, 0, 0}, { // probably a list without errors // indicates which edges has to be intersected -constexpr int intersected_edges[256] = { - 0, 265, 515, 778, 2060, 2309, 2575, 2822, 1030, 1295, 1541, 1804, 3082, 3331, 3593, 3840, 400, 153, 915, - 666, 2460, 2197, 2975, 2710, 1430, 1183, 1941, 1692, 3482, 3219, 3993, 3728, 560, 825, 51, 314, 2620, 2869, - 2111, 2358, 1590, 1855, 1077, 1340, 3642, 3891, 3129, 3376, 928, 681, 419, 170, 2988, 2725, 2479, 2214, 1958, - 1711, 1445, 1196, 4010, 3747, 3497, 3232, 2240, 2505, 2755, 3018, 204, 453, 719, 966, 3270, 3535, 3781, 4044, - 1226, 1475, 1737, 1984, 2384, 2137, 2899, 2650, 348, 85, 863, 598, 3414, 3167, 3925, 3676, 1370, 1107, 1881, - 1616, 2800, 3065, 2291, 2554, 764, 1013, 255, 502, 3830, 4095, 3317, 3580, 1786, 2035, 1273, 1520, 2912, 2665, - 2403, 2154, 876, 613, 367, 102, 3942, 3695, 3429, 3180, 1898, 1635, 1385, 1120, 1120, 1385, 1635, 1898, 3180, - 3429, 3695, 3942, 102, 367, 613, 876, 2154, 2403, 2665, 2912, 1520, 1273, 2035, 1786, 3580, 3317, 4095, 3830, - 502, 255, 1013, 764, 2554, 2291, 3065, 2800, 1616, 1881, 1107, 1370, 3676, 3925, 3167, 3414, 598, 863, 85, - 348, 2650, 2899, 2137, 2384, 1984, 1737, 1475, 1226, 4044, 3781, 3535, 3270, 966, 719, 453, 204, 3018, 2755, - 2505, 2240, 3232, 3497, 3747, 4010, 1196, 1445, 1711, 1958, 2214, 2479, 2725, 2988, 170, 419, 681, 928, 3376, - 3129, 3891, 3642, 1340, 1077, 1855, 1590, 2358, 2111, 2869, 2620, 314, 51, 825, 560, 3728, 3993, 3219, 3482, - 1692, 1941, 1183, 1430, 2710, 2975, 2197, 2460, 666, 915, 153, 400, 3840, 3593, 3331, 3082, 1804, 1541, 1295, - 1030, 2822, 2575, 2309, 2060, 778, 515, 265, 0}; +constexpr int intersected_edges[256] = +{ + 0, 265, 515, 778, 2060, 2309, 2575, 2822, 1030, 1295, 1541, 1804, 3082, 3331, 3593, 3840, 400, 153, 915, + 666, 2460, 2197, 2975, 2710, 1430, 1183, 1941, 1692, 3482, 3219, 3993, 3728, 560, 825, 51, 314, 2620, 2869, + 2111, 2358, 1590, 1855, 1077, 1340, 3642, 3891, 3129, 3376, 928, 681, 419, 170, 2988, 2725, 2479, 2214, 1958, + 1711, 1445, 1196, 4010, 3747, 3497, 3232, 2240, 2505, 2755, 3018, 204, 453, 719, 966, 3270, 3535, 3781, 4044, + 1226, 1475, 1737, 1984, 2384, 2137, 2899, 2650, 348, 85, 863, 598, 3414, 3167, 3925, 3676, 1370, 1107, 1881, + 1616, 2800, 3065, 2291, 2554, 764, 1013, 255, 502, 3830, 4095, 3317, 3580, 1786, 2035, 1273, 1520, 2912, 2665, + 2403, 2154, 876, 613, 367, 102, 3942, 3695, 3429, 3180, 1898, 1635, 1385, 1120, 1120, 1385, 1635, 1898, 3180, + 3429, 3695, 3942, 102, 367, 613, 876, 2154, 2403, 2665, 2912, 1520, 1273, 2035, 1786, 3580, 3317, 4095, 3830, + 502, 255, 1013, 764, 2554, 2291, 3065, 2800, 1616, 1881, 1107, 1370, 3676, 3925, 3167, 3414, 598, 863, 85, + 348, 2650, 2899, 2137, 2384, 1984, 1737, 1475, 1226, 4044, 3781, 3535, 3270, 966, 719, 453, 204, 3018, 2755, + 2505, 2240, 3232, 3497, 3747, 4010, 1196, 1445, 1711, 1958, 2214, 2479, 2725, 2988, 170, 419, 681, 928, 3376, + 3129, 3891, 3642, 1340, 1077, 1855, 1590, 2358, 2111, 2869, 2620, 314, 51, 825, 560, 3728, 3993, 3219, 3482, + 1692, 1941, 1183, 1430, 2710, 2975, 2197, 2460, 666, 915, 153, 400, 3840, 3593, 3331, 3082, 1804, 1541, 1295, + 1030, 2822, 2575, 2309, 2060, 778, 515, 265, 0 +}; // list of triangles for Marching Cubes case t, position at t*16 + tri -constexpr int triangle_cases[4096] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 0 <-> mc: 0, class rep: 0 - 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 1 <-> mc: 1, class rep: 1 - 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 2 <-> mc: 2, class rep: 1 - 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 3 <-> mc: 3, class rep: 3 - 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 4 <-> mc: 8, class rep: 1 - 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 5 <-> mc: 9, class rep: 3 - 1, 0, 9, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 6 <-> mc: 10, class rep: 6 - 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 7 <-> mc: 11, class rep: 7 - 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 8 <-> mc: 4, class rep: 1 - 0, 3, 8, 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 9 <-> mc: 5, class rep: 6 - 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 10 <-> mc: 6, class rep: 3 - 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 11 <-> mc: 7, class rep: 7 - 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 12 <-> mc: 12, class rep: 3 - 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 13 <-> mc: 13, class rep: 7 - 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 14 <-> mc: 14, class rep: 7 - 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 15 <-> mc: 15, class rep: 15 - 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 16 <-> mc: 16, class rep: 1 - 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 17 <-> mc: 17, class rep: 3 - 0, 9, 1, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 18 <-> mc: 18, class rep: 6 - 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 19 <-> mc: 19, class rep: 7 - 8, 7, 4, 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 20 <-> mc: 24, class rep: 6 - 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 21 <-> mc: 25, class rep: 7 - 9, 1, 0, 8, 7, 4, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 22 <-> mc: 26, class rep: 22 - 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1, // quitte: 23 <-> mc: 27, class rep: 23 - 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 24 <-> mc: 20, class rep: 24 - 3, 7, 4, 3, 4, 0, 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 25 <-> mc: 21, class rep: 25 - 9, 10, 2, 9, 2, 0, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 26 <-> mc: 22, class rep: 25 - 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1, // quitte: 27 <-> mc: 23, class rep: 27 - 3, 1, 10, 3, 10, 11, 7, 4, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 28 <-> mc: 28, class rep: 25 - 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1, // quitte: 29 <-> mc: 29, class rep: 29 - 4, 8, 7, 9, 11, 0, 9, 10, 11, 11, 3, 0, -1, -1, -1, -1, // quitte: 30 <-> mc: 30, class rep: 30 - 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 31 <-> mc: 31, class rep: 7 - 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 32 <-> mc: 32, class rep: 1 - 9, 4, 5, 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 33 <-> mc: 33, class rep: 6 - 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 34 <-> mc: 34, class rep: 3 - 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 35 <-> mc: 35, class rep: 7 - 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 36 <-> mc: 40, class rep: 24 - 0, 2, 11, 0, 11, 8, 4, 5, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 37 <-> mc: 41, class rep: 25 - 0, 4, 5, 0, 5, 1, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 38 <-> mc: 42, class rep: 25 - 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1, // quitte: 39 <-> mc: 43, class rep: 29 - 1, 10, 2, 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 40 <-> mc: 36, class rep: 6 - 3, 8, 0, 1, 10, 2, 4, 5, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 41 <-> mc: 37, class rep: 22 - 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 42 <-> mc: 38, class rep: 7 - 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1, // quitte: 43 <-> mc: 39, class rep: 23 - 10, 11, 3, 10, 3, 1, 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 44 <-> mc: 44, class rep: 25 - 4, 5, 9, 0, 1, 8, 8, 1, 10, 8, 10, 11, -1, -1, -1, -1, // quitte: 45 <-> mc: 45, class rep: 30 - 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1, // quitte: 46 <-> mc: 46, class rep: 27 - 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 47 <-> mc: 47, class rep: 7 - 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 48 <-> mc: 48, class rep: 3 - 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 49 <-> mc: 49, class rep: 7 - 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 50 <-> mc: 50, class rep: 7 - 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 51 <-> mc: 51, class rep: 15 - 7, 5, 9, 7, 9, 8, 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 52 <-> mc: 56, class rep: 25 - 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1, // quitte: 53 <-> mc: 57, class rep: 27 - 2, 11, 3, 0, 8, 1, 1, 8, 7, 1, 7, 5, -1, -1, -1, -1, // quitte: 54 <-> mc: 58, class rep: 30 - 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 55 <-> mc: 59, class rep: 7 - 9, 8, 7, 9, 7, 5, 10, 2, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 56 <-> mc: 52, class rep: 25 - 10, 2, 1, 9, 0, 5, 5, 0, 3, 5, 3, 7, -1, -1, -1, -1, // quitte: 57 <-> mc: 53, class rep: 30 - 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1, // quitte: 58 <-> mc: 54, class rep: 29 - 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 59 <-> mc: 55, class rep: 7 - 9, 8, 5, 8, 7, 5, 10, 3, 1, 10, 11, 3, -1, -1, -1, -1, // quitte: 60 <-> mc: 60, class rep: 60 - 5, 0, 7, 5, 9, 0, 7, 0, 11, 1, 10, 0, 11, 0, 10, -1, // quitte: 61 <-> mc: 61, class rep: 25 - 11, 0, 10, 11, 3, 0, 10, 0, 5, 8, 7, 0, 5, 0, 7, -1, // quitte: 62 <-> mc: 62, class rep: 25 - 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 63 <-> mc: 63, class rep: 3 - 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 64 <-> mc: 128, class rep: 1 - 3, 8, 0, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 65 <-> mc: 129, class rep: 6 - 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 66 <-> mc: 130, class rep: 24 - 8, 9, 1, 8, 1, 3, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 67 <-> mc: 131, class rep: 25 - 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 68 <-> mc: 136, class rep: 3 - 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 69 <-> mc: 137, class rep: 7 - 2, 6, 7, 2, 7, 3, 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 70 <-> mc: 138, class rep: 25 - 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1, // quitte: 71 <-> mc: 139, class rep: 27 - 10, 2, 1, 6, 7, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 72 <-> mc: 132, class rep: 6 - 1, 10, 2, 3, 8, 0, 6, 7, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 73 <-> mc: 133, class rep: 22 - 2, 0, 9, 2, 9, 10, 6, 7, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 74 <-> mc: 134, class rep: 25 - 6, 7, 11, 2, 3, 10, 10, 3, 8, 10, 8, 9, -1, -1, -1, -1, // quitte: 75 <-> mc: 135, class rep: 30 - 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 76 <-> mc: 140, class rep: 7 - 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1, // quitte: 77 <-> mc: 141, class rep: 23 - 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1, // quitte: 78 <-> mc: 142, class rep: 29 - 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 79 <-> mc: 143, class rep: 7 - 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 80 <-> mc: 144, class rep: 3 - 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 81 <-> mc: 145, class rep: 7 - 8, 11, 6, 8, 6, 4, 9, 1, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 82 <-> mc: 146, class rep: 25 - 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1, // quitte: 83 <-> mc: 147, class rep: 29 - 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 84 <-> mc: 152, class rep: 7 - 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 85 <-> mc: 153, class rep: 15 - 1, 0, 9, 2, 4, 3, 2, 6, 4, 4, 8, 3, -1, -1, -1, -1, // quitte: 86 <-> mc: 154, class rep: 30 - 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 87 <-> mc: 155, class rep: 7 - 6, 4, 8, 6, 8, 11, 2, 1, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 88 <-> mc: 148, class rep: 25 - 1, 10, 2, 3, 11, 0, 0, 11, 6, 0, 6, 4, -1, -1, -1, -1, // quitte: 89 <-> mc: 149, class rep: 30 - 4, 8, 11, 4, 11, 6, 0, 9, 2, 2, 9, 10, -1, -1, -1, -1, // quitte: 90 <-> mc: 150, class rep: 60 - 10, 3, 9, 10, 2, 3, 9, 3, 4, 11, 6, 3, 4, 3, 6, -1, // quitte: 91 <-> mc: 151, class rep: 25 - 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1, // quitte: 92 <-> mc: 156, class rep: 27 - 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 93 <-> mc: 157, class rep: 7 - 4, 3, 6, 4, 8, 3, 6, 3, 10, 0, 9, 3, 10, 3, 9, -1, // quitte: 94 <-> mc: 158, class rep: 25 - 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 95 <-> mc: 159, class rep: 3 - 4, 5, 9, 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 96 <-> mc: 160, class rep: 6 - 0, 3, 8, 4, 5, 9, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 97 <-> mc: 161, class rep: 22 - 5, 1, 0, 5, 0, 4, 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 98 <-> mc: 162, class rep: 25 - 11, 6, 7, 8, 4, 3, 3, 4, 5, 3, 5, 1, -1, -1, -1, -1, // quitte: 99 <-> mc: 163, class rep: 30 - 7, 3, 2, 7, 2, 6, 5, 9, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 100 <-> mc: 168, class rep: 25 - 9, 4, 5, 0, 6, 8, 0, 2, 6, 6, 7, 8, -1, -1, -1, -1, // quitte: 101 <-> mc: 169, class rep: 30 - 3, 2, 6, 3, 6, 7, 1, 0, 5, 5, 0, 4, -1, -1, -1, -1, // quitte: 102 <-> mc: 170, class rep: 60 - 6, 8, 2, 6, 7, 8, 2, 8, 1, 4, 5, 8, 1, 8, 5, -1, // quitte: 103 <-> mc: 171, class rep: 25 - 9, 4, 5, 10, 2, 1, 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 104 <-> mc: 164, class rep: 22 - 6, 7, 11, 1, 10, 2, 0, 3, 8, 4, 5, 9, -1, -1, -1, -1, // quitte: 105 <-> mc: 165, class rep: 105 - 7, 11, 6, 5, 10, 4, 4, 10, 2, 4, 2, 0, -1, -1, -1, -1, // quitte: 106 <-> mc: 166, class rep: 30 - 3, 8, 4, 3, 4, 5, 3, 5, 2, 10, 2, 5, 11, 6, 7, -1, // quitte: 107 <-> mc: 167, class rep: 22 - 9, 4, 5, 10, 6, 1, 1, 6, 7, 1, 7, 3, -1, -1, -1, -1, // quitte: 108 <-> mc: 172, class rep: 30 - 1, 10, 6, 1, 6, 7, 1, 7, 0, 8, 0, 7, 9, 4, 5, -1, // quitte: 109 <-> mc: 173, class rep: 22 - 4, 10, 0, 4, 5, 10, 0, 10, 3, 6, 7, 10, 3, 10, 7, -1, // quitte: 110 <-> mc: 174, class rep: 25 - 7, 10, 6, 7, 8, 10, 5, 10, 4, 4, 10, 8, -1, -1, -1, -1, // quitte: 111 <-> mc: 175, class rep: 6 - 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 112 <-> mc: 176, class rep: 7 - 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1, // quitte: 113 <-> mc: 177, class rep: 23 - 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1, // quitte: 114 <-> mc: 178, class rep: 27 - 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 115 <-> mc: 179, class rep: 7 - 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1, // quitte: 116 <-> mc: 184, class rep: 29 - 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 117 <-> mc: 185, class rep: 7 - 1, 8, 5, 1, 0, 8, 5, 8, 6, 3, 2, 8, 6, 8, 2, -1, // quitte: 118 <-> mc: 186, class rep: 25 - 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 119 <-> mc: 187, class rep: 3 - 1, 10, 2, 9, 11, 5, 9, 8, 11, 11, 6, 5, -1, -1, -1, -1, // quitte: 120 <-> mc: 180, class rep: 30 - 0, 3, 11, 0, 11, 6, 0, 6, 9, 5, 9, 6, 1, 10, 2, -1, // quitte: 121 <-> mc: 181, class rep: 22 - 11, 5, 8, 11, 6, 5, 8, 5, 0, 10, 2, 5, 0, 5, 2, -1, // quitte: 122 <-> mc: 182, class rep: 25 - 6, 3, 11, 6, 5, 3, 2, 3, 10, 10, 3, 5, -1, -1, -1, -1, // quitte: 123 <-> mc: 183, class rep: 6 - 1, 6, 3, 1, 10, 6, 3, 6, 8, 5, 9, 6, 8, 6, 9, -1, // quitte: 124 <-> mc: 188, class rep: 25 - 10, 0, 1, 10, 6, 0, 9, 0, 5, 5, 0, 6, -1, -1, -1, -1, // quitte: 125 <-> mc: 189, class rep: 6 - 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 126 <-> mc: 190, class rep: 24 - 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 127 <-> mc: 191, class rep: 1 - 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 128 <-> mc: 64, class rep: 1 - 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 129 <-> mc: 65, class rep: 24 - 9, 1, 0, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 130 <-> mc: 66, class rep: 6 - 1, 3, 8, 1, 8, 9, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 131 <-> mc: 67, class rep: 25 - 2, 11, 3, 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 132 <-> mc: 72, class rep: 6 - 11, 8, 0, 11, 0, 2, 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 133 <-> mc: 73, class rep: 25 - 0, 9, 1, 2, 11, 3, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 134 <-> mc: 74, class rep: 22 - 5, 6, 10, 1, 2, 9, 9, 2, 11, 9, 11, 8, -1, -1, -1, -1, // quitte: 135 <-> mc: 75, class rep: 30 - 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 136 <-> mc: 68, class rep: 3 - 1, 5, 6, 1, 6, 2, 3, 8, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 137 <-> mc: 69, class rep: 25 - 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 138 <-> mc: 70, class rep: 7 - 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1, // quitte: 139 <-> mc: 71, class rep: 29 - 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 140 <-> mc: 76, class rep: 7 - 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1, // quitte: 141 <-> mc: 77, class rep: 27 - 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1, // quitte: 142 <-> mc: 78, class rep: 23 - 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 143 <-> mc: 79, class rep: 7 - 5, 6, 10, 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 144 <-> mc: 80, class rep: 6 - 4, 0, 3, 4, 3, 7, 6, 10, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 145 <-> mc: 81, class rep: 25 - 1, 0, 9, 5, 6, 10, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 146 <-> mc: 82, class rep: 22 - 10, 5, 6, 1, 7, 9, 1, 3, 7, 7, 4, 9, -1, -1, -1, -1, // quitte: 147 <-> mc: 83, class rep: 30 - 3, 2, 11, 7, 4, 8, 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 148 <-> mc: 88, class rep: 22 - 5, 6, 10, 4, 2, 7, 4, 0, 2, 2, 11, 7, -1, -1, -1, -1, // quitte: 149 <-> mc: 89, class rep: 30 - 0, 9, 1, 4, 8, 7, 2, 11, 3, 5, 6, 10, -1, -1, -1, -1, // quitte: 150 <-> mc: 90, class rep: 105 - 9, 1, 2, 9, 2, 11, 9, 11, 4, 7, 4, 11, 5, 6, 10, -1, // quitte: 151 <-> mc: 91, class rep: 22 - 6, 2, 1, 6, 1, 5, 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 152 <-> mc: 84, class rep: 25 - 1, 5, 2, 5, 6, 2, 3, 4, 0, 3, 7, 4, -1, -1, -1, -1, // quitte: 153 <-> mc: 85, class rep: 60 - 8, 7, 4, 9, 5, 0, 0, 5, 6, 0, 6, 2, -1, -1, -1, -1, // quitte: 154 <-> mc: 86, class rep: 30 - 7, 9, 3, 7, 4, 9, 3, 9, 2, 5, 6, 9, 2, 9, 6, -1, // quitte: 155 <-> mc: 87, class rep: 25 - 8, 7, 4, 3, 5, 11, 3, 1, 5, 5, 6, 11, -1, -1, -1, -1, // quitte: 156 <-> mc: 92, class rep: 30 - 5, 11, 1, 5, 6, 11, 1, 11, 0, 7, 4, 11, 0, 11, 4, -1, // quitte: 157 <-> mc: 93, class rep: 25 - 0, 9, 5, 0, 5, 6, 0, 6, 3, 11, 3, 6, 8, 7, 4, -1, // quitte: 158 <-> mc: 94, class rep: 22 - 6, 9, 5, 6, 11, 9, 4, 9, 7, 7, 9, 11, -1, -1, -1, -1, // quitte: 159 <-> mc: 95, class rep: 6 - 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 160 <-> mc: 96, class rep: 3 - 4, 6, 10, 4, 10, 9, 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 161 <-> mc: 97, class rep: 25 - 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 162 <-> mc: 98, class rep: 7 - 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1, // quitte: 163 <-> mc: 99, class rep: 27 - 10, 9, 4, 10, 4, 6, 11, 3, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 164 <-> mc: 104, class rep: 25 - 0, 2, 8, 2, 11, 8, 4, 10, 9, 4, 6, 10, -1, -1, -1, -1, // quitte: 165 <-> mc: 105, class rep: 60 - 3, 2, 11, 0, 6, 1, 0, 4, 6, 6, 10, 1, -1, -1, -1, -1, // quitte: 166 <-> mc: 106, class rep: 30 - 6, 1, 4, 6, 10, 1, 4, 1, 8, 2, 11, 1, 8, 1, 11, -1, // quitte: 167 <-> mc: 107, class rep: 25 - 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 168 <-> mc: 100, class rep: 7 - 3, 8, 0, 1, 9, 2, 2, 9, 4, 2, 4, 6, -1, -1, -1, -1, // quitte: 169 <-> mc: 101, class rep: 30 - 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 170 <-> mc: 102, class rep: 15 - 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 171 <-> mc: 103, class rep: 7 - 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1, // quitte: 172 <-> mc: 108, class rep: 29 - 8, 1, 11, 8, 0, 1, 11, 1, 6, 9, 4, 1, 6, 1, 4, -1, // quitte: 173 <-> mc: 109, class rep: 25 - 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 174 <-> mc: 110, class rep: 7 - 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 175 <-> mc: 111, class rep: 3 - 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 176 <-> mc: 112, class rep: 7 - 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1, // quitte: 177 <-> mc: 113, class rep: 29 - 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1, // quitte: 178 <-> mc: 114, class rep: 23 - 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 179 <-> mc: 115, class rep: 7 - 2, 11, 3, 10, 8, 6, 10, 9, 8, 8, 7, 6, -1, -1, -1, -1, // quitte: 180 <-> mc: 120, class rep: 30 - 2, 7, 0, 2, 11, 7, 0, 7, 9, 6, 10, 7, 9, 7, 10, -1, // quitte: 181 <-> mc: 121, class rep: 25 - 1, 0, 8, 1, 8, 7, 1, 7, 10, 6, 10, 7, 2, 11, 3, -1, // quitte: 182 <-> mc: 122, class rep: 22 - 11, 1, 2, 11, 7, 1, 10, 1, 6, 6, 1, 7, -1, -1, -1, -1, // quitte: 183 <-> mc: 123, class rep: 6 - 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1, // quitte: 184 <-> mc: 116, class rep: 27 - 2, 9, 6, 2, 1, 9, 6, 9, 7, 0, 3, 9, 7, 9, 3, -1, // quitte: 185 <-> mc: 117, class rep: 25 - 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 186 <-> mc: 118, class rep: 7 - 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 187 <-> mc: 119, class rep: 3 - 8, 6, 9, 8, 7, 6, 9, 6, 1, 11, 3, 6, 1, 6, 3, -1, // quitte: 188 <-> mc: 124, class rep: 25 - 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 189 <-> mc: 125, class rep: 24 - 7, 0, 8, 7, 6, 0, 3, 0, 11, 11, 0, 6, -1, -1, -1, -1, // quitte: 190 <-> mc: 126, class rep: 6 - 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 191 <-> mc: 127, class rep: 1 - 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 192 <-> mc: 192, class rep: 3 - 11, 10, 5, 11, 5, 7, 8, 0, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 193 <-> mc: 193, class rep: 25 - 5, 7, 11, 5, 11, 10, 1, 0, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 194 <-> mc: 194, class rep: 25 - 10, 5, 7, 10, 7, 11, 9, 1, 8, 8, 1, 3, -1, -1, -1, -1, // quitte: 195 <-> mc: 195, class rep: 60 - 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 196 <-> mc: 200, class rep: 7 - 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1, // quitte: 197 <-> mc: 201, class rep: 29 - 9, 1, 0, 5, 3, 10, 5, 7, 3, 3, 2, 10, -1, -1, -1, -1, // quitte: 198 <-> mc: 202, class rep: 30 - 9, 2, 8, 9, 1, 2, 8, 2, 7, 10, 5, 2, 7, 2, 5, -1, // quitte: 199 <-> mc: 203, class rep: 25 - 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 200 <-> mc: 196, class rep: 7 - 0, 3, 8, 1, 7, 2, 1, 5, 7, 7, 11, 2, -1, -1, -1, -1, // quitte: 201 <-> mc: 197, class rep: 30 - 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1, // quitte: 202 <-> mc: 198, class rep: 27 - 7, 2, 5, 7, 11, 2, 5, 2, 9, 3, 8, 2, 9, 2, 8, -1, // quitte: 203 <-> mc: 199, class rep: 25 - 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 204 <-> mc: 204, class rep: 15 - 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 205 <-> mc: 205, class rep: 7 - 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 206 <-> mc: 206, class rep: 7 - 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 207 <-> mc: 207, class rep: 3 - 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 208 <-> mc: 208, class rep: 7 - 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1, // quitte: 209 <-> mc: 209, class rep: 27 - 0, 9, 1, 8, 10, 4, 8, 11, 10, 10, 5, 4, -1, -1, -1, -1, // quitte: 210 <-> mc: 210, class rep: 30 - 10, 4, 11, 10, 5, 4, 11, 4, 3, 9, 1, 4, 3, 4, 1, -1, // quitte: 211 <-> mc: 211, class rep: 25 - 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1, // quitte: 212 <-> mc: 216, class rep: 23 - 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 213 <-> mc: 217, class rep: 7 - 3, 2, 10, 3, 10, 5, 3, 5, 8, 4, 8, 5, 0, 9, 1, -1, // quitte: 214 <-> mc: 218, class rep: 22 - 5, 2, 10, 5, 4, 2, 1, 2, 9, 9, 2, 4, -1, -1, -1, -1, // quitte: 215 <-> mc: 219, class rep: 6 - 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1, // quitte: 216 <-> mc: 212, class rep: 29 - 0, 11, 4, 0, 3, 11, 4, 11, 5, 2, 1, 11, 5, 11, 1, -1, // quitte: 217 <-> mc: 213, class rep: 25 - 0, 5, 2, 0, 9, 5, 2, 5, 11, 4, 8, 5, 11, 5, 8, -1, // quitte: 218 <-> mc: 214, class rep: 25 - 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 219 <-> mc: 215, class rep: 24 - 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 220 <-> mc: 220, class rep: 7 - 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 221 <-> mc: 221, class rep: 3 - 8, 5, 4, 8, 3, 5, 9, 5, 0, 0, 5, 3, -1, -1, -1, -1, // quitte: 222 <-> mc: 222, class rep: 6 - 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 223 <-> mc: 223, class rep: 1 - 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 224 <-> mc: 224, class rep: 7 - 0, 3, 8, 4, 7, 9, 9, 7, 11, 9, 11, 10, -1, -1, -1, -1, // quitte: 225 <-> mc: 225, class rep: 30 - 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1, // quitte: 226 <-> mc: 226, class rep: 29 - 3, 4, 1, 3, 8, 4, 1, 4, 10, 7, 11, 4, 10, 4, 11, -1, // quitte: 227 <-> mc: 227, class rep: 25 - 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1, // quitte: 228 <-> mc: 232, class rep: 27 - 9, 7, 10, 9, 4, 7, 10, 7, 2, 8, 0, 7, 2, 7, 0, -1, // quitte: 229 <-> mc: 233, class rep: 25 - 3, 10, 7, 3, 2, 10, 7, 10, 4, 1, 0, 10, 4, 10, 0, -1, // quitte: 230 <-> mc: 234, class rep: 25 - 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 231 <-> mc: 235, class rep: 24 - 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1, // quitte: 232 <-> mc: 228, class rep: 23 - 9, 4, 7, 9, 7, 11, 9, 11, 1, 2, 1, 11, 0, 3, 8, -1, // quitte: 233 <-> mc: 229, class rep: 22 - 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 234 <-> mc: 230, class rep: 7 - 11, 4, 7, 11, 2, 4, 8, 4, 3, 3, 4, 2, -1, -1, -1, -1, // quitte: 235 <-> mc: 231, class rep: 6 - 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 236 <-> mc: 236, class rep: 7 - 4, 1, 9, 4, 7, 1, 0, 1, 8, 8, 1, 7, -1, -1, -1, -1, // quitte: 237 <-> mc: 237, class rep: 6 - 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 238 <-> mc: 238, class rep: 3 - 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 239 <-> mc: 239, class rep: 1 - 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 240 <-> mc: 240, class rep: 15 - 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 241 <-> mc: 241, class rep: 7 - 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 242 <-> mc: 242, class rep: 7 - 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 243 <-> mc: 243, class rep: 3 - 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 244 <-> mc: 248, class rep: 7 - 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 245 <-> mc: 249, class rep: 3 - 2, 8, 3, 2, 10, 8, 0, 8, 1, 1, 8, 10, -1, -1, -1, -1, // quitte: 246 <-> mc: 250, class rep: 6 - 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 247 <-> mc: 251, class rep: 1 - 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 248 <-> mc: 244, class rep: 7 - 3, 9, 0, 3, 11, 9, 1, 9, 2, 2, 9, 11, -1, -1, -1, -1, // quitte: 249 <-> mc: 245, class rep: 6 - 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 250 <-> mc: 246, class rep: 3 - 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 251 <-> mc: 247, class rep: 1 - 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 252 <-> mc: 252, class rep: 3 - 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 253 <-> mc: 253, class rep: 1 - 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 254 <-> mc: 254, class rep: 1 - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // quitte: 255 <-> mc: 255, class rep: 0 +constexpr int triangle_cases[4096] = +{ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 0 <-> mc: 0, class rep: 0 + 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 1 <-> mc: 1, class rep: 1 + 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 2 <-> mc: 2, class rep: 1 + 1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 3 <-> mc: 3, class rep: 3 + 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 4 <-> mc: 8, class rep: 1 + 0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 5 <-> mc: 9, class rep: 3 + 1, 0, 9, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 6 <-> mc: 10, class rep: 6 + 1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 7 <-> mc: 11, class rep: 7 + 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 8 <-> mc: 4, class rep: 1 + 0, 3, 8, 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 9 <-> mc: 5, class rep: 6 + 9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 10 <-> mc: 6, class rep: 3 + 2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 11 <-> mc: 7, class rep: 7 + 3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 12 <-> mc: 12, class rep: 3 + 0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 13 <-> mc: 13, class rep: 7 + 3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 14 <-> mc: 14, class rep: 7 + 9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 15 <-> mc: 15, class rep: 15 + 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 16 <-> mc: 16, class rep: 1 + 4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 17 <-> mc: 17, class rep: 3 + 0, 9, 1, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 18 <-> mc: 18, class rep: 6 + 4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 19 <-> mc: 19, class rep: 7 + 8, 7, 4, 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 20 <-> mc: 24, class rep: 6 + 11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 21 <-> mc: 25, class rep: 7 + 9, 1, 0, 8, 7, 4, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 22 <-> mc: 26, class rep: 22 + 4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1, // quitte: 23 <-> mc: 27, class rep: 23 + 1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 24 <-> mc: 20, class rep: 24 + 3, 7, 4, 3, 4, 0, 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 25 <-> mc: 21, class rep: 25 + 9, 10, 2, 9, 2, 0, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 26 <-> mc: 22, class rep: 25 + 2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1, // quitte: 27 <-> mc: 23, class rep: 27 + 3, 1, 10, 3, 10, 11, 7, 4, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 28 <-> mc: 28, class rep: 25 + 1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1, // quitte: 29 <-> mc: 29, class rep: 29 + 4, 8, 7, 9, 11, 0, 9, 10, 11, 11, 3, 0, -1, -1, -1, -1, // quitte: 30 <-> mc: 30, class rep: 30 + 4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 31 <-> mc: 31, class rep: 7 + 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 32 <-> mc: 32, class rep: 1 + 9, 4, 5, 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 33 <-> mc: 33, class rep: 6 + 0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 34 <-> mc: 34, class rep: 3 + 8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 35 <-> mc: 35, class rep: 7 + 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 36 <-> mc: 40, class rep: 24 + 0, 2, 11, 0, 11, 8, 4, 5, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 37 <-> mc: 41, class rep: 25 + 0, 4, 5, 0, 5, 1, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 38 <-> mc: 42, class rep: 25 + 2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1, // quitte: 39 <-> mc: 43, class rep: 29 + 1, 10, 2, 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 40 <-> mc: 36, class rep: 6 + 3, 8, 0, 1, 10, 2, 4, 5, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 41 <-> mc: 37, class rep: 22 + 5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 42 <-> mc: 38, class rep: 7 + 2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1, // quitte: 43 <-> mc: 39, class rep: 23 + 10, 11, 3, 10, 3, 1, 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 44 <-> mc: 44, class rep: 25 + 4, 5, 9, 0, 1, 8, 8, 1, 10, 8, 10, 11, -1, -1, -1, -1, // quitte: 45 <-> mc: 45, class rep: 30 + 5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1, // quitte: 46 <-> mc: 46, class rep: 27 + 5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 47 <-> mc: 47, class rep: 7 + 9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 48 <-> mc: 48, class rep: 3 + 9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 49 <-> mc: 49, class rep: 7 + 0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 50 <-> mc: 50, class rep: 7 + 1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 51 <-> mc: 51, class rep: 15 + 7, 5, 9, 7, 9, 8, 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 52 <-> mc: 56, class rep: 25 + 9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1, // quitte: 53 <-> mc: 57, class rep: 27 + 2, 11, 3, 0, 8, 1, 1, 8, 7, 1, 7, 5, -1, -1, -1, -1, // quitte: 54 <-> mc: 58, class rep: 30 + 11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 55 <-> mc: 59, class rep: 7 + 9, 8, 7, 9, 7, 5, 10, 2, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 56 <-> mc: 52, class rep: 25 + 10, 2, 1, 9, 0, 5, 5, 0, 3, 5, 3, 7, -1, -1, -1, -1, // quitte: 57 <-> mc: 53, class rep: 30 + 8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1, // quitte: 58 <-> mc: 54, class rep: 29 + 2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 59 <-> mc: 55, class rep: 7 + 9, 8, 5, 8, 7, 5, 10, 3, 1, 10, 11, 3, -1, -1, -1, -1, // quitte: 60 <-> mc: 60, class rep: 60 + 5, 0, 7, 5, 9, 0, 7, 0, 11, 1, 10, 0, 11, 0, 10, -1, // quitte: 61 <-> mc: 61, class rep: 25 + 11, 0, 10, 11, 3, 0, 10, 0, 5, 8, 7, 0, 5, 0, 7, -1, // quitte: 62 <-> mc: 62, class rep: 25 + 11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 63 <-> mc: 63, class rep: 3 + 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 64 <-> mc: 128, class rep: 1 + 3, 8, 0, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 65 <-> mc: 129, class rep: 6 + 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 66 <-> mc: 130, class rep: 24 + 8, 9, 1, 8, 1, 3, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 67 <-> mc: 131, class rep: 25 + 7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 68 <-> mc: 136, class rep: 3 + 7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 69 <-> mc: 137, class rep: 7 + 2, 6, 7, 2, 7, 3, 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 70 <-> mc: 138, class rep: 25 + 1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1, // quitte: 71 <-> mc: 139, class rep: 27 + 10, 2, 1, 6, 7, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 72 <-> mc: 132, class rep: 6 + 1, 10, 2, 3, 8, 0, 6, 7, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 73 <-> mc: 133, class rep: 22 + 2, 0, 9, 2, 9, 10, 6, 7, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 74 <-> mc: 134, class rep: 25 + 6, 7, 11, 2, 3, 10, 10, 3, 8, 10, 8, 9, -1, -1, -1, -1, // quitte: 75 <-> mc: 135, class rep: 30 + 10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 76 <-> mc: 140, class rep: 7 + 10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1, // quitte: 77 <-> mc: 141, class rep: 23 + 0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1, // quitte: 78 <-> mc: 142, class rep: 29 + 7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 79 <-> mc: 143, class rep: 7 + 6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 80 <-> mc: 144, class rep: 3 + 3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 81 <-> mc: 145, class rep: 7 + 8, 11, 6, 8, 6, 4, 9, 1, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 82 <-> mc: 146, class rep: 25 + 9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1, // quitte: 83 <-> mc: 147, class rep: 29 + 8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 84 <-> mc: 152, class rep: 7 + 0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 85 <-> mc: 153, class rep: 15 + 1, 0, 9, 2, 4, 3, 2, 6, 4, 4, 8, 3, -1, -1, -1, -1, // quitte: 86 <-> mc: 154, class rep: 30 + 1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 87 <-> mc: 155, class rep: 7 + 6, 4, 8, 6, 8, 11, 2, 1, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 88 <-> mc: 148, class rep: 25 + 1, 10, 2, 3, 11, 0, 0, 11, 6, 0, 6, 4, -1, -1, -1, -1, // quitte: 89 <-> mc: 149, class rep: 30 + 4, 8, 11, 4, 11, 6, 0, 9, 2, 2, 9, 10, -1, -1, -1, -1, // quitte: 90 <-> mc: 150, class rep: 60 + 10, 3, 9, 10, 2, 3, 9, 3, 4, 11, 6, 3, 4, 3, 6, -1, // quitte: 91 <-> mc: 151, class rep: 25 + 8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1, // quitte: 92 <-> mc: 156, class rep: 27 + 10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 93 <-> mc: 157, class rep: 7 + 4, 3, 6, 4, 8, 3, 6, 3, 10, 0, 9, 3, 10, 3, 9, -1, // quitte: 94 <-> mc: 158, class rep: 25 + 10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 95 <-> mc: 159, class rep: 3 + 4, 5, 9, 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 96 <-> mc: 160, class rep: 6 + 0, 3, 8, 4, 5, 9, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 97 <-> mc: 161, class rep: 22 + 5, 1, 0, 5, 0, 4, 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 98 <-> mc: 162, class rep: 25 + 11, 6, 7, 8, 4, 3, 3, 4, 5, 3, 5, 1, -1, -1, -1, -1, // quitte: 99 <-> mc: 163, class rep: 30 + 7, 3, 2, 7, 2, 6, 5, 9, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 100 <-> mc: 168, class rep: 25 + 9, 4, 5, 0, 6, 8, 0, 2, 6, 6, 7, 8, -1, -1, -1, -1, // quitte: 101 <-> mc: 169, class rep: 30 + 3, 2, 6, 3, 6, 7, 1, 0, 5, 5, 0, 4, -1, -1, -1, -1, // quitte: 102 <-> mc: 170, class rep: 60 + 6, 8, 2, 6, 7, 8, 2, 8, 1, 4, 5, 8, 1, 8, 5, -1, // quitte: 103 <-> mc: 171, class rep: 25 + 9, 4, 5, 10, 2, 1, 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 104 <-> mc: 164, class rep: 22 + 6, 7, 11, 1, 10, 2, 0, 3, 8, 4, 5, 9, -1, -1, -1, -1, // quitte: 105 <-> mc: 165, class rep: 105 + 7, 11, 6, 5, 10, 4, 4, 10, 2, 4, 2, 0, -1, -1, -1, -1, // quitte: 106 <-> mc: 166, class rep: 30 + 3, 8, 4, 3, 4, 5, 3, 5, 2, 10, 2, 5, 11, 6, 7, -1, // quitte: 107 <-> mc: 167, class rep: 22 + 9, 4, 5, 10, 6, 1, 1, 6, 7, 1, 7, 3, -1, -1, -1, -1, // quitte: 108 <-> mc: 172, class rep: 30 + 1, 10, 6, 1, 6, 7, 1, 7, 0, 8, 0, 7, 9, 4, 5, -1, // quitte: 109 <-> mc: 173, class rep: 22 + 4, 10, 0, 4, 5, 10, 0, 10, 3, 6, 7, 10, 3, 10, 7, -1, // quitte: 110 <-> mc: 174, class rep: 25 + 7, 10, 6, 7, 8, 10, 5, 10, 4, 4, 10, 8, -1, -1, -1, -1, // quitte: 111 <-> mc: 175, class rep: 6 + 6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 112 <-> mc: 176, class rep: 7 + 3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1, // quitte: 113 <-> mc: 177, class rep: 23 + 0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1, // quitte: 114 <-> mc: 178, class rep: 27 + 6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 115 <-> mc: 179, class rep: 7 + 5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1, // quitte: 116 <-> mc: 184, class rep: 29 + 9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 117 <-> mc: 185, class rep: 7 + 1, 8, 5, 1, 0, 8, 5, 8, 6, 3, 2, 8, 6, 8, 2, -1, // quitte: 118 <-> mc: 186, class rep: 25 + 1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 119 <-> mc: 187, class rep: 3 + 1, 10, 2, 9, 11, 5, 9, 8, 11, 11, 6, 5, -1, -1, -1, -1, // quitte: 120 <-> mc: 180, class rep: 30 + 0, 3, 11, 0, 11, 6, 0, 6, 9, 5, 9, 6, 1, 10, 2, -1, // quitte: 121 <-> mc: 181, class rep: 22 + 11, 5, 8, 11, 6, 5, 8, 5, 0, 10, 2, 5, 0, 5, 2, -1, // quitte: 122 <-> mc: 182, class rep: 25 + 6, 3, 11, 6, 5, 3, 2, 3, 10, 10, 3, 5, -1, -1, -1, -1, // quitte: 123 <-> mc: 183, class rep: 6 + 1, 6, 3, 1, 10, 6, 3, 6, 8, 5, 9, 6, 8, 6, 9, -1, // quitte: 124 <-> mc: 188, class rep: 25 + 10, 0, 1, 10, 6, 0, 9, 0, 5, 5, 0, 6, -1, -1, -1, -1, // quitte: 125 <-> mc: 189, class rep: 6 + 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 126 <-> mc: 190, class rep: 24 + 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 127 <-> mc: 191, class rep: 1 + 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 128 <-> mc: 64, class rep: 1 + 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 129 <-> mc: 65, class rep: 24 + 9, 1, 0, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 130 <-> mc: 66, class rep: 6 + 1, 3, 8, 1, 8, 9, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 131 <-> mc: 67, class rep: 25 + 2, 11, 3, 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 132 <-> mc: 72, class rep: 6 + 11, 8, 0, 11, 0, 2, 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 133 <-> mc: 73, class rep: 25 + 0, 9, 1, 2, 11, 3, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 134 <-> mc: 74, class rep: 22 + 5, 6, 10, 1, 2, 9, 9, 2, 11, 9, 11, 8, -1, -1, -1, -1, // quitte: 135 <-> mc: 75, class rep: 30 + 1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 136 <-> mc: 68, class rep: 3 + 1, 5, 6, 1, 6, 2, 3, 8, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 137 <-> mc: 69, class rep: 25 + 9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 138 <-> mc: 70, class rep: 7 + 5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1, // quitte: 139 <-> mc: 71, class rep: 29 + 6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 140 <-> mc: 76, class rep: 7 + 0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1, // quitte: 141 <-> mc: 77, class rep: 27 + 3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1, // quitte: 142 <-> mc: 78, class rep: 23 + 6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 143 <-> mc: 79, class rep: 7 + 5, 6, 10, 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 144 <-> mc: 80, class rep: 6 + 4, 0, 3, 4, 3, 7, 6, 10, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 145 <-> mc: 81, class rep: 25 + 1, 0, 9, 5, 6, 10, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 146 <-> mc: 82, class rep: 22 + 10, 5, 6, 1, 7, 9, 1, 3, 7, 7, 4, 9, -1, -1, -1, -1, // quitte: 147 <-> mc: 83, class rep: 30 + 3, 2, 11, 7, 4, 8, 10, 5, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 148 <-> mc: 88, class rep: 22 + 5, 6, 10, 4, 2, 7, 4, 0, 2, 2, 11, 7, -1, -1, -1, -1, // quitte: 149 <-> mc: 89, class rep: 30 + 0, 9, 1, 4, 8, 7, 2, 11, 3, 5, 6, 10, -1, -1, -1, -1, // quitte: 150 <-> mc: 90, class rep: 105 + 9, 1, 2, 9, 2, 11, 9, 11, 4, 7, 4, 11, 5, 6, 10, -1, // quitte: 151 <-> mc: 91, class rep: 22 + 6, 2, 1, 6, 1, 5, 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 152 <-> mc: 84, class rep: 25 + 1, 5, 2, 5, 6, 2, 3, 4, 0, 3, 7, 4, -1, -1, -1, -1, // quitte: 153 <-> mc: 85, class rep: 60 + 8, 7, 4, 9, 5, 0, 0, 5, 6, 0, 6, 2, -1, -1, -1, -1, // quitte: 154 <-> mc: 86, class rep: 30 + 7, 9, 3, 7, 4, 9, 3, 9, 2, 5, 6, 9, 2, 9, 6, -1, // quitte: 155 <-> mc: 87, class rep: 25 + 8, 7, 4, 3, 5, 11, 3, 1, 5, 5, 6, 11, -1, -1, -1, -1, // quitte: 156 <-> mc: 92, class rep: 30 + 5, 11, 1, 5, 6, 11, 1, 11, 0, 7, 4, 11, 0, 11, 4, -1, // quitte: 157 <-> mc: 93, class rep: 25 + 0, 9, 5, 0, 5, 6, 0, 6, 3, 11, 3, 6, 8, 7, 4, -1, // quitte: 158 <-> mc: 94, class rep: 22 + 6, 9, 5, 6, 11, 9, 4, 9, 7, 7, 9, 11, -1, -1, -1, -1, // quitte: 159 <-> mc: 95, class rep: 6 + 10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 160 <-> mc: 96, class rep: 3 + 4, 6, 10, 4, 10, 9, 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 161 <-> mc: 97, class rep: 25 + 10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 162 <-> mc: 98, class rep: 7 + 8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1, // quitte: 163 <-> mc: 99, class rep: 27 + 10, 9, 4, 10, 4, 6, 11, 3, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 164 <-> mc: 104, class rep: 25 + 0, 2, 8, 2, 11, 8, 4, 10, 9, 4, 6, 10, -1, -1, -1, -1, // quitte: 165 <-> mc: 105, class rep: 60 + 3, 2, 11, 0, 6, 1, 0, 4, 6, 6, 10, 1, -1, -1, -1, -1, // quitte: 166 <-> mc: 106, class rep: 30 + 6, 1, 4, 6, 10, 1, 4, 1, 8, 2, 11, 1, 8, 1, 11, -1, // quitte: 167 <-> mc: 107, class rep: 25 + 1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 168 <-> mc: 100, class rep: 7 + 3, 8, 0, 1, 9, 2, 2, 9, 4, 2, 4, 6, -1, -1, -1, -1, // quitte: 169 <-> mc: 101, class rep: 30 + 0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 170 <-> mc: 102, class rep: 15 + 8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 171 <-> mc: 103, class rep: 7 + 9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1, // quitte: 172 <-> mc: 108, class rep: 29 + 8, 1, 11, 8, 0, 1, 11, 1, 6, 9, 4, 1, 6, 1, 4, -1, // quitte: 173 <-> mc: 109, class rep: 25 + 3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1, // quitte: 174 <-> mc: 110, class rep: 7 + 6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 175 <-> mc: 111, class rep: 3 + 7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 176 <-> mc: 112, class rep: 7 + 0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1, // quitte: 177 <-> mc: 113, class rep: 29 + 10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1, // quitte: 178 <-> mc: 114, class rep: 23 + 10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 179 <-> mc: 115, class rep: 7 + 2, 11, 3, 10, 8, 6, 10, 9, 8, 8, 7, 6, -1, -1, -1, -1, // quitte: 180 <-> mc: 120, class rep: 30 + 2, 7, 0, 2, 11, 7, 0, 7, 9, 6, 10, 7, 9, 7, 10, -1, // quitte: 181 <-> mc: 121, class rep: 25 + 1, 0, 8, 1, 8, 7, 1, 7, 10, 6, 10, 7, 2, 11, 3, -1, // quitte: 182 <-> mc: 122, class rep: 22 + 11, 1, 2, 11, 7, 1, 10, 1, 6, 6, 1, 7, -1, -1, -1, -1, // quitte: 183 <-> mc: 123, class rep: 6 + 1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1, // quitte: 184 <-> mc: 116, class rep: 27 + 2, 9, 6, 2, 1, 9, 6, 9, 7, 0, 3, 9, 7, 9, 3, -1, // quitte: 185 <-> mc: 117, class rep: 25 + 7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1, // quitte: 186 <-> mc: 118, class rep: 7 + 7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 187 <-> mc: 119, class rep: 3 + 8, 6, 9, 8, 7, 6, 9, 6, 1, 11, 3, 6, 1, 6, 3, -1, // quitte: 188 <-> mc: 124, class rep: 25 + 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 189 <-> mc: 125, class rep: 24 + 7, 0, 8, 7, 6, 0, 3, 0, 11, 11, 0, 6, -1, -1, -1, -1, // quitte: 190 <-> mc: 126, class rep: 6 + 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 191 <-> mc: 127, class rep: 1 + 11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 192 <-> mc: 192, class rep: 3 + 11, 10, 5, 11, 5, 7, 8, 0, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 193 <-> mc: 193, class rep: 25 + 5, 7, 11, 5, 11, 10, 1, 0, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 194 <-> mc: 194, class rep: 25 + 10, 5, 7, 10, 7, 11, 9, 1, 8, 8, 1, 3, -1, -1, -1, -1, // quitte: 195 <-> mc: 195, class rep: 60 + 2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 196 <-> mc: 200, class rep: 7 + 8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1, // quitte: 197 <-> mc: 201, class rep: 29 + 9, 1, 0, 5, 3, 10, 5, 7, 3, 3, 2, 10, -1, -1, -1, -1, // quitte: 198 <-> mc: 202, class rep: 30 + 9, 2, 8, 9, 1, 2, 8, 2, 7, 10, 5, 2, 7, 2, 5, -1, // quitte: 199 <-> mc: 203, class rep: 25 + 11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 200 <-> mc: 196, class rep: 7 + 0, 3, 8, 1, 7, 2, 1, 5, 7, 7, 11, 2, -1, -1, -1, -1, // quitte: 201 <-> mc: 197, class rep: 30 + 9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1, // quitte: 202 <-> mc: 198, class rep: 27 + 7, 2, 5, 7, 11, 2, 5, 2, 9, 3, 8, 2, 9, 2, 8, -1, // quitte: 203 <-> mc: 199, class rep: 25 + 1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 204 <-> mc: 204, class rep: 15 + 0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1, // quitte: 205 <-> mc: 205, class rep: 7 + 9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1, // quitte: 206 <-> mc: 206, class rep: 7 + 9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 207 <-> mc: 207, class rep: 3 + 5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 208 <-> mc: 208, class rep: 7 + 5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1, // quitte: 209 <-> mc: 209, class rep: 27 + 0, 9, 1, 8, 10, 4, 8, 11, 10, 10, 5, 4, -1, -1, -1, -1, // quitte: 210 <-> mc: 210, class rep: 30 + 10, 4, 11, 10, 5, 4, 11, 4, 3, 9, 1, 4, 3, 4, 1, -1, // quitte: 211 <-> mc: 211, class rep: 25 + 2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1, // quitte: 212 <-> mc: 216, class rep: 23 + 5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1, // quitte: 213 <-> mc: 217, class rep: 7 + 3, 2, 10, 3, 10, 5, 3, 5, 8, 4, 8, 5, 0, 9, 1, -1, // quitte: 214 <-> mc: 218, class rep: 22 + 5, 2, 10, 5, 4, 2, 1, 2, 9, 9, 2, 4, -1, -1, -1, -1, // quitte: 215 <-> mc: 219, class rep: 6 + 2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1, // quitte: 216 <-> mc: 212, class rep: 29 + 0, 11, 4, 0, 3, 11, 4, 11, 5, 2, 1, 11, 5, 11, 1, -1, // quitte: 217 <-> mc: 213, class rep: 25 + 0, 5, 2, 0, 9, 5, 2, 5, 11, 4, 8, 5, 11, 5, 8, -1, // quitte: 218 <-> mc: 214, class rep: 25 + 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 219 <-> mc: 215, class rep: 24 + 8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1, // quitte: 220 <-> mc: 220, class rep: 7 + 0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 221 <-> mc: 221, class rep: 3 + 8, 5, 4, 8, 3, 5, 9, 5, 0, 0, 5, 3, -1, -1, -1, -1, // quitte: 222 <-> mc: 222, class rep: 6 + 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 223 <-> mc: 223, class rep: 1 + 4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 224 <-> mc: 224, class rep: 7 + 0, 3, 8, 4, 7, 9, 9, 7, 11, 9, 11, 10, -1, -1, -1, -1, // quitte: 225 <-> mc: 225, class rep: 30 + 1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1, // quitte: 226 <-> mc: 226, class rep: 29 + 3, 4, 1, 3, 8, 4, 1, 4, 10, 7, 11, 4, 10, 4, 11, -1, // quitte: 227 <-> mc: 227, class rep: 25 + 2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1, // quitte: 228 <-> mc: 232, class rep: 27 + 9, 7, 10, 9, 4, 7, 10, 7, 2, 8, 0, 7, 2, 7, 0, -1, // quitte: 229 <-> mc: 233, class rep: 25 + 3, 10, 7, 3, 2, 10, 7, 10, 4, 1, 0, 10, 4, 10, 0, -1, // quitte: 230 <-> mc: 234, class rep: 25 + 1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 231 <-> mc: 235, class rep: 24 + 4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1, // quitte: 232 <-> mc: 228, class rep: 23 + 9, 4, 7, 9, 7, 11, 9, 11, 1, 2, 1, 11, 0, 3, 8, -1, // quitte: 233 <-> mc: 229, class rep: 22 + 11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1, // quitte: 234 <-> mc: 230, class rep: 7 + 11, 4, 7, 11, 2, 4, 8, 4, 3, 3, 4, 2, -1, -1, -1, -1, // quitte: 235 <-> mc: 231, class rep: 6 + 4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1, // quitte: 236 <-> mc: 236, class rep: 7 + 4, 1, 9, 4, 7, 1, 0, 1, 8, 8, 1, 7, -1, -1, -1, -1, // quitte: 237 <-> mc: 237, class rep: 6 + 4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 238 <-> mc: 238, class rep: 3 + 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 239 <-> mc: 239, class rep: 1 + 9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 240 <-> mc: 240, class rep: 15 + 3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1, // quitte: 241 <-> mc: 241, class rep: 7 + 0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1, // quitte: 242 <-> mc: 242, class rep: 7 + 3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 243 <-> mc: 243, class rep: 3 + 2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1, // quitte: 244 <-> mc: 248, class rep: 7 + 9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 245 <-> mc: 249, class rep: 3 + 2, 8, 3, 2, 10, 8, 0, 8, 1, 1, 8, 10, -1, -1, -1, -1, // quitte: 246 <-> mc: 250, class rep: 6 + 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 247 <-> mc: 251, class rep: 1 + 1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1, // quitte: 248 <-> mc: 244, class rep: 7 + 3, 9, 0, 3, 11, 9, 1, 9, 2, 2, 9, 11, -1, -1, -1, -1, // quitte: 249 <-> mc: 245, class rep: 6 + 0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 250 <-> mc: 246, class rep: 3 + 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 251 <-> mc: 247, class rep: 1 + 1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 252 <-> mc: 252, class rep: 3 + 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 253 <-> mc: 253, class rep: 1 + 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 254 <-> mc: 254, class rep: 1 + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // quitte: 255 <-> mc: 255, class rep: 0 }; // list of ambiguous cases -constexpr int t_ambig[256] = { - 0, // quitte: 0 <-> mc: 0, class representative: 0 - 1, // quitte: 1 <-> mc: 1, class representative: 1 - 2, // quitte: 2 <-> mc: 2, class representative: 1 - 3, // quitte: 3 <-> mc: 3, class representative: 3 - 4, // quitte: 4 <-> mc: 8, class representative: 1 - 5, // quitte: 5 <-> mc: 9, class representative: 3 - 105, // quitte: 6 <-> mc: 10, class representative: 6 - 7, // quitte: 7 <-> mc: 11, class representative: 7 - 8, // quitte: 8 <-> mc: 4, class representative: 1 - 105, // quitte: 9 <-> mc: 5, class representative: 6 - 10, // quitte: 10 <-> mc: 6, class representative: 3 - 11, // quitte: 11 <-> mc: 7, class representative: 7 - 12, // quitte: 12 <-> mc: 12, class representative: 3 - 13, // quitte: 13 <-> mc: 13, class representative: 7 - 14, // quitte: 14 <-> mc: 14, class representative: 7 - 15, // quitte: 15 <-> mc: 15, class representative: 15 - 16, // quitte: 16 <-> mc: 16, class representative: 1 - 17, // quitte: 17 <-> mc: 17, class representative: 3 - 105, // quitte: 18 <-> mc: 18, class representative: 6 - 19, // quitte: 19 <-> mc: 19, class representative: 7 - 105, // quitte: 20 <-> mc: 24, class representative: 6 - 21, // quitte: 21 <-> mc: 25, class representative: 7 - 105, // quitte: 22 <-> mc: 26, class representative: 22 - 23, // quitte: 23 <-> mc: 27, class representative: 23 - 105, // quitte: 24 <-> mc: 20, class representative: 24 - 105, // quitte: 25 <-> mc: 21, class representative: 25 - 105, // quitte: 26 <-> mc: 22, class representative: 25 - 27, // quitte: 27 <-> mc: 23, class representative: 27 - 105, // quitte: 28 <-> mc: 28, class representative: 25 - 29, // quitte: 29 <-> mc: 29, class representative: 29 - 105, // quitte: 30 <-> mc: 30, class representative: 30 - 31, // quitte: 31 <-> mc: 31, class representative: 7 - 32, // quitte: 32 <-> mc: 32, class representative: 1 - 105, // quitte: 33 <-> mc: 33, class representative: 6 - 34, // quitte: 34 <-> mc: 34, class representative: 3 - 35, // quitte: 35 <-> mc: 35, class representative: 7 - 105, // quitte: 36 <-> mc: 40, class representative: 24 - 105, // quitte: 37 <-> mc: 41, class representative: 25 - 105, // quitte: 38 <-> mc: 42, class representative: 25 - 39, // quitte: 39 <-> mc: 43, class representative: 29 - 105, // quitte: 40 <-> mc: 36, class representative: 6 - 105, // quitte: 41 <-> mc: 37, class representative: 22 - 42, // quitte: 42 <-> mc: 38, class representative: 7 - 43, // quitte: 43 <-> mc: 39, class representative: 23 - 105, // quitte: 44 <-> mc: 44, class representative: 25 - 105, // quitte: 45 <-> mc: 45, class representative: 30 - 46, // quitte: 46 <-> mc: 46, class representative: 27 - 47, // quitte: 47 <-> mc: 47, class representative: 7 - 48, // quitte: 48 <-> mc: 48, class representative: 3 - 49, // quitte: 49 <-> mc: 49, class representative: 7 - 50, // quitte: 50 <-> mc: 50, class representative: 7 - 51, // quitte: 51 <-> mc: 51, class representative: 15 - 105, // quitte: 52 <-> mc: 56, class representative: 25 - 53, // quitte: 53 <-> mc: 57, class representative: 27 - 105, // quitte: 54 <-> mc: 58, class representative: 30 - 55, // quitte: 55 <-> mc: 59, class representative: 7 - 105, // quitte: 56 <-> mc: 52, class representative: 25 - 105, // quitte: 57 <-> mc: 53, class representative: 30 - 58, // quitte: 58 <-> mc: 54, class representative: 29 - 59, // quitte: 59 <-> mc: 55, class representative: 7 - 105, // quitte: 60 <-> mc: 60, class representative: 60 - 105, // quitte: 61 <-> mc: 61, class representative: 25 - 105, // quitte: 62 <-> mc: 62, class representative: 25 - 63, // quitte: 63 <-> mc: 63, class representative: 3 - 64, // quitte: 64 <-> mc: 128, class representative: 1 - 105, // quitte: 65 <-> mc: 129, class representative: 6 - 105, // quitte: 66 <-> mc: 130, class representative: 24 - 105, // quitte: 67 <-> mc: 131, class representative: 25 - 68, // quitte: 68 <-> mc: 136, class representative: 3 - 69, // quitte: 69 <-> mc: 137, class representative: 7 - 105, // quitte: 70 <-> mc: 138, class representative: 25 - 71, // quitte: 71 <-> mc: 139, class representative: 27 - 105, // quitte: 72 <-> mc: 132, class representative: 6 - 105, // quitte: 73 <-> mc: 133, class representative: 22 - 105, // quitte: 74 <-> mc: 134, class representative: 25 - 105, // quitte: 75 <-> mc: 135, class representative: 30 - 76, // quitte: 76 <-> mc: 140, class representative: 7 - 77, // quitte: 77 <-> mc: 141, class representative: 23 - 78, // quitte: 78 <-> mc: 142, class representative: 29 - 79, // quitte: 79 <-> mc: 143, class representative: 7 - 80, // quitte: 80 <-> mc: 144, class representative: 3 - 81, // quitte: 81 <-> mc: 145, class representative: 7 - 105, // quitte: 82 <-> mc: 146, class representative: 25 - 83, // quitte: 83 <-> mc: 147, class representative: 29 - 84, // quitte: 84 <-> mc: 152, class representative: 7 - 85, // quitte: 85 <-> mc: 153, class representative: 15 - 105, // quitte: 86 <-> mc: 154, class representative: 30 - 87, // quitte: 87 <-> mc: 155, class representative: 7 - 105, // quitte: 88 <-> mc: 148, class representative: 25 - 105, // quitte: 89 <-> mc: 149, class representative: 30 - 105, // quitte: 90 <-> mc: 150, class representative: 60 - 105, // quitte: 91 <-> mc: 151, class representative: 25 - 92, // quitte: 92 <-> mc: 156, class representative: 27 - 93, // quitte: 93 <-> mc: 157, class representative: 7 - 105, // quitte: 94 <-> mc: 158, class representative: 25 - 95, // quitte: 95 <-> mc: 159, class representative: 3 - 105, // quitte: 96 <-> mc: 160, class representative: 6 - 105, // quitte: 97 <-> mc: 161, class representative: 22 - 105, // quitte: 98 <-> mc: 162, class representative: 25 - 105, // quitte: 99 <-> mc: 163, class representative: 30 - 105, // quitte: 100 <-> mc: 168, class representative: 25 - 105, // quitte: 101 <-> mc: 169, class representative: 30 - 105, // quitte: 102 <-> mc: 170, class representative: 60 - 105, // quitte: 103 <-> mc: 171, class representative: 25 - 105, // quitte: 104 <-> mc: 164, class representative: 22 - 105, // quitte: 105 <-> mc: 165, class representative: 105 - 105, // quitte: 106 <-> mc: 166, class representative: 30 - 105, // quitte: 107 <-> mc: 167, class representative: 22 - 105, // quitte: 108 <-> mc: 172, class representative: 30 - 105, // quitte: 109 <-> mc: 173, class representative: 22 - 105, // quitte: 110 <-> mc: 174, class representative: 25 - 105, // quitte: 111 <-> mc: 175, class representative: 6 - 112, // quitte: 112 <-> mc: 176, class representative: 7 - 113, // quitte: 113 <-> mc: 177, class representative: 23 - 114, // quitte: 114 <-> mc: 178, class representative: 27 - 115, // quitte: 115 <-> mc: 179, class representative: 7 - 116, // quitte: 116 <-> mc: 184, class representative: 29 - 117, // quitte: 117 <-> mc: 185, class representative: 7 - 105, // quitte: 118 <-> mc: 186, class representative: 25 - 119, // quitte: 119 <-> mc: 187, class representative: 3 - 105, // quitte: 120 <-> mc: 180, class representative: 30 - 105, // quitte: 121 <-> mc: 181, class representative: 22 - 105, // quitte: 122 <-> mc: 182, class representative: 25 - 105, // quitte: 123 <-> mc: 183, class representative: 6 - 105, // quitte: 124 <-> mc: 188, class representative: 25 - 105, // quitte: 125 <-> mc: 189, class representative: 6 - 105, // quitte: 126 <-> mc: 190, class representative: 24 - 127, // quitte: 127 <-> mc: 191, class representative: 1 - 128, // quitte: 128 <-> mc: 64, class representative: 1 - 105, // quitte: 129 <-> mc: 65, class representative: 24 - 105, // quitte: 130 <-> mc: 66, class representative: 6 - 105, // quitte: 131 <-> mc: 67, class representative: 25 - 105, // quitte: 132 <-> mc: 72, class representative: 6 - 105, // quitte: 133 <-> mc: 73, class representative: 25 - 105, // quitte: 134 <-> mc: 74, class representative: 22 - 105, // quitte: 135 <-> mc: 75, class representative: 30 - 136, // quitte: 136 <-> mc: 68, class representative: 3 - 105, // quitte: 137 <-> mc: 69, class representative: 25 - 138, // quitte: 138 <-> mc: 70, class representative: 7 - 139, // quitte: 139 <-> mc: 71, class representative: 29 - 140, // quitte: 140 <-> mc: 76, class representative: 7 - 141, // quitte: 141 <-> mc: 77, class representative: 27 - 142, // quitte: 142 <-> mc: 78, class representative: 23 - 143, // quitte: 143 <-> mc: 79, class representative: 7 - 105, // quitte: 144 <-> mc: 80, class representative: 6 - 105, // quitte: 145 <-> mc: 81, class representative: 25 - 105, // quitte: 146 <-> mc: 82, class representative: 22 - 105, // quitte: 147 <-> mc: 83, class representative: 30 - 105, // quitte: 148 <-> mc: 88, class representative: 22 - 105, // quitte: 149 <-> mc: 89, class representative: 30 - 105, // quitte: 150 <-> mc: 90, class representative: 105 - 105, // quitte: 151 <-> mc: 91, class representative: 22 - 105, // quitte: 152 <-> mc: 84, class representative: 25 - 105, // quitte: 153 <-> mc: 85, class representative: 60 - 105, // quitte: 154 <-> mc: 86, class representative: 30 - 105, // quitte: 155 <-> mc: 87, class representative: 25 - 105, // quitte: 156 <-> mc: 92, class representative: 30 - 105, // quitte: 157 <-> mc: 93, class representative: 25 - 105, // quitte: 158 <-> mc: 94, class representative: 22 - 105, // quitte: 159 <-> mc: 95, class representative: 6 - 160, // quitte: 160 <-> mc: 96, class representative: 3 - 105, // quitte: 161 <-> mc: 97, class representative: 25 - 162, // quitte: 162 <-> mc: 98, class representative: 7 - 163, // quitte: 163 <-> mc: 99, class representative: 27 - 105, // quitte: 164 <-> mc: 104, class representative: 25 - 105, // quitte: 165 <-> mc: 105, class representative: 60 - 105, // quitte: 166 <-> mc: 106, class representative: 30 - 105, // quitte: 167 <-> mc: 107, class representative: 25 - 168, // quitte: 168 <-> mc: 100, class representative: 7 - 105, // quitte: 169 <-> mc: 101, class representative: 30 - 170, // quitte: 170 <-> mc: 102, class representative: 15 - 171, // quitte: 171 <-> mc: 103, class representative: 7 - 172, // quitte: 172 <-> mc: 108, class representative: 29 - 105, // quitte: 173 <-> mc: 109, class representative: 25 - 174, // quitte: 174 <-> mc: 110, class representative: 7 - 175, // quitte: 175 <-> mc: 111, class representative: 3 - 176, // quitte: 176 <-> mc: 112, class representative: 7 - 177, // quitte: 177 <-> mc: 113, class representative: 29 - 178, // quitte: 178 <-> mc: 114, class representative: 23 - 179, // quitte: 179 <-> mc: 115, class representative: 7 - 105, // quitte: 180 <-> mc: 120, class representative: 30 - 105, // quitte: 181 <-> mc: 121, class representative: 25 - 105, // quitte: 182 <-> mc: 122, class representative: 22 - 105, // quitte: 183 <-> mc: 123, class representative: 6 - 184, // quitte: 184 <-> mc: 116, class representative: 27 - 105, // quitte: 185 <-> mc: 117, class representative: 25 - 186, // quitte: 186 <-> mc: 118, class representative: 7 - 187, // quitte: 187 <-> mc: 119, class representative: 3 - 105, // quitte: 188 <-> mc: 124, class representative: 25 - 105, // quitte: 189 <-> mc: 125, class representative: 24 - 105, // quitte: 190 <-> mc: 126, class representative: 6 - 191, // quitte: 191 <-> mc: 127, class representative: 1 - 192, // quitte: 192 <-> mc: 192, class representative: 3 - 105, // quitte: 193 <-> mc: 193, class representative: 25 - 105, // quitte: 194 <-> mc: 194, class representative: 25 - 105, // quitte: 195 <-> mc: 195, class representative: 60 - 196, // quitte: 196 <-> mc: 200, class representative: 7 - 197, // quitte: 197 <-> mc: 201, class representative: 29 - 105, // quitte: 198 <-> mc: 202, class representative: 30 - 105, // quitte: 199 <-> mc: 203, class representative: 25 - 200, // quitte: 200 <-> mc: 196, class representative: 7 - 105, // quitte: 201 <-> mc: 197, class representative: 30 - 202, // quitte: 202 <-> mc: 198, class representative: 27 - 105, // quitte: 203 <-> mc: 199, class representative: 25 - 204, // quitte: 204 <-> mc: 204, class representative: 15 - 205, // quitte: 205 <-> mc: 205, class representative: 7 - 206, // quitte: 206 <-> mc: 206, class representative: 7 - 207, // quitte: 207 <-> mc: 207, class representative: 3 - 208, // quitte: 208 <-> mc: 208, class representative: 7 - 209, // quitte: 209 <-> mc: 209, class representative: 27 - 105, // quitte: 210 <-> mc: 210, class representative: 30 - 105, // quitte: 211 <-> mc: 211, class representative: 25 - 212, // quitte: 212 <-> mc: 216, class representative: 23 - 213, // quitte: 213 <-> mc: 217, class representative: 7 - 105, // quitte: 214 <-> mc: 218, class representative: 22 - 105, // quitte: 215 <-> mc: 219, class representative: 6 - 216, // quitte: 216 <-> mc: 212, class representative: 29 - 105, // quitte: 217 <-> mc: 213, class representative: 25 - 105, // quitte: 218 <-> mc: 214, class representative: 25 - 105, // quitte: 219 <-> mc: 215, class representative: 24 - 220, // quitte: 220 <-> mc: 220, class representative: 7 - 221, // quitte: 221 <-> mc: 221, class representative: 3 - 105, // quitte: 222 <-> mc: 222, class representative: 6 - 223, // quitte: 223 <-> mc: 223, class representative: 1 - 224, // quitte: 224 <-> mc: 224, class representative: 7 - 105, // quitte: 225 <-> mc: 225, class representative: 30 - 226, // quitte: 226 <-> mc: 226, class representative: 29 - 105, // quitte: 227 <-> mc: 227, class representative: 25 - 228, // quitte: 228 <-> mc: 232, class representative: 27 - 105, // quitte: 229 <-> mc: 233, class representative: 25 - 105, // quitte: 230 <-> mc: 234, class representative: 25 - 105, // quitte: 231 <-> mc: 235, class representative: 24 - 232, // quitte: 232 <-> mc: 228, class representative: 23 - 105, // quitte: 233 <-> mc: 229, class representative: 22 - 234, // quitte: 234 <-> mc: 230, class representative: 7 - 105, // quitte: 235 <-> mc: 231, class representative: 6 - 236, // quitte: 236 <-> mc: 236, class representative: 7 - 105, // quitte: 237 <-> mc: 237, class representative: 6 - 238, // quitte: 238 <-> mc: 238, class representative: 3 - 239, // quitte: 239 <-> mc: 239, class representative: 1 - 240, // quitte: 240 <-> mc: 240, class representative: 15 - 241, // quitte: 241 <-> mc: 241, class representative: 7 - 242, // quitte: 242 <-> mc: 242, class representative: 7 - 243, // quitte: 243 <-> mc: 243, class representative: 3 - 244, // quitte: 244 <-> mc: 248, class representative: 7 - 245, // quitte: 245 <-> mc: 249, class representative: 3 - 105, // quitte: 246 <-> mc: 250, class representative: 6 - 247, // quitte: 247 <-> mc: 251, class representative: 1 - 248, // quitte: 248 <-> mc: 244, class representative: 7 - 105, // quitte: 249 <-> mc: 245, class representative: 6 - 250, // quitte: 250 <-> mc: 246, class representative: 3 - 251, // quitte: 251 <-> mc: 247, class representative: 1 - 252, // quitte: 252 <-> mc: 252, class representative: 3 - 253, // quitte: 253 <-> mc: 253, class representative: 1 - 254, // quitte: 254 <-> mc: 254, class representative: 1 - 255 // quitte: 255 <-> mc: 255, class representative: 0 +constexpr int t_ambig[256] = +{ + 0, // quitte: 0 <-> mc: 0, class representative: 0 + 1, // quitte: 1 <-> mc: 1, class representative: 1 + 2, // quitte: 2 <-> mc: 2, class representative: 1 + 3, // quitte: 3 <-> mc: 3, class representative: 3 + 4, // quitte: 4 <-> mc: 8, class representative: 1 + 5, // quitte: 5 <-> mc: 9, class representative: 3 + 105, // quitte: 6 <-> mc: 10, class representative: 6 + 7, // quitte: 7 <-> mc: 11, class representative: 7 + 8, // quitte: 8 <-> mc: 4, class representative: 1 + 105, // quitte: 9 <-> mc: 5, class representative: 6 + 10, // quitte: 10 <-> mc: 6, class representative: 3 + 11, // quitte: 11 <-> mc: 7, class representative: 7 + 12, // quitte: 12 <-> mc: 12, class representative: 3 + 13, // quitte: 13 <-> mc: 13, class representative: 7 + 14, // quitte: 14 <-> mc: 14, class representative: 7 + 15, // quitte: 15 <-> mc: 15, class representative: 15 + 16, // quitte: 16 <-> mc: 16, class representative: 1 + 17, // quitte: 17 <-> mc: 17, class representative: 3 + 105, // quitte: 18 <-> mc: 18, class representative: 6 + 19, // quitte: 19 <-> mc: 19, class representative: 7 + 105, // quitte: 20 <-> mc: 24, class representative: 6 + 21, // quitte: 21 <-> mc: 25, class representative: 7 + 105, // quitte: 22 <-> mc: 26, class representative: 22 + 23, // quitte: 23 <-> mc: 27, class representative: 23 + 105, // quitte: 24 <-> mc: 20, class representative: 24 + 105, // quitte: 25 <-> mc: 21, class representative: 25 + 105, // quitte: 26 <-> mc: 22, class representative: 25 + 27, // quitte: 27 <-> mc: 23, class representative: 27 + 105, // quitte: 28 <-> mc: 28, class representative: 25 + 29, // quitte: 29 <-> mc: 29, class representative: 29 + 105, // quitte: 30 <-> mc: 30, class representative: 30 + 31, // quitte: 31 <-> mc: 31, class representative: 7 + 32, // quitte: 32 <-> mc: 32, class representative: 1 + 105, // quitte: 33 <-> mc: 33, class representative: 6 + 34, // quitte: 34 <-> mc: 34, class representative: 3 + 35, // quitte: 35 <-> mc: 35, class representative: 7 + 105, // quitte: 36 <-> mc: 40, class representative: 24 + 105, // quitte: 37 <-> mc: 41, class representative: 25 + 105, // quitte: 38 <-> mc: 42, class representative: 25 + 39, // quitte: 39 <-> mc: 43, class representative: 29 + 105, // quitte: 40 <-> mc: 36, class representative: 6 + 105, // quitte: 41 <-> mc: 37, class representative: 22 + 42, // quitte: 42 <-> mc: 38, class representative: 7 + 43, // quitte: 43 <-> mc: 39, class representative: 23 + 105, // quitte: 44 <-> mc: 44, class representative: 25 + 105, // quitte: 45 <-> mc: 45, class representative: 30 + 46, // quitte: 46 <-> mc: 46, class representative: 27 + 47, // quitte: 47 <-> mc: 47, class representative: 7 + 48, // quitte: 48 <-> mc: 48, class representative: 3 + 49, // quitte: 49 <-> mc: 49, class representative: 7 + 50, // quitte: 50 <-> mc: 50, class representative: 7 + 51, // quitte: 51 <-> mc: 51, class representative: 15 + 105, // quitte: 52 <-> mc: 56, class representative: 25 + 53, // quitte: 53 <-> mc: 57, class representative: 27 + 105, // quitte: 54 <-> mc: 58, class representative: 30 + 55, // quitte: 55 <-> mc: 59, class representative: 7 + 105, // quitte: 56 <-> mc: 52, class representative: 25 + 105, // quitte: 57 <-> mc: 53, class representative: 30 + 58, // quitte: 58 <-> mc: 54, class representative: 29 + 59, // quitte: 59 <-> mc: 55, class representative: 7 + 105, // quitte: 60 <-> mc: 60, class representative: 60 + 105, // quitte: 61 <-> mc: 61, class representative: 25 + 105, // quitte: 62 <-> mc: 62, class representative: 25 + 63, // quitte: 63 <-> mc: 63, class representative: 3 + 64, // quitte: 64 <-> mc: 128, class representative: 1 + 105, // quitte: 65 <-> mc: 129, class representative: 6 + 105, // quitte: 66 <-> mc: 130, class representative: 24 + 105, // quitte: 67 <-> mc: 131, class representative: 25 + 68, // quitte: 68 <-> mc: 136, class representative: 3 + 69, // quitte: 69 <-> mc: 137, class representative: 7 + 105, // quitte: 70 <-> mc: 138, class representative: 25 + 71, // quitte: 71 <-> mc: 139, class representative: 27 + 105, // quitte: 72 <-> mc: 132, class representative: 6 + 105, // quitte: 73 <-> mc: 133, class representative: 22 + 105, // quitte: 74 <-> mc: 134, class representative: 25 + 105, // quitte: 75 <-> mc: 135, class representative: 30 + 76, // quitte: 76 <-> mc: 140, class representative: 7 + 77, // quitte: 77 <-> mc: 141, class representative: 23 + 78, // quitte: 78 <-> mc: 142, class representative: 29 + 79, // quitte: 79 <-> mc: 143, class representative: 7 + 80, // quitte: 80 <-> mc: 144, class representative: 3 + 81, // quitte: 81 <-> mc: 145, class representative: 7 + 105, // quitte: 82 <-> mc: 146, class representative: 25 + 83, // quitte: 83 <-> mc: 147, class representative: 29 + 84, // quitte: 84 <-> mc: 152, class representative: 7 + 85, // quitte: 85 <-> mc: 153, class representative: 15 + 105, // quitte: 86 <-> mc: 154, class representative: 30 + 87, // quitte: 87 <-> mc: 155, class representative: 7 + 105, // quitte: 88 <-> mc: 148, class representative: 25 + 105, // quitte: 89 <-> mc: 149, class representative: 30 + 105, // quitte: 90 <-> mc: 150, class representative: 60 + 105, // quitte: 91 <-> mc: 151, class representative: 25 + 92, // quitte: 92 <-> mc: 156, class representative: 27 + 93, // quitte: 93 <-> mc: 157, class representative: 7 + 105, // quitte: 94 <-> mc: 158, class representative: 25 + 95, // quitte: 95 <-> mc: 159, class representative: 3 + 105, // quitte: 96 <-> mc: 160, class representative: 6 + 105, // quitte: 97 <-> mc: 161, class representative: 22 + 105, // quitte: 98 <-> mc: 162, class representative: 25 + 105, // quitte: 99 <-> mc: 163, class representative: 30 + 105, // quitte: 100 <-> mc: 168, class representative: 25 + 105, // quitte: 101 <-> mc: 169, class representative: 30 + 105, // quitte: 102 <-> mc: 170, class representative: 60 + 105, // quitte: 103 <-> mc: 171, class representative: 25 + 105, // quitte: 104 <-> mc: 164, class representative: 22 + 105, // quitte: 105 <-> mc: 165, class representative: 105 + 105, // quitte: 106 <-> mc: 166, class representative: 30 + 105, // quitte: 107 <-> mc: 167, class representative: 22 + 105, // quitte: 108 <-> mc: 172, class representative: 30 + 105, // quitte: 109 <-> mc: 173, class representative: 22 + 105, // quitte: 110 <-> mc: 174, class representative: 25 + 105, // quitte: 111 <-> mc: 175, class representative: 6 + 112, // quitte: 112 <-> mc: 176, class representative: 7 + 113, // quitte: 113 <-> mc: 177, class representative: 23 + 114, // quitte: 114 <-> mc: 178, class representative: 27 + 115, // quitte: 115 <-> mc: 179, class representative: 7 + 116, // quitte: 116 <-> mc: 184, class representative: 29 + 117, // quitte: 117 <-> mc: 185, class representative: 7 + 105, // quitte: 118 <-> mc: 186, class representative: 25 + 119, // quitte: 119 <-> mc: 187, class representative: 3 + 105, // quitte: 120 <-> mc: 180, class representative: 30 + 105, // quitte: 121 <-> mc: 181, class representative: 22 + 105, // quitte: 122 <-> mc: 182, class representative: 25 + 105, // quitte: 123 <-> mc: 183, class representative: 6 + 105, // quitte: 124 <-> mc: 188, class representative: 25 + 105, // quitte: 125 <-> mc: 189, class representative: 6 + 105, // quitte: 126 <-> mc: 190, class representative: 24 + 127, // quitte: 127 <-> mc: 191, class representative: 1 + 128, // quitte: 128 <-> mc: 64, class representative: 1 + 105, // quitte: 129 <-> mc: 65, class representative: 24 + 105, // quitte: 130 <-> mc: 66, class representative: 6 + 105, // quitte: 131 <-> mc: 67, class representative: 25 + 105, // quitte: 132 <-> mc: 72, class representative: 6 + 105, // quitte: 133 <-> mc: 73, class representative: 25 + 105, // quitte: 134 <-> mc: 74, class representative: 22 + 105, // quitte: 135 <-> mc: 75, class representative: 30 + 136, // quitte: 136 <-> mc: 68, class representative: 3 + 105, // quitte: 137 <-> mc: 69, class representative: 25 + 138, // quitte: 138 <-> mc: 70, class representative: 7 + 139, // quitte: 139 <-> mc: 71, class representative: 29 + 140, // quitte: 140 <-> mc: 76, class representative: 7 + 141, // quitte: 141 <-> mc: 77, class representative: 27 + 142, // quitte: 142 <-> mc: 78, class representative: 23 + 143, // quitte: 143 <-> mc: 79, class representative: 7 + 105, // quitte: 144 <-> mc: 80, class representative: 6 + 105, // quitte: 145 <-> mc: 81, class representative: 25 + 105, // quitte: 146 <-> mc: 82, class representative: 22 + 105, // quitte: 147 <-> mc: 83, class representative: 30 + 105, // quitte: 148 <-> mc: 88, class representative: 22 + 105, // quitte: 149 <-> mc: 89, class representative: 30 + 105, // quitte: 150 <-> mc: 90, class representative: 105 + 105, // quitte: 151 <-> mc: 91, class representative: 22 + 105, // quitte: 152 <-> mc: 84, class representative: 25 + 105, // quitte: 153 <-> mc: 85, class representative: 60 + 105, // quitte: 154 <-> mc: 86, class representative: 30 + 105, // quitte: 155 <-> mc: 87, class representative: 25 + 105, // quitte: 156 <-> mc: 92, class representative: 30 + 105, // quitte: 157 <-> mc: 93, class representative: 25 + 105, // quitte: 158 <-> mc: 94, class representative: 22 + 105, // quitte: 159 <-> mc: 95, class representative: 6 + 160, // quitte: 160 <-> mc: 96, class representative: 3 + 105, // quitte: 161 <-> mc: 97, class representative: 25 + 162, // quitte: 162 <-> mc: 98, class representative: 7 + 163, // quitte: 163 <-> mc: 99, class representative: 27 + 105, // quitte: 164 <-> mc: 104, class representative: 25 + 105, // quitte: 165 <-> mc: 105, class representative: 60 + 105, // quitte: 166 <-> mc: 106, class representative: 30 + 105, // quitte: 167 <-> mc: 107, class representative: 25 + 168, // quitte: 168 <-> mc: 100, class representative: 7 + 105, // quitte: 169 <-> mc: 101, class representative: 30 + 170, // quitte: 170 <-> mc: 102, class representative: 15 + 171, // quitte: 171 <-> mc: 103, class representative: 7 + 172, // quitte: 172 <-> mc: 108, class representative: 29 + 105, // quitte: 173 <-> mc: 109, class representative: 25 + 174, // quitte: 174 <-> mc: 110, class representative: 7 + 175, // quitte: 175 <-> mc: 111, class representative: 3 + 176, // quitte: 176 <-> mc: 112, class representative: 7 + 177, // quitte: 177 <-> mc: 113, class representative: 29 + 178, // quitte: 178 <-> mc: 114, class representative: 23 + 179, // quitte: 179 <-> mc: 115, class representative: 7 + 105, // quitte: 180 <-> mc: 120, class representative: 30 + 105, // quitte: 181 <-> mc: 121, class representative: 25 + 105, // quitte: 182 <-> mc: 122, class representative: 22 + 105, // quitte: 183 <-> mc: 123, class representative: 6 + 184, // quitte: 184 <-> mc: 116, class representative: 27 + 105, // quitte: 185 <-> mc: 117, class representative: 25 + 186, // quitte: 186 <-> mc: 118, class representative: 7 + 187, // quitte: 187 <-> mc: 119, class representative: 3 + 105, // quitte: 188 <-> mc: 124, class representative: 25 + 105, // quitte: 189 <-> mc: 125, class representative: 24 + 105, // quitte: 190 <-> mc: 126, class representative: 6 + 191, // quitte: 191 <-> mc: 127, class representative: 1 + 192, // quitte: 192 <-> mc: 192, class representative: 3 + 105, // quitte: 193 <-> mc: 193, class representative: 25 + 105, // quitte: 194 <-> mc: 194, class representative: 25 + 105, // quitte: 195 <-> mc: 195, class representative: 60 + 196, // quitte: 196 <-> mc: 200, class representative: 7 + 197, // quitte: 197 <-> mc: 201, class representative: 29 + 105, // quitte: 198 <-> mc: 202, class representative: 30 + 105, // quitte: 199 <-> mc: 203, class representative: 25 + 200, // quitte: 200 <-> mc: 196, class representative: 7 + 105, // quitte: 201 <-> mc: 197, class representative: 30 + 202, // quitte: 202 <-> mc: 198, class representative: 27 + 105, // quitte: 203 <-> mc: 199, class representative: 25 + 204, // quitte: 204 <-> mc: 204, class representative: 15 + 205, // quitte: 205 <-> mc: 205, class representative: 7 + 206, // quitte: 206 <-> mc: 206, class representative: 7 + 207, // quitte: 207 <-> mc: 207, class representative: 3 + 208, // quitte: 208 <-> mc: 208, class representative: 7 + 209, // quitte: 209 <-> mc: 209, class representative: 27 + 105, // quitte: 210 <-> mc: 210, class representative: 30 + 105, // quitte: 211 <-> mc: 211, class representative: 25 + 212, // quitte: 212 <-> mc: 216, class representative: 23 + 213, // quitte: 213 <-> mc: 217, class representative: 7 + 105, // quitte: 214 <-> mc: 218, class representative: 22 + 105, // quitte: 215 <-> mc: 219, class representative: 6 + 216, // quitte: 216 <-> mc: 212, class representative: 29 + 105, // quitte: 217 <-> mc: 213, class representative: 25 + 105, // quitte: 218 <-> mc: 214, class representative: 25 + 105, // quitte: 219 <-> mc: 215, class representative: 24 + 220, // quitte: 220 <-> mc: 220, class representative: 7 + 221, // quitte: 221 <-> mc: 221, class representative: 3 + 105, // quitte: 222 <-> mc: 222, class representative: 6 + 223, // quitte: 223 <-> mc: 223, class representative: 1 + 224, // quitte: 224 <-> mc: 224, class representative: 7 + 105, // quitte: 225 <-> mc: 225, class representative: 30 + 226, // quitte: 226 <-> mc: 226, class representative: 29 + 105, // quitte: 227 <-> mc: 227, class representative: 25 + 228, // quitte: 228 <-> mc: 232, class representative: 27 + 105, // quitte: 229 <-> mc: 233, class representative: 25 + 105, // quitte: 230 <-> mc: 234, class representative: 25 + 105, // quitte: 231 <-> mc: 235, class representative: 24 + 232, // quitte: 232 <-> mc: 228, class representative: 23 + 105, // quitte: 233 <-> mc: 229, class representative: 22 + 234, // quitte: 234 <-> mc: 230, class representative: 7 + 105, // quitte: 235 <-> mc: 231, class representative: 6 + 236, // quitte: 236 <-> mc: 236, class representative: 7 + 105, // quitte: 237 <-> mc: 237, class representative: 6 + 238, // quitte: 238 <-> mc: 238, class representative: 3 + 239, // quitte: 239 <-> mc: 239, class representative: 1 + 240, // quitte: 240 <-> mc: 240, class representative: 15 + 241, // quitte: 241 <-> mc: 241, class representative: 7 + 242, // quitte: 242 <-> mc: 242, class representative: 7 + 243, // quitte: 243 <-> mc: 243, class representative: 3 + 244, // quitte: 244 <-> mc: 248, class representative: 7 + 245, // quitte: 245 <-> mc: 249, class representative: 3 + 105, // quitte: 246 <-> mc: 250, class representative: 6 + 247, // quitte: 247 <-> mc: 251, class representative: 1 + 248, // quitte: 248 <-> mc: 244, class representative: 7 + 105, // quitte: 249 <-> mc: 245, class representative: 6 + 250, // quitte: 250 <-> mc: 246, class representative: 3 + 251, // quitte: 251 <-> mc: 247, class representative: 1 + 252, // quitte: 252 <-> mc: 252, class representative: 3 + 253, // quitte: 253 <-> mc: 253, class representative: 1 + 254, // quitte: 254 <-> mc: 254, class representative: 1 + 255 // quitte: 255 <-> mc: 255, class representative: 0 }; -} // namespace Cube_table +} // namespace Cube_table -} // namespace internal -} // namespace Isosurfacing -} // namespace CGAL +} // namespace internal +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_MARCHING_CUBES_3_INTERNAL_TABLES_H \ No newline at end of file +#endif // CGAL_ISOSURFACING_3_INTERNAL_TABLES_H \ No newline at end of file diff --git a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Tmc_internal.h b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Tmc_internal.h index 9a4a7da8e96..840f08f6695 100644 --- a/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Tmc_internal.h +++ b/Isosurfacing_3/include/CGAL/Isosurfacing_3/internal/Tmc_internal.h @@ -38,8 +38,8 @@ // https://github.com/rogrosso/tmc available on 15th of September 2022. // -#ifndef CGAL_TMC_INTERNAL_TMC_H -#define CGAL_TMC_INTERNAL_TMC_H +#ifndef CGAL_ISOSURFACING_3_INTERNAL_TMC_INTERNAL_H +#define CGAL_ISOSURFACING_3_INTERNAL_TMC_INTERNAL_H #include @@ -56,918 +56,1088 @@ namespace CGAL { namespace Isosurfacing { namespace internal { -template -class TMC_functor { +template +class TMC_functor +{ private: - typedef Domain_ Domain; - typedef PointRange Point_range; - typedef PolygonRange Polygon_range; + using Domain = Domain_; + using Point_range = PointRange; + using Polygon_range = PolygonRange; - typedef typename Domain::FT FT; - typedef typename Domain::Point Point; - typedef typename Domain::Vector Vector; - typedef typename Domain::Edge_descriptor Edge_descriptor; - typedef typename Domain::Cell_descriptor Cell_descriptor; + using FT = typename Domain::FT; + using Point = typename Domain::Point; + using Vector = typename Domain::Vector; + using Edge_descriptor = typename Domain::Edge_descriptor; + using Cell_descriptor = typename Domain::Cell_descriptor; - typedef unsigned int uint; + using uint = unsigned int; public: - TMC_functor(const Domain& domain, const FT isovalue, Point_range& points, Polygon_range& polygons) - : domain(domain), isovalue(isovalue), points(points), polygons(polygons) {} + TMC_functor(const Domain& domain, + const FT isovalue, + Point_range& points, + Polygon_range& polygons) + : domain(domain), + isovalue(isovalue), + points(points), + polygons(polygons) + { } - void operator()(const Cell_descriptor& cell) { + void operator()(const Cell_descriptor& cell) + { + FT values[8]; + Point corners[8]; + const int i_case = get_cell_corners(domain, cell, isovalue, corners, values); - FT values[8]; - Point corners[8]; - const int i_case = get_cell_corners(domain, cell, isovalue, corners, values); - - const int all_bits_set = (1 << (8 + 1)) - 1; // last 8 bits are 1 - if (Cube_table::intersected_edges[i_case] == 0 || Cube_table::intersected_edges[i_case] == all_bits_set) { - return; - } - - // this is the only difference to mc - int tcm = (int)Cube_table::t_ambig[i_case]; - if (tcm == 105) { - p_slice(cell, isovalue, values, corners, i_case); - return; - } - - std::array vertices; - mc_construct_vertices(domain.cell_edges(cell), isovalue, i_case, corners, values, vertices); - - // TODO: improve triangle generation - // construct triangles - std::lock_guard lock(mutex); - for (int t = 0; t < 16; t += 3) { - - const int t_index = i_case * 16 + t; - // if (e_tris_list[t_index] == 0x7f) - if (Cube_table::triangle_cases[t_index] == -1) break; - - const int eg0 = Cube_table::triangle_cases[t_index + 0]; // TODO: move more of this stuff into the table - const int eg1 = Cube_table::triangle_cases[t_index + 1]; - const int eg2 = Cube_table::triangle_cases[t_index + 2]; - - const std::size_t p0_idx = points.size(); - - points.push_back(vertices[eg0]); - points.push_back(vertices[eg1]); - points.push_back(vertices[eg2]); - - // insert new triangle in list - polygons.push_back({}); - auto& triangle = polygons.back(); - - triangle.push_back(p0_idx + 2); - triangle.push_back(p0_idx + 1); - triangle.push_back(p0_idx + 0); - } + const int all_bits_set = (1 << (8 + 1)) - 1; // last 8 bits are 1 + if(Cube_table::intersected_edges[i_case] == 0 || + Cube_table::intersected_edges[i_case] == all_bits_set) + { + return; } - void add_triangle(const std::size_t p0, const std::size_t p1, const std::size_t p2) { - std::lock_guard lock(mutex); - - polygons.push_back({}); - auto& triangle = polygons.back(); - - triangle.push_back(p0); - triangle.push_back(p1); - triangle.push_back(p2); + // this is the only difference to mc + int tcm = int(Cube_table::t_ambig[i_case]); + if(tcm == 105) + { + p_slice(cell, isovalue, values, corners, i_case); + return; } - void p_slice(const Cell_descriptor& cell, const double i0, FT* values, Point* corners, const int i_case) { - // there are 12 edges, assign to each vertex three edges, the global edge numbering - // consist of 3*global_vertex_id + edge_offset. - const unsigned long long gei_pattern_ = 670526590282893600ull; + std::array vertices; + mc_construct_vertices(domain.cell_edges(cell), isovalue, i_case, corners, values, vertices); - // code edge end vertices for each of the 12 edges - const unsigned char l_edges_[12] = {16, 49, 50, 32, 84, 117, 118, 100, 64, 81, 115, 98}; - auto get_edge_vertex = [](const int e, unsigned int& v0, unsigned int& v1, const unsigned char l_edges_[12]) { - v0 = (unsigned int)(l_edges_[e] & 0xF); - v1 = (unsigned int)(l_edges_[e] >> 4) & 0xF; - }; + // @todo improve triangle generation - // A hexahedron has twelve edges, save the intersection of the isosurface with the edge - // save global edge and global vertex index of isosurface - std::vector vertices(12); - // save loca coordinate along the edge of intersection point - std::vector ecoord{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + // construct triangles + std::lock_guard lock(mutex); + for(int t=0; t<16; t += 3) + { + const int t_index = i_case * 16 + t; + // if(e_tris_list[t_index] == 0x7f) + if(Cube_table::triangle_cases[t_index] == -1) + break; - // collect vertices - unsigned short flag{1}; - for (int eg = 0; eg < 12; eg++) { - if (flag & Cube_table::intersected_edges[i_case]) { - // the edge global index is given by the vertex global index + the edge offset - // uint shift = 5 * eg; - // const int ix = i_index + (int)((gei_pattern_ >> shift) & 1); // global_edge_id[eg][0]; - // const int iy = j_index + (int)((gei_pattern_ >> (shift + 1)) & 1); // global_edge_id[eg][1]; - // const int iz = k_index + (int)((gei_pattern_ >> (shift + 2)) & 1); // global_edge_id[eg][2]; - // const int off_val = (int)((gei_pattern_ >> (shift + 3)) & 3); + const int eg0 = Cube_table::triangle_cases[t_index + 0]; // TODO: move more of this stuff into the table + const int eg1 = Cube_table::triangle_cases[t_index + 1]; + const int eg2 = Cube_table::triangle_cases[t_index + 2]; - // int g_edg = int(m_cell_shift_factor * m_ugrid.global_index(ix, iy, iz) + off_val); + const std::size_t p0_idx = points.size(); - // generate vertex here, do not care at this point if vertex already exist - uint v0, v1; - get_edge_vertex(eg, v0, v1, l_edges_); + points.push_back(vertices[eg0]); + points.push_back(vertices[eg1]); + points.push_back(vertices[eg2]); - double l = (i0 - values[v0]) / (values[v1] - values[v0]); - ecoord[eg] = l; - // interpolate vertex - const FT px = (1 - l) * corners[v0][0] + l * corners[v1][0]; - const FT py = (1 - l) * corners[v0][1] + l * corners[v1][1]; - const FT pz = (1 - l) * corners[v0][2] + l * corners[v1][2]; + // insert new triangle in list + polygons.push_back({}); + auto& triangle = polygons.back(); - // set vertex in map - // set vertex index - // auto s_index = m_vertices.find(vertices[eg].g_edg); - // if (s_index == m_vertices.end()) { - const int g_idx = (int)points.size(); - vertices[eg] = g_idx; - // m_vertices[vertices[eg].g_edg] = g_idx; - points.push_back(Point(px, py, pz)); - //} else { - // vertices[eg] = s_index->second; - //} + triangle.push_back(p0_idx + 2); + triangle.push_back(p0_idx + 1); + triangle.push_back(p0_idx + 0); + } + } + + void add_triangle(const std::size_t p0, + const std::size_t p1, + const std::size_t p2) + { + std::lock_guard lock(mutex); + + polygons.push_back({}); + auto& triangle = polygons.back(); + + triangle.push_back(p0); + triangle.push_back(p1); + triangle.push_back(p2); + } + + void p_slice(const Cell_descriptor& cell, + const double i0, + FT* values, + Point* corners, + const int i_case) + { + // there are 12 edges, assign to each vertex three edges, the global edge numbering + // consist of 3*global_vertex_id + edge_offset. + const unsigned long long gei_pattern_ = 670526590282893600ull; + + // code edge end vertices for each of the 12 edges + const unsigned char l_edges_[12] = {16, 49, 50, 32, 84, 117, 118, 100, 64, 81, 115, 98}; + auto get_edge_vertex = [](const int e, unsigned int& v0, unsigned int& v1, const unsigned char l_edges_[12]) + { + v0 = (unsigned int)(l_edges_[e] & 0xF); + v1 = (unsigned int)(l_edges_[e] >> 4) & 0xF; + }; + + // A hexahedron has twelve edges, save the intersection of the isosurface with the edge + // save global edge and global vertex index of isosurface + std::vector vertices(12); + + // save loca coordinate along the edge of intersection point + std::vector ecoord{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + // collect vertices + unsigned short flag{1}; + for(int eg=0; eg<12; ++eg) + { + if(flag & Cube_table::intersected_edges[i_case]) + { + // the edge global index is given by the vertex global index + the edge offset + // uint shift = 5 * eg; + // const int ix = i_index + (int)((gei_pattern_ >> shift) & 1); // global_edge_id[eg][0]; + // const int iy = j_index + (int)((gei_pattern_ >> (shift + 1)) & 1); // global_edge_id[eg][1]; + // const int iz = k_index + (int)((gei_pattern_ >> (shift + 2)) & 1); // global_edge_id[eg][2]; + // const int off_val = (int)((gei_pattern_ >> (shift + 3)) & 3); + + // int g_edg = int(m_cell_shift_factor * m_ugrid.global_index(ix, iy, iz) + off_val); + + // generate vertex here, do not care at this point if vertex already exist + uint v0, v1; + get_edge_vertex(eg, v0, v1, l_edges_); + + double l = (i0 - values[v0]) / (values[v1] - values[v0]); + ecoord[eg] = l; + + // interpolate vertex + const FT px = (1 - l) * corners[v0][0] + l * corners[v1][0]; + const FT py = (1 - l) * corners[v0][1] + l * corners[v1][1]; + const FT pz = (1 - l) * corners[v0][2] + l * corners[v1][2]; + + // set vertex in map + // set vertex index + // auto s_index = m_vertices.find(vertices[eg].g_edg); + // if(s_index == m_vertices.end()) + // { + const int g_idx = (int)points.size(); + vertices[eg] = g_idx; + // m_vertices[vertices[eg].g_edg] = g_idx; + points.push_back(Point(px, py, pz)); + //} else { + // vertices[eg] = s_index->second; + //} + } + /*else { + e_set[eg] = false; + }*/ + + // next edge + flag <<= 1; + } + + // compute oriented contours + // A countour consists of segment at the faces connecting the intersection of the + // isosurface with the edges. For each edge we store the edge to which the segment + // is outgoing and the edge from which the segment in comming. Therefore a contour + // cab be reconstructed by connecting the edges in the direccion of the outgoing. + // The contour is oriented in such a way, that the positive vertices are outside. + // 1. build segments + // 2. connect segments + // build up segments + // set segments map + unsigned char segm_[12] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + auto set_segm = [](const int e, const int pos, const int val, unsigned char segm_[12]) + { + if(pos == 0) + { + segm_[e] &= 0xF0; + segm_[e] |= (unsigned char)val & 0xF; + } + else if(pos == 1) + { + segm_[e] &= 0xF; + segm_[e] |= val << 4; + } + }; + + auto get_segm = [](const int e, const int pos, unsigned char segm_[12]) + { + if(pos == 0) + return int(segm_[e] & 0xF); + else + return int((segm_[e] >> 4) & 0xF); + }; + + auto is_segm_set = [](const int e, unsigned char segm_[12]) { return (segm_[e] != 0xFF); }; + auto unset_segm = [](const int e, unsigned char segm_[12]) { segm_[e] = 0xFF; }; + + // In order to compute oriented segments, the hexahedron has to be flatten. + // The insides of the faces of the hexahedron have to be all at the same + // side of the flattend hexa. This requires changing the order of the + // edges when reading from the faces + // code edges at face + // unsigned short face_e_[6] = { 12816, 30292, 33936, 46754, 34739, 38305 }; + std::array e_face_{{291, 18277, 18696, 10859, 33719, 38305}}; + + // code vertices at face + // unsigned short face_v_[6] = { 12816, 30292, 21520, 30258, 25632, 30001 }; + std::array v_face_{{12576, 25717, 5380, 29538, 8292, 30001}}; + + // reading edge from face + auto get_face_e = [e_face_](const int f, const int e) { return ((e_face_[f] >> (4 * e)) & 0xF); }; + auto get_face_v = [v_face_](const int f, const int e) { return ((v_face_[f] >> (4 * e)) & 0xF); }; + + // compute oriented segments using the isoline scheme at the faces + const unsigned int BIT_1 = 1; + const unsigned int BIT_2 = 2; + const unsigned int BIT_3 = 4; + const unsigned int BIT_4 = 8; + auto asymptotic_decider = [](const double f0, const double f1, const double f2, const double f3) + { + return (f0 * f3 - f1 * f2) / (f0 + f3 - f1 - f2); + }; + + std::vector f_flag(6, false); + for(int f=0; f<6; ++f) + { + // classify face + unsigned int f_case{0}; + uint v0 = get_face_v(f, 0); + uint v1 = get_face_v(f, 1); + uint v2 = get_face_v(f, 2); + uint v3 = get_face_v(f, 3); + uint e0 = get_face_e(f, 0); + uint e1 = get_face_e(f, 1); + uint e2 = get_face_e(f, 2); + uint e3 = get_face_e(f, 3); + double f0 = values[v0]; + double f1 = values[v1]; + double f2 = values[v2]; + double f3 = values[v3]; + if(f0 >= i0) f_case |= BIT_1; + if(f1 >= i0) f_case |= BIT_2; + if(f2 >= i0) f_case |= BIT_3; + if(f3 >= i0) f_case |= BIT_4; + + switch (f_case) + { + case 1: + set_segm(e0, 0, e3, segm_); + set_segm(e3, 1, e0, segm_); + break; + case 2: + set_segm(e1, 0, e0, segm_); + set_segm(e0, 1, e1, segm_); + break; + case 3: + set_segm(e1, 0, e3, segm_); + set_segm(e3, 1, e1, segm_); + break; + case 4: + set_segm(e3, 0, e2, segm_); + set_segm(e2, 1, e3, segm_); + break; + case 5: + set_segm(e0, 0, e2, segm_); + set_segm(e2, 1, e0, segm_); + break; + case 6: + { + const double val = asymptotic_decider(f0, f1, f2, f3); + if(val > i0) + { + set_segm(e3, 0, e0, segm_); + set_segm(e0, 1, e3, segm_); + set_segm(e1, 0, e2, segm_); + set_segm(e2, 1, e1, segm_); + } + else if(val < i0) + { + set_segm(e1, 0, e0, segm_); + set_segm(e0, 1, e1, segm_); + set_segm(e3, 0, e2, segm_); + set_segm(e2, 1, e3, segm_); + } + else + { + f_flag[f] = true; + // singular case val == i0, there are no asymptotes + // check if there is a reasonable triangulation of the face + unsigned short e_flag = 0x218; + unsigned short bit_1 = 0x1; + unsigned short bit_2 = 0x2; + double ec0 = ecoord[e0]; + double ec1 = ecoord[e1]; + double ec2 = ecoord[e2]; + double ec3 = ecoord[e3]; + + if((e_flag >> (f * 2)) & bit_1) + { + ec0 = 1 - ec0; + ec2 = 1 - ec2; } - /*else { - e_set[eg] = false; - }*/ - // next edge - flag <<= 1; - } - // compute oriented contours - // A countour consists of segment at the faces connecting the intersection of the - // isosurface with the edges. For each edge we store the edge to which the segment - // is outgoing and the edge from which the segment in comming. Therefore a contour - // cab be reconstructed by connecting the edges in the direccion of the outgoing. - // The contour is oriented in such a way, that the positive vertices are outside. - // 1. build segments - // 2. connect segments - // build up segments - // set segments map - unsigned char segm_[12] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; - auto set_segm = [](const int e, const int pos, const int val, unsigned char segm_[12]) { - if (pos == 0) { - segm_[e] &= 0xF0; - segm_[e] |= (unsigned char)val & 0xF; - } else if (pos == 1) { - segm_[e] &= 0xF; - segm_[e] |= val << 4; + if((e_flag >> (f * 2)) & bit_2) + { + ec1 = 1 - ec1; + ec3 = 1 - ec3; + } + + if(ec1 < ec3 && ec0 > ec2) + { + set_segm(e1, 0, e0, segm_); + set_segm(e0, 1, e1, segm_); + set_segm(e3, 0, e2, segm_); + set_segm(e2, 1, e3, segm_); + } + else if(ec1 > ec3 && ec0 < ec2) + { + set_segm(e3, 0, e0, segm_); + set_segm(e0, 1, e3, segm_); + set_segm(e1, 0, e2, segm_); + set_segm(e2, 1, e1, segm_); } - }; - auto get_segm = [](const int e, const int pos, unsigned char segm_[12]) { - if (pos == 0) - return (int)(segm_[e] & 0xF); else - return (int)((segm_[e] >> 4) & 0xF); - }; - auto is_segm_set = [](const int e, unsigned char segm_[12]) { return (segm_[e] != 0xFF); }; - auto unset_segm = [](const int e, unsigned char segm_[12]) { segm_[e] = 0xFF; }; - // In order to compute oriented segments, the hexahedron has to be flatten. - // The insides of the faces of the hexahedron have to be all at the same - // side of the flattend hexa. This requires changing the order of the - // edges when reading from the faces - // code edges at face - // unsigned short face_e_[6] = { 12816, 30292, 33936, 46754, 34739, 38305 }; - std::array e_face_{{291, 18277, 18696, 10859, 33719, 38305}}; - // code vertices at face - // unsigned short face_v_[6] = { 12816, 30292, 21520, 30258, 25632, 30001 }; - std::array v_face_{{12576, 25717, 5380, 29538, 8292, 30001}}; - - // reading edge from face - auto get_face_e = [e_face_](const int f, const int e) { return ((e_face_[f] >> (4 * e)) & 0xF); }; - auto get_face_v = [v_face_](const int f, const int e) { return ((v_face_[f] >> (4 * e)) & 0xF); }; - // compute oriented segments using the isoline scheme at the faces - const unsigned int BIT_1 = 1; - const unsigned int BIT_2 = 2; - const unsigned int BIT_3 = 4; - const unsigned int BIT_4 = 8; - auto asymptotic_decider = [](const double f0, const double f1, const double f2, const double f3) { - return (f0 * f3 - f1 * f2) / (f0 + f3 - f1 - f2); - }; - std::vector f_flag(6, false); - for (int f = 0; f < 6; f++) { - // classify face - unsigned int f_case{0}; - uint v0 = get_face_v(f, 0); - uint v1 = get_face_v(f, 1); - uint v2 = get_face_v(f, 2); - uint v3 = get_face_v(f, 3); - uint e0 = get_face_e(f, 0); - uint e1 = get_face_e(f, 1); - uint e2 = get_face_e(f, 2); - uint e3 = get_face_e(f, 3); - double f0 = values[v0]; - double f1 = values[v1]; - double f2 = values[v2]; - double f3 = values[v3]; - if (f0 >= i0) f_case |= BIT_1; - if (f1 >= i0) f_case |= BIT_2; - if (f2 >= i0) f_case |= BIT_3; - if (f3 >= i0) f_case |= BIT_4; - switch (f_case) { - case 1: - set_segm(e0, 0, e3, segm_); - set_segm(e3, 1, e0, segm_); - break; - case 2: - set_segm(e1, 0, e0, segm_); - set_segm(e0, 1, e1, segm_); - break; - case 3: - set_segm(e1, 0, e3, segm_); - set_segm(e3, 1, e1, segm_); - break; - case 4: - set_segm(e3, 0, e2, segm_); - set_segm(e2, 1, e3, segm_); - break; - case 5: - set_segm(e0, 0, e2, segm_); - set_segm(e2, 1, e0, segm_); - break; - case 6: { - const double val = asymptotic_decider(f0, f1, f2, f3); - if (val > i0) { - set_segm(e3, 0, e0, segm_); - set_segm(e0, 1, e3, segm_); - set_segm(e1, 0, e2, segm_); - set_segm(e2, 1, e1, segm_); - } else if (val < i0) { - set_segm(e1, 0, e0, segm_); - set_segm(e0, 1, e1, segm_); - set_segm(e3, 0, e2, segm_); - set_segm(e2, 1, e3, segm_); - } else { - f_flag[f] = true; - // singular case val == i0, there are no asymptotes - // check if there is a reasonable triangulation of the face - unsigned short e_flag = 0x218; - unsigned short bit_1 = 0x1; - unsigned short bit_2 = 0x2; - double ec0 = ecoord[e0]; - double ec1 = ecoord[e1]; - double ec2 = ecoord[e2]; - double ec3 = ecoord[e3]; - if ((e_flag >> (f * 2)) & bit_1) { - ec0 = 1 - ec0; - ec2 = 1 - ec2; - } - if ((e_flag >> (f * 2)) & bit_2) { - ec1 = 1 - ec1; - ec3 = 1 - ec3; - } - if (ec1 < ec3 && ec0 > ec2) { - set_segm(e1, 0, e0, segm_); - set_segm(e0, 1, e1, segm_); - set_segm(e3, 0, e2, segm_); - set_segm(e2, 1, e3, segm_); - } else if (ec1 > ec3 && ec0 < ec2) { - set_segm(e3, 0, e0, segm_); - set_segm(e0, 1, e3, segm_); - set_segm(e1, 0, e2, segm_); - set_segm(e2, 1, e1, segm_); - } else { - std::cerr << "ERROR: can't correctly triangulate cell's face\n"; - return; - } - } - } break; - case 7: - set_segm(e1, 0, e2, segm_); - set_segm(e2, 1, e1, segm_); - break; - case 8: - set_segm(e2, 0, e1, segm_); - set_segm(e1, 1, e2, segm_); - break; - case 9: { - const double val = asymptotic_decider(f0, f1, f2, f3); - if (val > i0) { - set_segm(e0, 0, e1, segm_); - set_segm(e1, 1, e0, segm_); - set_segm(e2, 0, e3, segm_); - set_segm(e3, 1, e2, segm_); - } else if (val < i0) { - set_segm(e0, 0, e3, segm_); - set_segm(e3, 1, e0, segm_); - set_segm(e2, 0, e1, segm_); - set_segm(e1, 1, e2, segm_); - } else { - f_flag[f] = true; - // singular case val == i0, there are no asymptotes - // check if there is a reasonable triangulation of the face - unsigned short e_flag = 0x218; - unsigned short bit_1 = 0x1; - unsigned short bit_2 = 0x2; - double ec0 = ecoord[e0]; - double ec1 = ecoord[e1]; - double ec2 = ecoord[e2]; - double ec3 = ecoord[e3]; - if ((e_flag >> (f * 2)) & bit_1) { - ec0 = 1 - ec0; - ec2 = 1 - ec2; - } - if ((e_flag >> (f * 2)) & bit_2) { - ec1 = 1 - ec1; - ec3 = 1 - ec3; - } - if (ec1 < ec3 && ec0 > ec2) { - set_segm(e0, 0, e1, segm_); - set_segm(e1, 1, e0, segm_); - set_segm(e2, 0, e3, segm_); - set_segm(e3, 1, e2, segm_); - } else if (ec1 > ec3 && ec0 < ec2) { - set_segm(e0, 0, e3, segm_); - set_segm(e3, 1, e0, segm_); - set_segm(e2, 0, e1, segm_); - set_segm(e1, 1, e2, segm_); - } else { - std::cerr << "ERROR: can't correctly triangulate cell's face\n"; - return; - } - } - } break; - case 10: - set_segm(e2, 0, e0, segm_); - set_segm(e0, 1, e2, segm_); - - break; - case 11: - set_segm(e2, 0, e3, segm_); - set_segm(e3, 1, e2, segm_); - - break; - case 12: - set_segm(e3, 0, e1, segm_); - set_segm(e1, 1, e3, segm_); - - break; - case 13: - set_segm(e0, 0, e1, segm_); - set_segm(e1, 1, e0, segm_); - - break; - case 14: - set_segm(e3, 0, e0, segm_); - set_segm(e0, 1, e3, segm_); - break; - default: - break; + { + std::cerr << "ERROR: can't correctly triangulate cell's face\n"; + return; } + } } + break; + case 7: + set_segm(e1, 0, e2, segm_); + set_segm(e2, 1, e1, segm_); + break; + case 8: + set_segm(e2, 0, e1, segm_); + set_segm(e1, 1, e2, segm_); + break; + case 9: + { + const double val = asymptotic_decider(f0, f1, f2, f3); + if(val > i0) + { + set_segm(e0, 0, e1, segm_); + set_segm(e1, 1, e0, segm_); + set_segm(e2, 0, e3, segm_); + set_segm(e3, 1, e2, segm_); + } + else if(val < i0) + { + set_segm(e0, 0, e3, segm_); + set_segm(e3, 1, e0, segm_); + set_segm(e2, 0, e1, segm_); + set_segm(e1, 1, e2, segm_); + } + else + { + f_flag[f] = true; + // singular case val == i0, there are no asymptotes + // check if there is a reasonable triangulation of the face + unsigned short e_flag = 0x218; + unsigned short bit_1 = 0x1; + unsigned short bit_2 = 0x2; + double ec0 = ecoord[e0]; + double ec1 = ecoord[e1]; + double ec2 = ecoord[e2]; + double ec3 = ecoord[e3]; - // connect oriented segments into oriented contours - // closed contours are coded in 64 bit unsigned long long - // 1) Each entry has 4 bits - // 2) The first 4 entries are reserved for the size of the contours - // 3) The next 12 entries are the indices of the edges constituting the contorus - // The indices are numbers from 0 to 12 - unsigned long long c_ = 0xFFFFFFFFFFFF0000; - // in the 4 first bits store size of contours - auto get_cnt_size = [](const int cnt, unsigned long long& c_) { - return (size_t)((c_ & (0xF << 4 * cnt)) >> 4 * cnt); - }; - auto set_cnt_size = [](const int cnt, const int size, unsigned long long& c_) { - // unset contour size - c_ &= ~(0xF << 4 * cnt); - c_ |= (size << 4 * cnt); - }; - // set corresponging edge - auto set_c = [](const int cnt, const int pos, const int val, unsigned long long& c_) { - const uint mask[4] = {0x0, 0xF, 0xFF, 0xFFF}; - const uint c_sz = c_ & mask[cnt]; - const uint e = 16 + 4 * ((c_sz & 0xF) + ((c_sz & 0xF0) >> 4) + ((c_sz & 0xF00) >> 8) + pos); - c_ &= ~(((unsigned long long)0xF) << e); - c_ |= (((unsigned long long)val) << e); - }; - // read edge from contour - auto get_c = [](const int cnt, const int pos, unsigned long long c_) { - const uint mask[4] = {0x0, 0xF, 0xFF, 0xFFF}; - const uint c_sz = (uint)(c_ & mask[cnt]); - const uint e = 16 + 4 * ((c_sz & 0xF) + ((c_sz & 0xF0) >> 4) + ((c_sz & 0xF00) >> 8) + pos); - return (int)((c_ >> e) & 0xF); - }; - - - // connect oriented contours - uint cnt_{0}; - for (uint e = 0; e < 12; e++) { - if (is_segm_set(e, segm_)) { - uint eTo = get_segm(e, 0, segm_); - uint eIn = get_segm(e, 1, segm_); - uint eStart = e; - uint pos = 0; - set_c(cnt_, pos, eStart, c_); - while (eTo != eStart) { - pos = pos + 1; - set_c(cnt_, pos, eTo, c_); - eIn = eTo; - eTo = get_segm(eIn, 0, segm_); - unset_segm(eIn, segm_); - } - // set contour length - set_cnt_size(cnt_, pos + 1, c_); - // update number of contours - cnt_ = cnt_ + 1; + if((e_flag >> (f * 2)) & bit_1) + { + ec0 = 1 - ec0; + ec2 = 1 - ec2; } + + if((e_flag >> (f * 2)) & bit_2) + { + ec1 = 1 - ec1; + ec3 = 1 - ec3; + } + + if(ec1 < ec3 && ec0 > ec2) + { + set_segm(e0, 0, e1, segm_); + set_segm(e1, 1, e0, segm_); + set_segm(e2, 0, e3, segm_); + set_segm(e3, 1, e2, segm_); + } + else if(ec1 > ec3 && ec0 < ec2) + { + set_segm(e0, 0, e3, segm_); + set_segm(e3, 1, e0, segm_); + set_segm(e2, 0, e1, segm_); + set_segm(e1, 1, e2, segm_); + } + else + { + std::cerr << "ERROR: can't correctly triangulate cell's face\n"; + return; + } + } } - - // compute intersection of opposite faces - // It is enough to compute a pair of solutions for one face - // The other solutions are obtained by evaluating the equations - // for the common variable - double ui[2]{}; - double vi[2]{}; - double wi[2]{}; - unsigned char q_sol{0}; - const double a = (values[0] - values[1]) * (-values[6] + values[7] + values[4] - values[5]) - - (values[4] - values[5]) * (-values[2] + values[3] + values[0] - values[1]); - const double b = (i0 - values[0]) * (-values[6] + values[7] + values[4] - values[5]) + - (values[0] - values[1]) * (values[6] - values[4]) - - (i0 - values[4]) * (-values[2] + values[3] + values[0] - values[1]) - - (values[4] - values[5]) * (values[2] - values[0]); - const double c = (i0 - values[0]) * (values[6] - values[4]) - (i0 - values[4]) * (values[2] - values[0]); - ; - double d = b * b - 4 * a * c; - if (d > 0) { - d = std::sqrt(d); - // compute u-coord of solutions - ui[0] = (-b - d) / (2 * a); - ui[1] = (-b + d) / (2 * a); - // compute v-coord of solutions - double g1 = values[0] * (1 - ui[0]) + values[1] * ui[0]; - double g2 = values[2] * (1 - ui[0]) + values[3] * ui[0]; - vi[0] = (i0 - g1) / (g2 - g1); - if (std::isnan(vi[0]) || std::isinf(vi[0])) vi[0] = -1.f; - g1 = values[0] * (1 - ui[1]) + values[1] * ui[1]; - g2 = values[2] * (1 - ui[1]) + values[3] * ui[1]; - vi[1] = (i0 - g1) / (g2 - g1); - if (std::isnan(vi[1]) || std::isinf(vi[1])) vi[1] = -1.f; - // compute w-coordinates of solutions - g1 = values[0] * (1 - ui[0]) + values[1] * ui[0]; - g2 = values[4] * (1 - ui[0]) + values[5] * ui[0]; - wi[0] = (i0 - g1) / (g2 - g1); - if (std::isnan(wi[0]) || std::isinf(wi[0])) wi[0] = -1.f; - g1 = values[0] * (1 - ui[1]) + values[1] * ui[1]; - g2 = values[4] * (1 - ui[1]) + values[5] * ui[1]; - wi[1] = (i0 - g1) / (g2 - g1); - if (std::isnan(wi[1]) || std::isinf(wi[1])) wi[1] = -1.f; - // correct values for roots of quadratic equations - // in case the asymptotic decider has failed - if (f_flag[0] == true) { // face 1, w = 0; - if (wi[0] < wi[1]) - wi[0] = 0; - else - wi[1] = 0; - } - if (f_flag[1] == true) { // face 2, w = 1 - if (wi[0] > wi[1]) - wi[1] = 1; - else - wi[1] = 1; - } - if (f_flag[2] == true) { // face 3, v = 0 - if (vi[0] < vi[1]) - vi[0] = 0; - else - vi[1] = 0; - } - if (f_flag[3] == true) { // face 4, v = 1 - if (vi[0] > vi[1]) - vi[0] = 1; - else - vi[1] = 1; - } - if (f_flag[4] == true) { // face 5, u = 0 - if (ui[0] < ui[1]) - ui[0] = 0; - else - ui[1] = 0; - } - if (f_flag[5] == true) { // face 6, u = 1 - if (ui[0] > ui[1]) - ui[0] = 1; - else - ui[1] = 1; - } - - // check solution intervals - if (0 < ui[0] && ui[0] < 1) { - q_sol |= 1; - } - if (0 < ui[1] && ui[1] < 1) { - q_sol |= 2; - } - if (0 < vi[0] && vi[0] < 1) { - q_sol |= 4; - } - if (0 < vi[1] && vi[1] < 1) { - q_sol |= 8; - } - if (0 < wi[0] && wi[0] < 1) { - q_sol |= 16; - } - if (0 < wi[1] && wi[1] < 1) { - q_sol |= 32; - } - } - - // - // count the number of set bits - auto numberOfSetBits = [](const unsigned char n) { - // C or C++: use uint32_t - uint b = (uint)n; - b = b - ((b >> 1) & 0x55555555); - b = (b & 0x33333333) + ((b >> 2) & 0x33333333); - return (((b + (b >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; - }; - // compute the number of solutions to the quadratic equation for a given face - auto nrQSolFace = [](const uint f, const unsigned char n) { - uint nr{0}; - switch (f) { - case 0: - if ((n & 0x5) == 0x5) nr = nr + 1; - if ((n & 0xA) == 0xA) nr = nr + 1; - break; - case 1: - if ((n & 0x11) == 0x11) nr = nr + 1; - if ((n & 0x22) == 0x22) nr = nr + 1; - break; - case 2: - if ((n & 0x18) == 0x18) nr = nr + 1; - if ((n & 0x24) == 0x24) nr = nr + 1; - break; - } - return nr; - }; - - - // triangulate contours - // if all bits are set, then there are three pairs of nontrivial solutions - // to the quadratic equations. In this case, there is a tunnel or a contour - // with 12 vertices. If there are three contours, then there is a tunnel and - // one of the contorus with only three vertices is not part of it. - if (numberOfSetBits(q_sol) == 6) { - // there are at most three contours - // Possible cases: - // 1) a single contour with 12 vertices - // 2) two contours which build a tunnel - // 3) three contours, one has only 3 vertices and does not belong to the tunnel - - // construct the six vertices of the inner hexagon - double hvt[6][3]; - hvt[0][0] = ui[0]; - hvt[0][1] = vi[0]; - hvt[0][2] = wi[0]; - hvt[1][0] = ui[0]; - hvt[1][1] = vi[0]; - hvt[1][2] = wi[1]; - hvt[2][0] = ui[1]; - hvt[2][1] = vi[0]; - hvt[2][2] = wi[1]; - hvt[3][0] = ui[1]; - hvt[3][1] = vi[1]; - hvt[3][2] = wi[1]; - hvt[4][0] = ui[1]; - hvt[4][1] = vi[1]; - hvt[4][2] = wi[0]; - hvt[5][0] = ui[0]; - hvt[5][1] = vi[1]; - hvt[5][2] = wi[0]; - - // construct vertices at intersections with the edges - auto e_vert = [&ecoord](const int e, const int i) { - const unsigned int l_coord[3]{1324855, 5299420, 16733440}; - unsigned char flag = (l_coord[i] >> (2 * e)) & 3; - if (flag == 3) - return ecoord[e]; - else - return (FT)(flag); - }; - - // if there are three contours, then there is a tunnel and one - // of the contours is not part of it. - unsigned char _not_tunnel = 0xF; - if (cnt_ == 3) { - // loop over the contorus - // triangulate the contour which is not part of - // the tunnel - const double uc_min = (ui[0] < ui[1]) ? ui[0] : ui[1]; - const double uc_max = (ui[0] < ui[1]) ? ui[1] : ui[0]; - for (int t = 0; t < (int)cnt_; t++) { - if (get_cnt_size(t, c_) == 3) { - double umin = 2; - double umax = -2; - uint e0 = get_c(t, 0, c_); - uint e1 = get_c(t, 1, c_); - uint e2 = get_c(t, 2, c_); - const double u_e0 = e_vert(e0, 0); - const double u_e1 = e_vert(e1, 0); - const double u_e2 = e_vert(e2, 0); - umin = (u_e0 < umin) ? u_e0 : umin; - umin = (u_e1 < umin) ? u_e1 : umin; - umin = (u_e2 < umin) ? u_e2 : umin; - umax = (u_e0 > umax) ? u_e0 : umax; - umax = (u_e1 > umax) ? u_e1 : umax; - umax = (u_e2 > umax) ? u_e1 : umax; - if (uc_min > umax || uc_max < umin) { - // this contour is not part of the tunnel - _not_tunnel = t; - - add_triangle(vertices[e0], vertices[e1], vertices[e2]); - } - } - } - } - - // compute vertices of inner hexagon, save new vertices in list and compute and keep - // global vertice index to build triangle connectivity later on. - uint tg_idx[6]; - for (int i = 0; i < 6; i++) { - - const double u = hvt[i][0]; - const double v = hvt[i][1]; - const double w = hvt[i][2]; - const FT px = (1 - w) * ((1 - v) * (corners[0][0] + u * (corners[1][0] - corners[0][0])) + - v * (corners[2][0] + u * (corners[3][0] - corners[2][0]))) + - w * ((1 - v) * (corners[4][0] + u * (corners[5][0] - corners[4][0])) + - v * (corners[6][0] + u * (corners[7][0] - corners[6][0]))); - const FT py = (1 - w) * ((1 - v) * (corners[0][1] + u * (corners[1][1] - corners[0][1])) + - v * (corners[2][1] + u * (corners[3][1] - corners[2][1]))) + - w * ((1 - v) * (corners[4][1] + u * (corners[5][1] - corners[4][1])) + - v * (corners[6][1] + u * (corners[7][1] - corners[6][1]))); - const FT pz = (1 - w) * ((1 - v) * (corners[0][2] + u * (corners[1][2] - corners[0][2])) + - v * (corners[2][2] + u * (corners[3][2] - corners[2][2]))) + - w * ((1 - v) * (corners[4][2] + u * (corners[5][2] - corners[4][2])) + - v * (corners[6][2] + u * (corners[7][2] - corners[6][2]))); - - tg_idx[i] = (uint)points.size(); - points.push_back(Point(px, py, pz)); - } - - // triangulate contours with inner hexagon - unsigned char tcon_[12]; - for (int i = 0; i < (int)cnt_; i++) { - if (_not_tunnel != i) { // contour belongs to tunnel - const int cnt_sz = (int)get_cnt_size(i, c_); - for (int r = 0; r < cnt_sz; r++) { - uint index = -1; - double dist = 1000.; - uint ci = get_c(i, r, c_); - const double u_edge = e_vert(ci, 0); - const double v_edge = e_vert(ci, 1); - const double w_edge = e_vert(ci, 2); - for (int s = 0; s < 6; s++) { - const double uval = u_edge - hvt[s][0]; - const double vval = v_edge - hvt[s][1]; - const double wval = w_edge - hvt[s][2]; - double val = uval * uval + vval * vval + wval * wval; - if (dist > val) { - index = s; - dist = val; - } - } - tcon_[ci] = (unsigned char)index; - } - - // correspondence between vertices found - // create triangles - // needs some functions - auto distanceRingIntsModulo = [](const int d1, const int d2) { - const int r = (d1 - d2) < 0 ? d2 - d1 : d1 - d2; - return (r > 2 ? 6 - r : r); - }; - auto midpointRingIntModulo = [](const int d1, const int d2) { - const int dmax = (d1 > d2) ? d1 : d2; - const int dmin = (d1 < d2) ? d1 : d2; - return ((dmax + 2) % 6 == dmin) ? (dmax + 1) % 6 : (dmax + dmin) / 2; - }; - - for (int r = 0; r < cnt_sz; r++) { - const uint tid1 = get_c(i, r, c_); - const uint tid2 = get_c(i, ((r + 1) % cnt_sz), c_); - const uint cid1 = tcon_[tid1]; - const uint cid2 = tcon_[tid2]; - // compute index distance - const int dst = distanceRingIntsModulo(cid1, cid2); - switch (dst) { - case 0: { - add_triangle(vertices[tid1], vertices[tid2], tg_idx[cid1]); - } break; - case 1: { - // measure diagonals - // triangulate along shortest diagonal - double u_edge = e_vert(tid1, 0); - double v_edge = e_vert(tid1, 1); - double w_edge = e_vert(tid1, 2); - const double l1 = (u_edge - hvt[cid2][0]) * (u_edge - hvt[cid2][0]) + - (v_edge - hvt[cid2][1]) * (v_edge - hvt[cid2][1]) + - (w_edge - hvt[cid2][2]) * (w_edge - hvt[cid2][2]); - u_edge = e_vert(tid2, 0); - v_edge = e_vert(tid2, 1); - w_edge = e_vert(tid2, 2); - const double l2 = (u_edge - hvt[cid1][0]) * (u_edge - hvt[cid1][0]) + - (v_edge - hvt[cid1][1]) * (v_edge - hvt[cid1][1]) + - (w_edge - hvt[cid1][2]) * (w_edge - hvt[cid1][2]); - - if (l1 < l2) { - add_triangle(vertices[tid1], vertices[tid2], tg_idx[cid2]); - add_triangle(vertices[tid1], tg_idx[cid2], tg_idx[cid1]); - } else { - add_triangle(vertices[tid1], vertices[tid2], tg_idx[cid1]); - add_triangle(vertices[tid2], tg_idx[cid2], tg_idx[cid1]); - } - } break; - case 2: { - const int cidm = midpointRingIntModulo(cid1, cid2); - - add_triangle(vertices[tid1], vertices[tid2], tg_idx[cidm]); - add_triangle(vertices[tid1], tg_idx[cidm], tg_idx[cid1]); - add_triangle(vertices[tid2], tg_idx[cid2], tg_idx[cidm]); - } break; - } // switch - } // for loop over the vertices of the contour - } // if (_not_tunnel) - } // for loop over contours - if (cnt_ == 1) { - // there is a single contour - // triangulate and close inner hexagon - // triangle must have the correct orientation - // use asymptotic_decider() to see if positive vertices - // are separated, in thic case orientation must be changed - const bool s_ = (asymptotic_decider(values[0], values[1], values[2], values[3]) <= i0); - const bool of_ = (wi[1] < wi[0]) ? s_ : !s_; - - if (!of_) { - add_triangle(tg_idx[0], tg_idx[2], tg_idx[1]); - add_triangle(tg_idx[2], tg_idx[4], tg_idx[3]); - add_triangle(tg_idx[0], tg_idx[5], tg_idx[4]); - add_triangle(tg_idx[0], tg_idx[4], tg_idx[2]); - } else { - add_triangle(tg_idx[0], tg_idx[1], tg_idx[2]); - add_triangle(tg_idx[2], tg_idx[3], tg_idx[4]); - add_triangle(tg_idx[0], tg_idx[4], tg_idx[5]); - add_triangle(tg_idx[0], tg_idx[2], tg_idx[4]); - } - } - } else { - // there is no tunnel - // handle case with no saddle point as simple polygons with 3, 4, 5 or six vertices - const unsigned char nr_u{(unsigned char)nrQSolFace(0, q_sol)}; - const unsigned char nr_v{(unsigned char)nrQSolFace(1, q_sol)}; - const unsigned char nr_w{(unsigned char)nrQSolFace(2, q_sol)}; - const unsigned char nr_t{(unsigned char)(nr_u + nr_v + nr_w)}; - if (nr_t == nr_u || nr_t == nr_v || nr_t == nr_w) { - // loop over all contours - for (int i = 0; i < (int)cnt_; i++) { - switch (get_cnt_size(i, c_)) { - case 3: { - add_triangle(vertices[get_c(i, 0, c_)], vertices[get_c(i, 1, c_)], - vertices[get_c(i, 2, c_)]); - } break; - case 4: { - add_triangle(vertices[get_c(i, 0, c_)], vertices[get_c(i, 1, c_)], - vertices[get_c(i, 2, c_)]); - add_triangle(vertices[get_c(i, 0, c_)], vertices[get_c(i, 2, c_)], - vertices[get_c(i, 3, c_)]); - } break; - case 5: { - add_triangle(vertices[get_c(i, 0, c_)], vertices[get_c(i, 1, c_)], - vertices[get_c(i, 2, c_)]); - add_triangle(vertices[get_c(i, 0, c_)], vertices[get_c(i, 2, c_)], - vertices[get_c(i, 3, c_)]); - add_triangle(vertices[get_c(i, 0, c_)], vertices[get_c(i, 3, c_)], - vertices[get_c(i, 4, c_)]); - } break; - case 6: { - add_triangle(vertices[get_c(i, 0, c_)], vertices[get_c(i, 1, c_)], - vertices[get_c(i, 3, c_)]); - add_triangle(vertices[get_c(i, 1, c_)], vertices[get_c(i, 2, c_)], - vertices[get_c(i, 3, c_)]); - add_triangle(vertices[get_c(i, 0, c_)], vertices[get_c(i, 3, c_)], - vertices[get_c(i, 4, c_)]); - add_triangle(vertices[get_c(i, 0, c_)], vertices[get_c(i, 4, c_)], - vertices[get_c(i, 5, c_)]); - } break; - } // switch over size of contour - } // loop over contorus - } // thre are no saddle points - else { - // there are saddle points - // fc1 = fs(1, 1)*fs(2, 1) + fs(1, 2)*fs(2, 2); - // fc2 = fs(1, 1)*fs(3, 1) + fs(1, 2)*fs(3, 2); - // fc3 = fs(2, 1)*fs(3, 2) + fs(2, 2)*fs(3, 1); - typedef unsigned char uchar; // TODO - - unsigned char fs[3][2]{{(uchar)(q_sol & 1), (uchar)((q_sol >> 1) & 1)}, - {(uchar)((q_sol >> 2) & 1), (uchar)((q_sol >> 3) & 1)}, - {(uchar)((q_sol >> 4) & 1), (uchar)((q_sol >> 5) & 1)}}; - - const unsigned char fc1 = fs[0][0] * fs[1][0] + fs[0][1] * fs[1][1]; - const unsigned char fc2 = fs[0][0] * fs[2][0] + fs[0][1] * fs[2][1]; - const unsigned char fc3 = fs[1][0] * fs[2][1] + fs[1][1] * fs[2][0]; - const unsigned char c_faces = fc1 + fc2 + fc3; - double ucoord{}; - double vcoord{}; - double wcoord{}; - switch (c_faces) { - case 2: { - if (fc1 == 0) { - ucoord = fs[0][0] * ui[0] + fs[0][1] * ui[1]; - vcoord = fs[1][0] * vi[0] + fs[1][1] * vi[1]; - wcoord = fs[1][0] * wi[1] + fs[1][1] * wi[0]; - } else if (fc2 == 0) { - ucoord = fs[0][0] * ui[0] + fs[0][1] * ui[1]; - vcoord = fs[0][0] * vi[0] + fs[0][1] * vi[1]; - wcoord = fs[0][0] * wi[1] + fs[0][1] * wi[0]; - } else if (fc3 == 0) { - ucoord = fs[1][0] * ui[0] + fs[1][1] * ui[1]; - vcoord = fs[1][0] * vi[0] + fs[1][1] * vi[1]; - wcoord = fs[1][0] * wi[0] + fs[1][1] * wi[1]; - } - } break; - case 3: { - ucoord = (fs[0][0] * ui[0] + fs[0][1] * ui[1]) / (fs[0][0] + fs[0][1]); - vcoord = (fs[1][0] * vi[0] + fs[1][1] * vi[1]) / (fs[1][0] + fs[1][1]); - wcoord = (fs[2][0] * wi[0] + fs[2][1] * wi[1]) / (fs[2][0] + fs[2][1]); - } break; - case 4: { - const unsigned char nr_u = fs[0][0] + fs[0][1]; - const unsigned char nr_v = fs[1][0] + fs[1][1]; - const unsigned char nr_w = fs[2][0] + fs[2][1]; - if (nr_w == 1) { - ucoord = fs[2][0] * ui[0] + fs[2][1] * ui[1]; - vcoord = fs[2][1] * vi[0] + fs[2][0] * vi[1]; - wcoord = fs[2][0] * wi[0] + fs[2][1] * wi[1]; - } else if (nr_v == 1) { - ucoord = fs[1][0] * ui[0] + fs[1][1] * ui[1]; - vcoord = fs[1][0] * vi[0] + fs[1][1] * vi[1]; - wcoord = fs[1][1] * wi[0] + fs[1][0] * wi[1]; - } else if (nr_u == 1) { - ucoord = fs[0][0] * ui[0] + fs[0][1] * ui[1]; - vcoord = fs[0][0] * vi[0] + fs[0][1] * vi[1]; - wcoord = fs[0][0] * wi[0] + fs[0][1] * wi[1]; - } - } break; - } // switch(c_faces) - - // create inner vertex - const FT px = - (1 - wcoord) * ((1 - vcoord) * (corners[0][0] + ucoord * (corners[1][0] - corners[0][0])) + - vcoord * (corners[2][0] + ucoord * (corners[3][0] - corners[2][0]))) + - wcoord * ((1 - vcoord) * (corners[4][0] + ucoord * (corners[5][0] - corners[4][0])) + - vcoord * (corners[6][0] + ucoord * (corners[7][0] - corners[6][0]))); - const FT py = - (1 - wcoord) * ((1 - vcoord) * (corners[0][1] + ucoord * (corners[1][1] - corners[0][1])) + - vcoord * (corners[2][1] + ucoord * (corners[3][1] - corners[2][1]))) + - wcoord * ((1 - vcoord) * (corners[4][1] + ucoord * (corners[5][1] - corners[4][1])) + - vcoord * (corners[6][1] + ucoord * (corners[7][1] - corners[6][1]))); - const FT pz = - (1 - wcoord) * ((1 - vcoord) * (corners[0][2] + ucoord * (corners[1][2] - corners[0][2])) + - vcoord * (corners[2][2] + ucoord * (corners[3][2] - corners[2][2]))) + - wcoord * ((1 - vcoord) * (corners[4][2] + ucoord * (corners[5][2] - corners[4][2])) + - vcoord * (corners[6][2] + ucoord * (corners[7][2] - corners[6][2]))); - - const uint g_index = (uint)points.size(); - // loop over the contorus - bool pt_used = false; - for (int i = 0; i < (int)cnt_; i++) { - const unsigned char cnt_sz = (unsigned char)get_cnt_size(i, c_); - if (cnt_sz == 3) { - add_triangle(vertices[get_c(i, 0, c_)], vertices[get_c(i, 1, c_)], vertices[get_c(i, 2, c_)]); - } else { - pt_used = true; - for (int t = 0; t < cnt_sz; t++) { - add_triangle(vertices[get_c(i, t, c_)], vertices[get_c(i, (t + 1) % cnt_sz, c_)], g_index); - } - } - } - if (pt_used) { - points.push_back(Point(px, py, pz)); - } - } // else - there are saddle points - } + break; + case 10: + set_segm(e2, 0, e0, segm_); + set_segm(e0, 1, e2, segm_); + break; + case 11: + set_segm(e2, 0, e3, segm_); + set_segm(e3, 1, e2, segm_); + break; + case 12: + set_segm(e3, 0, e1, segm_); + set_segm(e1, 1, e3, segm_); + break; + case 13: + set_segm(e0, 0, e1, segm_); + set_segm(e1, 1, e0, segm_); + break; + case 14: + set_segm(e3, 0, e0, segm_); + set_segm(e0, 1, e3, segm_); + break; + default: + break; + } } + // connect oriented segments into oriented contours + // closed contours are coded in 64 bit unsigned long long + // 1) Each entry has 4 bits + // 2) The first 4 entries are reserved for the size of the contours + // 3) The next 12 entries are the indices of the edges constituting the contorus + // The indices are numbers from 0 to 12 + unsigned long long c_ = 0xFFFFFFFFFFFF0000; + + // in the 4 first bits store size of contours + auto get_cnt_size = [](const int cnt, unsigned long long& c_) + { + return (size_t)((c_ & (0xF << 4 * cnt)) >> 4 * cnt); + }; + + auto set_cnt_size = [](const int cnt, const int size, unsigned long long& c_) + { + // unset contour size + c_ &= ~(0xF << 4 * cnt); + c_ |= (size << 4 * cnt); + }; + + // set corresponging edge + auto set_c = [](const int cnt, const int pos, const int val, unsigned long long& c_) + { + const uint mask[4] = {0x0, 0xF, 0xFF, 0xFFF}; + const uint c_sz = c_ & mask[cnt]; + const uint e = 16 + 4 * ((c_sz & 0xF) + ((c_sz & 0xF0) >> 4) + ((c_sz & 0xF00) >> 8) + pos); + c_ &= ~(((unsigned long long)0xF) << e); + c_ |= (((unsigned long long)val) << e); + }; + + // read edge from contour + auto get_c = [](const int cnt, const int pos, unsigned long long c_) + { + const uint mask[4] = {0x0, 0xF, 0xFF, 0xFFF}; + const uint c_sz = (uint)(c_ & mask[cnt]); + const uint e = 16 + 4 * ((c_sz & 0xF) + ((c_sz & 0xF0) >> 4) + ((c_sz & 0xF00) >> 8) + pos); + return (int)((c_ >> e) & 0xF); + }; + + // connect oriented contours + uint cnt_{0}; + for(uint e=0; e<12; ++e) + { + if(is_segm_set(e, segm_)) + { + uint eTo = get_segm(e, 0, segm_); + uint eIn = get_segm(e, 1, segm_); + uint eStart = e; + uint pos = 0; + set_c(cnt_, pos, eStart, c_); + + while(eTo != eStart) + { + pos = pos + 1; + set_c(cnt_, pos, eTo, c_); + eIn = eTo; + eTo = get_segm(eIn, 0, segm_); + unset_segm(eIn, segm_); + } + + // set contour length + set_cnt_size(cnt_, pos + 1, c_); + + // update number of contours + cnt_ = cnt_ + 1; + } + } + + // compute intersection of opposite faces + // It is enough to compute a pair of solutions for one face + // The other solutions are obtained by evaluating the equations + // for the common variable + double ui[2]{}; + double vi[2]{}; + double wi[2]{}; + unsigned char q_sol{0}; + const double a = (values[0] - values[1]) * (-values[6] + values[7] + values[4] - values[5]) - + (values[4] - values[5]) * (-values[2] + values[3] + values[0] - values[1]); + const double b = (i0 - values[0]) * (-values[6] + values[7] + values[4] - values[5]) + + (values[0] - values[1]) * (values[6] - values[4]) - + (i0 - values[4]) * (-values[2] + values[3] + values[0] - values[1]) - + (values[4] - values[5]) * (values[2] - values[0]); + const double c = (i0 - values[0]) * (values[6] - values[4]) - (i0 - values[4]) * (values[2] - values[0]); + + double d = b * b - 4 * a * c; + if(d > 0) + { + d = std::sqrt(d); + + // compute u-coord of solutions + ui[0] = (-b - d) / (2 * a); + ui[1] = (-b + d) / (2 * a); + + // compute v-coord of solutions + double g1 = values[0] * (1 - ui[0]) + values[1] * ui[0]; + double g2 = values[2] * (1 - ui[0]) + values[3] * ui[0]; + vi[0] = (i0 - g1) / (g2 - g1); + if(std::isnan(vi[0]) || std::isinf(vi[0])) + vi[0] = -1.f; + + g1 = values[0] * (1 - ui[1]) + values[1] * ui[1]; + g2 = values[2] * (1 - ui[1]) + values[3] * ui[1]; + vi[1] = (i0 - g1) / (g2 - g1); + if(std::isnan(vi[1]) || std::isinf(vi[1])) + vi[1] = -1.f; + + // compute w-coordinates of solutions + g1 = values[0] * (1 - ui[0]) + values[1] * ui[0]; + g2 = values[4] * (1 - ui[0]) + values[5] * ui[0]; + wi[0] = (i0 - g1) / (g2 - g1); + if(std::isnan(wi[0]) || std::isinf(wi[0])) wi[0] = -1.f; + g1 = values[0] * (1 - ui[1]) + values[1] * ui[1]; + g2 = values[4] * (1 - ui[1]) + values[5] * ui[1]; + wi[1] = (i0 - g1) / (g2 - g1); + if(std::isnan(wi[1]) || std::isinf(wi[1])) + wi[1] = -1.f; + + // correct values for roots of quadratic equations + // in case the asymptotic decider has failed + if(f_flag[0] == true) { // face 1, w = 0; + if(wi[0] < wi[1]) + wi[0] = 0; + else + wi[1] = 0; + } + + if(f_flag[1] == true) { // face 2, w = 1 + if(wi[0] > wi[1]) + wi[1] = 1; + else + wi[1] = 1; + } + + if(f_flag[2] == true) { // face 3, v = 0 + if(vi[0] < vi[1]) + vi[0] = 0; + else + vi[1] = 0; + } + + if(f_flag[3] == true) { // face 4, v = 1 + if(vi[0] > vi[1]) + vi[0] = 1; + else + vi[1] = 1; + } + + if(f_flag[4] == true) { // face 5, u = 0 + if(ui[0] < ui[1]) + ui[0] = 0; + else + ui[1] = 0; + } + + if(f_flag[5] == true) { // face 6, u = 1 + if(ui[0] > ui[1]) + ui[0] = 1; + else + ui[1] = 1; + } + + // check solution intervals + if(0 < ui[0] && ui[0] < 1) + q_sol |= 1; + + if(0 < ui[1] && ui[1] < 1) + q_sol |= 2; + + if(0 < vi[0] && vi[0] < 1) + q_sol |= 4; + + if(0 < vi[1] && vi[1] < 1) + q_sol |= 8; + + if(0 < wi[0] && wi[0] < 1) + q_sol |= 16; + + if(0 < wi[1] && wi[1] < 1) + q_sol |= 32; + } + + // count the number of set bits + auto numberOfSetBits = [](const unsigned char n) + { + // C or C++: use uint32_t + uint b = (uint)n; + b = b - ((b >> 1) & 0x55555555); + b = (b & 0x33333333) + ((b >> 2) & 0x33333333); + return (((b + (b >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; + }; + + // compute the number of solutions to the quadratic equation for a given face + auto nrQSolFace = [](const uint f, const unsigned char n) + { + uint nr{0}; + switch (f) + { + case 0: + if((n & 0x5) == 0x5) nr = nr + 1; + if((n & 0xA) == 0xA) nr = nr + 1; + break; + case 1: + if((n & 0x11) == 0x11) nr = nr + 1; + if((n & 0x22) == 0x22) nr = nr + 1; + break; + case 2: + if((n & 0x18) == 0x18) nr = nr + 1; + if((n & 0x24) == 0x24) nr = nr + 1; + break; + } + return nr; + }; + + // triangulate contours + // if all bits are set, then there are three pairs of nontrivial solutions + // to the quadratic equations. In this case, there is a tunnel or a contour + // with 12 vertices. If there are three contours, then there is a tunnel and + // one of the contorus with only three vertices is not part of it. + if(numberOfSetBits(q_sol) == 6) + { + // there are at most three contours + // Possible cases: + // 1) a single contour with 12 vertices + // 2) two contours which build a tunnel + // 3) three contours, one has only 3 vertices and does not belong to the tunnel + + // construct the six vertices of the inner hexagon + double hvt[6][3]; + hvt[0][0] = ui[0]; + hvt[0][1] = vi[0]; + hvt[0][2] = wi[0]; + hvt[1][0] = ui[0]; + hvt[1][1] = vi[0]; + hvt[1][2] = wi[1]; + hvt[2][0] = ui[1]; + hvt[2][1] = vi[0]; + hvt[2][2] = wi[1]; + hvt[3][0] = ui[1]; + hvt[3][1] = vi[1]; + hvt[3][2] = wi[1]; + hvt[4][0] = ui[1]; + hvt[4][1] = vi[1]; + hvt[4][2] = wi[0]; + hvt[5][0] = ui[0]; + hvt[5][1] = vi[1]; + hvt[5][2] = wi[0]; + + // construct vertices at intersections with the edges + auto e_vert = [&ecoord](const int e, const int i) + { + const unsigned int l_coord[3]{1324855, 5299420, 16733440}; + unsigned char flag = (l_coord[i] >> (2 * e)) & 3; + if(flag == 3) + return ecoord[e]; + else + return (FT)(flag); + }; + + // if there are three contours, then there is a tunnel and one + // of the contours is not part of it. + unsigned char _not_tunnel = 0xF; + if(cnt_ == 3) + { + // loop over the contorus + // triangulate the contour which is not part of + // the tunnel + const double uc_min = (ui[0] < ui[1]) ? ui[0] : ui[1]; + const double uc_max = (ui[0] < ui[1]) ? ui[1] : ui[0]; + for(int t=0; t < (int)cnt_; ++t) + { + if(get_cnt_size(t, c_) == 3) + { + double umin = 2; + double umax = -2; + uint e0 = get_c(t, 0, c_); + uint e1 = get_c(t, 1, c_); + uint e2 = get_c(t, 2, c_); + const double u_e0 = e_vert(e0, 0); + const double u_e1 = e_vert(e1, 0); + const double u_e2 = e_vert(e2, 0); + umin = (u_e0 < umin) ? u_e0 : umin; + umin = (u_e1 < umin) ? u_e1 : umin; + umin = (u_e2 < umin) ? u_e2 : umin; + umax = (u_e0 > umax) ? u_e0 : umax; + umax = (u_e1 > umax) ? u_e1 : umax; + umax = (u_e2 > umax) ? u_e1 : umax; + if(uc_min > umax || uc_max < umin) + { + // this contour is not part of the tunnel + _not_tunnel = t; + + add_triangle(vertices[e0], vertices[e1], vertices[e2]); + } + } + } + } + + // compute vertices of inner hexagon, save new vertices in list and compute and keep + // global vertice index to build triangle connectivity later on. + uint tg_idx[6]; + for(int i=0; i<6; ++i) + { + const double u = hvt[i][0]; + const double v = hvt[i][1]; + const double w = hvt[i][2]; + const FT px = (1 - w) * ((1 - v) * (corners[0][0] + u * (corners[1][0] - corners[0][0])) + + v * (corners[2][0] + u * (corners[3][0] - corners[2][0]))) + + w * ((1 - v) * (corners[4][0] + u * (corners[5][0] - corners[4][0])) + + v * (corners[6][0] + u * (corners[7][0] - corners[6][0]))); + const FT py = (1 - w) * ((1 - v) * (corners[0][1] + u * (corners[1][1] - corners[0][1])) + + v * (corners[2][1] + u * (corners[3][1] - corners[2][1]))) + + w * ((1 - v) * (corners[4][1] + u * (corners[5][1] - corners[4][1])) + + v * (corners[6][1] + u * (corners[7][1] - corners[6][1]))); + const FT pz = (1 - w) * ((1 - v) * (corners[0][2] + u * (corners[1][2] - corners[0][2])) + + v * (corners[2][2] + u * (corners[3][2] - corners[2][2]))) + + w * ((1 - v) * (corners[4][2] + u * (corners[5][2] - corners[4][2])) + + v * (corners[6][2] + u * (corners[7][2] - corners[6][2]))); + + tg_idx[i] = (uint)points.size(); + points.push_back(Point(px, py, pz)); + } + + // triangulate contours with inner hexagon + unsigned char tcon_[12]; + for(int i=0; i<(int)cnt_; ++i) + { + if(_not_tunnel != i) + { + // contour belongs to tunnel + const int cnt_sz = int(get_cnt_size(i, c_)); + for(int r=0; r val) + { + index = s; + dist = val; + } + } + + tcon_[ci] = (unsigned char)(index); + } + + // correspondence between vertices found + // create triangles + // needs some functions + auto distanceRingIntsModulo = [](const int d1, const int d2) + { + const int r = (d1 - d2) < 0 ? d2 - d1 : d1 - d2; + return (r > 2 ? 6 - r : r); + }; + + auto midpointRingIntModulo = [](const int d1, const int d2) + { + const int dmax = (d1 > d2) ? d1 : d2; + const int dmin = (d1 < d2) ? d1 : d2; + return ((dmax + 2) % 6 == dmin) ? (dmax + 1) % 6 : (dmax + dmin) / 2; + }; + + for(int r=0; r> 1) & 1)}, + {(uchar)((q_sol >> 2) & 1), (uchar)((q_sol >> 3) & 1)}, + {(uchar)((q_sol >> 4) & 1), (uchar)((q_sol >> 5) & 1)}}; + + const unsigned char fc1 = fs[0][0] * fs[1][0] + fs[0][1] * fs[1][1]; + const unsigned char fc2 = fs[0][0] * fs[2][0] + fs[0][1] * fs[2][1]; + const unsigned char fc3 = fs[1][0] * fs[2][1] + fs[1][1] * fs[2][0]; + const unsigned char c_faces = fc1 + fc2 + fc3; + double ucoord{}; + double vcoord{}; + double wcoord{}; + switch(c_faces) + { + case 2: + { + if(fc1 == 0) + { + ucoord = fs[0][0] * ui[0] + fs[0][1] * ui[1]; + vcoord = fs[1][0] * vi[0] + fs[1][1] * vi[1]; + wcoord = fs[1][0] * wi[1] + fs[1][1] * wi[0]; + } + else if(fc2 == 0) + { + ucoord = fs[0][0] * ui[0] + fs[0][1] * ui[1]; + vcoord = fs[0][0] * vi[0] + fs[0][1] * vi[1]; + wcoord = fs[0][0] * wi[1] + fs[0][1] * wi[0]; + } + else if(fc3 == 0) + { + ucoord = fs[1][0] * ui[0] + fs[1][1] * ui[1]; + vcoord = fs[1][0] * vi[0] + fs[1][1] * vi[1]; + wcoord = fs[1][0] * wi[0] + fs[1][1] * wi[1]; + } + } + break; + case 3: + { + ucoord = (fs[0][0] * ui[0] + fs[0][1] * ui[1]) / (fs[0][0] + fs[0][1]); + vcoord = (fs[1][0] * vi[0] + fs[1][1] * vi[1]) / (fs[1][0] + fs[1][1]); + wcoord = (fs[2][0] * wi[0] + fs[2][1] * wi[1]) / (fs[2][0] + fs[2][1]); + } + break; + case 4: + { + const unsigned char nr_u = fs[0][0] + fs[0][1]; + const unsigned char nr_v = fs[1][0] + fs[1][1]; + const unsigned char nr_w = fs[2][0] + fs[2][1]; + if(nr_w == 1) + { + ucoord = fs[2][0] * ui[0] + fs[2][1] * ui[1]; + vcoord = fs[2][1] * vi[0] + fs[2][0] * vi[1]; + wcoord = fs[2][0] * wi[0] + fs[2][1] * wi[1]; + } + else if(nr_v == 1) + { + ucoord = fs[1][0] * ui[0] + fs[1][1] * ui[1]; + vcoord = fs[1][0] * vi[0] + fs[1][1] * vi[1]; + wcoord = fs[1][1] * wi[0] + fs[1][0] * wi[1]; + } + else if(nr_u == 1) + { + ucoord = fs[0][0] * ui[0] + fs[0][1] * ui[1]; + vcoord = fs[0][0] * vi[0] + fs[0][1] * vi[1]; + wcoord = fs[0][0] * wi[0] + fs[0][1] * wi[1]; + } + } + break; + } // switch(c_faces) + + // create inner vertex + const FT px = + (1 - wcoord) * ((1 - vcoord) * (corners[0][0] + ucoord * (corners[1][0] - corners[0][0])) + + vcoord * (corners[2][0] + ucoord * (corners[3][0] - corners[2][0]))) + + wcoord * ((1 - vcoord) * (corners[4][0] + ucoord * (corners[5][0] - corners[4][0])) + + vcoord * (corners[6][0] + ucoord * (corners[7][0] - corners[6][0]))); + const FT py = + (1 - wcoord) * ((1 - vcoord) * (corners[0][1] + ucoord * (corners[1][1] - corners[0][1])) + + vcoord * (corners[2][1] + ucoord * (corners[3][1] - corners[2][1]))) + + wcoord * ((1 - vcoord) * (corners[4][1] + ucoord * (corners[5][1] - corners[4][1])) + + vcoord * (corners[6][1] + ucoord * (corners[7][1] - corners[6][1]))); + const FT pz = + (1 - wcoord) * ((1 - vcoord) * (corners[0][2] + ucoord * (corners[1][2] - corners[0][2])) + + vcoord * (corners[2][2] + ucoord * (corners[3][2] - corners[2][2]))) + + wcoord * ((1 - vcoord) * (corners[4][2] + ucoord * (corners[5][2] - corners[4][2])) + + vcoord * (corners[6][2] + ucoord * (corners[7][2] - corners[6][2]))); + + const uint g_index = uint(points.size()); + + // loop over the contorus + bool pt_used = false; + for(int i=0; i vertex_map; + // compute a unique global index for vertices + // use as key the unique edge number + std::map vertex_map; - std::mutex mutex; + std::mutex mutex; }; -} // namespace internal -} // namespace Isosurfacing -} // namespace CGAL +} // namespace internal +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_TMC_INTERNAL_TMC_H +#endif // CGAL_ISOSURFACING_3_INTERNAL_TMC_INTERNAL_H diff --git a/Isosurfacing_3/include/CGAL/Marching_cubes_3.h b/Isosurfacing_3/include/CGAL/Marching_cubes_3.h index c1b22dbdf7c..efe548911d1 100644 --- a/Isosurfacing_3/include/CGAL/Marching_cubes_3.h +++ b/Isosurfacing_3/include/CGAL/Marching_cubes_3.h @@ -44,24 +44,34 @@ namespace Isosurfacing { * \param triangles each element in the vector describes a triangle using the indices of the points in `points` * \param topologically_correct decides whether the topologically correct variant of Marching Cubes should be used */ -template -void marching_cubes(const Domain_& domain, const typename Domain_::FT isovalue, PointRange& points, - TriangleRange& triangles, bool topologically_correct = true) { +template +void marching_cubes(const Domain_& domain, + const typename Domain_::FT isovalue, + PointRange& points, + TriangleRange& triangles, + bool topologically_correct = true) +{ + if(topologically_correct) + { + // run TMC and directly write the result to points and triangles + internal::TMC_functor functor(domain, isovalue, points, triangles); + domain.template iterate_cells(functor); + } + else + { + // run MC + internal::Marching_cubes_3 functor(domain, isovalue); + domain.template iterate_cells(functor); - if (topologically_correct) { - // run TMC and directly write the result to points and triangles - internal::TMC_functor functor(domain, isovalue, points, triangles); - domain.template iterate_cells(functor); - } else { - // run MC - internal::Marching_cubes_3 functor(domain, isovalue); - domain.template iterate_cells(functor); - // copy the result to points and triangles - internal::to_indexed_face_set(functor.triangles(), points, triangles); - } + // copy the result to points and triangles + internal::to_indexed_face_set(functor.triangles(), points, triangles); + } } -} // namespace Isosurfacing -} // namespace CGAL +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_MARCHING_CUBES_3_H +#endif // CGAL_MARCHING_CUBES_3_H diff --git a/Isosurfacing_3/include/CGAL/Octree_wrapper.h b/Isosurfacing_3/include/CGAL/Octree_wrapper.h index c3a39dc1571..0ae0191cf0c 100644 --- a/Isosurfacing_3/include/CGAL/Octree_wrapper.h +++ b/Isosurfacing_3/include/CGAL/Octree_wrapper.h @@ -23,514 +23,589 @@ namespace CGAL { namespace Isosurfacing { template -class Octree_wrapper { - /* - * Naming convention from "A parallel dual marching cubes approach to quad - * only surface reconstruction - Grosso & Zint" - * - * ^ y - * | - * v2------e2------v3 - * /| /| - * e11| e10| - * / e3 / e1 - * v6------e6------v7 | - * | | | | - * | v0------e0--|---v1 --> x - * e7 / e5 / - * | e8 | e9 - * |/ |/ - * v4------e4------v5 - * / - * < z - */ +class Octree_wrapper +{ + /* + * Naming convention from "A parallel dual marching cubes approach to quad + * only surface reconstruction - Grosso & Zint" + * + * ^ y + * | + * v2------e2------v3 + * /| /| + * e11| e10| + * / e3 / e1 + * v6------e6------v7 | + * | | | | + * | v0------e0--|---v1 --> x + * e7 / e5 / + * | e8 | e9 + * |/ |/ + * v4------e4------v5 + * / + * < z + */ public: - typedef GeomTraits Kernel; - typedef typename GeomTraits::FT FT; - typedef typename GeomTraits::Point_3 Point_3; - typedef typename GeomTraits::Vector_3 Vector_3; + using Kernel = GeomTraits; + using FT = typename GeomTraits::FT; + using Point_3 = typename GeomTraits::Point_3; + using Vector_3 = typename GeomTraits::Vector_3; - typedef CGAL::Octree> Octree; + using Octree = CGAL::Octree >; - typedef std::size_t Vertex_handle; - typedef std::tuple Edge_handle; - typedef std::size_t Voxel_handle; + using Vertex_handle = std::size_t; + using Edge_handle = std::tuple; + using Voxel_handle = std::size_t; - typedef typename Octree::Node Node; - typedef typename Node::Global_coordinates Uniform_coords; // coordinates on max depth level + using Node = typename Octree::Node; + using Uniform_coords = typename Node::Global_coordinates; // coordinates on max depth level private: - std::size_t max_depth_ = 0; + std::size_t max_depth_ = 0; - FT offset_x_; - FT offset_y_; - FT offset_z_; + FT offset_x_; + FT offset_y_; + FT offset_z_; - CGAL::Bbox_3 bbox_; + CGAL::Bbox_3 bbox_; - std::size_t dim_ = 1; + std::size_t dim_ = 1; - FT hx_ = 0; + FT hx_ = 0; - std::vector point_range_; - Octree octree_; + std::vector point_range_; + Octree octree_; - // std::set leaf_node_uniform_coordinates_; - std::vector leaf_voxels_; - std::vector leaf_edges_; - std::vector leaf_vertices_; - std::map vertex_values_; - std::map vertex_gradients_; + // std::set leaf_node_uniform_coordinates_; + std::vector leaf_voxels_; + std::vector leaf_edges_; + std::vector leaf_vertices_; + std::map vertex_values_; + std::map vertex_gradients_; public: - Octree_wrapper(const CGAL::Bbox_3& bbox) - : offset_x_(bbox.xmin()), - offset_y_(bbox.ymin()), - offset_z_(bbox.zmin()), - bbox_(bbox), - point_range_({{bbox.xmin(), bbox.ymin(), bbox.zmin()}, {bbox.xmax(), bbox.ymax(), bbox.zmax()}}), - octree_(point_range_) {} + Octree_wrapper(const CGAL::Bbox_3& bbox) + : offset_x_(bbox.xmin()), + offset_y_(bbox.ymin()), + offset_z_(bbox.zmin()), + bbox_(bbox), + point_range_({{bbox.xmin(), bbox.ymin(), bbox.zmin()}, {bbox.xmax(), bbox.ymax(), bbox.zmax()}}), + octree_(point_range_) + { } - template - void refine(const Split_predicate& split_predicate) { - namespace Tables = internal::Cube_table; + template + void refine(const Split_predicate& split_predicate) + { + namespace Tables = internal::Cube_table; - octree_.refine(split_predicate); + octree_.refine(split_predicate); - max_depth_ = octree_.depth(); - dim_ = std::size_t(1) << max_depth_; - hx_ = bbox_.x_span() / dim_; + max_depth_ = octree_.depth(); + dim_ = std::size_t(1) << max_depth_; + hx_ = bbox_.x_span() / dim_; - // store leaf elements in sets + initialize value maps - std::set leaf_voxels_set; - std::set leaf_edges_set; - std::set leaf_vertices_set; - for (Node node : octree_.traverse(CGAL::Orthtrees::Leaves_traversal())) { - const auto& coords_uniform = uniform_coordinates(node); - // write all leaf nodes in a set - leaf_voxels_set.insert(lex_index(coords_uniform[0], coords_uniform[1], coords_uniform[2], max_depth_)); + // store leaf elements in sets + initialize value maps + std::set leaf_voxels_set; + std::set leaf_edges_set; + std::set leaf_vertices_set; + for(Node node : octree_.traverse(CGAL::Orthtrees::Leaves_traversal())) + { + const auto& coords_uniform = uniform_coordinates(node); + // write all leaf nodes in a set + leaf_voxels_set.insert(lex_index(coords_uniform[0], coords_uniform[1], coords_uniform[2], max_depth_)); - // init vertex values - for (int i = 0; i < Tables::N_VERTICES; ++i) { - Uniform_coords vuc = vertex_uniform_coordinates(node, i); - const auto lex = lex_index(vuc[0], vuc[1], vuc[2], max_depth_); - leaf_vertices_set.insert(lex); - vertex_values_[lex] = 0; - } + // init vertex values + for(int i=0; i= dim_ || y >= dim_ || z >= dim_) { - are_all_voxels_leafs = false; - break; - } + // write all leaf edges in a set + const auto& coords_global = node.global_coordinates(); + const auto& depth = node.depth(); + const auto& df = depth_factor(node.depth()); + for(const auto& edge_voxels : Tables::edge_to_voxel_neighbor) + { + bool are_all_voxels_leafs = true; + for(const auto& node_ijk : edge_voxels) + { + const std::size_t x = coords_uniform[0] + df * node_ijk[0]; + const std::size_t y = coords_uniform[1] + df * node_ijk[1]; + const std::size_t z = coords_uniform[2] + df * node_ijk[2]; + // check for overflow / ignore edges on boundary + if(x >= dim_ || y >= dim_ || z >= dim_) + { + are_all_voxels_leafs = false; + break; + } - const Node n = get_node(x, y, z); - if (n.depth() > depth) { - are_all_voxels_leafs = false; - break; - } - } - if (are_all_voxels_leafs) { - // add to leaf edge set - std::size_t e_gl = - e_glIndex(edge_voxels[0][3], coords_global[0], coords_global[1], coords_global[2], depth); - leaf_edges_set.insert({e_gl, depth}); - } - } + const Node n = get_node(x, y, z); + if(n.depth() > depth) + { + are_all_voxels_leafs = false; + break; + } } - leaf_voxels_ = std::vector(leaf_voxels_set.begin(), leaf_voxels_set.end()); - leaf_edges_ = std::vector(leaf_edges_set.begin(), leaf_edges_set.end()); - leaf_vertices_ = std::vector(leaf_vertices_set.begin(), leaf_vertices_set.end()); - } - - std::size_t dim() const { - return dim_; - } - FT hx() const { - return hx_; - } - FT offset_x() const { - return offset_x_; - } - FT offset_y() const { - return offset_y_; - } - FT offset_z() const { - return offset_z_; - } - std::size_t max_depth() const { - return max_depth_; - } - - const std::vector& leaf_edges() const { - return leaf_edges_; - } - const std::vector& leaf_vertices() const { - return leaf_vertices_; - } - const std::vector& leaf_voxels() const { - return leaf_voxels_; - } - - FT value(const Vertex_handle& v) const { - return vertex_values_.at(v); - } - FT& value(const Vertex_handle& v) { - return vertex_values_[v]; - } - - Vector_3 gradient(const Vertex_handle& v) const { - return vertex_gradients_.at(v); - } - Vector_3& gradient(const Vertex_handle& v) { - return vertex_gradients_[v]; - } - - std::size_t depth_factor(const std::size_t& depth) const { - return std::size_t(1) << (max_depth_ - depth); - } - - Uniform_coords uniform_coordinates(const Node& node) const { - auto coords = node.global_coordinates(); - const std::size_t df = depth_factor(node.depth()); - for (int i = 0; i < Node::Dimension::value; ++i) { - coords[i] *= df; + if(are_all_voxels_leafs) + { + // add to leaf edge set + std::size_t e_gl = e_glIndex(edge_voxels[0][3], + coords_global[0], coords_global[1], coords_global[2], + depth); + leaf_edges_set.insert({e_gl, depth}); } - - return coords; + } } - std::array node_points(const Node& node) const { - auto coords = node.global_coordinates(); - const std::size_t df = depth_factor(node.depth()); + leaf_voxels_ = std::vector(leaf_voxels_set.begin(), leaf_voxels_set.end()); + leaf_edges_ = std::vector(leaf_edges_set.begin(), leaf_edges_set.end()); + leaf_vertices_ = std::vector(leaf_vertices_set.begin(), leaf_vertices_set.end()); + } - const FT x0 = offset_x_ + coords[0] * df * hx_; - const FT y0 = offset_y_ + coords[1] * df * hx_; - const FT z0 = offset_z_ + coords[2] * df * hx_; - const FT x1 = offset_x_ + (coords[0] + 1) * df * hx_; - const FT y1 = offset_y_ + (coords[1] + 1) * df * hx_; - const FT z1 = offset_z_ + (coords[2] + 1) * df * hx_; + std::size_t dim() const + { + return dim_; + } - std::array points; - points[0] = {x0, y0, z0}; - points[1] = {x1, y0, z0}; - points[2] = {x0, y1, z0}; - points[3] = {x1, y1, z0}; + FT hx() const + { + return hx_; + } - points[4] = {x0, y0, z1}; - points[5] = {x1, y0, z1}; - points[6] = {x0, y1, z1}; - points[7] = {x1, y1, z1}; + FT offset_x() const + { + return offset_x_; + } - return points; + FT offset_y() const + { + return offset_y_; + } + + FT offset_z() const + { + return offset_z_; + } + + std::size_t max_depth() const + { + return max_depth_; + } + + const std::vector& leaf_edges() const + { + return leaf_edges_; + } + + const std::vector& leaf_vertices() const + { + return leaf_vertices_; + } + + const std::vector& leaf_voxels() const + { + return leaf_voxels_; + } + + FT value(const Vertex_handle& v) const + { + return vertex_values_.at(v); + } + + FT& value(const Vertex_handle& v) + { + return vertex_values_[v]; + } + + Vector_3 gradient(const Vertex_handle& v) const + { + return vertex_gradients_.at(v); + } + + Vector_3& gradient(const Vertex_handle& v) + { + return vertex_gradients_[v]; + } + + std::size_t depth_factor(const std::size_t& depth) const + { + return std::size_t(1) << (max_depth_ - depth); + } + + Uniform_coords uniform_coordinates(const Node& node) const + { + auto coords = node.global_coordinates(); + const std::size_t df = depth_factor(node.depth()); + for(int i=0; i node_points(const Node& node) const + { + auto coords = node.global_coordinates(); + const std::size_t df = depth_factor(node.depth()); + + const FT x0 = offset_x_ + coords[0] * df * hx_; + const FT y0 = offset_y_ + coords[1] * df * hx_; + const FT z0 = offset_z_ + coords[2] * df * hx_; + const FT x1 = offset_x_ + (coords[0] + 1) * df * hx_; + const FT y1 = offset_y_ + (coords[1] + 1) * df * hx_; + const FT z1 = offset_z_ + (coords[2] + 1) * df * hx_; + + std::array points; + points[0] = {x0, y0, z0}; + points[1] = {x1, y0, z0}; + points[2] = {x0, y1, z0}; + points[3] = {x1, y1, z0}; + + points[4] = {x0, y0, z1}; + points[5] = {x1, y0, z1}; + points[6] = {x0, y1, z1}; + points[7] = {x1, y1, z1}; + + return points; + } + + Point_3 point(const Uniform_coords& vertex_coordinates) const + { + const FT x0 = offset_x_ + vertex_coordinates[0] * hx_; + const FT y0 = offset_y_ + vertex_coordinates[1] * hx_; + const FT z0 = offset_z_ + vertex_coordinates[2] * hx_; + + return {x0, y0, z0}; + } + + Point_3 point(const Vertex_handle& v) const + { + std::size_t i, j, k; + std::tie(i, j, k) = ijk_index(v, max_depth_); + + const FT x0 = offset_x_ + i * hx_; + const FT y0 = offset_y_ + j * hx_; + const FT z0 = offset_z_ + k * hx_; + + return {x0, y0, z0}; + } + + Uniform_coords vertex_uniform_coordinates(const Node& node, + const typename Node::Local_coordinates local_coords) const + { + const auto node_coords = node.global_coordinates(); + auto v_coords = node_coords; + for(int i=0; i ijk_index(const std::size_t& lex_index, + const std::size_t& depth) const + { + const std::size_t dim = (std::size_t(1) << depth) + 1; + return std::make_tuple(lex_index % dim, (lex_index / dim) % dim, lex_index / (dim * dim)); + } + + /// + /// compute unique edge global index. + /// + /// local edge index + /// i-index of cell + /// j-index of cell + /// k-index of cell + /// depth of cell + /// + std::size_t e_glIndex(const std::size_t& e, + const std::size_t& i_idx, + const std::size_t& j_idx, + const std::size_t& k_idx, + const std::size_t& depth) const + { + const unsigned long long gei_pattern_ = 670526590282893600ull; + const size_t i = i_idx + (size_t)((gei_pattern_ >> 5 * e) & 1); // global_edge_id[eg][0]; + const size_t j = j_idx + (size_t)((gei_pattern_ >> (5 * e + 1)) & 1); // global_edge_id[eg][1]; + const size_t k = k_idx + (size_t)((gei_pattern_ >> (5 * e + 2)) & 1); // global_edge_id[eg][2]; + const size_t offs = (size_t)((gei_pattern_ >> (5 * e + 3)) & 3); + + return (3 * lex_index(i, j, k, depth) + offs); + } + + std::array voxel_values(const Voxel_handle& vox) const + { + namespace Tables = internal::Cube_table; + + std::size_t i, j, k; + std::tie(i, j, k) = ijk_index(vox, max_depth_); + Node node = get_node(i, j, k); + const auto& df = depth_factor(node.depth()); + + std::array v; + for(int v_id=0; v_id s; + std::transform(v.begin(), v.end(), s.begin(), [this](const auto& e) { return this->vertex_values_.at(e); }); - const FT x0 = offset_x_ + i * hx_; - const FT y0 = offset_y_ + j * hx_; - const FT z0 = offset_z_ + k * hx_; - return {x0, y0, z0}; + return s; + } + + FT vertex_value(const Vertex_handle& v) const + { + return vertex_values_.at(v); + } + + std::array voxel_edges(const Voxel_handle& vox) const + { + std::size_t i, j, k; + std::tie(i, j, k) = ijk_index(vox, max_depth_); + Node node = get_node(i, j, k); + + const auto& coords_global = node.global_coordinates(); + const auto& depth = node.depth(); + + std::array edges; + for(int e_id=0; e_id voxel_vertices(const Voxel_handle& vox) const + { + namespace Tables = internal::Cube_table; - return v_coords; + std::size_t i, j, k; + std::tie(i, j, k) = ijk_index(vox, max_depth_); + Node node = get_node(i, j, k); + const auto& df = depth_factor(node.depth()); + + std::array v; + for(int v_id=0; v_id voxel_gradients(const Voxel_handle& vox) const + { + namespace Tables = internal::Cube_table; + + std::size_t i, j, k; + std::tie(i, j, k) = ijk_index(vox, max_depth_); + Node node = get_node(i, j, k); + const auto& df = depth_factor(node.depth()); + + std::array v; + for(int v_id=0; v_id s; + std::transform(v.begin(), v.end(), s.begin(), [this](const auto& e) { return this->vertex_gradients_.at(e); }); - std::size_t lex_index(const std::size_t& i, const std::size_t& j, const std::size_t& k, - const std::size_t& depth) const { - std::size_t dim = (std::size_t(1) << depth) + 1; - return k * dim * dim + j * dim + i; - } + return s; + } - std::size_t i_index(const std::size_t& lex_index, const std::size_t& depth) const { - std::size_t dim = (std::size_t(1) << depth) + 1; - return lex_index % dim; - } - std::size_t j_index(const std::size_t& lex_index, const std::size_t& depth) const { - std::size_t dim = (std::size_t(1) << depth) + 1; - return ((lex_index / dim) % dim); - } - std::size_t k_index(const std::size_t& lex_index, const std::size_t& depth) const { - std::size_t dim = (std::size_t(1) << depth) + 1; - return (lex_index / (dim * dim)); - } + std::array voxel_vertex_positions(const Voxel_handle& vox) const + { + Node node = get_node(vox); + return node_points(node); + } - std::tuple ijk_index(const std::size_t& lex_index, - const std::size_t& depth) const { - const std::size_t dim = (std::size_t(1) << depth) + 1; - return std::make_tuple(lex_index % dim, (lex_index / dim) % dim, lex_index / (dim * dim)); - } + /// + /// Get the values at the incident two vertices. Vertices are sorted in + /// ascending order. + /// + /// + /// + std::array edge_values(const Edge_handle& e_id) const + { + namespace Tables = internal::Cube_table; - /// - /// compute unique edge global index. - /// - /// local edge index - /// i-index of cell - /// j-index of cell - /// k-index of cell - /// depth of cell - /// - std::size_t e_glIndex(const std::size_t& e, const std::size_t& i_idx, const std::size_t& j_idx, - const std::size_t& k_idx, const std::size_t& depth) const { - const unsigned long long gei_pattern_ = 670526590282893600ull; - const size_t i = i_idx + (size_t)((gei_pattern_ >> 5 * e) & 1); // global_edge_id[eg][0]; - const size_t j = j_idx + (size_t)((gei_pattern_ >> (5 * e + 1)) & 1); // global_edge_id[eg][1]; - const size_t k = k_idx + (size_t)((gei_pattern_ >> (5 * e + 2)) & 1); // global_edge_id[eg][2]; - const size_t offs = (size_t)((gei_pattern_ >> (5 * e + 3)) & 3); - return (3 * lex_index(i, j, k, depth) + offs); - } + std::size_t e_global_id, depth; + std::tie(e_global_id, depth) = e_id; + const auto df = depth_factor(depth); - std::array voxel_values(const Voxel_handle& vox) const { - namespace Tables = internal::Cube_table; + const size_t v0_lex_index = e_global_id / 3; + std::size_t i0, j0, k0; + std::tie(i0, j0, k0) = ijk_index(v0_lex_index, depth); - std::size_t i, j, k; - std::tie(i, j, k) = ijk_index(vox, max_depth_); - Node node = get_node(i, j, k); - const auto& df = depth_factor(node.depth()); + // v1 + const std::size_t e_local_index = Tables::edge_store_index[e_global_id % 3]; + const auto& v1_local = Tables::local_vertex_position[Tables::edge_to_vertex[e_local_index][1]]; - std::array v; - for (int v_id = 0; v_id < Tables::N_VERTICES; ++v_id) { - const auto& l = Tables::local_vertex_position[v_id]; - const auto lex = lex_index(i + df * l[0], j + df * l[1], k + df * l[2], max_depth_); - v[v_id] = lex; - } + const std::size_t i1 = i0 + v1_local[0]; + const std::size_t j1 = j0 + v1_local[1]; + const std::size_t k1 = k0 + v1_local[2]; - std::array s; - std::transform(v.begin(), v.end(), s.begin(), [this](const auto& e) { return this->vertex_values_.at(e); }); + const auto v0 = lex_index(df * i0, df * j0, df * k0, max_depth_); + const auto v1 = lex_index(df * i1, df * j1, df * k1, max_depth_); - return s; - } + return { value(v0), value(v1) }; + } - FT vertex_value(const Vertex_handle& v) const { - return vertex_values_.at(v); - } + std::array edge_vertices(const Edge_handle& e_id) const + { + namespace Tables = internal::Cube_table; - std::array voxel_edges(const Voxel_handle& vox) const { + std::size_t e_global_id, depth; + std::tie(e_global_id, depth) = e_id; + const auto df = depth_factor(depth); - std::size_t i, j, k; - std::tie(i, j, k) = ijk_index(vox, max_depth_); - Node node = get_node(i, j, k); + const size_t v0_lex_index = e_global_id / 3; + std::size_t i0, j0, k0; + std::tie(i0, j0, k0) = ijk_index(v0_lex_index, depth); - const auto& coords_global = node.global_coordinates(); - const auto& depth = node.depth(); + // v1 + const std::size_t e_local_index = Tables::edge_store_index[e_global_id % 3]; + const auto& v1_local = Tables::local_vertex_position[Tables::edge_to_vertex[e_local_index][1]]; - std::array edges; - for (int e_id = 0; e_id < edges.size(); ++e_id) { + const std::size_t i1 = i0 + v1_local[0]; + const std::size_t j1 = j0 + v1_local[1]; + const std::size_t k1 = k0 + v1_local[2]; - const std::size_t e_gl = e_glIndex(e_id, coords_global[0], coords_global[1], coords_global[2], depth); - edges[e_id] = {e_gl, depth}; - } + const auto v0 = lex_index(df * i0, df * j0, df * k0, max_depth_); + const auto v1 = lex_index(df * i1, df * j1, df * k1, max_depth_); - return edges; - } + return { v0, v1 }; + } - std::array voxel_vertices(const Voxel_handle& vox) const { - namespace Tables = internal::Cube_table; + /// + /// Get the 4 voxels incident to an edge. If an edge has only three incident + /// voxels, one will appear twice. The voxels are given with the uniform + /// lexicographical index. + /// + /// + /// + std::array edge_voxels(const Edge_handle& e_id) const + { + namespace Tables = internal::Cube_table; - std::size_t i, j, k; - std::tie(i, j, k) = ijk_index(vox, max_depth_); - Node node = get_node(i, j, k); - const auto& df = depth_factor(node.depth()); + std::size_t e_global_id, depth; + std::tie(e_global_id, depth) = e_id; + const std::size_t e_local_index = Tables::edge_store_index[e_global_id % 3]; - std::array v; - for (int v_id = 0; v_id < Tables::N_VERTICES; ++v_id) { - const auto& l = Tables::local_vertex_position[v_id]; - const auto lex = lex_index(i + df * l[0], j + df * l[1], k + df * l[2], max_depth_); - v[v_id] = lex; - } + const auto df = depth_factor(depth); - return v; - } + const size_t v0_lex_index = e_global_id / 3; + std::size_t i, j, k; + std::tie(i, j, k) = ijk_index(v0_lex_index, depth); + i *= df; + j *= df; + k *= df; - std::array voxel_gradients(const Voxel_handle& vox) const { - namespace Tables = internal::Cube_table; + const auto& voxel_neighbors = Tables::edge_to_voxel_neighbor[e_local_index]; + Node n0 = get_node(i + voxel_neighbors[0][0], j + voxel_neighbors[0][1], k + voxel_neighbors[0][2]); + Node n1 = get_node(i + voxel_neighbors[1][0], j + voxel_neighbors[1][1], k + voxel_neighbors[1][2]); + Node n2 = get_node(i + voxel_neighbors[2][0], j + voxel_neighbors[2][1], k + voxel_neighbors[2][2]); + Node n3 = get_node(i + voxel_neighbors[3][0], j + voxel_neighbors[3][1], k + voxel_neighbors[3][2]); - std::size_t i, j, k; - std::tie(i, j, k) = ijk_index(vox, max_depth_); - Node node = get_node(i, j, k); - const auto& df = depth_factor(node.depth()); + const Uniform_coords n0_uniform_coords = uniform_coordinates(n0); + const Uniform_coords n1_uniform_coords = uniform_coordinates(n1); + const Uniform_coords n2_uniform_coords = uniform_coordinates(n2); + const Uniform_coords n3_uniform_coords = uniform_coordinates(n3); - std::array v; - for (int v_id = 0; v_id < Tables::N_VERTICES; ++v_id) { - const auto& l = Tables::local_vertex_position[v_id]; - const auto lex = lex_index(i + df * l[0], j + df * l[1], k + df * l[2], max_depth_); - v[v_id] = lex; - } + std::size_t n0_lex = lex_index(n0_uniform_coords[0], n0_uniform_coords[1], n0_uniform_coords[2], max_depth_); + std::size_t n1_lex = lex_index(n1_uniform_coords[0], n1_uniform_coords[1], n1_uniform_coords[2], max_depth_); + std::size_t n2_lex = lex_index(n2_uniform_coords[0], n2_uniform_coords[1], n2_uniform_coords[2], max_depth_); + std::size_t n3_lex = lex_index(n3_uniform_coords[0], n3_uniform_coords[1], n3_uniform_coords[2], max_depth_); - std::array s; - std::transform(v.begin(), v.end(), s.begin(), [this](const auto& e) { return this->vertex_gradients_.at(e); }); + return {n0_lex, n1_lex, n2_lex, n3_lex}; - return s; - } - std::array voxel_vertex_positions(const Voxel_handle& vox) const { - Node node = get_node(vox); - return node_points(node); - } - - /// - /// Get the values at the incident two vertices. Vertices are sorted in - /// ascending order. - /// - /// - /// - std::array edge_values(const Edge_handle& e_id) const { - namespace Tables = internal::Cube_table; - - std::size_t e_global_id, depth; - std::tie(e_global_id, depth) = e_id; - const auto df = depth_factor(depth); - - const size_t v0_lex_index = e_global_id / 3; - std::size_t i0, j0, k0; - std::tie(i0, j0, k0) = ijk_index(v0_lex_index, depth); - - // v1 - const std::size_t e_local_index = Tables::edge_store_index[e_global_id % 3]; - const auto& v1_local = Tables::local_vertex_position[Tables::edge_to_vertex[e_local_index][1]]; - - const std::size_t i1 = i0 + v1_local[0]; - const std::size_t j1 = j0 + v1_local[1]; - const std::size_t k1 = k0 + v1_local[2]; - - const auto v0 = lex_index(df * i0, df * j0, df * k0, max_depth_); - const auto v1 = lex_index(df * i1, df * j1, df * k1, max_depth_); - - return {value(v0), value(v1)}; - } - - std::array edge_vertices(const Edge_handle& e_id) const { - namespace Tables = internal::Cube_table; - - std::size_t e_global_id, depth; - std::tie(e_global_id, depth) = e_id; - const auto df = depth_factor(depth); - - const size_t v0_lex_index = e_global_id / 3; - std::size_t i0, j0, k0; - std::tie(i0, j0, k0) = ijk_index(v0_lex_index, depth); - - // v1 - const std::size_t e_local_index = Tables::edge_store_index[e_global_id % 3]; - const auto& v1_local = Tables::local_vertex_position[Tables::edge_to_vertex[e_local_index][1]]; - - const std::size_t i1 = i0 + v1_local[0]; - const std::size_t j1 = j0 + v1_local[1]; - const std::size_t k1 = k0 + v1_local[2]; - - const auto v0 = lex_index(df * i0, df * j0, df * k0, max_depth_); - const auto v1 = lex_index(df * i1, df * j1, df * k1, max_depth_); - - return {v0, v1}; - } - - /// - /// Get the 4 voxels incident to an edge. If an edge has only three incident - /// voxels, one will appear twice. The voxels are given with the uniform - /// lexicographical index. - /// - /// - /// - std::array edge_voxels(const Edge_handle& e_id) const { - namespace Tables = internal::Cube_table; - - std::size_t e_global_id, depth; - std::tie(e_global_id, depth) = e_id; - const std::size_t e_local_index = Tables::edge_store_index[e_global_id % 3]; - - const auto df = depth_factor(depth); - - const size_t v0_lex_index = e_global_id / 3; - std::size_t i, j, k; - std::tie(i, j, k) = ijk_index(v0_lex_index, depth); - i *= df; - j *= df; - k *= df; - - const auto& voxel_neighbors = Tables::edge_to_voxel_neighbor[e_local_index]; - Node n0 = get_node(i + voxel_neighbors[0][0], j + voxel_neighbors[0][1], k + voxel_neighbors[0][2]); - Node n1 = get_node(i + voxel_neighbors[1][0], j + voxel_neighbors[1][1], k + voxel_neighbors[1][2]); - Node n2 = get_node(i + voxel_neighbors[2][0], j + voxel_neighbors[2][1], k + voxel_neighbors[2][2]); - Node n3 = get_node(i + voxel_neighbors[3][0], j + voxel_neighbors[3][1], k + voxel_neighbors[3][2]); - - const Uniform_coords n0_uniform_coords = uniform_coordinates(n0); - const Uniform_coords n1_uniform_coords = uniform_coordinates(n1); - const Uniform_coords n2_uniform_coords = uniform_coordinates(n2); - const Uniform_coords n3_uniform_coords = uniform_coordinates(n3); - - std::size_t n0_lex = lex_index(n0_uniform_coords[0], n0_uniform_coords[1], n0_uniform_coords[2], max_depth_); - std::size_t n1_lex = lex_index(n1_uniform_coords[0], n1_uniform_coords[1], n1_uniform_coords[2], max_depth_); - std::size_t n2_lex = lex_index(n2_uniform_coords[0], n2_uniform_coords[1], n2_uniform_coords[2], max_depth_); - std::size_t n3_lex = lex_index(n3_uniform_coords[0], n3_uniform_coords[1], n3_uniform_coords[2], max_depth_); - - return {n0_lex, n1_lex, n2_lex, n3_lex}; - - // return { value( i0, j0, k0 ), value( i1, j1, k1 ) }; - } + // return { value( i0, j0, k0 ), value( i1, j1, k1 ) }; + } }; -} // namespace Isosurfacing -} // namespace CGAL +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_OCTREE_WRAPPER_H +#endif // CGAL_OCTREE_WRAPPER_H diff --git a/Isosurfacing_3/include/CGAL/Zero_gradient.h b/Isosurfacing_3/include/CGAL/Zero_gradient.h index 38a40db693a..ca24decd821 100644 --- a/Isosurfacing_3/include/CGAL/Zero_gradient.h +++ b/Isosurfacing_3/include/CGAL/Zero_gradient.h @@ -26,30 +26,32 @@ namespace Isosurfacing { * * \tparam GeomTraits the traits for this gradient. */ -template -class Zero_gradient { +template +class Zero_gradient +{ public: - typedef GeomTraits Geom_traits; - typedef typename Geom_traits::Point_3 Point; - typedef typename Geom_traits::Vector_3 Vector; + using Geom_traits = GeomTraits; + using Point = typename Geom_traits::Point_3; + using Vector = typename Geom_traits::Vector_3; public: - /** - * \ingroup PkgIsosurfacing3Ref - * - * \brief Evaluate the gradient at a point in space. - * - * \param point the point at which the gradient is computed - */ - Vector operator()(const Point& point) const { - return zero; - } + /** + * \ingroup PkgIsosurfacing3Ref + * + * \brief Evaluate the gradient at a point in space. + * + * \param point the point at which the gradient is computed + */ + Vector operator()(const Point& point) const + { + return zero; + } private: - const Vector zero = Vector(0, 0, 0); + const Vector zero = Vector(0, 0, 0); }; -} // namespace Isosurfacing -} // namespace CGAL +} // namespace Isosurfacing +} // namespace CGAL -#endif // CGAL_ZERO_GRADIENT_H +#endif // CGAL_ZERO_GRADIENT_H diff --git a/Isosurfacing_3/package_info/Isosurfacing_3/long_description.txt b/Isosurfacing_3/package_info/Isosurfacing_3/long_description.txt index 6650e546139..89d45921492 100644 --- a/Isosurfacing_3/package_info/Isosurfacing_3/long_description.txt +++ b/Isosurfacing_3/package_info/Isosurfacing_3/long_description.txt @@ -1 +1,5 @@ -This component takes a 3D domain as input and a user-specified isovalue, and generates a surface mesh approximating the specified isovalue. The meshing algorithm can be chosen among two isosurfacing algorithms: marching cubes and dual contouring. Two variants of the marching cubes algorithm are offererd: with or without topological guarantees. The domain can be created from an explicit grid, an implicit grid or a volumetric image. +This component takes a 3D domain as input and a user-specified isovalue, and generates a surface mesh +approximating the specified isovalue. The meshing algorithm can be chosen among two isosurfacing algorithms: +marching cubes and dual contouring. Two variants of the marching cubes algorithm are offererd: +with or without topological guarantees. The domain can be created from an explicit grid, +an implicit grid or a volumetric image. diff --git a/Isosurfacing_3/test/Isosurfacing_3/Timer.h b/Isosurfacing_3/test/Isosurfacing_3/Timer.h index 6d5f87a6424..50dec258fe4 100644 --- a/Isosurfacing_3/test/Isosurfacing_3/Timer.h +++ b/Isosurfacing_3/test/Isosurfacing_3/Timer.h @@ -22,7 +22,7 @@ public: } ~ScopeTimer() { - if (running) { + if(running) { TimePoint end = Clock::now(); int64_t duration = std::chrono::duration_cast(end - start).count(); std::cout << msg << ": " << duration << " ms" << std::endl; @@ -35,4 +35,4 @@ private: bool running; }; -#endif // SCOPE_TIMER_H +#endif // SCOPE_TIMER_H diff --git a/Isosurfacing_3/test/Isosurfacing_3/test_dual_contouring.cpp b/Isosurfacing_3/test/Isosurfacing_3/test_dual_contouring.cpp index 0e1122c0d3f..50c6a4a31a9 100644 --- a/Isosurfacing_3/test/Isosurfacing_3/test_dual_contouring.cpp +++ b/Isosurfacing_3/test/Isosurfacing_3/test_dual_contouring.cpp @@ -1,3 +1,6 @@ +#include +#include + #include #include #include @@ -5,80 +8,83 @@ #include #include #include -#include -#include + #include #include #include "Timer.h" -typedef CGAL::Simple_cartesian Kernel; -typedef typename Kernel::Vector_3 Vector; -typedef typename Kernel::Point_3 Point; +using Kernel = CGAL::Simple_cartesian; +using Vector = typename Kernel::Vector_3; +using Point = typename Kernel::Point_3; -typedef CGAL::Surface_mesh Mesh; -typedef CGAL::Cartesian_grid_3 Grid; +using Mesh = CGAL::Surface_mesh; +using Grid CGAL::Cartesian_grid_3; -typedef std::vector Point_range; -typedef std::vector> Polygon_range; +using Point_range = std::vector; +using Polygon_range = std::vector >; -int main() { - const Vector spacing(0.002, 0.002, 0.02); - const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1}; +int main() +{ + const Vector spacing(0.002, 0.002, 0.02); + const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1}; - auto sphere_function = [](const Point& point) { - return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z()); - }; + auto sphere_function = [](const Point& point) + { + return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z()); + }; - typedef CGAL::Isosurfacing::Finite_difference_gradient Gradient; + using Gradient = CGAL::Isosurfacing::Finite_difference_gradient; - auto implicit_domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain( - bbox, spacing, sphere_function, Gradient(sphere_function, 0.0001)); + auto implicit_domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain( + bbox, spacing, sphere_function, Gradient(sphere_function, 0.0001)); - const std::size_t nx = static_cast(2.0 / spacing.x()); - const std::size_t ny = static_cast(2.0 / spacing.y()); - const std::size_t nz = static_cast(2.0 / spacing.z()); + const std::size_t nx = static_cast(2.0 / spacing.x()); + const std::size_t ny = static_cast(2.0 / spacing.y()); + const std::size_t nz = static_cast(2.0 / spacing.z()); - std::shared_ptr grid = std::make_shared(nx, ny, nz, bbox); + std::shared_ptr grid = std::make_shared(nx, ny, nz, bbox); - for (std::size_t x = 0; x < grid->xdim(); x++) { - for (std::size_t y = 0; y < grid->ydim(); y++) { - for (std::size_t z = 0; z < grid->zdim(); z++) { + for(std::size_t x=0; xxdim(); ++x) { + for(std::size_t y=0; yydim(); ++y) { + for(std::size_t z=0; zzdim(); ++z) + { + const Point pos(x * spacing.x() + bbox.xmin(), + y * spacing.y() + bbox.ymin(), + z * spacing.z() + bbox.zmin()); - const Point pos(x * spacing.x() + bbox.xmin(), y * spacing.y() + bbox.ymin(), - z * spacing.z() + bbox.zmin()); - - grid->value(x, y, z) = sphere_function(pos); - } - } + grid->value(x, y, z) = sphere_function(pos); + } } + } - const std::string fname = "../data/skull_2.9.inr"; - // Load image - // CGAL::Image_3 image; - // if (!image.read(fname)) { - // std::cerr << "Error: Cannot read file " << fname << std::endl; - // return EXIT_FAILURE; - //} - // Grid grid(image); + const std::string fname = "../data/skull_2.9.inr"; - auto grid_domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid); + // Load image + // CGAL::Image_3 image; + // if(!image.read(fname)) { + // std::cerr << "Error: Cannot read file " << fname << std::endl; + // return EXIT_FAILURE; + //} + // Grid grid(image); - Point_range points; - Polygon_range polygons; + auto grid_domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid); - { - ScopeTimer timer; - CGAL::Isosurfacing::dual_contouring(implicit_domain, 0.8f, points, polygons); - } + Point_range points; + Polygon_range polygons; - // TODO: compare results with mesh_3 + { + ScopeTimer timer; + CGAL::Isosurfacing::dual_contouring(implicit_domain, 0.8f, points, polygons); + } - // Mesh mesh; - // CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, mesh); + // @todo compare results with mesh_3 - // CGAL::IO::write_OFF("result.off", mesh); - CGAL::IO::write_OFF("result.off", points, polygons); + // Mesh mesh; + // CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, mesh); - return 0; + // CGAL::IO::write_OFF("result.off", mesh); + CGAL::IO::write_OFF("result.off", points, polygons); + + return 0; } diff --git a/Isosurfacing_3/test/Isosurfacing_3/test_marching_cubes.cpp b/Isosurfacing_3/test/Isosurfacing_3/test_marching_cubes.cpp index eb08a326b7b..e3067e6a0e8 100644 --- a/Isosurfacing_3/test/Isosurfacing_3/test_marching_cubes.cpp +++ b/Isosurfacing_3/test/Isosurfacing_3/test_marching_cubes.cpp @@ -5,92 +5,102 @@ #define WRITE_OFF -struct Sphere_function { - FT operator()(const Point& point) const { - return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z()); - } +struct Sphere_function +{ + FT operator()(const Point& point) const + { + return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z()); + } }; -template -void run(const Domain_& domain, const FT isovalue, Point_range& points, Polygon_range& polygons) { - CGAL::Isosurfacing::marching_cubes(domain, isovalue, points, polygons); +template +void run(const Domain_& domain, + const FT isovalue, + Point_range& points, + Polygon_range& polygons) +{ + CGAL::Isosurfacing::marching_cubes(domain, isovalue, points, polygons); } -void test_implicit_sphere() { - const std::string test_name = "test_implicit_sphere()"; +void test_implicit_sphere() +{ + const std::string test_name = "test_implicit_sphere()"; - const Vector spacing(0.2, 0.2, 0.2); - const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1}; + const Vector spacing(0.2, 0.2, 0.2); + const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1}; - auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain(bbox, spacing, Sphere_function()); + auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain(bbox, spacing, Sphere_function()); - Point_range points; - Polygon_range polygons; - run(domain, 0.8, points, polygons); + Point_range points; + Polygon_range polygons; + run(domain, 0.8, points, polygons); #ifdef WRITE_OFF - CGAL::IO::write_OFF(test_name + ".off", points, polygons); + CGAL::IO::write_OFF(test_name + ".off", points, polygons); #endif - assert(is_polygon_mesh(polygons)); - Mesh m = to_mesh(points, polygons); + assert(is_polygon_mesh(polygons)); + Mesh m = to_mesh(points, polygons); - assert(is_manifold(m)); - assert(!has_degenerate_faces(m)); + assert(is_manifold(m)); + assert(!has_degenerate_faces(m)); - std::cout << "Test passed: " << test_name << std::endl; + std::cout << "Test passed: " << test_name << std::endl; } -void test_grid_sphere(const std::size_t n) { - const std::string test_name = "test_grid_sphere(" + std::to_string(n) + ")"; +void test_grid_sphere(const std::size_t n) +{ + const std::string test_name = "test_grid_sphere(" + std::to_string(n) + ")"; - const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1}; - const Vector spacing(2.0 / (n - 1), 2.0 / (n - 1), 2.0 / (n - 1)); + const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1}; + const Vector spacing(2.0 / (n - 1), 2.0 / (n - 1), 2.0 / (n - 1)); - Sphere_function sphere_function; + Sphere_function sphere_function; - std::shared_ptr grid = std::make_shared(n, n, n, bbox); + std::shared_ptr grid = std::make_shared(n, n, n, bbox); - for (std::size_t x = 0; x < grid->xdim(); x++) { - for (std::size_t y = 0; y < grid->ydim(); y++) { - for (std::size_t z = 0; z < grid->zdim(); z++) { + for(std::size_t x=0; xxdim(); ++x) { + for(std::size_t y=0; yydim(); ++y) { + for(std::size_t z=0; zzdim(); ++z) + { + const Point pos(x * spacing.x() + bbox.xmin(), + y * spacing.y() + bbox.ymin(), + z * spacing.z() + bbox.zmin()); - const Point pos(x * spacing.x() + bbox.xmin(), y * spacing.y() + bbox.ymin(), - z * spacing.z() + bbox.zmin()); - - grid->value(x, y, z) = sphere_function(pos); - } - } + grid->value(x, y, z) = sphere_function(pos); + } } + } - auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid); + auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain(grid); - Point_range points; - Polygon_range polygons; - run(domain, 0.777, points, polygons); + Point_range points; + Polygon_range polygons; + run(domain, 0.777, points, polygons); #ifdef WRITE_OFF - CGAL::IO::write_OFF(test_name + ".off", points, polygons); + CGAL::IO::write_OFF(test_name + ".off", points, polygons); #endif - assert(is_polygon_mesh(polygons)); - Mesh m = to_mesh(points, polygons); + assert(is_polygon_mesh(polygons)); + Mesh m = to_mesh(points, polygons); - assert(is_manifold(m)); - assert(!has_degenerate_faces(m)); + assert(is_manifold(m)); + assert(!has_degenerate_faces(m)); - std::cout << "Test passed: " << test_name << std::endl; + std::cout << "Test passed: " << test_name << std::endl; } -int main() { - test_implicit_sphere(); - test_grid_sphere(2); - test_grid_sphere(3); - test_grid_sphere(10); - test_grid_sphere(11); - test_grid_sphere(100); +int main() +{ + test_implicit_sphere(); + test_grid_sphere(2); + test_grid_sphere(3); + test_grid_sphere(10); + test_grid_sphere(11); + test_grid_sphere(100); - std::cout << "All tests passed" << std::endl; + std::cout << "All tests passed" << std::endl; - return 0; + return 0; } diff --git a/Isosurfacing_3/test/Isosurfacing_3/test_util.h b/Isosurfacing_3/test/Isosurfacing_3/test_util.h index fe3cd320c84..737c7e62a8d 100644 --- a/Isosurfacing_3/test/Isosurfacing_3/test_util.h +++ b/Isosurfacing_3/test/Isosurfacing_3/test_util.h @@ -1,8 +1,10 @@ #ifndef CGAL_ISOSURFACING_TEST_UTIL_H #define CGAL_ISOSURFACING_TEST_UTIL_H -#include #include +#include + +#include #include #include #include @@ -10,60 +12,67 @@ #include #include #include -#include #include #include -typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; -typedef typename Kernel::FT FT; -typedef typename Kernel::Vector_3 Vector; -typedef typename Kernel::Point_3 Point; +using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; +using FT = typename Kernel::FT; +using Vector = typename Kernel::Vector_3; +using Point = typename Kernel::Point_3; -typedef CGAL::Surface_mesh Mesh; -typedef CGAL::Cartesian_grid_3 Grid; +using Mesh = CGAL::Surface_mesh; +using Grid = CGAL::Cartesian_grid_3; -typedef std::vector Point_range; -typedef std::vector> Polygon_range; +using Point_range = std::vector; +using Polygon_range = std::vector >; namespace PMP = CGAL::Polygon_mesh_processing; -bool has_duplicate_points(Point_range points, Polygon_range polygons) { - return PMP::merge_duplicate_points_in_polygon_soup(points, polygons) != 0; +bool has_duplicate_points(Point_range points, Polygon_range polygons) +{ + return PMP::merge_duplicate_points_in_polygon_soup(points, polygons) != 0; } -bool has_duplicate_polygons(Point_range points, Polygon_range polygons) { - return PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons) != 0; +bool has_duplicate_polygons(Point_range points, Polygon_range polygons) +{ + return PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons) != 0; } -bool has_isolated_vertices(Point_range points, Polygon_range polygons) { - return PMP::remove_isolated_points_in_polygon_soup(points, polygons) != 0; +bool has_isolated_vertices(Point_range points, Polygon_range polygons) +{ + return PMP::remove_isolated_points_in_polygon_soup(points, polygons) != 0; } -bool is_polygon_mesh(const Polygon_range& polygons) { - return PMP::is_polygon_soup_a_polygon_mesh(polygons); +bool is_polygon_mesh(const Polygon_range& polygons) +{ + return PMP::is_polygon_soup_a_polygon_mesh(polygons); } -Mesh to_mesh(const Point_range& points, const Polygon_range& polygons) { - Mesh m; - PMP::polygon_soup_to_polygon_mesh(points, polygons, m); - return m; +Mesh to_mesh(const Point_range& points, const Polygon_range& polygons) +{ + Mesh m; + PMP::polygon_soup_to_polygon_mesh(points, polygons, m); + return m; } -bool is_manifold(Mesh& m) { - return PMP::duplicate_non_manifold_vertices(m, CGAL::parameters::dry_run(true)) == 0; +bool is_manifold(Mesh& m) +{ + return PMP::duplicate_non_manifold_vertices(m, CGAL::parameters::dry_run(true)) == 0; } -bool has_degenerate_faces(Mesh& m) { - return PMP::remove_connected_components_of_negligible_size( - m, CGAL::parameters::dry_run(true).area_threshold(std::numeric_limits::epsilon())) != 0; +bool has_degenerate_faces(Mesh& m) +{ + return PMP::remove_connected_components_of_negligible_size( + m, CGAL::parameters::dry_run(true).area_threshold(std::numeric_limits::epsilon())) != 0; } -bool check_mesh_distance(const Mesh& m0, const Mesh& m1) { - auto dist = PMP::approximate_Hausdorff_distance( - m0, m1, CGAL::parameters::number_of_points_per_area_unit(4000)); - std::cout << dist << std::endl; - return true; +bool check_mesh_distance(const Mesh& m0, const Mesh& m1) +{ + auto dist = PMP::approximate_Hausdorff_distance( + m0, m1, CGAL::parameters::number_of_points_per_area_unit(4000)); + std::cout << dist << std::endl; + return true; } -#endif // CGAL_ISOSURFACING_TEST_UTIL_H +#endif // CGAL_ISOSURFACING_TEST_UTIL_H