4 --> 2 spaces indentation and "typedef" --> "using"

This commit is contained in:
Mael Rouxel-Labbé 2023-01-06 16:34:49 +01:00
parent c51bd444e1
commit 93a59fcd77
37 changed files with 4355 additions and 3799 deletions

View File

@ -1,5 +1,6 @@
/*! /*!
\ingroup PkgIsosurfacing3Concepts \ingroup PkgIsosurfacing3Concepts
\cgalConcept \cgalConcept
The concept `IsosurfacingDomain` describes the set of requirements to be The concept `IsosurfacingDomain` describes the set of requirements to be
@ -7,10 +8,9 @@ fulfilled by any class used as input data for any isosurfacing algorithms.
\cgalHasModel `CGAL::Isosurfacing::Explicit_cartesian_grid_domain` \cgalHasModel `CGAL::Isosurfacing::Explicit_cartesian_grid_domain`
\cgalHasModel `CGAL::Isosurfacing::Implicit_cartesian_grid_domain` \cgalHasModel `CGAL::Isosurfacing::Implicit_cartesian_grid_domain`
*/ */
class IsosurfacingDomain
class IsosurfacingDomain { {
public: public:
/// \name Types /// \name Types
/// @{ /// @{
@ -172,6 +172,5 @@ public:
template <typename Concurrency_tag, typename Functor> template <typename Concurrency_tag, typename Functor>
void iterate_cells(Functor& f) const; void iterate_cells(Functor& f) const;
/// @} /// @}
}; };

View File

@ -1,5 +1,6 @@
/*! /*!
\ingroup PkgIsosurfacing3Concepts \ingroup PkgIsosurfacing3Concepts
\cgalConcept \cgalConcept
The concept `IsosurfacingDomainWithGradient` describes the set of requirements to be The concept `IsosurfacingDomainWithGradient` describes the set of requirements to be
@ -7,10 +8,10 @@ fulfilled by any class used as input data for some isosurfacing algorithms.
\cgalHasModel `CGAL::Isosurfacing::Explicit_cartesian_grid_domain` \cgalHasModel `CGAL::Isosurfacing::Explicit_cartesian_grid_domain`
\cgalHasModel `CGAL::Isosurfacing::Implicit_cartesian_grid_domain` \cgalHasModel `CGAL::Isosurfacing::Implicit_cartesian_grid_domain`
*/ */
class IsosurfacingDomainWithGradient
class IsosurfacingDomainWithGradient : public IsosurfacingDomain { : public IsosurfacingDomain
{
public: public:
/// \name Types /// \name Types
/// @{ /// @{

View File

@ -1,35 +1,39 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Cartesian_grid_3.h> #include <CGAL/Cartesian_grid_3.h>
#include <CGAL/Dual_contouring_3.h> #include <CGAL/Dual_contouring_3.h>
#include <CGAL/Explicit_cartesian_grid_domain.h> #include <CGAL/Explicit_cartesian_grid_domain.h>
#include <CGAL/Marching_cubes_3.h> #include <CGAL/Marching_cubes_3.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/boost/graph/IO/OFF.h> #include <CGAL/boost/graph/IO/OFF.h>
typedef CGAL::Simple_cartesian<double> Kernel; using Kernel = CGAL::Simple_cartesian<double>;
typedef typename Kernel::FT FT; using FT = typename Kernel::FT;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef typename Kernel::Vector_3 Vector; using Vector = typename Kernel::Vector_3;
typedef CGAL::Cartesian_grid_3<Kernel> Grid; using Grid = CGAL::Cartesian_grid_3<Kernel>;
typedef std::vector<Point> Point_range; using Point_range = std::vector<Point>;
typedef std::vector<std::vector<std::size_t>> Polygon_range; using Polygon_range = std::vector<std::vector<std::size_t> >;
// return 1.0 if value has positive sign, and -1.0 otherwise // return 1.0 if value has positive sign, and -1.0 otherwise
FT sign(FT value) { FT sign(FT value)
{
return (value > 0.0) - (value < 0.0); return (value > 0.0) - (value < 0.0);
} }
int main() { int main()
{
// create a cartesian grid with 7^3 grid points and the bounding box [-1, 1]^3 // 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); const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
std::shared_ptr<Grid> grid = std::make_shared<Grid>(7, 7, 7, bbox); std::shared_ptr<Grid> grid = std::make_shared<Grid>(7, 7, 7, bbox);
// calculate the value at all grid points // calculate the value at all grid points
for (std::size_t x = 0; x < grid->xdim(); x++) { for(std::size_t x=0; x<grid->xdim(); ++x) {
for (std::size_t y = 0; y < grid->ydim(); y++) { for(std::size_t y=0; y<grid->ydim(); ++y) {
for (std::size_t z = 0; z < grid->zdim(); z++) { for(std::size_t z=0; z<grid->zdim(); ++z)
{
const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin(); 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_y = y * grid->get_spacing()[1] + bbox.ymin();
const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin(); const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin();
@ -41,24 +45,25 @@ int main() {
} }
// compute function gradient // compute function gradient
auto cube_gradient = [](const Point& p) { auto cube_gradient = [](const Point& p)
{
// the normal depends on the side of the cube // 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())}); 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); Vector g(0.0, 0.0, 0.0);
if (max_value == std::abs(p.x())) { if(max_value == std::abs(p.x()))
g += Vector(sign(p.x()), 0.0, 0.0); g += Vector(sign(p.x()), 0.0, 0.);
}
if (max_value == std::abs(p.y())) { if(max_value == std::abs(p.y()))
g += Vector(0.0, sign(p.y()), 0.0); g += Vector(0.0, sign(p.y()), 0.0);
}
if (max_value == std::abs(p.z())) { if(max_value == std::abs(p.z()))
g += Vector(0.0, 0.0, sign(p.z())); g += Vector(0.0, 0.0, sign(p.z()));
}
const FT length_sq = g.squared_length(); const FT length_sq = g.squared_length();
if (length_sq > 0.00001) { if(length_sq > 0.00001)
g /= CGAL::approximate_sqrt(length_sq); g /= CGAL::approximate_sqrt(length_sq);
}
return g; return g;
}; };

View File

@ -1,31 +1,33 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Cartesian_grid_3.h> #include <CGAL/Cartesian_grid_3.h>
#include <CGAL/Explicit_cartesian_grid_gradient.h> #include <CGAL/Explicit_cartesian_grid_gradient.h>
#include <CGAL/Dual_contouring_3.h> #include <CGAL/Dual_contouring_3.h>
#include <CGAL/Explicit_cartesian_grid_domain.h> #include <CGAL/Explicit_cartesian_grid_domain.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/boost/graph/IO/OFF.h> #include <CGAL/boost/graph/IO/OFF.h>
typedef CGAL::Simple_cartesian<double> Kernel; using Kernel = CGAL::Simple_cartesian<double>;
typedef typename Kernel::FT FT; using FT = typename Kernel::FT;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef typename Kernel::Vector_3 Vector; using Vector = typename Kernel::Vector_3;
typedef CGAL::Cartesian_grid_3<Kernel> Grid; using Grid = CGAL::Cartesian_grid_3<Kernel>;
typedef std::vector<Point> Point_range; using Point_range = std::vector<Point>;
typedef std::vector<std::vector<std::size_t>> Polygon_range; using Polygon_range = std::vector<std::vector<std::size_t> >;
int main() {
int main()
{
// create bounding box and grid // create bounding box and grid
const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0); const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
std::shared_ptr<Grid> grid = std::make_shared<Grid>(30, 30, 30, bbox); std::shared_ptr<Grid> grid = std::make_shared<Grid>(30, 30, 30, bbox);
// compute field values and gradients // compute field values and gradients
for (std::size_t x = 0; x < grid->xdim(); x++) { for(std::size_t x=0; x<grid->xdim(); ++x) {
for (std::size_t y = 0; y < grid->ydim(); y++) { for(std::size_t y=0; y<grid->ydim(); ++y) {
for (std::size_t z = 0; z < grid->zdim(); z++) { for(std::size_t z=0; z<grid->zdim(); ++z)
{
const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin(); 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_y = y * grid->get_spacing()[1] + bbox.ymin();
const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin(); const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin();
@ -34,7 +36,7 @@ int main() {
const FT distance = CGAL::approximate_sqrt(direction.squared_length()); const FT distance = CGAL::approximate_sqrt(direction.squared_length());
grid->value(x, y, z) = distance; grid->value(x, y, z) = distance;
grid->gradient(x, y, z) = direction / distance; // TODO: check division / 0 grid->gradient(x, y, z) = direction / distance; // @todo check division / 0
} }
} }
} }

View File

@ -1,29 +1,33 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Bbox_3.h> #include <CGAL/Bbox_3.h>
#include <CGAL/Dual_contouring_3.h> #include <CGAL/Dual_contouring_3.h>
#include <CGAL/Implicit_cartesian_grid_domain.h> #include <CGAL/Implicit_cartesian_grid_domain.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/boost/graph/IO/OFF.h> #include <CGAL/boost/graph/IO/OFF.h>
typedef CGAL::Simple_cartesian<double> Kernel; using Kernel = CGAL::Simple_cartesian<double>;
typedef typename Kernel::FT FT; using FT = typename Kernel::FT;
typedef typename Kernel::Vector_3 Vector; using Vector = typename Kernel::Vector_3;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef std::vector<Point> Point_range; using Point_range = std::vector<Point>;
typedef std::vector<std::vector<std::size_t>> Polygon_range; using Polygon_range = std::vector<std::vector<std::size_t> >;
int main()
int main() { {
const FT alpha = 5.01; const FT alpha = 5.01;
auto iwp_value = [alpha](const Point& point) { auto iwp_value = [alpha](const Point& point)
{
const FT x = alpha * (point.x() + 1) * CGAL_PI; const FT x = alpha * (point.x() + 1) * CGAL_PI;
const FT y = alpha * (point.y() + 1) * CGAL_PI; const FT y = alpha * (point.y() + 1) * CGAL_PI;
const FT z = alpha * (point.z() + 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 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) { auto iwp_gradient = [alpha](const Point& point)
{
const FT x = alpha * (point.x() + 1) * CGAL_PI; const FT x = alpha * (point.x() + 1) * CGAL_PI;
const FT y = alpha * (point.y() + 1) * CGAL_PI; const FT y = alpha * (point.y() + 1) * CGAL_PI;
const FT z = alpha * (point.z() + 1) * CGAL_PI; const FT z = alpha * (point.z() + 1) * CGAL_PI;
@ -39,8 +43,7 @@ int main() {
const Vector vec_spacing(spacing, spacing, spacing); const Vector vec_spacing(spacing, spacing, spacing);
// create a domain with given bounding box and grid spacing // create a domain with given bounding box and grid spacing
auto domain = auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, vec_spacing, iwp_value, iwp_gradient);
CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, vec_spacing, iwp_value, iwp_gradient);
// prepare collections for the result // prepare collections for the result
Point_range points; Point_range points;

View File

@ -1,37 +1,42 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Dual_contouring_3.h>
#include <CGAL/Implicit_cartesian_grid_domain.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h> #include <CGAL/AABB_face_graph_triangle_primitive.h>
#include <CGAL/AABB_traits.h> #include <CGAL/AABB_traits.h>
#include <CGAL/AABB_tree.h> #include <CGAL/AABB_tree.h>
#include <CGAL/Bbox_3.h> #include <CGAL/Bbox_3.h>
#include <CGAL/Dual_contouring_3.h>
#include <CGAL/Implicit_cartesian_grid_domain.h>
#include <CGAL/Side_of_triangle_mesh.h> #include <CGAL/Side_of_triangle_mesh.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/IO/OFF.h> #include <CGAL/boost/graph/IO/OFF.h>
#include <iostream> #include <iostream>
typedef CGAL::Simple_cartesian<double> Kernel; using Kernel = CGAL::Simple_cartesian<double>;
typedef typename Kernel::FT FT; using FT = typename Kernel::FT;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef typename Kernel::Vector_3 Vector; using Vector = typename Kernel::Vector_3;
typedef CGAL::Surface_mesh<Point> Mesh; using Mesh = CGAL::Surface_mesh<Point>;
typedef CGAL::AABB_face_graph_triangle_primitive<Mesh> Primitive; using Primitive = CGAL::AABB_face_graph_triangle_primitive<Mesh>;
typedef CGAL::AABB_traits<Kernel, Primitive> Traits; using Traits = CGAL::AABB_traits<Kernel, Primitive>;
typedef CGAL::AABB_tree<Traits> Tree; using Tree = CGAL::AABB_tree<Traits>;
typedef std::vector<Point> Point_range; using Point_range = std::vector<Point>;
typedef std::vector<std::vector<std::size_t> > Polygon_range; using Polygon_range = std::vector<std::vector<std::size_t> >;
int main() { int main()
{
const std::string input_name = CGAL::data_file_path("meshes/cross.off"); const std::string input_name = CGAL::data_file_path("meshes/cross.off");
const Vector grid_spacing(0.1, 0.1, 0.1); const Vector grid_spacing(0.1, 0.1, 0.1);
const FT offset_value = 0.2; const FT offset_value = 0.2;
Mesh mesh_input; Mesh mesh_input;
if (!CGAL::IO::read_OFF(input_name, mesh_input)) { if(!CGAL::IO::read_OFF(input_name, mesh_input))
{
std::cerr << "Could not read input mesh" << std::endl; std::cerr << "Could not read input mesh" << std::endl;
exit(-1); exit(-1);
} }
@ -48,14 +53,16 @@ int main() {
CGAL::Side_of_triangle_mesh<Mesh, CGAL::GetGeomTraits<Mesh>::type> sotm(mesh_input); CGAL::Side_of_triangle_mesh<Mesh, CGAL::GetGeomTraits<Mesh>::type> sotm(mesh_input);
// functors for addressing distance and normal queries // functors for addressing distance and normal queries
auto mesh_distance = [&tree](const Point& p) { auto mesh_distance = [&tree](const Point& p)
{
const Point& x = tree.closest_point(p); const Point& x = tree.closest_point(p);
return std::sqrt((p - x).squared_length()); return std::sqrt((p - x).squared_length());
}; };
auto mesh_normal = [&tree](const Point& p) { auto mesh_normal = [&tree](const Point& p)
{
const Point& x = tree.closest_point(p); const Point& x = tree.closest_point(p);
const Vector n = p - x; // TODO: address case where norm = zero const Vector n = p - x; // @todo address case where norm = zero
return n / std::sqrt(n.squared_length()); // normalize output vector return n / std::sqrt(n.squared_length()); // normalize output vector
}; };

View File

@ -1,76 +1,88 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Dual_contouring_3.h> #include <CGAL/Dual_contouring_3.h>
#include <CGAL/Implicit_octree_domain.h> #include <CGAL/Implicit_octree_domain.h>
#include <CGAL/Octree_wrapper.h> #include <CGAL/Octree_wrapper.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/boost/graph/IO/OFF.h> #include <CGAL/boost/graph/IO/OFF.h>
#include <math.h>
#include <iostream> #include <iostream>
#include <math.h>
typedef CGAL::Simple_cartesian<double> Kernel; using Kernel = CGAL::Simple_cartesian<double>;
typedef typename Kernel::FT FT; using FT = typename Kernel::FT;
typedef typename Kernel::Vector_3 Vector; using Vector = typename Kernel::Vector_3;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef std::vector<Point> Point_range; using Point_range = std::vector<Point>;
typedef std::vector<std::vector<std::size_t>> Polygon_range; using Polygon_range = std::vector<std::vector<std::size_t> >;
typedef CGAL::Isosurfacing::Octree_wrapper<Kernel> Octree_wrapper_; using Octree_wrapper_ = CGAL::Isosurfacing::Octree_wrapper<Kernel>;
struct Refine_one_eighth { struct Refine_one_eighth
{
std::size_t min_depth_; std::size_t min_depth_;
std::size_t max_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 { Octree_wrapper_::Uniform_coords uniform_coordinates(const Octree_wrapper_::Octree::Node& node) const
{
auto coords = node.global_coordinates(); auto coords = node.global_coordinates();
const std::size_t depth_factor = std::size_t(1) << (max_depth_ - node.depth()); 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) { for(int i=0; i < Octree_wrapper_::Octree::Node::Dimension::value; ++i)
coords[i] *= (uint32_t)depth_factor; 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) { 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_; octree_dim_ = std::size_t(1) << max_depth_;
} }
bool operator()(const Octree_wrapper_::Octree::Node& n) const { bool operator()(const Octree_wrapper_::Octree::Node& n) const
{
// n.depth() // n.depth()
if (n.depth() < min_depth_) { if(n.depth() < min_depth_)
return true; return true;
}
if (n.depth() == max_depth_) { if(n.depth() == max_depth_)
return false; return false;
}
auto leaf_coords = uniform_coordinates(n); auto leaf_coords = uniform_coordinates(n);
if (leaf_coords[0] >= octree_dim_ / 2) { if(leaf_coords[0] >= octree_dim_ / 2)
return false; return false;
}
if (leaf_coords[1] >= octree_dim_ / 2) { if(leaf_coords[1] >= octree_dim_ / 2)
return false; return false;
}
if (leaf_coords[2] >= octree_dim_ / 2) { // if(leaf_coords[2] >= octree_dim_ / 2)
// return false; // return false;
}
return true; return true;
} }
}; };
int main() { int main()
const CGAL::Bbox_3 bbox(-1, -1, -1, 1, 1, 1); {
const CGAL::Bbox_3 bbox(-1., -1., -1., 1., 1., 1.);
std::shared_ptr<Octree_wrapper_> octree_wrap = std::make_shared<Octree_wrapper_>(bbox); std::shared_ptr<Octree_wrapper_> octree_wrap = std::make_shared<Octree_wrapper_>(bbox);
Refine_one_eighth split_predicate(3, 4); Refine_one_eighth split_predicate(3, 4);
octree_wrap->refine(split_predicate); 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) { auto sphere_gradient = [&](const Point& p)
{
const Vector g = p - CGAL::ORIGIN; const Vector g = p - CGAL::ORIGIN;
return g / std::sqrt(g.squared_length()); return g / std::sqrt(g.squared_length());
}; };

View File

@ -5,25 +5,26 @@
#include <CGAL/Simple_cartesian.h> #include <CGAL/Simple_cartesian.h>
#include <CGAL/boost/graph/IO/OFF.h> #include <CGAL/boost/graph/IO/OFF.h>
typedef CGAL::Simple_cartesian<double> Kernel; using Kernel = CGAL::Simple_cartesian<double>;
typedef typename Kernel::FT FT; using FT = typename Kernel::FT;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef CGAL::Cartesian_grid_3<Kernel> Grid; using Grid = CGAL::Cartesian_grid_3<Kernel>;
typedef std::vector<Point> Point_range; using Point_range = std::vector<Point>;
typedef std::vector<std::vector<std::size_t>> Polygon_range; using Polygon_range = std::vector<std::vector<std::size_t> >;
int main() { int main()
{
// create a cartesian grid with 100^3 grid points and the bounding box [-1, 1]^3 // 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); const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
std::shared_ptr<Grid> grid = std::make_shared<Grid>(50, 50, 50, bbox); std::shared_ptr<Grid> grid = std::make_shared<Grid>(50, 50, 50, bbox);
// compute and store function values at all grid points // compute and store function values at all grid points
for (std::size_t x = 0; x < grid->xdim(); x++) { for(std::size_t x=0; x<grid->xdim(); ++x) {
for (std::size_t y = 0; y < grid->ydim(); y++) { for(std::size_t y=0; y<grid->ydim(); ++y) {
for (std::size_t z = 0; z < grid->zdim(); z++) { for(std::size_t z=0; z<grid->zdim(); ++z)
{
const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin(); 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_y = y * grid->get_spacing()[1] + bbox.ymin();
const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin(); const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin();

View File

@ -1,24 +1,30 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Bbox_3.h> #include <CGAL/Bbox_3.h>
#include <CGAL/Implicit_cartesian_grid_domain.h> #include <CGAL/Implicit_cartesian_grid_domain.h>
#include <CGAL/Marching_cubes_3.h> #include <CGAL/Marching_cubes_3.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/boost/graph/IO/OFF.h> #include <CGAL/boost/graph/IO/OFF.h>
typedef CGAL::Simple_cartesian<double> Kernel; using Kernel = CGAL::Simple_cartesian<double>;
typedef typename Kernel::FT FT; using FT = typename Kernel::FT;
typedef typename Kernel::Vector_3 Vector; using Vector = typename Kernel::Vector_3;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef std::vector<Point> Point_range; using Point_range = std::vector<Point>;
typedef std::vector<std::vector<std::size_t> > Polygon_range; using Polygon_range = std::vector<std::vector<std::size_t> >;
int main() { int main()
const CGAL::Bbox_3 bbox{-1.0, -1.0, -1.0, 1.0, 1.0, 1.0}; {
const CGAL::Bbox_3 bbox { -1.0, -1.0, -1.0, 1.0, 1.0, 1.0 };
const FT spacing = 0.04; const FT spacing = 0.04;
const Vector vec_spacing(spacing, spacing, spacing); const Vector vec_spacing(spacing, spacing, spacing);
// Euclidean distance function to the origin // 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()); }; 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 // create a domain with given bounding box and grid spacing
auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, vec_spacing, sphere_function); auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, vec_spacing, sphere_function);

View File

@ -1,23 +1,26 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Cartesian_grid_3.h> #include <CGAL/Cartesian_grid_3.h>
#include <CGAL/Explicit_cartesian_grid_domain.h> #include <CGAL/Explicit_cartesian_grid_domain.h>
#include <CGAL/Marching_cubes_3.h> #include <CGAL/Marching_cubes_3.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/boost/graph/IO/OFF.h> #include <CGAL/boost/graph/IO/OFF.h>
typedef CGAL::Simple_cartesian<double> Kernel; using Kernel = CGAL::Simple_cartesian<double>;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef CGAL::Cartesian_grid_3<Kernel> Grid; using Grid = CGAL::Cartesian_grid_3<Kernel>;
typedef std::vector<Point> Point_range; using Point_range = std::vector<Point>;
typedef std::vector<std::vector<std::size_t>> Polygon_range; using Polygon_range = std::vector<std::vector<std::size_t> >;
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 // load volumetric image from a file
CGAL::Image_3 image; CGAL::Image_3 image;
if (!image.read(fname)) { if(!image.read(fname))
{
std::cerr << "Error: Cannot read image file " << fname << std::endl; std::cerr << "Error: Cannot read image file " << fname << std::endl;
return EXIT_FAILURE; return EXIT_FAILURE;
} }

View File

@ -1,3 +1,6 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/AABB_face_graph_triangle_primitive.h> #include <CGAL/AABB_face_graph_triangle_primitive.h>
#include <CGAL/AABB_traits.h> #include <CGAL/AABB_traits.h>
#include <CGAL/AABB_tree.h> #include <CGAL/AABB_tree.h>
@ -5,44 +8,46 @@
#include <CGAL/Explicit_cartesian_grid_domain.h> #include <CGAL/Explicit_cartesian_grid_domain.h>
#include <CGAL/Marching_cubes_3.h> #include <CGAL/Marching_cubes_3.h>
#include <CGAL/Side_of_triangle_mesh.h> #include <CGAL/Side_of_triangle_mesh.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/IO/OFF.h> #include <CGAL/boost/graph/IO/OFF.h>
#include <iostream> #include <iostream>
typedef CGAL::Simple_cartesian<double> Kernel; using Kernel = CGAL::Simple_cartesian<double>;
typedef typename Kernel::FT FT; using FT = typename Kernel::FT;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef typename Kernel::Vector_3 Vector; using Vector = typename Kernel::Vector_3;
typedef CGAL::Cartesian_grid_3<Kernel> Grid; using Grid = CGAL::Cartesian_grid_3<Kernel>;
typedef CGAL::Surface_mesh<Point> Mesh; using Mesh = CGAL::Surface_mesh<Point>;
typedef CGAL::AABB_face_graph_triangle_primitive<Mesh> Primitive; using Primitive = CGAL::AABB_face_graph_triangle_primitive<Mesh>;
typedef CGAL::AABB_traits<Kernel, Primitive> Traits; using Traits = CGAL::AABB_traits<Kernel, Primitive>;
typedef CGAL::AABB_tree<Traits> Tree; using Tree = CGAL::AABB_tree<Traits>;
typedef std::vector<Point> Point_range;
typedef std::vector<std::vector<std::size_t>> Polygon_range;
using Point_range = std::vector<Point>;
using Polygon_range = std::vector<std::vector<std::size_t> >;
// computes the Euclidean distance from query point p to the mesh // computes the Euclidean distance from query point p to the mesh
// via the AABB tree data structure // via the AABB tree data structure
inline Kernel::FT distance_to_mesh(const Tree& tree, const Point& p) { inline Kernel::FT distance_to_mesh(const Tree& tree,
const Point& p)
{
const Point& x = tree.closest_point(p); const Point& x = tree.closest_point(p);
return std::sqrt((p - x).squared_length()); return std::sqrt((p - x).squared_length());
} }
int main() { int main()
{
const std::string input_name = CGAL::data_file_path("meshes/cross.off"); const std::string input_name = CGAL::data_file_path("meshes/cross.off");
const int n_voxels = 20; const int n_voxels = 20;
const FT offset_value = 0.2; const FT offset_value = 0.2;
// load input mesh // load input mesh
Mesh mesh_input; Mesh mesh_input;
if (!CGAL::IO::read_OFF(input_name, mesh_input)) { if(!CGAL::IO::read_OFF(input_name, mesh_input))
{
std::cerr << "Could not read input mesh" << std::endl; std::cerr << "Could not read input mesh" << std::endl;
exit(-1); exit(-1);
} }
@ -61,10 +66,10 @@ int main() {
// create grid // create grid
std::shared_ptr<Grid> grid = std::make_shared<Grid>(n_voxels, n_voxels, n_voxels, aabb_grid); std::shared_ptr<Grid> grid = std::make_shared<Grid>(n_voxels, n_voxels, n_voxels, aabb_grid);
for (std::size_t z = 0; z < grid->zdim(); z++) { for(std::size_t z=0; z<grid->zdim(); ++z) {
for (std::size_t y = 0; y < grid->ydim(); y++) { for(std::size_t y=0; y<grid->ydim(); ++y) {
for (std::size_t x = 0; x < grid->xdim(); x++) { for(std::size_t x=0; x<grid->xdim(); ++x)
{
const FT pos_x = x * grid->get_spacing()[0] + grid->get_bbox().xmin(); 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_y = y * grid->get_spacing()[1] + grid->get_bbox().ymin();
const FT pos_z = z * grid->get_spacing()[2] + grid->get_bbox().zmin(); const FT pos_z = z * grid->get_spacing()[2] + grid->get_bbox().zmin();
@ -75,12 +80,11 @@ int main() {
// sign distance so that it is negative inside the mesh // sign distance so that it is negative inside the mesh
const bool is_inside = (sotm(p) == CGAL::ON_BOUNDED_SIDE); const bool is_inside = (sotm(p) == CGAL::ON_BOUNDED_SIDE);
if (is_inside) { if(is_inside)
grid->value(x, y, z) *= -1.0; grid->value(x, y, z) *= -1.0;
} }
} }
} }
}
// create domain from the grid // create domain from the grid
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid); auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);

View File

@ -31,14 +31,15 @@ namespace CGAL {
* *
* \tparam GeomTraits the traits type * \tparam GeomTraits the traits type
*/ */
template <class GeomTraits> template <typename GeomTraits>
class Cartesian_grid_3 { class Cartesian_grid_3
{
public: public:
typedef GeomTraits Geom_traits; using Geom_traits = GeomTraits;
typedef typename Geom_traits::FT FT; using FT = typename Geom_traits::FT;
typedef typename Geom_traits::Vector_3 Vector; using Vector = typename Geom_traits::Vector_3;
typedef Isosurfacing::internal::Grid_topology::Vertex_descriptor VertexDescriptor; using VertexDescriptor = Isosurfacing::internal::Grid_topology::Vertex_descriptor;
public: public:
/** /**
@ -52,9 +53,13 @@ public:
* \param zdim the number of grid points in z direction * \param zdim the number of grid points in z direction
* \param bbox the bounding box * \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) Cartesian_grid_3(const std::size_t xdim,
: sizes{xdim, ydim, zdim}, bbox(bbox) { const std::size_t ydim,
const std::size_t zdim,
const Bbox_3& bbox)
: sizes{xdim, ydim, zdim},
bbox(bbox)
{
// pre-allocate memory // pre-allocate memory
values.resize(xdim * ydim * zdim); values.resize(xdim * ydim * zdim);
gradients.resize(xdim * ydim * zdim); gradients.resize(xdim * ydim * zdim);
@ -75,7 +80,8 @@ public:
* *
* \param image the image providing the data * \param image the image providing the data
*/ */
Cartesian_grid_3(const Image_3& image) { Cartesian_grid_3(const Image_3& image)
{
from_image(image); from_image(image);
} }
@ -88,7 +94,8 @@ public:
* *
* \return the stored value * \return the stored value
*/ */
FT operator()(const VertexDescriptor& v) const { FT operator()(const VertexDescriptor& v) const
{
return values[linear_index(v[0], v[1], v[2])]; return values[linear_index(v[0], v[1], v[2])];
} }
@ -103,7 +110,10 @@ public:
* *
* \return the stored value * \return the stored value
*/ */
FT value(const std::size_t x, const std::size_t y, const std::size_t z) const { 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)]; return values[linear_index(x, y, z)];
} }
@ -119,15 +129,24 @@ public:
* *
* \return a reference to the stored value * \return a reference to the stored value
*/ */
FT& value(const std::size_t x, const std::size_t y, const std::size_t z) { FT& value(const std::size_t x,
const std::size_t y,
const std::size_t z)
{
return values[linear_index(x, y, 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 { 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)]; return gradients[linear_index(x, y, z)];
} }
Vector& gradient(const std::size_t x, const std::size_t y, const std::size_t 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)]; return gradients[linear_index(x, y, z)];
} }
@ -136,7 +155,8 @@ public:
* *
* \return the number of grid points in x direction * \return the number of grid points in x direction
*/ */
std::size_t xdim() const { std::size_t xdim() const
{
return sizes[0]; return sizes[0];
} }
@ -145,7 +165,8 @@ public:
* *
* \return the number of grid points in y direction * \return the number of grid points in y direction
*/ */
std::size_t ydim() const { std::size_t ydim() const
{
return sizes[1]; return sizes[1];
} }
@ -154,20 +175,26 @@ public:
* *
* \return the number of grid points in z direction * \return the number of grid points in z direction
*/ */
std::size_t zdim() const { std::size_t zdim() const
{
return sizes[2]; return sizes[2];
} }
const Bbox_3& get_bbox() const { const Bbox_3& get_bbox() const
{
return bbox; return bbox;
} }
const Vector& get_spacing() const { const Vector& get_spacing() const
{
return spacing; return spacing;
} }
private: private:
std::size_t linear_index(const std::size_t x, const std::size_t y, const std::size_t z) const { 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 // convert x, y, z into a linear index to access the vector
return (z * ydim() + y) * xdim() + x; return (z * ydim() + y) * xdim() + x;
} }
@ -186,7 +213,10 @@ private:
}; };
template <typename GeomTraits> template <typename GeomTraits>
void Cartesian_grid_3<GeomTraits>::from_image(const Image_3& image) { void
Cartesian_grid_3<GeomTraits>::
from_image(const Image_3& image)
{
// compute bounding box // compute bounding box
const FT max_x = image.tx() + (image.xdim() - 1) * image.vx(); 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_y = image.ty() + (image.ydim() - 1) * image.vy();
@ -206,28 +236,27 @@ void Cartesian_grid_3<GeomTraits>::from_image(const Image_3& image) {
gradients.resize(xdim() * ydim() * zdim()); gradients.resize(xdim() * ydim() * zdim());
// copy values // copy values
for (std::size_t x = 0; x < sizes[0]; x++) { for(std::size_t x=0; x<sizes[0]; ++x)
for (std::size_t y = 0; y < sizes[1]; y++) { for(std::size_t y=0; y<sizes[1]; ++y)
for (std::size_t z = 0; z < sizes[2]; z++) { for(std::size_t z=0; z<sizes[2]; ++z)
value(x, y, z) = image.value(x, y, z); value(x, y, z) = image.value(x, y, z);
}
}
}
} }
template <typename GeomTraits> template <typename GeomTraits>
Image_3 Cartesian_grid_3<GeomTraits>::to_image() const { Image_3
Cartesian_grid_3<GeomTraits>::
to_image() const
{
// select the number type // select the number type
WORD_KIND wordkind; WORD_KIND wordkind;
if (std::is_floating_point<FT>::value) if(std::is_floating_point<FT>::value)
wordkind = WK_FLOAT; wordkind = WK_FLOAT;
else else
wordkind = WK_FIXED; wordkind = WK_FIXED;
// select signed or unsigned // select signed or unsigned
SIGN sign; SIGN sign;
if (std::is_signed<FT>::value) if(std::is_signed<FT>::value)
sign = SGN_SIGNED; sign = SGN_SIGNED;
else else
sign = SGN_UNSIGNED; sign = SGN_UNSIGNED;
@ -246,9 +275,8 @@ Image_3 Cartesian_grid_3<GeomTraits>::to_image() const {
sign); // image word sign sign); // image word sign
// error handling // error handling
if (im == nullptr || im->data == nullptr) { if(im == nullptr || im->data == nullptr)
throw std::bad_alloc(); // TODO: idk? throw std::bad_alloc(); // @todo idk?
}
// set min coordinates // set min coordinates
im->tx = bbox.xmin(); im->tx = bbox.xmin();
@ -257,18 +285,14 @@ Image_3 Cartesian_grid_3<GeomTraits>::to_image() const {
// copy data // copy data
FT* data = (FT*)im->data; FT* data = (FT*)im->data;
for (std::size_t x = 0; x < xdim(); x++) { for(std::size_t x=0; x<xdim(); ++x)
for (std::size_t y = 0; y < ydim(); y++) { for(std::size_t y=0; y<ydim(); ++y)
for (std::size_t z = 0; z < zdim(); z++) { for(std::size_t z=0; z<zdim(); ++z)
data[(z * ydim() + y) * xdim() + x] = value(x, y, z); data[(z * ydim() + y) * xdim() + x] = value(x, y, z);
}
}
}
return Image_3(im, Image_3::OWN_THE_DATA); return Image_3(im, Image_3::OWN_THE_DATA);
} }
} // end namespace CGAL } // namespace CGAL
#endif // CGAL_CARTESIAN_GRID_3_H #endif // CGAL_CARTESIAN_GRID_3_H

View File

@ -48,11 +48,17 @@ namespace Isosurfacing {
* \param polygons each element in the vector describes a polygon using the indices of the points in `points` * \param polygons each element in the vector describes a polygon using the indices of the points in `points`
* \param positioning the functor dealing with vertex positioning inside a cell * \param positioning the functor dealing with vertex positioning inside a cell
*/ */
template <typename Concurrency_tag = Sequential_tag, class Domain_, class PointRange, class PolygonRange, template <typename Concurrency_tag = Sequential_tag,
class Positioning = internal::Positioning::QEM_SVD<true>> typename Domain_,
void dual_contouring(const Domain_& domain, const typename Domain_::FT isovalue, PointRange& points, typename PointRange,
PolygonRange& polygons, const Positioning& positioning = Positioning()) { typename PolygonRange,
typename Positioning = internal::Positioning::QEM_SVD<true> >
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 // create vertices in each relevant cell
internal::Dual_contouring_vertex_positioning<Domain_, Positioning> pos_func(domain, isovalue, positioning); internal::Dual_contouring_vertex_positioning<Domain_, Positioning> pos_func(domain, isovalue, positioning);
domain.template iterate_cells<Concurrency_tag>(pos_func); domain.template iterate_cells<Concurrency_tag>(pos_func);
@ -63,25 +69,25 @@ void dual_contouring(const Domain_& domain, const typename Domain_::FT isovalue,
// copy vertices to point range // copy vertices to point range
points.resize(pos_func.points_counter); points.resize(pos_func.points_counter);
for (const auto& vtop : pos_func.map_voxel_to_point) { for(const auto& vtop : pos_func.map_voxel_to_point)
points[pos_func.map_voxel_to_point_id[vtop.first]] = vtop.second; points[pos_func.map_voxel_to_point_id[vtop.first]] = vtop.second;
}
// copy faces to polygon range // copy faces to polygon range
polygons.reserve(face_generation.faces.size()); polygons.reserve(face_generation.faces.size());
for (const auto& q : face_generation.faces) { for(const auto& q : face_generation.faces)
{
std::vector<std::size_t> vertex_ids; std::vector<std::size_t> vertex_ids;
for (const auto& v_id : q.second) { for(const auto& v_id : q.second)
{
// ignore voxels that are outside the valid region and are not stored in the map // 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) { 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]); vertex_ids.push_back(pos_func.map_voxel_to_point_id[v_id]);
} }
}
// ignore degenerated faces // ignore degenerated faces
if (vertex_ids.size() > 2) { if(vertex_ids.size() > 2)
polygons.push_back(vertex_ids); polygons.push_back(vertex_ids);
} }
}
} }
} // namespace Isosurfacing } // namespace Isosurfacing

View File

@ -30,13 +30,17 @@ namespace Isosurfacing {
* `IsosurfacingDomainWithGradient`. * `IsosurfacingDomainWithGradient`.
* *
* \tparam GeomTraits the traits type * \tparam GeomTraits the traits type
* \tparam Gradient_ the type of the gradient functor. It must implement `GeomTraits::Vector operator()(const * \tparam Gradient_ the type of the gradient functor. It must implement
* GeomTraits::Point& point) const`. * `GeomTraits::Vector operator()(const GeomTraits::Point& point) const`.
*/ */
template <class GeomTraits, typename Gradient_> template <typename GeomTraits,
typename Gradient_>
using Explicit_cartesian_grid_domain = using Explicit_cartesian_grid_domain =
internal::Base_domain<GeomTraits, internal::Grid_topology, internal::Cartesian_grid_geometry<GeomTraits>, internal::Base_domain<GeomTraits,
Cartesian_grid_3<GeomTraits>, Gradient_>; internal::Grid_topology,
internal::Cartesian_grid_geometry<GeomTraits>,
Cartesian_grid_3<GeomTraits>,
Gradient_>;
/** /**
* \ingroup PkgIsosurfacing3Ref * \ingroup PkgIsosurfacing3Ref
@ -52,15 +56,18 @@ using Explicit_cartesian_grid_domain =
* *
* \return a new `Explicit_cartesian_grid_domain` * \return a new `Explicit_cartesian_grid_domain`
*/ */
template <class GeomTraits, typename Gradient_ = Zero_gradient<GeomTraits>> template <typename GeomTraits,
Explicit_cartesian_grid_domain<GeomTraits, Gradient_> create_explicit_cartesian_grid_domain( typename Gradient_ = Zero_gradient<GeomTraits> >
const std::shared_ptr<Cartesian_grid_3<GeomTraits>> grid, const Gradient_& gradient = Gradient_()) { Explicit_cartesian_grid_domain<GeomTraits, Gradient_>
create_explicit_cartesian_grid_domain(const std::shared_ptr<Cartesian_grid_3<GeomTraits> > grid,
const Gradient_& gradient = Gradient_())
{
using Domain = Explicit_cartesian_grid_domain<GeomTraits, Gradient_>;
typedef Explicit_cartesian_grid_domain<GeomTraits, Gradient_> Domain; using Topology = typename Domain::Topology ;
typedef typename Domain::Topology Topology; using Geometry = typename Domain::Geometry;
typedef typename Domain::Geometry Geometry; using Function = typename Domain::Function;
typedef typename Domain::Function Function; using Gradient = typename Domain::Gradient;
typedef typename Domain::Gradient Gradient;
const std::size_t size_i = grid->xdim(); const std::size_t size_i = grid->xdim();
const std::size_t size_j = grid->ydim(); const std::size_t size_j = grid->ydim();

View File

@ -29,15 +29,16 @@ namespace Isosurfacing {
* *
* \tparam GeomTraits the traits for this gradient. * \tparam GeomTraits the traits for this gradient.
*/ */
template <class GeomTraits> template <typename GeomTraits>
class Explicit_cartesian_grid_gradient { class Explicit_cartesian_grid_gradient
{
public: public:
typedef GeomTraits Geom_traits; using Geom_traits = GeomTraits;
typedef typename Geom_traits::FT FT; using FT = typename Geom_traits::FT;
typedef typename Geom_traits::Point_3 Point; using Point = typename Geom_traits::Point_3;
typedef typename Geom_traits::Vector_3 Vector; using Vector = typename Geom_traits::Vector_3;
typedef std::shared_ptr<Cartesian_grid_3<Geom_traits>> Grid; using Grid = std::shared_ptr<Cartesian_grid_3<Geom_traits> >;
public: public:
/** /**
@ -47,7 +48,9 @@ public:
* *
* \param grid the cartesian grid that stores the gradient * \param grid the cartesian grid that stores the gradient
*/ */
Explicit_cartesian_grid_gradient(const Grid& grid) : grid(grid) {} Explicit_cartesian_grid_gradient(const Grid& grid)
: grid(grid)
{ }
/** /**
* \ingroup PkgIsosurfacing3Ref * \ingroup PkgIsosurfacing3Ref
@ -56,7 +59,8 @@ public:
* *
* \param point the point at which the gradient is computed * \param point the point at which the gradient is computed
*/ */
Vector operator()(const Point& point) const { Vector operator()(const Point& point) const
{
// trilinear interpolation of stored gradients // trilinear interpolation of stored gradients
const Bbox_3& bbox = grid->get_bbox(); const Bbox_3& bbox = grid->get_bbox();
@ -66,15 +70,15 @@ public:
std::size_t min_i = (point.x() - bbox.xmin()) / spacing.x(); 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_j = (point.y() - bbox.ymin()) / spacing.y();
std::size_t min_k = (point.z() - bbox.zmin()) / spacing.z(); std::size_t min_k = (point.z() - bbox.zmin()) / spacing.z();
if (min_i == grid->xdim() - 1) { if(min_i == grid->xdim() - 1)
min_i--; --min_i;
}
if (min_j == grid->ydim() - 1) { if(min_j == grid->ydim() - 1)
min_j--; --min_j;
}
if (min_k == grid->zdim() - 1) { if(min_k == grid->zdim() - 1)
min_k--; --min_k;
}
// calculate coordinates of min index // calculate coordinates of min index
const FT min_x = min_i * spacing.x() + bbox.xmin(); const FT min_x = min_i * spacing.x() + bbox.xmin();

View File

@ -30,13 +30,15 @@ namespace Isosurfacing {
* \tparam PointFunction the type of the implicit function. It must implement `GeomTraits::FT operator()(const * \tparam PointFunction the type of the implicit function. It must implement `GeomTraits::FT operator()(const
* GeomTraits::Point& point) const`. * GeomTraits::Point& point) const`.
*/ */
template <class GeomTraits, typename PointFunction> template <typename GeomTraits,
class Finite_difference_gradient { typename PointFunction>
class Finite_difference_gradient
{
public: public:
typedef GeomTraits Geom_traits; using Geom_traits = GeomTraits;
typedef typename Geom_traits::FT FT; using FT = typename Geom_traits::FT;
typedef typename Geom_traits::Point_3 Point; using Point = typename Geom_traits::Point_3;
typedef typename Geom_traits::Vector_3 Vector; using Vector = typename Geom_traits::Vector_3;
public: public:
/** /**
@ -47,8 +49,11 @@ public:
* \param point_function the function with a point as argument * \param point_function the function with a point as argument
* \param delta the distance for calculating the finite differences * \param delta the distance for calculating the finite differences
*/ */
Finite_difference_gradient(const PointFunction& point_function, const FT delta = 0.001) Finite_difference_gradient(const PointFunction& point_function,
: func(point_function), delta(delta) {} const FT delta = 0.001)
: func(point_function),
delta(delta)
{ }
/** /**
* \ingroup PkgIsosurfacing3Ref * \ingroup PkgIsosurfacing3Ref
@ -57,7 +62,8 @@ public:
* *
* \param point the point at which the gradient is computed * \param point the point at which the gradient is computed
*/ */
Vector operator()(const Point& point) const { Vector operator()(const Point& point) const
{
// compute the gradient by sampling the function with finite differences // compute the gradient by sampling the function with finite differences
// at six points with distance delta around the query point // at six points with distance delta around the query point
const Point p0 = point + Vector(delta, 0, 0); const Point p0 = point + Vector(delta, 0, 0);

View File

@ -31,14 +31,21 @@ namespace Isosurfacing {
* `IsosurfacingDomainWithGradient`. * `IsosurfacingDomainWithGradient`.
* *
* \tparam GeomTraits the traits type * \tparam GeomTraits the traits type
* \tparam PointFunction the type of the implicit function. It must implement `GeomTraits::FT operator()(const * \tparam PointFunction the type of the implicit function. It must implement
* GeomTraits::Point& point) const`. \tparam Gradient_ the type of the gradient functor. 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`. * `GeomTraits::Vector operator()(const GeomTraits::Point& point) const`.
*/ */
template <class GeomTraits, typename PointFunction, typename Gradient_> template <typename GeomTraits,
using Implicit_cartesian_grid_domain = internal::Base_domain< typename PointFunction,
GeomTraits, internal::Grid_topology, internal::Cartesian_grid_geometry<GeomTraits>, typename Gradient_>
internal::Implicit_function_with_geometry<GeomTraits, internal::Cartesian_grid_geometry<GeomTraits>, PointFunction>, using Implicit_cartesian_grid_domain =
internal::Base_domain<GeomTraits,
internal::Grid_topology,
internal::Cartesian_grid_geometry<GeomTraits>,
internal::Implicit_function_with_geometry<GeomTraits,
internal::Cartesian_grid_geometry<GeomTraits>,
PointFunction>,
Gradient_>; Gradient_>;
/** /**
@ -61,17 +68,22 @@ using Implicit_cartesian_grid_domain = internal::Base_domain<
* *
* \return a new `Implicit_cartesian_grid_domain` * \return a new `Implicit_cartesian_grid_domain`
*/ */
template <class GeomTraits, typename PointFunction, typename Gradient_ = Zero_gradient<GeomTraits>> template <typename GeomTraits,
Implicit_cartesian_grid_domain<GeomTraits, PointFunction, Gradient_> create_implicit_cartesian_grid_domain( typename PointFunction,
const Bbox_3& bbox, const typename GeomTraits::Vector_3& spacing, const PointFunction& point_function, typename Gradient_ = Zero_gradient<GeomTraits> >
const Gradient_& gradient = Gradient_()) { Implicit_cartesian_grid_domain<GeomTraits, PointFunction, Gradient_>
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<GeomTraits, PointFunction, Gradient_>;
typedef Implicit_cartesian_grid_domain<GeomTraits, PointFunction, Gradient_> Domain; using Topology = typename Domain::Topology;
typedef typename Domain::Topology Topology; using Geometry = typename Domain::Geometry;
typedef typename Domain::Geometry Geometry; using Function = typename Domain::Function;
typedef typename Domain::Function Function; using Gradient = typename Domain::Gradient;
typedef typename Domain::Gradient Gradient; using Point_function = typename Function::element_type::Point_function;
typedef typename Function::element_type::Point_function Point_function;
// calculate grid dimensions // calculate grid dimensions
const std::size_t size_i = std::ceil(bbox.x_span() / spacing.x()) + 1; const std::size_t size_i = std::ceil(bbox.x_span() / spacing.x()) + 1;

View File

@ -24,25 +24,34 @@
namespace CGAL { namespace CGAL {
namespace Isosurfacing { namespace Isosurfacing {
template <typename GeomTraits,
template <class GeomTraits, typename PointFunction, typename Gradient_> typename PointFunction,
using Implicit_octree_domain = internal::Base_domain< typename Gradient_>
GeomTraits, internal::Octree_topology<GeomTraits>, internal::Octree_geometry<GeomTraits>, using Implicit_octree_domain =
internal::Implicit_function_with_geometry<GeomTraits, internal::Octree_geometry<GeomTraits>, PointFunction>, internal::Base_domain<GeomTraits,
internal::Octree_topology<GeomTraits>,
internal::Octree_geometry<GeomTraits>,
internal::Implicit_function_with_geometry<GeomTraits,
internal::Octree_geometry<GeomTraits>,
PointFunction>,
Gradient_>; Gradient_>;
template <class GeomTraits, typename PointFunction, typename Gradient_ = Zero_gradient<GeomTraits>> template <typename GeomTraits,
Implicit_octree_domain<GeomTraits, PointFunction, Gradient_> create_implicit_octree_domain( typename PointFunction,
const std::shared_ptr<Octree_wrapper<GeomTraits>> octree, const PointFunction& point_function, typename Gradient_ = Zero_gradient<GeomTraits> >
const Gradient_& gradient = Gradient_()) { Implicit_octree_domain<GeomTraits, PointFunction, Gradient_>
create_implicit_octree_domain(const std::shared_ptr<Octree_wrapper<GeomTraits> > octree,
const PointFunction& point_function,
const Gradient_& gradient = Gradient_())
{
using Domain = Implicit_octree_domain<GeomTraits, PointFunction, Gradient_>;
typedef Implicit_octree_domain<GeomTraits, PointFunction, Gradient_> Domain; using Topology = typename Domain::Topology;
typedef typename Domain::Topology Topology; using Geometry = typename Domain::Geometry;
typedef typename Domain::Geometry Geometry; using Function = typename Domain::Function;
typedef typename Domain::Function Function; using Gradient = typename Domain::Gradient;
typedef typename Domain::Gradient Gradient; using Point_function = typename Function::element_type::Point_function;
typedef typename Function::element_type::Point_function Point_function; using Octree = typename Topology::element_type::Octree;
typedef typename Topology::element_type::Octree Octree;
const Octree oct = octree; const Octree oct = octree;
const Topology topo = std::make_shared<Topology::element_type>(oct); const Topology topo = std::make_shared<Topology::element_type>(oct);

View File

@ -9,8 +9,8 @@
// //
// Author(s) : Julian Stahl // Author(s) : Julian Stahl
#ifndef CGAL_BASE_DOMAIN_H #ifndef CGAL_ISOSURFACING_3_INTERNAL_BASE_DOMAIN_H
#define CGAL_BASE_DOMAIN_H #define CGAL_ISOSURFACING_3_INTERNAL_BASE_DOMAIN_H
#include <CGAL/license/Isosurfacing_3.h> #include <CGAL/license/Isosurfacing_3.h>
@ -22,89 +22,112 @@ namespace CGAL {
namespace Isosurfacing { namespace Isosurfacing {
namespace internal { namespace internal {
// A wrapper class to puzzle a domain together from different combinations of topology, geometry, function, and // A wrapper class to puzzle a domain together from different combinations of topology,
// gradient. // geometry, function, and gradient.
template <class GeomTraits, typename Topology_, typename Geometry_, typename Function_, typename Gradient_> template <typename GeomTraits,
class Base_domain { typename Topology_,
typename Geometry_,
typename Function_,
typename Gradient_>
class Base_domain
{
public: public:
typedef GeomTraits Geom_traits; using Geom_traits = GeomTraits;
typedef typename Geom_traits::FT FT;
typedef typename Geom_traits::Point_3 Point;
typedef typename Geom_traits::Vector_3 Vector;
typedef std::shared_ptr<Topology_> Topology; using FT = typename Geom_traits::FT;
typedef typename Topology_::Vertex_descriptor Vertex_descriptor; using Point = typename Geom_traits::Point_3;
typedef typename Topology_::Edge_descriptor Edge_descriptor; using Vector = typename Geom_traits::Vector_3;
typedef typename Topology_::Cell_descriptor Cell_descriptor;
using Topology = std::shared_ptr<Topology_>;
using Vertex_descriptor = typename Topology_::Vertex_descriptor;
using Edge_descriptor = typename Topology_::Edge_descriptor;
using Cell_descriptor = typename Topology_::Cell_descriptor;
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;
using Geometry = std::shared_ptr<Geometry_>;
using Function = std::shared_ptr<Function_>;
using Gradient = std::shared_ptr<Gradient_>;
static constexpr Cell_type CELL_TYPE = Topology_::CELL_TYPE; 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 VERTICES_PER_CELL = Topology_::VERTICES_PER_CELL;
static constexpr std::size_t EDGES_PER_CELL = Topology_::EDGES_PER_CELL; static constexpr std::size_t EDGES_PER_CELL = Topology_::EDGES_PER_CELL;
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;
typedef std::shared_ptr<Geometry_> Geometry;
typedef std::shared_ptr<Function_> Function;
typedef std::shared_ptr<Gradient_> Gradient;
public: public:
// Create a base_domain from a topology, geometry, input function, and gradient // 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) Base_domain(const Topology& topo,
: topo(topo), geom(geom), func(func), grad(grad) {} const Geometry& geom,
const Function& func,
const Gradient& grad)
: topo(topo),
geom(geom),
func(func),
grad(grad)
{ }
// Get the position of vertex v // Get the position of vertex v
Point position(const Vertex_descriptor& v) const { Point position(const Vertex_descriptor& v) const
{
return geom->operator()(v); return geom->operator()(v);
} }
// Get the value of the function at vertex v // Get the value of the function at vertex v
FT value(const Vertex_descriptor& v) const { FT value(const Vertex_descriptor& v) const
{
return func->operator()(v); return func->operator()(v);
} }
// Get the gradient at vertex v // Get the gradient at vertex v
Vector gradient(const Point& p) const { Vector gradient(const Point& p) const
{
return grad->operator()(p); return grad->operator()(p);
} }
// Get a container with the two vertices incident to the edge e // 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 edge_vertices(const Edge_descriptor& e) const
{
return topo->edge_vertices(e); return topo->edge_vertices(e);
} }
// Get a container with all cells incident to the 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 { Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const
{
return topo->cells_incident_to_edge(e); return topo->cells_incident_to_edge(e);
} }
// Get a container with all vertices of the cell c // Get a container with all vertices of the cell c
Cell_vertices cell_vertices(const Cell_descriptor& c) const { Cell_vertices cell_vertices(const Cell_descriptor& c) const
{
return topo->cell_vertices(c); return topo->cell_vertices(c);
} }
// Get a container with all edges of the cell c // Get a container with all edges of the cell c
Cell_edges cell_edges(const Cell_descriptor& c) const { Cell_edges cell_edges(const Cell_descriptor& c) const
{
return topo->cell_edges(c); return topo->cell_edges(c);
} }
// Iterate over all vertices v calling f(v) on every one // Iterate over all vertices v calling f(v) on every one
template <typename Concurrency_tag, typename Functor> template <typename Concurrency_tag, typename Functor>
void iterate_vertices(Functor& f) const { void iterate_vertices(Functor& f) const
{
topo->iterate_vertices(f, Concurrency_tag()); topo->iterate_vertices(f, Concurrency_tag());
} }
// Iterate over all edges e calling f(e) on every one // Iterate over all edges e calling f(e) on every one
template <typename Concurrency_tag, typename Functor> template <typename Concurrency_tag, typename Functor>
void iterate_edges(Functor& f) const { void iterate_edges(Functor& f) const
{
topo->iterate_edges(f, Concurrency_tag()); topo->iterate_edges(f, Concurrency_tag());
} }
// Iterate over all cells c calling f(c) on every one // Iterate over all cells c calling f(c) on every one
template <typename Concurrency_tag, typename Functor> template <typename Concurrency_tag, typename Functor>
void iterate_cells(Functor& f) const { void iterate_cells(Functor& f) const
{
topo->iterate_cells(f, Concurrency_tag()); topo->iterate_cells(f, Concurrency_tag());
} }
@ -119,4 +142,4 @@ private:
} // namespace Isosurfacing } // namespace Isosurfacing
} // namespace CGAL } // namespace CGAL
#endif // CGAL_BASE_DOMAIN_H #endif // CGAL_ISOSURFACING_3_INTERNAL_BASE_DOMAIN_H

View File

@ -9,8 +9,8 @@
// //
// Author(s) : Julian Stahl // Author(s) : Julian Stahl
#ifndef CGAL_CARTESIAN_GRID_GEOMETRY_H #ifndef CGAL_ISOSURFACING_3_INTERNAL_CARTESIAN_GRID_GEOMETRY_H
#define CGAL_CARTESIAN_GRID_GEOMETRY_H #define CGAL_ISOSURFACING_3_INTERNAL_CARTESIAN_GRID_GEOMETRY_H
#include <CGAL/license/Isosurfacing_3.h> #include <CGAL/license/Isosurfacing_3.h>
@ -22,23 +22,31 @@ namespace internal {
// Describes the geometry of a regular cartesian grid. Positions are not stored but calculated // Describes the geometry of a regular cartesian grid. Positions are not stored but calculated
// from an offset and grid spacing. // from an offset and grid spacing.
template <class GeomTraits> template <typename GeomTraits>
class Cartesian_grid_geometry { class Cartesian_grid_geometry
{
public: public:
typedef GeomTraits Geom_traits; using Geom_traits = GeomTraits;
typedef typename Geom_traits::Point_3 Point; using Point = typename Geom_traits::Point_3;
typedef typename Geom_traits::Vector_3 Vector; using Vector = typename Geom_traits::Vector_3;
typedef typename Grid_topology::Vertex_descriptor Vertex_descriptor; using Vertex_descriptor = typename Grid_topology::Vertex_descriptor;
public: public:
// Create a regular grid geometry where offset is the position of the vertex with index (0, 0, 0) // 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. // and spacing the distance between two connected vertices in each dimension.
Cartesian_grid_geometry(const Vector& offset, const Vector& spacing) : offset(offset), spacing(spacing) {} Cartesian_grid_geometry(const Vector& offset,
const Vector& spacing)
: offset(offset),
spacing(spacing)
{ }
// Get the position of vertex v // Get the position of vertex v
Point operator()(const Vertex_descriptor& v) const { Point operator()(const Vertex_descriptor& v) const
return Point(v[0] * spacing[0], v[1] * spacing[1], v[2] * spacing[2]) + offset; {
return Point(v[0] * spacing[0],
v[1] * spacing[1],
v[2] * spacing[2]) + offset;
} }
private: private:
@ -50,4 +58,4 @@ private:
} // namespace Isosurfacing } // namespace Isosurfacing
} // namespace CGAL } // namespace CGAL
#endif // CGAL_CARTESIAN_GRID_GEOMETRY_H #endif // CGAL_ISOSURFACING_3_INTERNAL_CARTESIAN_GRID_GEOMETRY_H

View File

@ -9,8 +9,8 @@
// //
// Author(s) : Julian Stahl // Author(s) : Julian Stahl
#ifndef CGAL_DOMAIN_CELL_TYPE #ifndef CGAL_ISOSURFACING_3_INTERNAL_DOMAIN_CELL_TYPE
#define CGAL_DOMAIN_CELL_TYPE #define CGAL_ISOSURFACING_3_INTERNAL_DOMAIN_CELL_TYPE
#include <CGAL/license/Isosurfacing_3.h> #include <CGAL/license/Isosurfacing_3.h>
@ -19,17 +19,16 @@
namespace CGAL { namespace CGAL {
namespace Isosurfacing { namespace Isosurfacing {
// Was supposed to check if an algorithm can handle a specific domain. Not used right now. // 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<Cell_type>::max)(); static constexpr Cell_type ANY_CELL = (std::numeric_limits<Cell_type>::max)();
static constexpr Cell_type POLYHERDAL_CELL = ((Cell_type)1) << 0; static constexpr Cell_type POLYHERDAL_CELL = (Cell_type(1) << 0);
static constexpr Cell_type TETRAHEDRAL_CELL = ((Cell_type)1) << 1; static constexpr Cell_type TETRAHEDRAL_CELL = (Cell_type(1) << 1);
static constexpr Cell_type CUBICAL_CELL = ((Cell_type)1) << 2; static constexpr Cell_type CUBICAL_CELL = (Cell_type(1) << 2);
} // namespace Isosurfacing } // namespace Isosurfacing
} // namespace CGAL } // namespace CGAL
#endif // CGAL_DOMAIN_CELL_TYPE #endif // CGAL_ISOSURFACING_3_INTERNAL_DOMAIN_CELL_TYPE

View File

@ -10,16 +10,17 @@
// Author(s) : Daniel Zint // Author(s) : Daniel Zint
// Julian Stahl // Julian Stahl
#ifndef CGAL_DUAL_CONTOURING_3_INTERNAL_DUAL_CONTOURING_3_H #ifndef CGAL_ISOSURFACING_3_INTERNAL_DUAL_CONTOURING_INTERNAL_H
#define CGAL_DUAL_CONTOURING_3_INTERNAL_DUAL_CONTOURING_3_H #define CGAL_ISOSURFACING_3_INTERNAL_DUAL_CONTOURING_INTERNAL_H
#include <CGAL/license/Isosurfacing_3.h> #include <CGAL/license/Isosurfacing_3.h>
#include <CGAL/Bbox_3.h> #include <CGAL/Bbox_3.h>
#include <CGAL/Origin.h>
#include <CGAL/centroid.h> #include <CGAL/centroid.h>
#include <CGAL/Origin.h>
#include <Eigen/SVD> #include <Eigen/SVD>
#include <array> #include <array>
#include <map> #include <map>
#include <mutex> #include <mutex>
@ -30,11 +31,12 @@ namespace Isosurfacing {
namespace internal { namespace internal {
namespace Positioning { namespace Positioning {
/** /**
* \ingroup PkgIsosurfacing3Ref * \ingroup PkgIsosurfacing3Ref
* *
* \brief Computes the vertex position for a point in Dual Contouring using Quadric Error Metrics and the SVD pseudo * \brief Computes the vertex position for a point in Dual Contouring
* inverse. * using Quadric Error Metrics and the SVD pseudo inverse.
* *
* \details * \details
* *
@ -42,7 +44,8 @@ namespace Positioning {
* *
*/ */
template <bool use_bbox = false> template <bool use_bbox = false>
class QEM_SVD { class QEM_SVD
{
public: public:
/** /**
* \ingroup PkgIsosurfacing3Ref * \ingroup PkgIsosurfacing3Ref
@ -60,12 +63,15 @@ public:
* *
* \return true, if the voxel intersects the isosurface * \return true, if the voxel intersects the isosurface
*/ */
template <class Domain_> template <typename Domain_>
bool position(const Domain_& domain, const typename Domain_::FT isovalue, bool position(const Domain_& domain,
const typename Domain_::Cell_descriptor& cell, typename Domain_::Point& point) const { const typename Domain_::FT isovalue,
typedef typename Domain_::Point Point; const typename Domain_::Cell_descriptor& cell,
typedef typename Domain_::Geom_traits::Vector_3 Vector; typename Domain_::Point& point) const
typedef typename Domain_::FT FT; {
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);
@ -73,13 +79,15 @@ public:
std::transform(vertices.begin(), vertices.end(), pos.begin(), std::transform(vertices.begin(), vertices.end(), pos.begin(),
[&](const auto& v) { return domain.position(v); }); [&](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 // compute edge intersections
std::vector<Point> edge_intersections; std::vector<Point> edge_intersections;
std::vector<Vector> edge_intersection_normals; std::vector<Vector> edge_intersection_normals;
for (const auto& edge : domain.cell_edges(cell)) { for(const auto& edge : domain.cell_edges(cell))
{
const auto& edge_vertices = domain.edge_vertices(edge); const auto& edge_vertices = domain.edge_vertices(edge);
const auto& v0 = edge_vertices[0]; const auto& v0 = edge_vertices[0];
const auto& v1 = edge_vertices[1]; const auto& v1 = edge_vertices[1];
@ -90,7 +98,9 @@ public:
const auto& p0 = domain.position(v0); const auto& p0 = domain.position(v0);
const auto& p1 = domain.position(v1); const auto& p1 = domain.position(v1);
if ((val0 <= isovalue) != (val1 <= isovalue)) { // this edge is intersected by the isosurface if((val0 <= isovalue) != (val1 <= isovalue))
{
// this edge is intersected by the isosurface
const FT u = (val0 - isovalue) / (val0 - val1); const FT u = (val0 - isovalue) / (val0 - val1);
const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN)); const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN));
edge_intersections.push_back(p_lerp); edge_intersections.push_back(p_lerp);
@ -98,19 +108,22 @@ public:
} }
} }
if (edge_intersections.empty()) { if(edge_intersections.empty())
return false; return false;
}
// SVD QEM // SVD QEM
Eigen::Matrix3d A; Eigen::Matrix3d A;
A.setZero(); A.setZero();
Eigen::Vector3d rhs; Eigen::Vector3d rhs;
rhs.setZero(); rhs.setZero();
for (std::size_t i = 0; i < edge_intersections.size(); ++i) { 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 n_k = { edge_intersection_normals[i].x(),
Eigen::Vector3d p_k = {edge_intersections[i].x(), edge_intersections[i].y(), edge_intersections[i].z()}; 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; double d_k = n_k.transpose() * p_k;
Eigen::Matrix3d A_k = n_k * n_k.transpose(); Eigen::Matrix3d A_k = n_k * n_k.transpose();
@ -120,8 +133,7 @@ public:
} }
Eigen::JacobiSVD<Eigen::MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV); Eigen::JacobiSVD<Eigen::MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
// set threshold as in Peter Lindstrom's paper, "Out-of-Core // set threshold as in Peter Lindstrom's paper, "Out-of-Core Simplification of Large Polygonal Models"
// Simplification of Large Polygonal Models"
svd.setThreshold(1e-3); svd.setThreshold(1e-3);
// Init x hat // Init x hat
@ -134,7 +146,8 @@ public:
point = Point(v_svd[0], v_svd[1], v_svd[2]); point = Point(v_svd[0], v_svd[1], v_svd[2]);
// bbox // bbox
if (use_bbox) { if(use_bbox)
{
CGAL::Bbox_3 bbox = pos[0].bbox() + pos[7].bbox(); // TODO remove[0],[7] CGAL::Bbox_3 bbox = pos[0].bbox() + pos[7].bbox(); // TODO remove[0],[7]
FT x = (std::min<FT>)((std::max<FT>)(point.x(), bbox.xmin()), bbox.xmax()); FT x = (std::min<FT>)((std::max<FT>)(point.x(), bbox.xmin()), bbox.xmax());
@ -152,7 +165,8 @@ public:
* *
* \brief Returns cell center. * \brief Returns cell center.
*/ */
class Cell_center { class Cell_center
{
public: public:
/** /**
* \ingroup PkgIsosurfacing3Ref * \ingroup PkgIsosurfacing3Ref
@ -170,12 +184,15 @@ public:
* *
* \return true, if the voxel intersects the isosurface * \return true, if the voxel intersects the isosurface
*/ */
template <class Domain_> template <typename Domain_>
bool position(const Domain_& domain, const typename Domain_::FT isovalue, bool position(const Domain_& domain,
const typename Domain_::Cell_descriptor& vh, typename Domain_::Point& point) const { const typename Domain_::FT isovalue,
typedef typename Domain_::Point Point; const typename Domain_::Cell_descriptor& vh,
typedef typename Domain_::Geom_traits::Vector_3 Vector; typename Domain_::Point& point) const
typedef typename Domain_::FT FT; {
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);
@ -183,19 +200,21 @@ public:
std::transform(vertices.begin(), vertices.end(), pos.begin(), std::transform(vertices.begin(), vertices.end(), pos.begin(),
[&](const auto& v) { return domain.position(v); }); [&](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 allSmaller = true;
bool allGreater = true; bool allGreater = true;
for (const auto& v : vertices) { for(const auto& v : vertices)
{
const bool& b = domain.value(v) <= isovalue; const bool& b = domain.value(v) <= isovalue;
allSmaller = allSmaller && b; allSmaller = allSmaller && b;
allGreater = allGreater && !b; allGreater = allGreater && !b;
} }
if (allSmaller || allGreater) { if(allSmaller || allGreater)
return false; return false;
}
return true; return true;
} }
@ -206,7 +225,8 @@ public:
* *
* \brief Computes the centroid of all cell edge intersections with the isosurface. * \brief Computes the centroid of all cell edge intersections with the isosurface.
*/ */
class Centroid_of_edge_intersections { class Centroid_of_edge_intersections
{
public: public:
/** /**
* \ingroup PkgIsosurfacing3Ref * \ingroup PkgIsosurfacing3Ref
@ -224,19 +244,23 @@ public:
* *
* \return true, if the voxel intersects the isosurface * \return true, if the voxel intersects the isosurface
*/ */
template <class Domain_> template <typename Domain_>
bool position(const Domain_& domain, const typename Domain_::FT isovalue, bool position(const Domain_& domain,
const typename Domain_::Cell_descriptor& cell, typename Domain_::Point& point) const { const typename Domain_::FT isovalue,
typedef typename Domain_::Point Point; const typename Domain_::Cell_descriptor& cell,
typedef typename Domain_::Geom_traits::Vector_3 Vector; typename Domain_::Point& point) const
typedef typename Domain_::FT FT; {
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 // compute edge intersections
std::vector<Point> edge_intersections; std::vector<Point> edge_intersections;
for (const auto& edge : domain.cell_edges(cell)) { for(const auto& edge : domain.cell_edges(cell))
{
const auto& edge_vertices = domain.edge_vertices(edge); const auto& edge_vertices = domain.edge_vertices(edge);
const auto& v0 = edge_vertices[0]; const auto& v0 = edge_vertices[0];
const auto& v1 = edge_vertices[1]; const auto& v1 = edge_vertices[1];
@ -247,16 +271,17 @@ public:
const auto& p0 = domain.position(v0); const auto& p0 = domain.position(v0);
const auto& p1 = domain.position(v1); const auto& p1 = domain.position(v1);
if ((val0 <= isovalue) != (val1 <= isovalue)) { // this edge is intersected by the isosurface if((val0 <= isovalue) != (val1 <= isovalue))
{
// this edge is intersected by the isosurface
const FT u = (val0 - isovalue) / (val0 - val1); const FT u = (val0 - isovalue) / (val0 - val1);
const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN)); const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN));
edge_intersections.push_back(p_lerp); edge_intersections.push_back(p_lerp);
} }
} }
if (edge_intersections.empty()) { if(edge_intersections.empty())
return false; return false;
}
point = CGAL::centroid(edge_intersections.begin(), edge_intersections.end(), point = CGAL::centroid(edge_intersections.begin(), edge_intersections.end(),
CGAL::Dimension_tag<0>()); // set point to center of edge intersections CGAL::Dimension_tag<0>()); // set point to center of edge intersections
@ -264,34 +289,44 @@ public:
return true; return true;
} }
}; };
} // namespace Positioning } // namespace Positioning
template <class Domain_, class Positioning_> template <typename Domain_,
class Dual_contouring_vertex_positioning { typename Positioning_>
class Dual_contouring_vertex_positioning
{
private: private:
typedef Domain_ Domain; using Domain = Domain_;
typedef Positioning_ Positioning; using Positioning = Positioning_;
typedef typename Domain::FT FT; using FT = typename Domain::FT;
typedef typename Domain::Point Point; using Point = typename Domain::Point;
typedef typename Domain::Cell_descriptor Cell_descriptor; using Cell_descriptor = typename Domain::Cell_descriptor;
public: public:
Dual_contouring_vertex_positioning(const Domain& domain, FT isovalue, const Positioning& positioning) Dual_contouring_vertex_positioning(const Domain& domain,
: domain(domain), isovalue(isovalue), positioning(positioning), points_counter(0) {} const FT isovalue,
const Positioning& positioning)
: domain(domain),
isovalue(isovalue),
positioning(positioning),
points_counter(0)
{ }
void operator()(const Cell_descriptor& v) { void operator()(const Cell_descriptor& v)
{
// compute dc-vertices // compute dc-vertices
Point p; Point p;
if (positioning.position(domain, isovalue, v, p)) { if(positioning.position(domain, isovalue, v, p))
{
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
map_voxel_to_point[v] = p; map_voxel_to_point[v] = p;
map_voxel_to_point_id[v] = points_counter++; map_voxel_to_point_id[v] = points_counter++;
} }
} }
// private: // private: // @todo
const Domain& domain; const Domain& domain;
FT isovalue; FT isovalue;
const Positioning& positioning; const Positioning& positioning;
@ -303,31 +338,39 @@ public:
std::mutex mutex; std::mutex mutex;
}; };
template <class Domain_> template <typename Domain_>
class Dual_contouring_face_generation { class Dual_contouring_face_generation
{
private: private:
typedef Domain_ Domain; using Domain = Domain_;
typedef typename Domain_::FT FT; using FT = typename Domain_::FT;
typedef typename Domain_::Edge_descriptor Edge_descriptor; using Edge_descriptor = typename Domain_::Edge_descriptor;
typedef typename Domain_::Cell_descriptor Cell_descriptor; using Cell_descriptor = typename Domain_::Cell_descriptor;
public: 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) { void operator()(const Edge_descriptor& e)
{
// save all faces // save all faces
const auto& vertices = domain.edge_vertices(e); const auto& vertices = domain.edge_vertices(e);
const FT s0 = domain.value(vertices[0]); const FT s0 = domain.value(vertices[0]);
const FT s1 = domain.value(vertices[1]); const FT s1 = domain.value(vertices[1]);
if (s0 <= isovalue && s1 > isovalue) { if(s0 <= isovalue && s1 > isovalue)
{
const auto& voxels = domain.cells_incident_to_edge(e); const auto& voxels = domain.cells_incident_to_edge(e);
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
faces[e].insert(faces[e].begin(), voxels.begin(), voxels.end()); faces[e].insert(faces[e].begin(), voxels.begin(), voxels.end());
}
} else if (s1 <= isovalue && s0 > isovalue) { else if(s1 <= isovalue && s0 > isovalue)
{
const auto& voxels = domain.cells_incident_to_edge(e); const auto& voxels = domain.cells_incident_to_edge(e);
std::lock_guard<std::mutex> lock(mutex); std::lock_guard<std::mutex> lock(mutex);
@ -335,7 +378,7 @@ public:
} }
} }
// private: // private: // @todo
std::map<Edge_descriptor, std::vector<Cell_descriptor>> faces; std::map<Edge_descriptor, std::vector<Cell_descriptor>> faces;
const Domain& domain; const Domain& domain;
@ -348,4 +391,4 @@ public:
} // namespace Isosurfacing } // namespace Isosurfacing
} // namespace CGAL } // namespace CGAL
#endif // CGAL_DUAL_CONTOURING_3_INTERNAL_DUAL_CONTOURING_3_H #endif // CGAL_ISOSURFACING_3_INTERNAL_DUAL_CONTOURING_INTERNAL_H

View File

@ -9,8 +9,8 @@
// //
// Author(s) : Julian Stahl // Author(s) : Julian Stahl
#ifndef CGAL_GRID_TOPOLOGY_H #ifndef CGAL_ISOSURFACING_3_INTERNAL_GRID_TOPOLOGY_H
#define CGAL_GRID_TOPOLOGY_H #define CGAL_ISOSURFACING_3_INTERNAL_GRID_TOPOLOGY_H
#include <CGAL/license/Isosurfacing_3.h> #include <CGAL/license/Isosurfacing_3.h>
@ -29,97 +29,116 @@ namespace Isosurfacing {
namespace internal { namespace internal {
// The topology of a cartesian grid. All elements are created with the help of the cube tables. // The topology of a cartesian grid. All elements are created with the help of the cube tables.
class Grid_topology { class Grid_topology
{
public: public:
// identify a vertex by its (i, j, k) indices // identify a vertex by its (i, j, k) indices
typedef std::array<std::size_t, 3> Vertex_descriptor; using Vertex_descriptor = std::array<std::size_t, 3>;
// identify an edge by its starting vertex (i, j, k) and the direction x -> 0, y -> 1, z -> 2 // identify an edge by its starting vertex (i, j, k) and the direction x -> 0, y -> 1, z -> 2
typedef std::array<std::size_t, 4> Edge_descriptor; using Edge_descriptor = std::array<std::size_t, 4>;
// identify a cell by its corner vertex with the smallest (i, j, k) index // identify a cell by its corner vertex with the smallest (i, j, k) index
typedef std::array<std::size_t, 3> Cell_descriptor; using Cell_descriptor = std::array<std::size_t, 3>;
static constexpr Cell_type CELL_TYPE = CUBICAL_CELL; static constexpr Cell_type CELL_TYPE = CUBICAL_CELL;
static constexpr std::size_t VERTICES_PER_CELL = 8; static constexpr std::size_t VERTICES_PER_CELL = 8;
static constexpr std::size_t EDGES_PER_CELL = 12; static constexpr std::size_t EDGES_PER_CELL = 12;
typedef std::array<Vertex_descriptor, 2> Vertices_incident_to_edge; using Vertices_incident_to_edge = std::array<Vertex_descriptor, 2>;
typedef std::array<Cell_descriptor, 4> Cells_incident_to_edge; using Cells_incident_to_edge = std::array<Cell_descriptor, 4>;
typedef std::array<Vertex_descriptor, VERTICES_PER_CELL> Cell_vertices; using Cell_vertices = std::array<Vertex_descriptor, VERTICES_PER_CELL>;
typedef std::array<Edge_descriptor, EDGES_PER_CELL> Cell_edges; using Cell_edges = std::array<Edge_descriptor, EDGES_PER_CELL>;
public: public:
// Create the topology of a grid with size_i, size_j, and size_k vertices in the respective dimensions. // 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) Grid_topology(const std::size_t size_i,
: size_i(size_i), size_j(size_j), size_k(size_k) {} 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 // 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 edge_vertices(const Edge_descriptor& e) const
{
Vertices_incident_to_edge ev; Vertices_incident_to_edge ev;
ev[0] = {e[0], e[1], e[2]}; // start vertex ev[0] = { e[0], e[1], e[2] }; // start vertex
ev[1] = {e[0], e[1], e[2]}; // end 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 ev[1][e[3]] += 1; // one position further in the direction of the edge
return ev; return ev;
} }
// Get a container with all cells incident to the 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 { Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const
{
// lookup the neighbor cells relative to the edge // lookup the neighbor cells relative to the edge
const int local = internal::Cube_table::edge_store_index[e[3]]; const int local = internal::Cube_table::edge_store_index[e[3]];
auto neighbors = internal::Cube_table::edge_to_voxel_neighbor[local]; auto neighbors = internal::Cube_table::edge_to_voxel_neighbor[local];
Cells_incident_to_edge cite; Cells_incident_to_edge cite;
for (std::size_t i = 0; i < cite.size(); i++) { for(std::size_t i=0; i<cite.size(); ++i)
for (std::size_t j = 0; j < cite[i].size(); j++) { {
for(std::size_t j=0; j<cite[i].size(); ++j)
{
cite[i][j] = e[j] + neighbors[i][j]; // offset the relative indices by the edge position cite[i][j] = e[j] + neighbors[i][j]; // offset the relative indices by the edge position
} }
} }
return cite; return cite;
} }
// Get a container with all vertices of the cell c // Get a container with all vertices of the cell c
Cell_vertices cell_vertices(const Cell_descriptor& c) const { Cell_vertices cell_vertices(const Cell_descriptor& c) const
{
Cell_vertices cv; Cell_vertices cv;
for (std::size_t i = 0; i < cv.size(); i++) { for(std::size_t i=0; i<cv.size(); ++i)
for (std::size_t j = 0; j < c.size(); j++) { {
for(std::size_t j=0; j<c.size(); ++j)
{
// lookup the relative vertex indices and offset them by the cell position // lookup the relative vertex indices and offset them by the cell position
cv[i][j] = c[j] + internal::Cube_table::local_vertex_position[i][j]; cv[i][j] = c[j] + internal::Cube_table::local_vertex_position[i][j];
} }
} }
return cv; return cv;
} }
// Get a container with all edges of the cell c // Get a container with all edges of the cell c
Cell_edges cell_edges(const Cell_descriptor& c) const { Cell_edges cell_edges(const Cell_descriptor& c) const
{
Cell_edges ce; Cell_edges ce;
for (std::size_t i = 0; i < ce.size(); i++) { for(std::size_t i=0; i<ce.size(); ++i)
for (std::size_t j = 0; j < c.size(); j++) { {
for(std::size_t j=0; j<c.size(); ++j)
{
// lookup the relative edge indices and offset them by the cell position // lookup the relative edge indices and offset them by the cell position
ce[i][j] = c[j] + internal::Cube_table::global_edge_id[i][j]; ce[i][j] = c[j] + internal::Cube_table::global_edge_id[i][j];
} }
// set the direction of the edge // set the direction of the edge
ce[i][3] = internal::Cube_table::global_edge_id[i][3]; ce[i][3] = internal::Cube_table::global_edge_id[i][3];
} }
return ce; return ce;
} }
// Iterate sequentially over all vertices v calling f(v) on every one // Iterate sequentially over all vertices v calling f(v) on every one
template <typename Functor> template <typename Functor>
void iterate_vertices(Functor& f, Sequential_tag) const { 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 i=0; i<size_i; ++i)
for (std::size_t k = 0; k < size_k; k++) { for(std::size_t j=0; j<size_j; ++j)
for(std::size_t k=0; k<size_k; ++k)
f({i, j, k}); f({i, j, k});
} }
}
}
}
// Iterate sequentially over all edges e calling f(e) on every one // Iterate sequentially over all edges e calling f(e) on every one
template <typename Functor> template <typename Functor>
void iterate_edges(Functor& f, Sequential_tag) const { 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 i=0; i<size_i-1; ++i) {
for (std::size_t k = 0; k < size_k - 1; k++) { 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) // all three edges starting at vertex (i, j, k)
f({i, j, k, 0}); f({i, j, k, 0});
f({i, j, k, 1}); f({i, j, k, 1});
@ -131,32 +150,29 @@ public:
// Iterate sequentially over all cells c calling f(c) on every one // Iterate sequentially over all cells c calling f(c) on every one
template <typename Functor> template <typename Functor>
void iterate_cells(Functor& f, Sequential_tag) const { 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 i=0; i<size_i-1; ++i)
for (std::size_t k = 0; k < size_k - 1; k++) { 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}); f({i, j, k});
} }
}
}
}
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
// Iterate in parallel over all vertices v calling f(v) on every one // Iterate in parallel over all vertices v calling f(v) on every one
template <typename Functor> template <typename Functor>
void iterate_vertices(Functor& f, Parallel_tag) const { void iterate_vertices(Functor& f, Parallel_tag) const
{
const std::size_t sj = size_j; const std::size_t sj = size_j;
const std::size_t sk = size_k; const std::size_t sk = size_k;
// for now only parallelize outer loop // for now only parallelize outer loop
auto iterator = [&f, sj, sk](const tbb::blocked_range<std::size_t>& r) { auto iterator = [&f, sj, sk](const tbb::blocked_range<std::size_t>& 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 i = r.begin(); i != r.end(); ++i)
for (std::size_t k = 0; k < sk; k++) { for(std::size_t j=0; j<sj; ++j)
for(std::size_t k=0; k<sk; ++k)
f({i, j, k}); f({i, j, k});
}
}
}
}; };
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, size_i), iterator); tbb::parallel_for(tbb::blocked_range<std::size_t>(0, size_i), iterator);
@ -164,15 +180,18 @@ public:
// Iterate in parallel over all edges e calling f(e) on every one // Iterate in parallel over all edges e calling f(e) on every one
template <typename Functor> template <typename Functor>
void iterate_edges(Functor& f, Parallel_tag) const { void iterate_edges(Functor& f, Parallel_tag) const
{
const std::size_t sj = size_j; const std::size_t sj = size_j;
const std::size_t sk = size_k; const std::size_t sk = size_k;
// for now only parallelize outer loop // for now only parallelize outer loop
auto iterator = [&f, sj, sk](const tbb::blocked_range<std::size_t>& r) { auto iterator = [&f, sj, sk](const tbb::blocked_range<std::size_t>& 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 i = r.begin(); i != r.end(); ++i) {
for (std::size_t k = 0; k < sk - 1; k++) { 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, 0});
f({i, j, k, 1}); f({i, j, k, 1});
f({i, j, k, 2}); f({i, j, k, 2});
@ -186,19 +205,17 @@ public:
// Iterate in parallel over all cells c calling f(c) on every one // Iterate in parallel over all cells c calling f(c) on every one
template <typename Functor> template <typename Functor>
void iterate_cells(Functor& f, Parallel_tag) const { void iterate_cells(Functor& f, Parallel_tag) const
{
const std::size_t sj = size_j; const std::size_t sj = size_j;
const std::size_t sk = size_k; const std::size_t sk = size_k;
// for now only parallelize outer loop // for now only parallelize outer loop
auto iterator = [&f, sj, sk](const tbb::blocked_range<std::size_t>& r) { auto iterator = [&f, sj, sk](const tbb::blocked_range<std::size_t>& r) {
for (std::size_t i = r.begin(); i != r.end(); i++) { 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 j=0; j<sj - 1; ++j)
for (std::size_t k = 0; k < sk - 1; k++) { for(std::size_t k=0; k<sk - 1; ++k)
f({i, j, k}); f({i, j, k});
}
}
}
}; };
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, size_i - 1), iterator); tbb::parallel_for(tbb::blocked_range<std::size_t>(0, size_i - 1), iterator);
@ -215,4 +232,4 @@ private:
} // namespace Isosurfacing } // namespace Isosurfacing
} // namespace CGAL } // namespace CGAL
#endif // CGAL_GRID_TOPOLOGY_H #endif // CGAL_ISOSURFACING_3_INTERNAL_GRID_TOPOLOGY_H

View File

@ -9,8 +9,8 @@
// //
// Author(s) : Julian Stahl // Author(s) : Julian Stahl
#ifndef CGAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H #ifndef CGAL_ISOSURFACING_3_INTERNAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H
#define CGAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H #define CGAL_ISOSURFACING_3_INTERNAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H
#include <CGAL/license/Isosurfacing_3.h> #include <CGAL/license/Isosurfacing_3.h>
@ -23,22 +23,30 @@ namespace internal {
// Wrapper for an implicit function that can only be evaluated at a position and not at a vertex. // 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. // Evaluates the geometry to get the vertex position and passes that to the function.
// Works for all VertexDescriptor types. // Works for all VertexDescriptor types.
template <class GeomTraits, typename Geometry_, typename PointFunction> template <typename GeomTraits,
class Implicit_function_with_geometry { typename Geometry_,
typename PointFunction>
class Implicit_function_with_geometry
{
public: public:
typedef GeomTraits Geom_traits; using Geom_traits = GeomTraits;
typedef typename Geom_traits::FT FT; using FT = typename Geom_traits::FT;
typedef std::shared_ptr<Geometry_> Geometry; using Geometry = std::shared_ptr<Geometry_>;
typedef std::shared_ptr<PointFunction> Point_function; using Point_function = std::shared_ptr<PointFunction>;
public: public:
// Create a function that uses the geometry to evaluate the function at vertex positions. // 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) {} Implicit_function_with_geometry(const Geometry& geom,
const Point_function& func)
: geom(geom),
func(func)
{ }
// Get the value of the function at vertex v // Get the value of the function at vertex v
template <typename VertexDescriptor> template <typename VertexDescriptor>
FT operator()(const VertexDescriptor& v) const { FT operator()(const VertexDescriptor& v) const
{
return func->operator()(geom->operator()(v)); return func->operator()(geom->operator()(v));
} }
@ -51,4 +59,4 @@ private:
} // namespace Isosurfacing } // namespace Isosurfacing
} // namespace CGAL } // namespace CGAL
#endif // CGAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H #endif // CGAL_ISOSURFACING_3_INTERNAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H

View File

@ -38,12 +38,13 @@
// https://github.com/rogrosso/tmc available on 15th of September 2022. // https://github.com/rogrosso/tmc available on 15th of September 2022.
// //
#ifndef CGAL_MARCHING_CUBES_3_INTERNAL_MARCHING_CUBES_3_H #ifndef CGAL_ISOSURFACING_3_INTERNAL_MARCHING_CUBES_3_INTERNAL_H
#define CGAL_MARCHING_CUBES_3_INTERNAL_MARCHING_CUBES_3_H #define CGAL_ISOSURFACING_3_INTERNAL_MARCHING_CUBES_3_INTERNAL_H
#include <CGAL/license/Isosurfacing_3.h> #include <CGAL/license/Isosurfacing_3.h>
#include <CGAL/Isosurfacing_3/internal/Tables.h> #include <CGAL/Isosurfacing_3/internal/Tables.h>
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
#include <tbb/concurrent_vector.h> #include <tbb/concurrent_vector.h>
#else #else
@ -61,63 +62,84 @@ namespace Isosurfacing {
namespace internal { namespace internal {
// Interpolate linearly between two vertex positions v0, v1 with values d0 and d1 according to the isovalue // Interpolate linearly between two vertex positions v0, v1 with values d0 and d1 according to the isovalue
template <class Point_3, typename FT> template <typename Point_3,
Point_3 vertex_interpolation(const Point_3& p0, const Point_3& p1, const FT d0, const FT d1, const FT isovalue) { typename FT>
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 // don't divide by 0
if (abs(d1 - d0) < 0.000001) { if(abs(d1 - d0) < 0.000001) // @todo
mu = 0.5; // if both points have the same value, assume isolevel is in the middle mu = 0.5; // if both points have the same value, assume isolevel is in the middle
} else { else
mu = (isovalue - d0) / (d1 - d0); mu = (isovalue - d0) / (d1 - d0);
}
assert(mu >= 0.0 || mu <= 1.0); assert(mu >= 0.0 || mu <= 1.0);
// linear interpolation // 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)); 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 // Retrieve the corner vertices and their values of a cell and return the lookup index
template <class Domain_, typename Corners_, typename Values_> template <typename Domain_,
std::size_t get_cell_corners(const Domain_& domain, const typename Domain_::Cell_descriptor& cell, typename Corners_,
const typename Domain_::FT isovalue, Corners_& corners, Values_& values) { typename Values_>
std::size_t get_cell_corners(const Domain_& domain,
typedef typename Domain_::Vertex_descriptor Vertex_descriptor; const typename Domain_::Cell_descriptor& cell,
const typename Domain_::FT isovalue,
Corners_& corners,
Values_& values)
{
using Vertex_descriptor = typename Domain_::Vertex_descriptor;
// collect function values and build index // collect function values and build index
std::size_t v_id = 0; std::size_t v_id = 0;
std::bitset<Domain_::VERTICES_PER_CELL> index = 0; std::bitset<Domain_::VERTICES_PER_CELL> index = 0;
for (const Vertex_descriptor& v : domain.cell_vertices(cell)) { for(const Vertex_descriptor& v : domain.cell_vertices(cell))
{
// collect scalar values and computex index // collect scalar values and computex index
corners[v_id] = domain.position(v); corners[v_id] = domain.position(v);
values[v_id] = domain.value(v); values[v_id] = domain.value(v);
if (values[v_id] >= isovalue) { if(values[v_id] >= isovalue)
index.set(v_id); index.set(v_id);
}
// next cell vertex // next cell vertex
v_id++; ++v_id;
} }
return static_cast<std::size_t>(index.to_ullong()); return static_cast<std::size_t>(index.to_ullong());
} }
// Create the vertices on the edges of one cell // Create the vertices on the edges of one cell
template <class CellEdges, typename FT, typename Corners_, typename Values_, typename Vertices_> template <typename CellEdges,
void mc_construct_vertices(const CellEdges& cell_edges, const FT isovalue, const std::size_t i_case, typename FT,
const Corners_& corners, const Values_& values, Vertices_& vertices) { typename Corners_,
typename Values_,
typename Vertices_>
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 // compute for this case the vertices
std::size_t flag = 1; std::size_t flag = 1;
std::size_t e_id = 0; std::size_t e_id = 0;
for (const auto& edge : cell_edges) { for(const auto& edge : cell_edges)
(void)edge; // TODO {
(void)edge; // @todo
if (flag & Cube_table::intersected_edges[i_case]) {
if(flag & Cube_table::intersected_edges[i_case])
{
// generate vertex here, do not care at this point if vertex already exist // 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 v0 = Cube_table::edge_to_vertex[e_id][0];
@ -125,20 +147,27 @@ void mc_construct_vertices(const CellEdges& cell_edges, const FT isovalue, const
vertices[e_id] = vertex_interpolation(corners[v0], corners[v1], values[v0], values[v1], isovalue); vertices[e_id] = vertex_interpolation(corners[v0], corners[v1], values[v0], values[v1], isovalue);
} }
flag <<= 1; flag <<= 1;
e_id++; ++e_id;
} }
} }
// Connect the vertices of one cell to form triangles // Connect the vertices of one cell to form triangles
template <typename Vertices_, class TriangleList> template <typename Vertices_,
void mc_construct_triangles(const int i_case, const Vertices_& vertices, TriangleList& triangles) { typename TriangleList>
void mc_construct_triangles(const int i_case,
const Vertices_& vertices,
TriangleList& triangles)
{
// construct triangles // construct triangles
for (int t = 0; t < 16; t += 3) { 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 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 eg1 = Cube_table::triangle_cases[t_index + 1];
@ -150,9 +179,15 @@ void mc_construct_triangles(const int i_case, const Vertices_& vertices, Triangl
} }
// Convert the triangle list to an indexed face set // Convert the triangle list to an indexed face set
template <class TriangleList, class PointRange, class PolygonRange> template <typename TriangleList,
void to_indexed_face_set(const TriangleList& triangle_list, PointRange& points, PolygonRange& polygons) { typename PointRange,
for (auto& triangle : triangle_list) { typename PolygonRange>
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(); const std::size_t id = points.size();
points.push_back(triangle[0]); points.push_back(triangle[0]);
@ -165,28 +200,33 @@ void to_indexed_face_set(const TriangleList& triangle_list, PointRange& points,
} }
// Marching Cubes implemented as a functor that runs on every cell of the grid // Marching Cubes implemented as a functor that runs on every cell of the grid
template <class Domain_> template <typename Domain_>
class Marching_cubes_3 { class Marching_cubes_3
{
private: private:
typedef Domain_ Domain; using Domain = Domain_;
typedef typename Domain::FT FT; using FT = typename Domain::FT;
typedef typename Domain::Point Point; using Point = typename Domain::Point;
typedef typename Domain::Cell_descriptor Cell_descriptor; using Cell_descriptor = typename Domain::Cell_descriptor;
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
typedef tbb::concurrent_vector<std::array<Point, 3>> Triangle_list; using Triangle_list = tbb::concurrent_vector<std::array<Point, 3> >;
#else #else
typedef std::vector<std::array<Point, 3>> Triangle_list; using Triangle_list = std::vector<std::array<Point, 3> >;
#endif #endif
public: public:
// Create a Marching Cubes functor for a domain and iso value // Create a Marching Cubes functor for a domain and iso value
Marching_cubes_3(const Domain& domain, const FT isovalue) : domain(domain), isovalue(isovalue) {} Marching_cubes_3(const Domain& domain,
const FT isovalue)
: domain(domain),
isovalue(isovalue)
{ }
// Compute one cell // Compute one cell
void operator()(const Cell_descriptor& cell) { void operator()(const Cell_descriptor& cell)
{
// TODO: maybe better checks if the domain can be processed? // @todo: maybe better checks if the domain can be processed?
assert(domain.cell_vertices(cell).size() == 8); assert(domain.cell_vertices(cell).size() == 8);
assert(domain.cell_edges(cell).size() == 12); assert(domain.cell_edges(cell).size() == 12);
@ -195,9 +235,8 @@ public:
const int i_case = get_cell_corners(domain, cell, isovalue, corners, values); 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 const int all_bits_set = (1 << (8 + 1)) - 1; // last 8 bits are 1
if (i_case == 0 || i_case == all_bits_set) { if(i_case == 0 || i_case == all_bits_set)
return; // skip empty cells return; // skip empty cells
}
std::array<Point, 12> vertices; std::array<Point, 12> vertices;
mc_construct_vertices(domain.cell_edges(cell), isovalue, i_case, corners, values, vertices); mc_construct_vertices(domain.cell_edges(cell), isovalue, i_case, corners, values, vertices);
@ -206,7 +245,8 @@ public:
} }
// Get the created triangle list // Get the created triangle list
const Triangle_list& triangles() const { const Triangle_list& triangles() const
{
return triangle_list; return triangle_list;
} }
@ -221,4 +261,4 @@ private:
} // namespace Isosurfacing } // namespace Isosurfacing
} // namespace CGAL } // namespace CGAL
#endif // CGAL_MARCHING_CUBES_3_INTERNAL_MARCHING_CUBES_3_H #endif // CGAL_ISOSURFACING_3_INTERNAL_MARCHING_CUBES_3_INTERNAL_H

View File

@ -9,8 +9,8 @@
// //
// Author(s) : Julian Stahl // Author(s) : Julian Stahl
#ifndef CGAL_OCTREE_GEOMETRY_H #ifndef CGAL_ISOSURFACING_3_INTERNAL_OCTREE_GEOMETRY_H
#define CGAL_OCTREE_GEOMETRY_H #define CGAL_ISOSURFACING_3_INTERNAL_OCTREE_GEOMETRY_H
#include <CGAL/license/Isosurfacing_3.h> #include <CGAL/license/Isosurfacing_3.h>
@ -23,20 +23,24 @@ namespace CGAL {
namespace Isosurfacing { namespace Isosurfacing {
namespace internal { namespace internal {
template <class GeomTraits> template <typename GeomTraits>
class Octree_geometry { class Octree_geometry
{
public: public:
typedef GeomTraits Geom_traits; using Geom_traits = GeomTraits;
typedef typename Geom_traits::Point_3 Point; using Point = typename Geom_traits::Point_3;
typedef std::shared_ptr<Octree_wrapper<Geom_traits>> Octree; using Octree = std::shared_ptr<Octree_wrapper<Geom_traits> >;
typedef typename Octree_topology<Geom_traits>::Vertex_descriptor Vertex_descriptor; using Vertex_descriptor = typename Octree_topology<Geom_traits>::Vertex_descriptor;
public: public:
Octree_geometry(const Octree& octree) : octree(octree) {} Octree_geometry(const Octree& octree)
: octree(octree)
{ }
Point operator()(const Vertex_descriptor& v) const { Point operator()(const Vertex_descriptor& v) const
{
return octree->point(v); return octree->point(v);
} }
@ -48,4 +52,4 @@ private:
} // namespace Isosurfacing } // namespace Isosurfacing
} // namespace CGAL } // namespace CGAL
#endif // CGAL_OCTREE_GEOMETRY_H #endif // CGAL_ISOSURFACING_3_INTERNAL_OCTREE_GEOMETRY_H

View File

@ -9,8 +9,8 @@
// //
// Author(s) : Julian Stahl // Author(s) : Julian Stahl
#ifndef CGAL_OCTREE_TOPOLOGY_H #ifndef CGAL_ISOSURFACING_3_INTERNAL_OCTREE_TOPOLOGY_H
#define CGAL_OCTREE_TOPOLOGY_H #define CGAL_ISOSURFACING_3_INTERNAL_OCTREE_TOPOLOGY_H
#include <CGAL/license/Isosurfacing_3.h> #include <CGAL/license/Isosurfacing_3.h>
@ -26,100 +26,110 @@ namespace CGAL {
namespace Isosurfacing { namespace Isosurfacing {
namespace internal { namespace internal {
template <class GeomTraits> // TODO: should not be necessary template <typename GeomTraits> // @todo should not be necessary
class Octree_topology { class Octree_topology
{
public: public:
typedef GeomTraits Geom_traits; using Geom_traits = GeomTraits;
typedef Octree_wrapper<Geom_traits> Octree_; using Octree_ = Octree_wrapper<Geom_traits>;
typedef std::shared_ptr<Octree_wrapper<Geom_traits>> Octree; using Octree = std::shared_ptr<Octree_wrapper<Geom_traits> >;
typedef typename Octree_::Vertex_handle Vertex_descriptor; using Vertex_descriptor = typename Octree_::Vertex_handle;
typedef typename Octree_::Edge_handle Edge_descriptor; using Edge_descriptor = typename Octree_::Edge_handle;
typedef typename Octree_::Voxel_handle Cell_descriptor; using Cell_descriptor = typename Octree_::Voxel_handle;
static constexpr Cell_type CELL_TYPE = CUBICAL_CELL; static constexpr Cell_type CELL_TYPE = CUBICAL_CELL;
static constexpr std::size_t VERTICES_PER_CELL = 8; static constexpr std::size_t VERTICES_PER_CELL = 8;
static constexpr std::size_t EDGES_PER_CELL = 12; static constexpr std::size_t EDGES_PER_CELL = 12;
typedef std::array<Vertex_descriptor, 2> Vertices_incident_to_edge; using Vertices_incident_to_edge = std::array<Vertex_descriptor, 2>;
typedef std::array<Cell_descriptor, 4> Cells_incident_to_edge; // TODO: not always 4 using Cells_incident_to_edge = std::array<Cell_descriptor, 4>; // @todo: not always 4
typedef std::array<Vertex_descriptor, 8> Cell_vertices; using Cell_vertices = std::array<Vertex_descriptor, 8>;
typedef std::array<Edge_descriptor, 12> Cell_edges; using Cell_edges = std::array<Edge_descriptor, 12>;
public: 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 { Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const
{
return octree->edge_vertices(e); return octree->edge_vertices(e);
} }
Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const { Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const
{
return octree->edge_voxels(e); return octree->edge_voxels(e);
} }
Cell_vertices cell_vertices(const Cell_descriptor& c) const { Cell_vertices cell_vertices(const Cell_descriptor& c) const
{
return octree->voxel_vertices(c); return octree->voxel_vertices(c);
} }
Cell_edges cell_edges(const Cell_descriptor& c) const { Cell_edges cell_edges(const Cell_descriptor& c) const
{
return octree->voxel_edges(c); return octree->voxel_edges(c);
} }
template <typename Functor> template <typename Functor>
void iterate_vertices(Functor& f, Sequential_tag) const { void iterate_vertices(Functor& f, Sequential_tag) const
for (const Vertex_descriptor& v : octree->leaf_vertices()) { {
for(const Vertex_descriptor& v : octree->leaf_vertices())
f(v); f(v);
} }
}
template <typename Functor> template <typename Functor>
void iterate_edges(Functor& f, Sequential_tag) const { void iterate_edges(Functor& f, Sequential_tag) const
for (const Edge_descriptor& e : octree->leaf_edges()) { {
for(const Edge_descriptor& e : octree->leaf_edges())
f(e); f(e);
} }
}
template <typename Functor> template <typename Functor>
void iterate_cells(Functor& f, Sequential_tag) const { void iterate_cells(Functor& f, Sequential_tag) const
for (const Cell_descriptor& v : octree->leaf_voxels()) { {
for(const Cell_descriptor& v : octree->leaf_voxels())
f(v); f(v);
} }
}
#ifdef CGAL_LINKED_WITH_TBB #ifdef CGAL_LINKED_WITH_TBB
template <typename Functor> template <typename Functor>
void iterate_vertices(Functor& f, Parallel_tag) const { void iterate_vertices(Functor& f, Parallel_tag) const
{
const auto& vertices = octree->leaf_vertices(); const auto& vertices = octree->leaf_vertices();
auto iterator = [&](const tbb::blocked_range<std::size_t>& r) { auto iterator = [&](const tbb::blocked_range<std::size_t>& r)
for (std::size_t i = r.begin(); i != r.end(); i++) { {
for(std::size_t i = r.begin(); i != r.end(); ++i)
f(vertices[i]); f(vertices[i]);
}
}; };
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, vertices.size()), iterator); tbb::parallel_for(tbb::blocked_range<std::size_t>(0, vertices.size()), iterator);
} }
template <typename Functor> template <typename Functor>
void iterate_edges(Functor& f, Parallel_tag) const { void iterate_edges(Functor& f, Parallel_tag) const
{
const auto& edges = octree->leaf_edges(); const auto& edges = octree->leaf_edges();
auto iterator = [&](const tbb::blocked_range<std::size_t>& r) { auto iterator = [&](const tbb::blocked_range<std::size_t>& r)
for (std::size_t i = r.begin(); i != r.end(); i++) { {
for(std::size_t i = r.begin(); i != r.end(); ++i)
f(edges[i]); f(edges[i]);
}
}; };
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, edges.size()), iterator); tbb::parallel_for(tbb::blocked_range<std::size_t>(0, edges.size()), iterator);
} }
template <typename Functor> template <typename Functor>
void iterate_cells(Functor& f, Parallel_tag) const { void iterate_cells(Functor& f, Parallel_tag) const
{
const auto& cells = octree->leaf_voxels(); const auto& cells = octree->leaf_voxels();
auto iterator = [&](const tbb::blocked_range<std::size_t>& r) { auto iterator = [&](const tbb::blocked_range<std::size_t>& r)
for (std::size_t i = r.begin(); i != r.end(); i++) { {
for(std::size_t i = r.begin(); i != r.end(); ++i)
f(cells[i]); f(cells[i]);
}
}; };
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, cells.size()), iterator); tbb::parallel_for(tbb::blocked_range<std::size_t>(0, cells.size()), iterator);
@ -134,4 +144,4 @@ private:
} // namespace Isosurfacing } // namespace Isosurfacing
} // namespace CGAL } // namespace CGAL
#endif // CGAL_OCTREE_TOPOLOGY_H #endif // CGAL_ISOSURFACING_3_INTERNAL_OCTREE_TOPOLOGY_H

View File

@ -38,8 +38,8 @@
// https://github.com/rogrosso/tmc available on 15th of September 2022. // https://github.com/rogrosso/tmc available on 15th of September 2022.
// //
#ifndef CGAL_MARCHING_CUBES_3_INTERNAL_TABLES_H #ifndef CGAL_ISOSURFACING_3_INTERNAL_TABLES_H
#define CGAL_MARCHING_CUBES_3_INTERNAL_TABLES_H #define CGAL_ISOSURFACING_3_INTERNAL_TABLES_H
#include <CGAL/license/Isosurfacing_3.h> #include <CGAL/license/Isosurfacing_3.h>
@ -74,7 +74,8 @@ 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 // 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. // 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] = { 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, 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, 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, 2}, {0, 0, -1, 6}, {0, 1, -1, 4}, {0, 1, 0, 0}}, // e2
@ -96,7 +97,8 @@ constexpr int edge_to_voxel_neighbor[N_EDGES][4][4] = {
constexpr int edge_store_index[3] = {0, 3, 8}; constexpr int edge_store_index[3] = {0, 3, 8};
// The local vertex indices of an edge. The indices are sorted by axis direction. // The local vertex indices of an edge. The indices are sorted by axis direction.
constexpr int edge_to_vertex[N_EDGES][2] = { constexpr int edge_to_vertex[N_EDGES][2] =
{
{0, 1}, // e0 {0, 1}, // e0
{1, 3}, // e1 {1, 3}, // e1
{2, 3}, // e2 {2, 3}, // e2
@ -112,7 +114,8 @@ constexpr int edge_to_vertex[N_EDGES][2] = {
}; };
// The local vertex coordinates within a voxel. // The local vertex coordinates within a voxel.
constexpr int local_vertex_position[N_VERTICES][3] = { constexpr int local_vertex_position[N_VERTICES][3] =
{
{0, 0, 0}, // v0 {0, 0, 0}, // v0
{1, 0, 0}, // v1 {1, 0, 0}, // v1
{0, 1, 0}, // v2 {0, 1, 0}, // v2
@ -137,7 +140,8 @@ constexpr int global_edge_id[][4] = {{0, 0, 0, 0}, {1, 0, 0, 1}, {0, 1, 0, 0}, {
// probably a list without errors // probably a list without errors
// indicates which edges has to be intersected // indicates which edges has to be intersected
constexpr int intersected_edges[256] = { constexpr int intersected_edges[256] =
{
0, 265, 515, 778, 2060, 2309, 2575, 2822, 1030, 1295, 1541, 1804, 3082, 3331, 3593, 3840, 400, 153, 915, 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, 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, 2111, 2358, 1590, 1855, 1077, 1340, 3642, 3891, 3129, 3376, 928, 681, 419, 170, 2988, 2725, 2479, 2214, 1958,
@ -151,10 +155,12 @@ constexpr int intersected_edges[256] = {
2505, 2240, 3232, 3497, 3747, 4010, 1196, 1445, 1711, 1958, 2214, 2479, 2725, 2988, 170, 419, 681, 928, 3376, 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, 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, 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}; 1030, 2822, 2575, 2309, 2060, 778, 515, 265, 0
};
// list of triangles for Marching Cubes case t, position at t*16 + tri // list of triangles for Marching Cubes case t, position at t*16 + tri
constexpr int triangle_cases[4096] = { 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 -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, 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 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // quitte: 2 <-> mc: 2, class rep: 1
@ -414,7 +420,8 @@ constexpr int triangle_cases[4096] = {
}; };
// list of ambiguous cases // list of ambiguous cases
constexpr int t_ambig[256] = { constexpr int t_ambig[256] =
{
0, // quitte: 0 <-> mc: 0, class representative: 0 0, // quitte: 0 <-> mc: 0, class representative: 0
1, // quitte: 1 <-> mc: 1, class representative: 1 1, // quitte: 1 <-> mc: 1, class representative: 1
2, // quitte: 2 <-> mc: 2, class representative: 1 2, // quitte: 2 <-> mc: 2, class representative: 1
@ -679,4 +686,4 @@ constexpr int t_ambig[256] = {
} // namespace Isosurfacing } // namespace Isosurfacing
} // namespace CGAL } // namespace CGAL
#endif // CGAL_MARCHING_CUBES_3_INTERNAL_TABLES_H #endif // CGAL_ISOSURFACING_3_INTERNAL_TABLES_H

View File

@ -44,18 +44,28 @@ namespace Isosurfacing {
* \param triangles each element in the vector describes a triangle using the indices of the points in `points` * \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 * \param topologically_correct decides whether the topologically correct variant of Marching Cubes should be used
*/ */
template <typename Concurrency_tag = Sequential_tag, class Domain_, class PointRange, class TriangleRange> template <typename Concurrency_tag = Sequential_tag,
void marching_cubes(const Domain_& domain, const typename Domain_::FT isovalue, PointRange& points, typename Domain_,
TriangleRange& triangles, bool topologically_correct = true) { typename PointRange,
typename TriangleRange>
if (topologically_correct) { 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 // run TMC and directly write the result to points and triangles
internal::TMC_functor<Domain_, PointRange, TriangleRange> functor(domain, isovalue, points, triangles); internal::TMC_functor<Domain_, PointRange, TriangleRange> functor(domain, isovalue, points, triangles);
domain.template iterate_cells<Concurrency_tag>(functor); domain.template iterate_cells<Concurrency_tag>(functor);
} else { }
else
{
// run MC // run MC
internal::Marching_cubes_3<Domain_> functor(domain, isovalue); internal::Marching_cubes_3<Domain_> functor(domain, isovalue);
domain.template iterate_cells<Concurrency_tag>(functor); domain.template iterate_cells<Concurrency_tag>(functor);
// copy the result to points and triangles // copy the result to points and triangles
internal::to_indexed_face_set(functor.triangles(), points, triangles); internal::to_indexed_face_set(functor.triangles(), points, triangles);
} }

View File

@ -23,7 +23,8 @@ namespace CGAL {
namespace Isosurfacing { namespace Isosurfacing {
template <typename GeomTraits> template <typename GeomTraits>
class Octree_wrapper { class Octree_wrapper
{
/* /*
* Naming convention from "A parallel dual marching cubes approach to quad * Naming convention from "A parallel dual marching cubes approach to quad
* only surface reconstruction - Grosso & Zint" * only surface reconstruction - Grosso & Zint"
@ -46,19 +47,19 @@ class Octree_wrapper {
*/ */
public: public:
typedef GeomTraits Kernel; using Kernel = GeomTraits;
typedef typename GeomTraits::FT FT; using FT = typename GeomTraits::FT;
typedef typename GeomTraits::Point_3 Point_3; using Point_3 = typename GeomTraits::Point_3;
typedef typename GeomTraits::Vector_3 Vector_3; using Vector_3 = typename GeomTraits::Vector_3;
typedef CGAL::Octree<Kernel, std::vector<Point_3>> Octree; using Octree = CGAL::Octree<Kernel, std::vector<Point_3> >;
typedef std::size_t Vertex_handle; using Vertex_handle = std::size_t;
typedef std::tuple<std::size_t, std::size_t> Edge_handle; using Edge_handle = std::tuple<std::size_t, std::size_t>;
typedef std::size_t Voxel_handle; using Voxel_handle = std::size_t;
typedef typename Octree::Node Node; using Node = typename Octree::Node;
typedef typename Node::Global_coordinates Uniform_coords; // coordinates on max depth level using Uniform_coords = typename Node::Global_coordinates; // coordinates on max depth level
private: private:
std::size_t max_depth_ = 0; std::size_t max_depth_ = 0;
@ -90,10 +91,12 @@ public:
offset_z_(bbox.zmin()), offset_z_(bbox.zmin()),
bbox_(bbox), bbox_(bbox),
point_range_({{bbox.xmin(), bbox.ymin(), bbox.zmin()}, {bbox.xmax(), bbox.ymax(), bbox.zmax()}}), point_range_({{bbox.xmin(), bbox.ymin(), bbox.zmin()}, {bbox.xmax(), bbox.ymax(), bbox.zmax()}}),
octree_(point_range_) {} octree_(point_range_)
{ }
template <class Split_predicate> template <typename Split_predicate>
void refine(const Split_predicate& split_predicate) { void refine(const Split_predicate& split_predicate)
{
namespace Tables = internal::Cube_table; namespace Tables = internal::Cube_table;
octree_.refine(split_predicate); octree_.refine(split_predicate);
@ -106,13 +109,15 @@ public:
std::set<Voxel_handle> leaf_voxels_set; std::set<Voxel_handle> leaf_voxels_set;
std::set<Edge_handle> leaf_edges_set; std::set<Edge_handle> leaf_edges_set;
std::set<Vertex_handle> leaf_vertices_set; std::set<Vertex_handle> leaf_vertices_set;
for (Node node : octree_.traverse(CGAL::Orthtrees::Leaves_traversal())) { for(Node node : octree_.traverse(CGAL::Orthtrees::Leaves_traversal()))
{
const auto& coords_uniform = uniform_coordinates(node); const auto& coords_uniform = uniform_coordinates(node);
// write all leaf nodes in a set // write all leaf nodes in a set
leaf_voxels_set.insert(lex_index(coords_uniform[0], coords_uniform[1], coords_uniform[2], max_depth_)); leaf_voxels_set.insert(lex_index(coords_uniform[0], coords_uniform[1], coords_uniform[2], max_depth_));
// init vertex values // init vertex values
for (int i = 0; i < Tables::N_VERTICES; ++i) { for(int i=0; i<Tables::N_VERTICES; ++i)
{
Uniform_coords vuc = vertex_uniform_coordinates(node, i); Uniform_coords vuc = vertex_uniform_coordinates(node, i);
const auto lex = lex_index(vuc[0], vuc[1], vuc[2], max_depth_); const auto lex = lex_index(vuc[0], vuc[1], vuc[2], max_depth_);
leaf_vertices_set.insert(lex); leaf_vertices_set.insert(lex);
@ -123,28 +128,35 @@ public:
const auto& coords_global = node.global_coordinates(); const auto& coords_global = node.global_coordinates();
const auto& depth = node.depth(); const auto& depth = node.depth();
const auto& df = depth_factor(node.depth()); const auto& df = depth_factor(node.depth());
for (const auto& edge_voxels : Tables::edge_to_voxel_neighbor) { for(const auto& edge_voxels : Tables::edge_to_voxel_neighbor)
{
bool are_all_voxels_leafs = true; bool are_all_voxels_leafs = true;
for (const auto& node_ijk : edge_voxels) { for(const auto& node_ijk : edge_voxels)
{
const std::size_t x = coords_uniform[0] + df * node_ijk[0]; 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 y = coords_uniform[1] + df * node_ijk[1];
const std::size_t z = coords_uniform[2] + df * node_ijk[2]; const std::size_t z = coords_uniform[2] + df * node_ijk[2];
// check for overflow / ignore edges on boundary // check for overflow / ignore edges on boundary
if (x >= dim_ || y >= dim_ || z >= dim_) { if(x >= dim_ || y >= dim_ || z >= dim_)
{
are_all_voxels_leafs = false; are_all_voxels_leafs = false;
break; break;
} }
const Node n = get_node(x, y, z); const Node n = get_node(x, y, z);
if (n.depth() > depth) { if(n.depth() > depth)
{
are_all_voxels_leafs = false; are_all_voxels_leafs = false;
break; break;
} }
} }
if (are_all_voxels_leafs) {
if(are_all_voxels_leafs)
{
// add to leaf edge set // add to leaf edge set
std::size_t e_gl = std::size_t e_gl = e_glIndex(edge_voxels[0][3],
e_glIndex(edge_voxels[0][3], coords_global[0], coords_global[1], coords_global[2], depth); coords_global[0], coords_global[1], coords_global[2],
depth);
leaf_edges_set.insert({e_gl, depth}); leaf_edges_set.insert({e_gl, depth});
} }
} }
@ -155,64 +167,88 @@ public:
leaf_vertices_ = std::vector<Vertex_handle>(leaf_vertices_set.begin(), leaf_vertices_set.end()); leaf_vertices_ = std::vector<Vertex_handle>(leaf_vertices_set.begin(), leaf_vertices_set.end());
} }
std::size_t dim() const { std::size_t dim() const
{
return dim_; return dim_;
} }
FT hx() const {
FT hx() const
{
return hx_; return hx_;
} }
FT offset_x() const {
FT offset_x() const
{
return offset_x_; return offset_x_;
} }
FT offset_y() const {
FT offset_y() const
{
return offset_y_; return offset_y_;
} }
FT offset_z() const {
FT offset_z() const
{
return offset_z_; return offset_z_;
} }
std::size_t max_depth() const {
std::size_t max_depth() const
{
return max_depth_; return max_depth_;
} }
const std::vector<Edge_handle>& leaf_edges() const { const std::vector<Edge_handle>& leaf_edges() const
{
return leaf_edges_; return leaf_edges_;
} }
const std::vector<Vertex_handle>& leaf_vertices() const {
const std::vector<Vertex_handle>& leaf_vertices() const
{
return leaf_vertices_; return leaf_vertices_;
} }
const std::vector<Voxel_handle>& leaf_voxels() const {
const std::vector<Voxel_handle>& leaf_voxels() const
{
return leaf_voxels_; return leaf_voxels_;
} }
FT value(const Vertex_handle& v) const { FT value(const Vertex_handle& v) const
{
return vertex_values_.at(v); return vertex_values_.at(v);
} }
FT& value(const Vertex_handle& v) {
FT& value(const Vertex_handle& v)
{
return vertex_values_[v]; return vertex_values_[v];
} }
Vector_3 gradient(const Vertex_handle& v) const { Vector_3 gradient(const Vertex_handle& v) const
{
return vertex_gradients_.at(v); return vertex_gradients_.at(v);
} }
Vector_3& gradient(const Vertex_handle& v) {
Vector_3& gradient(const Vertex_handle& v)
{
return vertex_gradients_[v]; return vertex_gradients_[v];
} }
std::size_t depth_factor(const std::size_t& depth) const { std::size_t depth_factor(const std::size_t& depth) const
{
return std::size_t(1) << (max_depth_ - depth); return std::size_t(1) << (max_depth_ - depth);
} }
Uniform_coords uniform_coordinates(const Node& node) const { Uniform_coords uniform_coordinates(const Node& node) const
{
auto coords = node.global_coordinates(); auto coords = node.global_coordinates();
const std::size_t df = depth_factor(node.depth()); const std::size_t df = depth_factor(node.depth());
for (int i = 0; i < Node::Dimension::value; ++i) { for(int i=0; i<Node::Dimension::value; ++i)
coords[i] *= df; coords[i] *= df;
}
return coords; return coords;
} }
std::array<Point_3, 8> node_points(const Node& node) const { std::array<Point_3, 8> node_points(const Node& node) const
{
auto coords = node.global_coordinates(); auto coords = node.global_coordinates();
const std::size_t df = depth_factor(node.depth()); const std::size_t df = depth_factor(node.depth());
@ -237,88 +273,110 @@ public:
return points; return points;
} }
Point_3 point(const Uniform_coords& vertex_coordinates) const { Point_3 point(const Uniform_coords& vertex_coordinates) const
{
const FT x0 = offset_x_ + vertex_coordinates[0] * hx_; const FT x0 = offset_x_ + vertex_coordinates[0] * hx_;
const FT y0 = offset_y_ + vertex_coordinates[1] * hx_; const FT y0 = offset_y_ + vertex_coordinates[1] * hx_;
const FT z0 = offset_z_ + vertex_coordinates[2] * hx_; const FT z0 = offset_z_ + vertex_coordinates[2] * hx_;
return {x0, y0, z0}; return {x0, y0, z0};
} }
Point_3 point(const Vertex_handle& v) const { Point_3 point(const Vertex_handle& v) const
{
std::size_t i, j, k; std::size_t i, j, k;
std::tie(i, j, k) = ijk_index(v, max_depth_); std::tie(i, j, k) = ijk_index(v, max_depth_);
const FT x0 = offset_x_ + i * hx_; const FT x0 = offset_x_ + i * hx_;
const FT y0 = offset_y_ + j * hx_; const FT y0 = offset_y_ + j * hx_;
const FT z0 = offset_z_ + k * hx_; const FT z0 = offset_z_ + k * hx_;
return {x0, y0, z0}; return {x0, y0, z0};
} }
Uniform_coords vertex_uniform_coordinates(const Node& node, Uniform_coords vertex_uniform_coordinates(const Node& node,
const typename Node::Local_coordinates local_coords) const { const typename Node::Local_coordinates local_coords) const
{
const auto node_coords = node.global_coordinates(); const auto node_coords = node.global_coordinates();
auto v_coords = node_coords; auto v_coords = node_coords;
for (int i = 0; i < Node::Dimension::value; ++i) { for(int i=0; i<Node::Dimension::value; ++i)
v_coords[i] += std::size_t(local_coords[i]); v_coords[i] += std::size_t(local_coords[i]);
}
const auto df = depth_factor(node.depth()); const auto df = depth_factor(node.depth());
for (int i = 0; i < Node::Dimension::value; ++i) { for(int i=0; i<Node::Dimension::value; ++i)
v_coords[i] *= df; v_coords[i] *= df;
}
return v_coords; return v_coords;
} }
Node get_node(const std::size_t& i, const std::size_t& j, const std::size_t& k) const { Node get_node(const std::size_t& i,
const std::size_t& j,
const std::size_t& k) const
{
Node node = octree_.root(); Node node = octree_.root();
const std::size_t& x = i; const std::size_t& x = i;
const std::size_t& y = j; const std::size_t& y = j;
const std::size_t& z = k; const std::size_t& z = k;
while (!node.is_leaf()) {
while(!node.is_leaf())
{
std::size_t dist_to_max = max_depth_ - node.depth() - 1; std::size_t dist_to_max = max_depth_ - node.depth() - 1;
typename Node::Local_coordinates loc; typename Node::Local_coordinates loc;
if (x & (std::size_t(1) << dist_to_max)) { if(x & (std::size_t(1) << dist_to_max))
loc[0] = true; loc[0] = true;
}
if (y & (std::size_t(1) << dist_to_max)) { if(y & (std::size_t(1) << dist_to_max))
loc[1] = true; loc[1] = true;
}
if (z & (std::size_t(1) << dist_to_max)) { if(z & (std::size_t(1) << dist_to_max))
loc[2] = true; loc[2] = true;
}
node = node[loc.to_ulong()]; node = node[loc.to_ulong()];
} }
return node; return node;
} }
Node get_node(const std::size_t lex_index) const { Node get_node(const std::size_t lex_index) const
{
std::size_t i, j, k; std::size_t i, j, k;
std::tie(i, j, k) = ijk_index(lex_index, max_depth_); std::tie(i, j, k) = ijk_index(lex_index, max_depth_);
return get_node(i, j, k); return get_node(i, j, k);
} }
std::size_t lex_index(const std::size_t& i, const std::size_t& j, const std::size_t& k, std::size_t lex_index(const std::size_t& i,
const std::size_t& depth) const { 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; std::size_t dim = (std::size_t(1) << depth) + 1;
return k * dim * dim + j * dim + i; return k * dim * dim + j * dim + i;
} }
std::size_t i_index(const std::size_t& lex_index, const std::size_t& depth) const { 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; std::size_t dim = (std::size_t(1) << depth) + 1;
return lex_index % dim; return lex_index % dim;
} }
std::size_t j_index(const std::size_t& lex_index, const std::size_t& depth) const {
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; std::size_t dim = (std::size_t(1) << depth) + 1;
return ((lex_index / dim) % dim); 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 k_index(const std::size_t& lex_index,
const std::size_t& depth) const
{
std::size_t dim = (std::size_t(1) << depth) + 1; std::size_t dim = (std::size_t(1) << depth) + 1;
return (lex_index / (dim * dim)); return (lex_index / (dim * dim));
} }
std::tuple<std::size_t, std::size_t, std::size_t> ijk_index(const std::size_t& lex_index, std::tuple<std::size_t, std::size_t, std::size_t> ijk_index(const std::size_t& lex_index,
const std::size_t& depth) const { const std::size_t& depth) const
{
const std::size_t dim = (std::size_t(1) << depth) + 1; 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)); return std::make_tuple(lex_index % dim, (lex_index / dim) % dim, lex_index / (dim * dim));
} }
@ -332,17 +390,23 @@ public:
/// <param name="k_idx">k-index of cell</param> /// <param name="k_idx">k-index of cell</param>
/// <param name="depth">depth of cell</param> /// <param name="depth">depth of cell</param>
/// <returns></returns> /// <returns></returns>
std::size_t e_glIndex(const std::size_t& e, const std::size_t& i_idx, const std::size_t& j_idx, std::size_t e_glIndex(const std::size_t& e,
const std::size_t& k_idx, const std::size_t& depth) const { 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 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 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 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 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); const size_t offs = (size_t)((gei_pattern_ >> (5 * e + 3)) & 3);
return (3 * lex_index(i, j, k, depth) + offs); return (3 * lex_index(i, j, k, depth) + offs);
} }
std::array<FT, 8> voxel_values(const Voxel_handle& vox) const { std::array<FT, 8> voxel_values(const Voxel_handle& vox) const
{
namespace Tables = internal::Cube_table; namespace Tables = internal::Cube_table;
std::size_t i, j, k; std::size_t i, j, k;
@ -351,7 +415,8 @@ public:
const auto& df = depth_factor(node.depth()); const auto& df = depth_factor(node.depth());
std::array<Vertex_handle, 8> v; std::array<Vertex_handle, 8> v;
for (int v_id = 0; v_id < Tables::N_VERTICES; ++v_id) { for(int v_id=0; v_id<Tables::N_VERTICES; ++v_id)
{
const auto& l = Tables::local_vertex_position[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_); const auto lex = lex_index(i + df * l[0], j + df * l[1], k + df * l[2], max_depth_);
v[v_id] = lex; v[v_id] = lex;
@ -363,12 +428,13 @@ public:
return s; return s;
} }
FT vertex_value(const Vertex_handle& v) const { FT vertex_value(const Vertex_handle& v) const
{
return vertex_values_.at(v); return vertex_values_.at(v);
} }
std::array<Edge_handle, 12> voxel_edges(const Voxel_handle& vox) const { std::array<Edge_handle, 12> voxel_edges(const Voxel_handle& vox) const
{
std::size_t i, j, k; std::size_t i, j, k;
std::tie(i, j, k) = ijk_index(vox, max_depth_); std::tie(i, j, k) = ijk_index(vox, max_depth_);
Node node = get_node(i, j, k); Node node = get_node(i, j, k);
@ -377,8 +443,8 @@ public:
const auto& depth = node.depth(); const auto& depth = node.depth();
std::array<Edge_handle, internal::Cube_table::N_EDGES> edges; std::array<Edge_handle, internal::Cube_table::N_EDGES> edges;
for (int e_id = 0; e_id < edges.size(); ++e_id) { for(int e_id=0; e_id<edges.size(); ++e_id)
{
const std::size_t e_gl = e_glIndex(e_id, coords_global[0], coords_global[1], coords_global[2], depth); 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}; edges[e_id] = {e_gl, depth};
} }
@ -386,7 +452,8 @@ public:
return edges; return edges;
} }
std::array<Vertex_handle, 8> voxel_vertices(const Voxel_handle& vox) const { std::array<Vertex_handle, 8> voxel_vertices(const Voxel_handle& vox) const
{
namespace Tables = internal::Cube_table; namespace Tables = internal::Cube_table;
std::size_t i, j, k; std::size_t i, j, k;
@ -395,7 +462,8 @@ public:
const auto& df = depth_factor(node.depth()); const auto& df = depth_factor(node.depth());
std::array<Vertex_handle, 8> v; std::array<Vertex_handle, 8> v;
for (int v_id = 0; v_id < Tables::N_VERTICES; ++v_id) { for(int v_id=0; v_id<Tables::N_VERTICES; ++v_id)
{
const auto& l = Tables::local_vertex_position[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_); const auto lex = lex_index(i + df * l[0], j + df * l[1], k + df * l[2], max_depth_);
v[v_id] = lex; v[v_id] = lex;
@ -404,7 +472,8 @@ public:
return v; return v;
} }
std::array<Vector_3, 8> voxel_gradients(const Voxel_handle& vox) const { std::array<Vector_3, 8> voxel_gradients(const Voxel_handle& vox) const
{
namespace Tables = internal::Cube_table; namespace Tables = internal::Cube_table;
std::size_t i, j, k; std::size_t i, j, k;
@ -413,7 +482,8 @@ public:
const auto& df = depth_factor(node.depth()); const auto& df = depth_factor(node.depth());
std::array<Vertex_handle, 8> v; std::array<Vertex_handle, 8> v;
for (int v_id = 0; v_id < Tables::N_VERTICES; ++v_id) { for(int v_id=0; v_id<Tables::N_VERTICES; ++v_id)
{
const auto& l = Tables::local_vertex_position[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_); const auto lex = lex_index(i + df * l[0], j + df * l[1], k + df * l[2], max_depth_);
v[v_id] = lex; v[v_id] = lex;
@ -424,7 +494,9 @@ public:
return s; return s;
} }
std::array<Point_3, 8> voxel_vertex_positions(const Voxel_handle& vox) const {
std::array<Point_3, 8> voxel_vertex_positions(const Voxel_handle& vox) const
{
Node node = get_node(vox); Node node = get_node(vox);
return node_points(node); return node_points(node);
} }
@ -435,7 +507,8 @@ public:
/// </summary> /// </summary>
/// <param name="e_id"></param> /// <param name="e_id"></param>
/// <returns></returns> /// <returns></returns>
std::array<FT, 2> edge_values(const Edge_handle& e_id) const { std::array<FT, 2> edge_values(const Edge_handle& e_id) const
{
namespace Tables = internal::Cube_table; namespace Tables = internal::Cube_table;
std::size_t e_global_id, depth; std::size_t e_global_id, depth;
@ -457,10 +530,11 @@ public:
const auto v0 = lex_index(df * i0, df * j0, df * k0, max_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_); const auto v1 = lex_index(df * i1, df * j1, df * k1, max_depth_);
return {value(v0), value(v1)}; return { value(v0), value(v1) };
} }
std::array<Vertex_handle, 2> edge_vertices(const Edge_handle& e_id) const { std::array<Vertex_handle, 2> edge_vertices(const Edge_handle& e_id) const
{
namespace Tables = internal::Cube_table; namespace Tables = internal::Cube_table;
std::size_t e_global_id, depth; std::size_t e_global_id, depth;
@ -482,7 +556,7 @@ public:
const auto v0 = lex_index(df * i0, df * j0, df * k0, max_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_); const auto v1 = lex_index(df * i1, df * j1, df * k1, max_depth_);
return {v0, v1}; return { v0, v1 };
} }
/// <summary> /// <summary>
@ -492,7 +566,8 @@ public:
/// </summary> /// </summary>
/// <param name="e_id"></param> /// <param name="e_id"></param>
/// <returns></returns> /// <returns></returns>
std::array<std::size_t, 4> edge_voxels(const Edge_handle& e_id) const { std::array<std::size_t, 4> edge_voxels(const Edge_handle& e_id) const
{
namespace Tables = internal::Cube_table; namespace Tables = internal::Cube_table;
std::size_t e_global_id, depth; std::size_t e_global_id, depth;

View File

@ -26,12 +26,13 @@ namespace Isosurfacing {
* *
* \tparam GeomTraits the traits for this gradient. * \tparam GeomTraits the traits for this gradient.
*/ */
template <class GeomTraits> template <typename GeomTraits>
class Zero_gradient { class Zero_gradient
{
public: public:
typedef GeomTraits Geom_traits; using Geom_traits = GeomTraits;
typedef typename Geom_traits::Point_3 Point; using Point = typename Geom_traits::Point_3;
typedef typename Geom_traits::Vector_3 Vector; using Vector = typename Geom_traits::Vector_3;
public: public:
/** /**
@ -41,7 +42,8 @@ public:
* *
* \param point the point at which the gradient is computed * \param point the point at which the gradient is computed
*/ */
Vector operator()(const Point& point) const { Vector operator()(const Point& point) const
{
return zero; return zero;
} }

View File

@ -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.

View File

@ -22,7 +22,7 @@ public:
} }
~ScopeTimer() { ~ScopeTimer() {
if (running) { if(running) {
TimePoint end = Clock::now(); TimePoint end = Clock::now();
int64_t duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count(); int64_t duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
std::cout << msg << ": " << duration << " ms" << std::endl; std::cout << msg << ": " << duration << " ms" << std::endl;

View File

@ -1,3 +1,6 @@
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Cartesian_grid_3.h> #include <CGAL/Cartesian_grid_3.h>
#include <CGAL/Dual_contouring_3.h> #include <CGAL/Dual_contouring_3.h>
#include <CGAL/Explicit_cartesian_grid_domain.h> #include <CGAL/Explicit_cartesian_grid_domain.h>
@ -5,32 +8,33 @@
#include <CGAL/Marching_cubes_3.h> #include <CGAL/Marching_cubes_3.h>
#include <CGAL/Octree_wrapper.h> #include <CGAL/Octree_wrapper.h>
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h> #include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
#include <CGAL/Simple_cartesian.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/boost/graph/IO/OFF.h> #include <CGAL/boost/graph/IO/OFF.h>
#include <CGAL/Finite_difference_gradient.h> #include <CGAL/Finite_difference_gradient.h>
#include "Timer.h" #include "Timer.h"
typedef CGAL::Simple_cartesian<double> Kernel; using Kernel = CGAL::Simple_cartesian<double>;
typedef typename Kernel::Vector_3 Vector; using Vector = typename Kernel::Vector_3;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef CGAL::Surface_mesh<Point> Mesh; using Mesh = CGAL::Surface_mesh<Point>;
typedef CGAL::Cartesian_grid_3<Kernel> Grid; using Grid CGAL::Cartesian_grid_3<Kernel>;
typedef std::vector<Point> Point_range; using Point_range = std::vector<Point>;
typedef std::vector<std::vector<std::size_t>> Polygon_range; using Polygon_range = std::vector<std::vector<std::size_t> >;
int main() { int main()
{
const Vector spacing(0.002, 0.002, 0.02); const Vector spacing(0.002, 0.002, 0.02);
const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1}; const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1};
auto sphere_function = [](const Point& point) { auto sphere_function = [](const Point& point)
{
return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z()); return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z());
}; };
typedef CGAL::Isosurfacing::Finite_difference_gradient<Kernel, decltype(sphere_function)> Gradient; using Gradient = CGAL::Isosurfacing::Finite_difference_gradient<Kernel, decltype(sphere_function)>;
auto implicit_domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>( auto implicit_domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(
bbox, spacing, sphere_function, Gradient(sphere_function, 0.0001)); bbox, spacing, sphere_function, Gradient(sphere_function, 0.0001));
@ -41,11 +45,12 @@ int main() {
std::shared_ptr<Grid> grid = std::make_shared<Grid>(nx, ny, nz, bbox); std::shared_ptr<Grid> grid = std::make_shared<Grid>(nx, ny, nz, bbox);
for (std::size_t x = 0; x < grid->xdim(); x++) { for(std::size_t x=0; x<grid->xdim(); ++x) {
for (std::size_t y = 0; y < grid->ydim(); y++) { for(std::size_t y=0; y<grid->ydim(); ++y) {
for (std::size_t z = 0; z < grid->zdim(); z++) { for(std::size_t z=0; z<grid->zdim(); ++z)
{
const Point pos(x * spacing.x() + bbox.xmin(), y * spacing.y() + bbox.ymin(), const Point pos(x * spacing.x() + bbox.xmin(),
y * spacing.y() + bbox.ymin(),
z * spacing.z() + bbox.zmin()); z * spacing.z() + bbox.zmin());
grid->value(x, y, z) = sphere_function(pos); grid->value(x, y, z) = sphere_function(pos);
@ -54,9 +59,10 @@ int main() {
} }
const std::string fname = "../data/skull_2.9.inr"; const std::string fname = "../data/skull_2.9.inr";
// Load image // Load image
// CGAL::Image_3 image; // CGAL::Image_3 image;
// if (!image.read(fname)) { // if(!image.read(fname)) {
// std::cerr << "Error: Cannot read file " << fname << std::endl; // std::cerr << "Error: Cannot read file " << fname << std::endl;
// return EXIT_FAILURE; // return EXIT_FAILURE;
//} //}
@ -72,7 +78,7 @@ int main() {
CGAL::Isosurfacing::dual_contouring<CGAL::Parallel_tag>(implicit_domain, 0.8f, points, polygons); CGAL::Isosurfacing::dual_contouring<CGAL::Parallel_tag>(implicit_domain, 0.8f, points, polygons);
} }
// TODO: compare results with mesh_3 // @todo compare results with mesh_3
// Mesh mesh; // Mesh mesh;
// CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, mesh); // CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, mesh);

View File

@ -5,18 +5,25 @@
#define WRITE_OFF #define WRITE_OFF
struct Sphere_function { struct Sphere_function
FT operator()(const Point& point) const { {
FT operator()(const Point& point) const
{
return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z()); return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z());
} }
}; };
template <class Domain_> template <typename Domain_>
void run(const Domain_& domain, const FT isovalue, Point_range& points, Polygon_range& polygons) { void run(const Domain_& domain,
const FT isovalue,
Point_range& points,
Polygon_range& polygons)
{
CGAL::Isosurfacing::marching_cubes<CGAL::Parallel_tag>(domain, isovalue, points, polygons); CGAL::Isosurfacing::marching_cubes<CGAL::Parallel_tag>(domain, isovalue, points, polygons);
} }
void test_implicit_sphere() { void test_implicit_sphere()
{
const std::string test_name = "test_implicit_sphere()"; const std::string test_name = "test_implicit_sphere()";
const Vector spacing(0.2, 0.2, 0.2); const Vector spacing(0.2, 0.2, 0.2);
@ -41,7 +48,8 @@ void test_implicit_sphere() {
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) { void test_grid_sphere(const std::size_t n)
{
const std::string test_name = "test_grid_sphere(" + std::to_string(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 CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1};
@ -51,11 +59,12 @@ void test_grid_sphere(const std::size_t n) {
std::shared_ptr<Grid> grid = std::make_shared<Grid>(n, n, n, bbox); std::shared_ptr<Grid> grid = std::make_shared<Grid>(n, n, n, bbox);
for (std::size_t x = 0; x < grid->xdim(); x++) { for(std::size_t x=0; x<grid->xdim(); ++x) {
for (std::size_t y = 0; y < grid->ydim(); y++) { for(std::size_t y=0; y<grid->ydim(); ++y) {
for (std::size_t z = 0; z < grid->zdim(); z++) { for(std::size_t z=0; z<grid->zdim(); ++z)
{
const Point pos(x * spacing.x() + bbox.xmin(), y * spacing.y() + bbox.ymin(), const Point pos(x * spacing.x() + bbox.xmin(),
y * spacing.y() + bbox.ymin(),
z * spacing.z() + bbox.zmin()); z * spacing.z() + bbox.zmin());
grid->value(x, y, z) = sphere_function(pos); grid->value(x, y, z) = sphere_function(pos);
@ -82,7 +91,8 @@ void test_grid_sphere(const std::size_t n) {
std::cout << "Test passed: " << test_name << std::endl; std::cout << "Test passed: " << test_name << std::endl;
} }
int main() { int main()
{
test_implicit_sphere(); test_implicit_sphere();
test_grid_sphere(2); test_grid_sphere(2);
test_grid_sphere(3); test_grid_sphere(3);

View File

@ -1,8 +1,10 @@
#ifndef CGAL_ISOSURFACING_TEST_UTIL_H #ifndef CGAL_ISOSURFACING_TEST_UTIL_H
#define CGAL_ISOSURFACING_TEST_UTIL_H #define CGAL_ISOSURFACING_TEST_UTIL_H
#include <CGAL/Cartesian_grid_3.h>
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h> #include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Surface_mesh.h>
#include <CGAL/Cartesian_grid_3.h>
#include <CGAL/Explicit_cartesian_grid_domain.h> #include <CGAL/Explicit_cartesian_grid_domain.h>
#include <CGAL/Implicit_cartesian_grid_domain.h> #include <CGAL/Implicit_cartesian_grid_domain.h>
#include <CGAL/Polygon_mesh_processing/distance.h> #include <CGAL/Polygon_mesh_processing/distance.h>
@ -10,56 +12,63 @@
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h> #include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
#include <CGAL/Polygon_mesh_processing/repair.h> #include <CGAL/Polygon_mesh_processing/repair.h>
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h> #include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
#include <CGAL/Surface_mesh.h>
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel; using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
typedef typename Kernel::FT FT; using FT = typename Kernel::FT;
typedef typename Kernel::Vector_3 Vector; using Vector = typename Kernel::Vector_3;
typedef typename Kernel::Point_3 Point; using Point = typename Kernel::Point_3;
typedef CGAL::Surface_mesh<Point> Mesh; using Mesh = CGAL::Surface_mesh<Point>;
typedef CGAL::Cartesian_grid_3<Kernel> Grid; using Grid = CGAL::Cartesian_grid_3<Kernel>;
typedef std::vector<Point> Point_range; using Point_range = std::vector<Point>;
typedef std::vector<std::vector<std::size_t>> Polygon_range; using Polygon_range = std::vector<std::vector<std::size_t> >;
namespace PMP = CGAL::Polygon_mesh_processing; namespace PMP = CGAL::Polygon_mesh_processing;
bool has_duplicate_points(Point_range points, Polygon_range polygons) { bool has_duplicate_points(Point_range points, Polygon_range polygons)
{
return PMP::merge_duplicate_points_in_polygon_soup(points, polygons) != 0; return PMP::merge_duplicate_points_in_polygon_soup(points, polygons) != 0;
} }
bool has_duplicate_polygons(Point_range points, Polygon_range polygons) { bool has_duplicate_polygons(Point_range points, Polygon_range polygons)
{
return PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons) != 0; return PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons) != 0;
} }
bool has_isolated_vertices(Point_range points, Polygon_range polygons) { bool has_isolated_vertices(Point_range points, Polygon_range polygons)
{
return PMP::remove_isolated_points_in_polygon_soup(points, polygons) != 0; return PMP::remove_isolated_points_in_polygon_soup(points, polygons) != 0;
} }
bool is_polygon_mesh(const Polygon_range& polygons) { bool is_polygon_mesh(const Polygon_range& polygons)
{
return PMP::is_polygon_soup_a_polygon_mesh(polygons); return PMP::is_polygon_soup_a_polygon_mesh(polygons);
} }
Mesh to_mesh(const Point_range& points, const Polygon_range& polygons) { Mesh to_mesh(const Point_range& points, const Polygon_range& polygons)
{
Mesh m; Mesh m;
PMP::polygon_soup_to_polygon_mesh(points, polygons, m); PMP::polygon_soup_to_polygon_mesh(points, polygons, m);
return m; return m;
} }
bool is_manifold(Mesh& m) { bool is_manifold(Mesh& m)
{
return PMP::duplicate_non_manifold_vertices(m, CGAL::parameters::dry_run(true)) == 0; return PMP::duplicate_non_manifold_vertices(m, CGAL::parameters::dry_run(true)) == 0;
} }
bool has_degenerate_faces(Mesh& m) { bool has_degenerate_faces(Mesh& m)
{
return PMP::remove_connected_components_of_negligible_size( return PMP::remove_connected_components_of_negligible_size(
m, CGAL::parameters::dry_run(true).area_threshold(std::numeric_limits<FT>::epsilon())) != 0; m, CGAL::parameters::dry_run(true).area_threshold(std::numeric_limits<FT>::epsilon())) != 0;
} }
bool check_mesh_distance(const Mesh& m0, const Mesh& m1) { bool check_mesh_distance(const Mesh& m0, const Mesh& m1)
{
auto dist = PMP::approximate_Hausdorff_distance<CGAL::Sequential_tag>( auto dist = PMP::approximate_Hausdorff_distance<CGAL::Sequential_tag>(
m0, m1, CGAL::parameters::number_of_points_per_area_unit(4000)); m0, m1, CGAL::parameters::number_of_points_per_area_unit(4000));
std::cout << dist << std::endl; std::cout << dist << std::endl;