mirror of https://github.com/CGAL/cgal
4 --> 2 spaces indentation and "typedef" --> "using"
This commit is contained in:
parent
c51bd444e1
commit
93a59fcd77
|
|
@ -1,5 +1,6 @@
|
|||
/*!
|
||||
\ingroup PkgIsosurfacing3Concepts
|
||||
|
||||
\cgalConcept
|
||||
|
||||
The concept `IsosurfacingDomain` describes the set of requirements to be
|
||||
|
|
@ -7,171 +8,169 @@ fulfilled by any class used as input data for any isosurfacing algorithms.
|
|||
|
||||
\cgalHasModel `CGAL::Isosurfacing::Explicit_cartesian_grid_domain`
|
||||
\cgalHasModel `CGAL::Isosurfacing::Implicit_cartesian_grid_domain`
|
||||
|
||||
*/
|
||||
|
||||
class IsosurfacingDomain {
|
||||
class IsosurfacingDomain
|
||||
{
|
||||
public:
|
||||
/// \name Types
|
||||
/// @{
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Traits type model of \cgal %Kernel
|
||||
*/
|
||||
typedef unspecified_type Geom_traits;
|
||||
/*!
|
||||
Traits type model of \cgal %Kernel
|
||||
*/
|
||||
typedef unspecified_type Geom_traits;
|
||||
|
||||
/*!
|
||||
The scalar type.
|
||||
*/
|
||||
typedef unspecified_type FT;
|
||||
/*!
|
||||
The scalar type.
|
||||
*/
|
||||
typedef unspecified_type FT;
|
||||
|
||||
/*!
|
||||
The point type.
|
||||
*/
|
||||
typedef unspecified_type Point;
|
||||
/*!
|
||||
The point type.
|
||||
*/
|
||||
typedef unspecified_type Point;
|
||||
|
||||
/*!
|
||||
A descriptor to uniquely identify a vertex.
|
||||
*/
|
||||
typedef unspecified_type Vertex_descriptor;
|
||||
/*!
|
||||
A descriptor to uniquely identify a vertex.
|
||||
*/
|
||||
typedef unspecified_type Vertex_descriptor;
|
||||
|
||||
/*!
|
||||
A descriptor to uniquely identify an edge.
|
||||
*/
|
||||
typedef unspecified_type Edge_descriptor;
|
||||
/*!
|
||||
A descriptor to uniquely identify an edge.
|
||||
*/
|
||||
typedef unspecified_type Edge_descriptor;
|
||||
|
||||
/*!
|
||||
A descriptor to uniquely identify a cell.
|
||||
*/
|
||||
typedef unspecified_type Cell_descriptor;
|
||||
/*!
|
||||
A descriptor to uniquely identify a cell.
|
||||
*/
|
||||
typedef unspecified_type Cell_descriptor;
|
||||
|
||||
/*!
|
||||
A container for the two vertices of an edge.
|
||||
Must be a model of the concept `RandomAccessContainer` with size 2 whose value type is `Vertex_descriptor`.
|
||||
*/
|
||||
typedef unspecified_type Vertices_incident_to_edge;
|
||||
/*!
|
||||
A container for the two vertices of an edge.
|
||||
Must be a model of the concept `RandomAccessContainer` with size 2 whose value type is `Vertex_descriptor`.
|
||||
*/
|
||||
typedef unspecified_type Vertices_incident_to_edge;
|
||||
|
||||
/*!
|
||||
A container for the cells incident to an edge.
|
||||
Must be a model of the concept `Container` whose value type is `Cell_descriptor`.
|
||||
*/
|
||||
typedef unspecified_type Cells_incident_to_edge;
|
||||
/*!
|
||||
A container for the cells incident to an edge.
|
||||
Must be a model of the concept `Container` whose value type is `Cell_descriptor`.
|
||||
*/
|
||||
typedef unspecified_type Cells_incident_to_edge;
|
||||
|
||||
/*!
|
||||
A container for the vertices of a cell.
|
||||
Must be a model of the concept `Container` whose value type is `Vertex_descriptor`.
|
||||
*/
|
||||
typedef unspecified_type Cell_vertices;
|
||||
/*!
|
||||
A container for the vertices of a cell.
|
||||
Must be a model of the concept `Container` whose value type is `Vertex_descriptor`.
|
||||
*/
|
||||
typedef unspecified_type Cell_vertices;
|
||||
|
||||
/*!
|
||||
A container for the edges of a cell.
|
||||
Must be a model of the concept `Container` whose value type is `Edge_descriptor`.
|
||||
*/
|
||||
typedef unspecified_type Cell_edges;
|
||||
/*!
|
||||
A container for the edges of a cell.
|
||||
Must be a model of the concept `Container` whose value type is `Edge_descriptor`.
|
||||
*/
|
||||
typedef unspecified_type Cell_edges;
|
||||
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
|
||||
/// \name Operations
|
||||
/// The following member functions must exist.
|
||||
/// @{
|
||||
/// \name Operations
|
||||
/// The following member functions must exist.
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Get the position of a vertex in 3D space
|
||||
/*!
|
||||
Get the position of a vertex in 3D space
|
||||
|
||||
\param v the descriptor of the vertex
|
||||
\param v the descriptor of the vertex
|
||||
|
||||
\return the position of the vertex as a point
|
||||
*/
|
||||
Point position(const Vertex_descriptor& v) const;
|
||||
\return the position of the vertex as a point
|
||||
*/
|
||||
Point position(const Vertex_descriptor& v) const;
|
||||
|
||||
/*!
|
||||
Get the value of the function at a vertex
|
||||
/*!
|
||||
Get the value of the function at a vertex
|
||||
|
||||
\param v the descriptor of the vertex
|
||||
\param v the descriptor of the vertex
|
||||
|
||||
\return the value of the function
|
||||
*/
|
||||
FT value(const Vertex_descriptor& v) const;
|
||||
\return the value of the function
|
||||
*/
|
||||
FT value(const Vertex_descriptor& v) const;
|
||||
|
||||
/*!
|
||||
Get the two vertices incident to an edge
|
||||
/*!
|
||||
Get the two vertices incident to an edge
|
||||
|
||||
\param e the descriptor of the edge
|
||||
\param e the descriptor of the edge
|
||||
|
||||
\return a collection of the two vertex descriptors
|
||||
*/
|
||||
Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const;
|
||||
\return a collection of the two vertex descriptors
|
||||
*/
|
||||
Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const;
|
||||
|
||||
/*!
|
||||
Get all cells incident to an edge
|
||||
/*!
|
||||
Get all cells incident to an edge
|
||||
|
||||
\param e the descriptor of the edge
|
||||
\param e the descriptor of the edge
|
||||
|
||||
\return a collection of cell descriptors
|
||||
*/
|
||||
Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const;
|
||||
\return a collection of cell descriptors
|
||||
*/
|
||||
Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const;
|
||||
|
||||
/*!
|
||||
Get all vertices of the a cell
|
||||
/*!
|
||||
Get all vertices of the a cell
|
||||
|
||||
\param c the descriptor of the cell
|
||||
\param c the descriptor of the cell
|
||||
|
||||
\return a collection of vertex descriptors
|
||||
*/
|
||||
Cell_vertices cell_vertices(const Cell_descriptor& c) const;
|
||||
\return a collection of vertex descriptors
|
||||
*/
|
||||
Cell_vertices cell_vertices(const Cell_descriptor& c) const;
|
||||
|
||||
/*!
|
||||
Get all edges of the cell c
|
||||
/*!
|
||||
Get all edges of the cell c
|
||||
|
||||
\param c the descriptor of the cell
|
||||
\param c the descriptor of the cell
|
||||
|
||||
\return a collection of edge descriptors
|
||||
*/
|
||||
Cell_edges cell_edges(const Cell_descriptor& c) const;
|
||||
\return a collection of edge descriptors
|
||||
*/
|
||||
Cell_edges cell_edges(const Cell_descriptor& c) const;
|
||||
|
||||
/*!
|
||||
Iterate over all vertices and call a functor on each one
|
||||
/*!
|
||||
Iterate over all vertices and call a functor on each one
|
||||
|
||||
/tparam Concurrency_tag decides if the vertices are iterated sequentially or in parallel.
|
||||
Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`.
|
||||
Only the sequential version has to be implemented. The parallel version is optional.
|
||||
/tparam Concurrency_tag decides if the vertices are iterated sequentially or in parallel.
|
||||
Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`.
|
||||
Only the sequential version has to be implemented. The parallel version is optional.
|
||||
|
||||
/tparam Functor must implement `void operator()(const Vertex_descriptor& vertex)`
|
||||
/tparam Functor must implement `void operator()(const Vertex_descriptor& vertex)`
|
||||
|
||||
\param f the functor called with every vertex
|
||||
*/
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_vertices(Functor& f) const;
|
||||
\param f the functor called with every vertex
|
||||
*/
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_vertices(Functor& f) const;
|
||||
|
||||
/*!
|
||||
Iterate over all edges and call the functor f on each one
|
||||
/*!
|
||||
Iterate over all edges and call the functor f on each one
|
||||
|
||||
/tparam Concurrency_tag decides if the edges are iterated sequentially or in parallel.
|
||||
Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`.
|
||||
Only the sequential version has to be implemented. The parallel version is optional.
|
||||
/tparam Concurrency_tag decides if the edges are iterated sequentially or in parallel.
|
||||
Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`.
|
||||
Only the sequential version has to be implemented. The parallel version is optional.
|
||||
|
||||
/tparam Functor must implement `void operator()(const Edge_descriptor& edge)`.
|
||||
/tparam Functor must implement `void operator()(const Edge_descriptor& edge)`.
|
||||
|
||||
\param f the functor called with every edge
|
||||
*/
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_edges(Functor& f) const;
|
||||
\param f the functor called with every edge
|
||||
*/
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_edges(Functor& f) const;
|
||||
|
||||
/*!
|
||||
Iterate sequentially over all cells and call the functor f on each one
|
||||
/*!
|
||||
Iterate sequentially over all cells and call the functor f on each one
|
||||
|
||||
/tparam Concurrency_tag decides if the cells are iterated sequentially or in parallel.
|
||||
Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`.
|
||||
Only the sequential version has to be implemented. The parallel version is optional.
|
||||
/tparam Concurrency_tag decides if the cells are iterated sequentially or in parallel.
|
||||
Can be either `CGAL::Sequential_tag` or `CGAL::Parallel_tag`.
|
||||
Only the sequential version has to be implemented. The parallel version is optional.
|
||||
|
||||
/tparam Functor must implement `void operator()(const Cell_descriptor& cell)`.
|
||||
/tparam Functor must implement `void operator()(const Cell_descriptor& cell)`.
|
||||
|
||||
\param f the functor called with every cell
|
||||
*/
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_cells(Functor& f) const;
|
||||
\param f the functor called with every cell
|
||||
*/
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_cells(Functor& f) const;
|
||||
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
/*!
|
||||
\ingroup PkgIsosurfacing3Concepts
|
||||
|
||||
\cgalConcept
|
||||
|
||||
The concept `IsosurfacingDomainWithGradient` describes the set of requirements to be
|
||||
|
|
@ -7,33 +8,33 @@ fulfilled by any class used as input data for some isosurfacing algorithms.
|
|||
|
||||
\cgalHasModel `CGAL::Isosurfacing::Explicit_cartesian_grid_domain`
|
||||
\cgalHasModel `CGAL::Isosurfacing::Implicit_cartesian_grid_domain`
|
||||
|
||||
*/
|
||||
|
||||
class IsosurfacingDomainWithGradient : public IsosurfacingDomain {
|
||||
class IsosurfacingDomainWithGradient
|
||||
: public IsosurfacingDomain
|
||||
{
|
||||
public:
|
||||
/// \name Types
|
||||
/// @{
|
||||
/// \name Types
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
The vector type.
|
||||
*/
|
||||
typedef unspecified_type Vector;
|
||||
/*!
|
||||
The vector type.
|
||||
*/
|
||||
typedef unspecified_type Vector;
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
|
||||
/// \name Operations
|
||||
/// The following member function must exist.
|
||||
/// @{
|
||||
/// \name Operations
|
||||
/// The following member function must exist.
|
||||
/// @{
|
||||
|
||||
/*!
|
||||
Get the gradient at a position
|
||||
/*!
|
||||
Get the gradient at a position
|
||||
|
||||
\param p the point at which the gradient is evaluated
|
||||
\param p the point at which the gradient is evaluated
|
||||
|
||||
\return the gradient vector
|
||||
*/
|
||||
Vector gradient(const Point& p) const;
|
||||
\return the gradient vector
|
||||
*/
|
||||
Vector gradient(const Point& p) const;
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,82 +1,87 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/Cartesian_grid_3.h>
|
||||
#include <CGAL/Dual_contouring_3.h>
|
||||
#include <CGAL/Explicit_cartesian_grid_domain.h>
|
||||
#include <CGAL/Marching_cubes_3.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/boost/graph/IO/OFF.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = typename Kernel::FT;
|
||||
using Point = typename Kernel::Point_3;
|
||||
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;
|
||||
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> >;
|
||||
|
||||
// return 1.0 if value has positive sign, and -1.0 otherwise
|
||||
FT sign(FT value) {
|
||||
return (value > 0.0) - (value < 0.0);
|
||||
FT sign(FT value)
|
||||
{
|
||||
return (value > 0.0) - (value < 0.0);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// create a cartesian grid with 7^3 grid points and the bounding box [-1, 1]^3
|
||||
const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
|
||||
std::shared_ptr<Grid> grid = std::make_shared<Grid>(7, 7, 7, bbox);
|
||||
int main()
|
||||
{
|
||||
// create a cartesian grid with 7^3 grid points and the bounding box [-1, 1]^3
|
||||
const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
|
||||
std::shared_ptr<Grid> grid = std::make_shared<Grid>(7, 7, 7, bbox);
|
||||
|
||||
// calculate the value at all grid points
|
||||
for (std::size_t x = 0; x < grid->xdim(); x++) {
|
||||
for (std::size_t y = 0; y < grid->ydim(); y++) {
|
||||
for (std::size_t z = 0; z < grid->zdim(); z++) {
|
||||
// calculate the value at all grid points
|
||||
for(std::size_t x=0; x<grid->xdim(); ++x) {
|
||||
for(std::size_t y=0; y<grid->ydim(); ++y) {
|
||||
for(std::size_t z=0; z<grid->zdim(); ++z)
|
||||
{
|
||||
const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin();
|
||||
const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin();
|
||||
const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin();
|
||||
|
||||
const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin();
|
||||
const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin();
|
||||
const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin();
|
||||
|
||||
// manhattan distance to the origin
|
||||
grid->value(x, y, z) = std::max({std::abs(pos_x), std::abs(pos_y), std::abs(pos_z)});
|
||||
}
|
||||
}
|
||||
// manhattan distance to the origin
|
||||
grid->value(x, y, z) = std::max({std::abs(pos_x), std::abs(pos_y), std::abs(pos_z)});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compute function gradient
|
||||
auto cube_gradient = [](const Point& p) {
|
||||
// the normal depends on the side of the cube
|
||||
const FT max_value = std::max({std::abs(p.x()), std::abs(p.y()), std::abs(p.z())});
|
||||
// compute function gradient
|
||||
auto cube_gradient = [](const Point& p)
|
||||
{
|
||||
// the normal depends on the side of the cube
|
||||
const FT max_value = std::max({std::abs(p.x()), std::abs(p.y()), std::abs(p.z())});
|
||||
|
||||
Vector g(0.0, 0.0, 0.0);
|
||||
if (max_value == std::abs(p.x())) {
|
||||
g += Vector(sign(p.x()), 0.0, 0.0);
|
||||
}
|
||||
if (max_value == std::abs(p.y())) {
|
||||
g += Vector(0.0, sign(p.y()), 0.0);
|
||||
}
|
||||
if (max_value == std::abs(p.z())) {
|
||||
g += Vector(0.0, 0.0, sign(p.z()));
|
||||
}
|
||||
const FT length_sq = g.squared_length();
|
||||
if (length_sq > 0.00001) {
|
||||
g /= CGAL::approximate_sqrt(length_sq);
|
||||
}
|
||||
return g;
|
||||
};
|
||||
Vector g(0.0, 0.0, 0.0);
|
||||
if(max_value == std::abs(p.x()))
|
||||
g += Vector(sign(p.x()), 0.0, 0.);
|
||||
|
||||
// create domain from given grid and gradient
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid, cube_gradient);
|
||||
if(max_value == std::abs(p.y()))
|
||||
g += Vector(0.0, sign(p.y()), 0.0);
|
||||
|
||||
// containers for output indexed surface meshes
|
||||
Point_range points_mc, points_dc;
|
||||
Polygon_range polygons_mc, polygons_dc;
|
||||
if(max_value == std::abs(p.z()))
|
||||
g += Vector(0.0, 0.0, sign(p.z()));
|
||||
|
||||
// run topologically correct marching cubes and dual contouring with given isovalue
|
||||
const FT isovalue = 0.88;
|
||||
CGAL::Isosurfacing::marching_cubes(domain, isovalue, points_mc, polygons_mc, true);
|
||||
CGAL::Isosurfacing::dual_contouring(domain, isovalue, points_dc, polygons_dc);
|
||||
const FT length_sq = g.squared_length();
|
||||
if(length_sq > 0.00001)
|
||||
g /= CGAL::approximate_sqrt(length_sq);
|
||||
|
||||
// save output indexed meshes to files, in the OFF format
|
||||
CGAL::IO::write_OFF("result_mc.off", points_mc, polygons_mc);
|
||||
CGAL::IO::write_OFF("result_dc.off", points_dc, polygons_dc);
|
||||
return g;
|
||||
};
|
||||
|
||||
return 0;
|
||||
// create domain from given grid and gradient
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid, cube_gradient);
|
||||
|
||||
// containers for output indexed surface meshes
|
||||
Point_range points_mc, points_dc;
|
||||
Polygon_range polygons_mc, polygons_dc;
|
||||
|
||||
// run topologically correct marching cubes and dual contouring with given isovalue
|
||||
const FT isovalue = 0.88;
|
||||
CGAL::Isosurfacing::marching_cubes(domain, isovalue, points_mc, polygons_mc, true);
|
||||
CGAL::Isosurfacing::dual_contouring(domain, isovalue, points_dc, polygons_dc);
|
||||
|
||||
// save output indexed meshes to files, in the OFF format
|
||||
CGAL::IO::write_OFF("result_mc.off", points_mc, polygons_mc);
|
||||
CGAL::IO::write_OFF("result_dc.off", points_dc, polygons_dc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,58 +1,60 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/Cartesian_grid_3.h>
|
||||
#include <CGAL/Explicit_cartesian_grid_gradient.h>
|
||||
#include <CGAL/Dual_contouring_3.h>
|
||||
#include <CGAL/Explicit_cartesian_grid_domain.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/boost/graph/IO/OFF.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = typename Kernel::FT;
|
||||
using Point = typename Kernel::Point_3;
|
||||
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;
|
||||
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> >;
|
||||
|
||||
int main() {
|
||||
int main()
|
||||
{
|
||||
// create bounding box and grid
|
||||
const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
|
||||
std::shared_ptr<Grid> grid = std::make_shared<Grid>(30, 30, 30, bbox);
|
||||
|
||||
// create bounding box and grid
|
||||
const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
|
||||
std::shared_ptr<Grid> grid = std::make_shared<Grid>(30, 30, 30, bbox);
|
||||
// compute field values and gradients
|
||||
for(std::size_t x=0; x<grid->xdim(); ++x) {
|
||||
for(std::size_t y=0; y<grid->ydim(); ++y) {
|
||||
for(std::size_t z=0; z<grid->zdim(); ++z)
|
||||
{
|
||||
const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin();
|
||||
const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin();
|
||||
const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin();
|
||||
|
||||
// compute field values and gradients
|
||||
for (std::size_t x = 0; x < grid->xdim(); x++) {
|
||||
for (std::size_t y = 0; y < grid->ydim(); y++) {
|
||||
for (std::size_t z = 0; z < grid->zdim(); z++) {
|
||||
const Vector direction(pos_x, pos_y, pos_z);
|
||||
const FT distance = CGAL::approximate_sqrt(direction.squared_length());
|
||||
|
||||
const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin();
|
||||
const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin();
|
||||
const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin();
|
||||
|
||||
const Vector direction(pos_x, pos_y, pos_z);
|
||||
const FT distance = CGAL::approximate_sqrt(direction.squared_length());
|
||||
|
||||
grid->value(x, y, z) = distance;
|
||||
grid->gradient(x, y, z) = direction / distance; // TODO: check division / 0
|
||||
}
|
||||
}
|
||||
grid->value(x, y, z) = distance;
|
||||
grid->gradient(x, y, z) = direction / distance; // @todo check division / 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// gradient field
|
||||
CGAL::Isosurfacing::Explicit_cartesian_grid_gradient<Kernel> gradient(grid);
|
||||
// gradient field
|
||||
CGAL::Isosurfacing::Explicit_cartesian_grid_gradient<Kernel> gradient(grid);
|
||||
|
||||
// create domain from scalar and gradient fields
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid, gradient);
|
||||
// create domain from scalar and gradient fields
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid, gradient);
|
||||
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// run dual contouring isosurfacing
|
||||
CGAL::Isosurfacing::dual_contouring(domain, 0.8, points, polygons);
|
||||
// run dual contouring isosurfacing
|
||||
CGAL::Isosurfacing::dual_contouring(domain, 0.8, points, polygons);
|
||||
|
||||
// write output indexed surface mesh to file, in OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
// write output indexed surface mesh to file, in OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +1,59 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/Dual_contouring_3.h>
|
||||
#include <CGAL/Implicit_cartesian_grid_domain.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/boost/graph/IO/OFF.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = typename Kernel::FT;
|
||||
using Vector = typename Kernel::Vector_3;
|
||||
using Point = typename Kernel::Point_3;
|
||||
|
||||
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> >;
|
||||
|
||||
int main()
|
||||
{
|
||||
const FT alpha = 5.01;
|
||||
|
||||
int main() {
|
||||
const FT alpha = 5.01;
|
||||
auto iwp_value = [alpha](const Point& point)
|
||||
{
|
||||
const FT x = alpha * (point.x() + 1) * CGAL_PI;
|
||||
const FT y = alpha * (point.y() + 1) * CGAL_PI;
|
||||
const FT z = alpha * (point.z() + 1) * CGAL_PI;
|
||||
return cos(x) * cos(y) + cos(y) * cos(z) + cos(z) * cos(x) - cos(x) * cos(y) * cos(z); // isovalue = 0
|
||||
};
|
||||
|
||||
auto iwp_value = [alpha](const Point& point) {
|
||||
const FT x = alpha * (point.x() + 1) * CGAL_PI;
|
||||
const FT y = alpha * (point.y() + 1) * CGAL_PI;
|
||||
const FT z = alpha * (point.z() + 1) * CGAL_PI;
|
||||
return cos(x) * cos(y) + cos(y) * cos(z) + cos(z) * cos(x) - cos(x) * cos(y) * cos(z); // isovalue = 0
|
||||
};
|
||||
auto iwp_gradient = [alpha](const Point& point)
|
||||
{
|
||||
const FT x = alpha * (point.x() + 1) * CGAL_PI;
|
||||
const FT y = alpha * (point.y() + 1) * CGAL_PI;
|
||||
const FT z = alpha * (point.z() + 1) * CGAL_PI;
|
||||
|
||||
auto iwp_gradient = [alpha](const Point& point) {
|
||||
const FT x = alpha * (point.x() + 1) * CGAL_PI;
|
||||
const FT y = alpha * (point.y() + 1) * CGAL_PI;
|
||||
const FT z = alpha * (point.z() + 1) * CGAL_PI;
|
||||
const FT gx = CGAL_PI * alpha * sin(x) * (cos(y) * (cos(z) - 1.0) - cos(z));
|
||||
const FT gy = CGAL_PI * alpha * sin(y) * (cos(x) * (cos(z) - 1.0) - cos(z));
|
||||
const FT gz = CGAL_PI * alpha * sin(z) * (cos(x) * (cos(y) - 1.0) - cos(y));
|
||||
return Vector(gx, gy, gz);
|
||||
};
|
||||
|
||||
const FT gx = CGAL_PI * alpha * sin(x) * (cos(y) * (cos(z) - 1.0) - cos(z));
|
||||
const FT gy = CGAL_PI * alpha * sin(y) * (cos(x) * (cos(z) - 1.0) - cos(z));
|
||||
const FT gz = CGAL_PI * alpha * sin(z) * (cos(x) * (cos(y) - 1.0) - cos(y));
|
||||
return Vector(gx, gy, gz);
|
||||
};
|
||||
const CGAL::Bbox_3 bbox{-1.0, -1.0, -1.0, 1.0, 1.0, 1.0};
|
||||
const FT spacing = 0.5;
|
||||
const Vector vec_spacing(spacing, spacing, spacing);
|
||||
|
||||
const CGAL::Bbox_3 bbox{-1.0, -1.0, -1.0, 1.0, 1.0, 1.0};
|
||||
const FT spacing = 0.5;
|
||||
const Vector vec_spacing(spacing, spacing, spacing);
|
||||
// create a domain with given bounding box and grid spacing
|
||||
auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, vec_spacing, iwp_value, iwp_gradient);
|
||||
|
||||
// create a domain with given bounding box and grid spacing
|
||||
auto domain =
|
||||
CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, vec_spacing, iwp_value, iwp_gradient);
|
||||
// prepare collections for the result
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// prepare collections for the result
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
// run marching cubes with an isovalue of 0.0
|
||||
CGAL::Isosurfacing::dual_contouring(domain, 0.0, points, polygons);
|
||||
|
||||
// run marching cubes with an isovalue of 0.0
|
||||
CGAL::Isosurfacing::dual_contouring(domain, 0.0, points, polygons);
|
||||
// save the result in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
|
||||
// save the result in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,76 +1,83 @@
|
|||
#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_traits.h>
|
||||
#include <CGAL/AABB_tree.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/Simple_cartesian.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/boost/graph/IO/OFF.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = typename Kernel::FT;
|
||||
using Point = typename Kernel::Point_3;
|
||||
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;
|
||||
typedef CGAL::AABB_traits<Kernel, Primitive> Traits;
|
||||
typedef CGAL::AABB_tree<Traits> Tree;
|
||||
using Primitive = CGAL::AABB_face_graph_triangle_primitive<Mesh>;
|
||||
using Traits = CGAL::AABB_traits<Kernel, Primitive>;
|
||||
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> >;
|
||||
|
||||
int main() {
|
||||
const std::string input_name = CGAL::data_file_path("meshes/cross.off");
|
||||
const Vector grid_spacing(0.1, 0.1, 0.1);
|
||||
const FT offset_value = 0.2;
|
||||
int main()
|
||||
{
|
||||
const std::string input_name = CGAL::data_file_path("meshes/cross.off");
|
||||
const Vector grid_spacing(0.1, 0.1, 0.1);
|
||||
const FT offset_value = 0.2;
|
||||
|
||||
Mesh mesh_input;
|
||||
if (!CGAL::IO::read_OFF(input_name, mesh_input)) {
|
||||
std::cerr << "Could not read input mesh" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
Mesh mesh_input;
|
||||
if(!CGAL::IO::read_OFF(input_name, mesh_input))
|
||||
{
|
||||
std::cerr << "Could not read input mesh" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// compute bounding box
|
||||
CGAL::Bbox_3 aabb_grid = CGAL::Polygon_mesh_processing::bbox(mesh_input);
|
||||
Vector aabb_increase_vec = Vector(offset_value + 0.01, offset_value + 0.01, offset_value + 0.01);
|
||||
aabb_grid += (Point(aabb_grid.xmax(), aabb_grid.ymax(), aabb_grid.zmax()) + aabb_increase_vec).bbox();
|
||||
aabb_grid += (Point(aabb_grid.xmin(), aabb_grid.ymin(), aabb_grid.zmin()) - aabb_increase_vec).bbox();
|
||||
// compute bounding box
|
||||
CGAL::Bbox_3 aabb_grid = CGAL::Polygon_mesh_processing::bbox(mesh_input);
|
||||
Vector aabb_increase_vec = Vector(offset_value + 0.01, offset_value + 0.01, offset_value + 0.01);
|
||||
aabb_grid += (Point(aabb_grid.xmax(), aabb_grid.ymax(), aabb_grid.zmax()) + aabb_increase_vec).bbox();
|
||||
aabb_grid += (Point(aabb_grid.xmin(), aabb_grid.ymin(), aabb_grid.zmin()) - aabb_increase_vec).bbox();
|
||||
|
||||
// construct AABB tree
|
||||
Tree tree(mesh_input.faces_begin(), mesh_input.faces_end(), mesh_input);
|
||||
// construct AABB tree
|
||||
Tree tree(mesh_input.faces_begin(), mesh_input.faces_end(), mesh_input);
|
||||
|
||||
CGAL::Side_of_triangle_mesh<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
|
||||
auto mesh_distance = [&tree](const Point& p) {
|
||||
const Point& x = tree.closest_point(p);
|
||||
return std::sqrt((p - x).squared_length());
|
||||
};
|
||||
// functors for addressing distance and normal queries
|
||||
auto mesh_distance = [&tree](const Point& p)
|
||||
{
|
||||
const Point& x = tree.closest_point(p);
|
||||
return std::sqrt((p - x).squared_length());
|
||||
};
|
||||
|
||||
auto mesh_normal = [&tree](const Point& p) {
|
||||
const Point& x = tree.closest_point(p);
|
||||
const Vector n = p - x; // TODO: address case where norm = zero
|
||||
return n / std::sqrt(n.squared_length()); // normalize output vector
|
||||
};
|
||||
auto mesh_normal = [&tree](const Point& p)
|
||||
{
|
||||
const Point& x = tree.closest_point(p);
|
||||
const Vector n = p - x; // @todo address case where norm = zero
|
||||
return n / std::sqrt(n.squared_length()); // normalize output vector
|
||||
};
|
||||
|
||||
// create a domain with given bounding box and grid spacing
|
||||
auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(aabb_grid, grid_spacing,
|
||||
mesh_distance, mesh_normal);
|
||||
// containers for output indexed surface mesh
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
// create a domain with given bounding box and grid spacing
|
||||
auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(aabb_grid, grid_spacing,
|
||||
mesh_distance, mesh_normal);
|
||||
// containers for output indexed surface mesh
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// run dual contouring
|
||||
CGAL::Isosurfacing::dual_contouring(domain, offset_value, points, polygons);
|
||||
// run dual contouring
|
||||
CGAL::Isosurfacing::dual_contouring(domain, offset_value, points, polygons);
|
||||
|
||||
// save output indexed mesh to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
// save output indexed mesh to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,88 +1,100 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/Dual_contouring_3.h>
|
||||
#include <CGAL/Implicit_octree_domain.h>
|
||||
#include <CGAL/Octree_wrapper.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/boost/graph/IO/OFF.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <math.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = typename Kernel::FT;
|
||||
using Vector = typename Kernel::Vector_3;
|
||||
using Point = typename Kernel::Point_3;
|
||||
|
||||
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> >;
|
||||
|
||||
typedef CGAL::Isosurfacing::Octree_wrapper<Kernel> Octree_wrapper_;
|
||||
using Octree_wrapper_ = CGAL::Isosurfacing::Octree_wrapper<Kernel>;
|
||||
|
||||
struct Refine_one_eighth {
|
||||
std::size_t min_depth_;
|
||||
std::size_t max_depth_;
|
||||
struct Refine_one_eighth
|
||||
{
|
||||
std::size_t min_depth_;
|
||||
std::size_t max_depth_;
|
||||
|
||||
std::size_t octree_dim_;
|
||||
std::size_t octree_dim_;
|
||||
|
||||
Octree_wrapper_::Uniform_coords uniform_coordinates(const Octree_wrapper_::Octree::Node& node) const {
|
||||
auto coords = node.global_coordinates();
|
||||
const std::size_t depth_factor = std::size_t(1) << (max_depth_ - node.depth());
|
||||
for (int i = 0; i < Octree_wrapper_::Octree::Node::Dimension::value; ++i) {
|
||||
coords[i] *= (uint32_t)depth_factor;
|
||||
}
|
||||
Octree_wrapper_::Uniform_coords uniform_coordinates(const Octree_wrapper_::Octree::Node& node) const
|
||||
{
|
||||
auto coords = node.global_coordinates();
|
||||
const std::size_t depth_factor = std::size_t(1) << (max_depth_ - node.depth());
|
||||
for(int i=0; i < Octree_wrapper_::Octree::Node::Dimension::value; ++i)
|
||||
coords[i] *= uint32_t(depth_factor);
|
||||
|
||||
return coords;
|
||||
}
|
||||
return coords;
|
||||
}
|
||||
|
||||
Refine_one_eighth(std::size_t min_depth, std::size_t max_depth) : min_depth_(min_depth), max_depth_(max_depth) {
|
||||
octree_dim_ = std::size_t(1) << max_depth_;
|
||||
}
|
||||
Refine_one_eighth(std::size_t min_depth,
|
||||
std::size_t max_depth)
|
||||
: min_depth_(min_depth),
|
||||
max_depth_(max_depth)
|
||||
{
|
||||
octree_dim_ = std::size_t(1) << max_depth_;
|
||||
}
|
||||
|
||||
bool operator()(const Octree_wrapper_::Octree::Node& n) const {
|
||||
// n.depth()
|
||||
if (n.depth() < min_depth_) {
|
||||
return true;
|
||||
}
|
||||
if (n.depth() == max_depth_) {
|
||||
return false;
|
||||
}
|
||||
bool operator()(const Octree_wrapper_::Octree::Node& n) const
|
||||
{
|
||||
// n.depth()
|
||||
if(n.depth() < min_depth_)
|
||||
return true;
|
||||
|
||||
auto leaf_coords = uniform_coordinates(n);
|
||||
if(n.depth() == max_depth_)
|
||||
return false;
|
||||
|
||||
if (leaf_coords[0] >= octree_dim_ / 2) {
|
||||
return false;
|
||||
}
|
||||
if (leaf_coords[1] >= octree_dim_ / 2) {
|
||||
return false;
|
||||
}
|
||||
if (leaf_coords[2] >= octree_dim_ / 2) {
|
||||
// return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
auto leaf_coords = uniform_coordinates(n);
|
||||
|
||||
if(leaf_coords[0] >= octree_dim_ / 2)
|
||||
return false;
|
||||
|
||||
if(leaf_coords[1] >= octree_dim_ / 2)
|
||||
return false;
|
||||
|
||||
// if(leaf_coords[2] >= octree_dim_ / 2)
|
||||
// return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
const CGAL::Bbox_3 bbox(-1, -1, -1, 1, 1, 1);
|
||||
std::shared_ptr<Octree_wrapper_> octree_wrap = std::make_shared<Octree_wrapper_>(bbox);
|
||||
int main()
|
||||
{
|
||||
const CGAL::Bbox_3 bbox(-1., -1., -1., 1., 1., 1.);
|
||||
std::shared_ptr<Octree_wrapper_> octree_wrap = std::make_shared<Octree_wrapper_>(bbox);
|
||||
|
||||
Refine_one_eighth split_predicate(3, 4);
|
||||
octree_wrap->refine(split_predicate);
|
||||
Refine_one_eighth split_predicate(3, 4);
|
||||
octree_wrap->refine(split_predicate);
|
||||
|
||||
auto sphere_function = [&](const Point& p) { return std::sqrt(p.x() * p.x() + p.y() * p.y() + p.z() * p.z()); };
|
||||
auto sphere_function = [&](const Point& p)
|
||||
{
|
||||
return std::sqrt(p.x() * p.x() + p.y() * p.y() + p.z() * p.z());
|
||||
};
|
||||
|
||||
auto sphere_gradient = [&](const Point& p) {
|
||||
const Vector g = p - CGAL::ORIGIN;
|
||||
return g / std::sqrt(g.squared_length());
|
||||
};
|
||||
auto sphere_gradient = [&](const Point& p)
|
||||
{
|
||||
const Vector g = p - CGAL::ORIGIN;
|
||||
return g / std::sqrt(g.squared_length());
|
||||
};
|
||||
|
||||
auto domain = CGAL::Isosurfacing::create_implicit_octree_domain(octree_wrap, sphere_function, sphere_gradient);
|
||||
auto domain = CGAL::Isosurfacing::create_implicit_octree_domain(octree_wrap, sphere_function, sphere_gradient);
|
||||
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
CGAL::Isosurfacing::dual_contouring(domain, 0.8, points, polygons);
|
||||
CGAL::Isosurfacing::dual_contouring(domain, 0.8, points, polygons);
|
||||
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,47 +5,48 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/boost/graph/IO/OFF.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = typename Kernel::FT;
|
||||
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;
|
||||
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> >;
|
||||
|
||||
int main() {
|
||||
// create a cartesian grid with 100^3 grid points and the bounding box [-1, 1]^3
|
||||
const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
|
||||
std::shared_ptr<Grid> grid = std::make_shared<Grid>(50, 50, 50, bbox);
|
||||
int main()
|
||||
{
|
||||
// create a cartesian grid with 100^3 grid points and the bounding box [-1, 1]^3
|
||||
const CGAL::Bbox_3 bbox(-1.0, -1.0, -1.0, 1.0, 1.0, 1.0);
|
||||
std::shared_ptr<Grid> grid = std::make_shared<Grid>(50, 50, 50, bbox);
|
||||
|
||||
// compute and store function values at all grid points
|
||||
for (std::size_t x = 0; x < grid->xdim(); x++) {
|
||||
for (std::size_t y = 0; y < grid->ydim(); y++) {
|
||||
for (std::size_t z = 0; z < grid->zdim(); z++) {
|
||||
// compute and store function values at all grid points
|
||||
for(std::size_t x=0; x<grid->xdim(); ++x) {
|
||||
for(std::size_t y=0; y<grid->ydim(); ++y) {
|
||||
for(std::size_t z=0; z<grid->zdim(); ++z)
|
||||
{
|
||||
const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin();
|
||||
const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin();
|
||||
const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin();
|
||||
|
||||
const FT pos_x = x * grid->get_spacing()[0] + bbox.xmin();
|
||||
const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin();
|
||||
const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin();
|
||||
|
||||
// Euclidean distance to the origin
|
||||
grid->value(x, y, z) = std::sqrt(pos_x * pos_x + pos_y * pos_y + pos_z * pos_z);
|
||||
}
|
||||
}
|
||||
// Euclidean distance to the origin
|
||||
grid->value(x, y, z) = std::sqrt(pos_x * pos_x + pos_y * pos_y + pos_z * pos_z);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create a domain from the grid
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
// create a domain from the grid
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
|
||||
// prepare collections for the result
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
// prepare collections for the result
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// run marching cubes with an isovalue of 0.8
|
||||
CGAL::Isosurfacing::marching_cubes(domain, 0.8, points, polygons);
|
||||
// run marching cubes with an isovalue of 0.8
|
||||
CGAL::Isosurfacing::marching_cubes(domain, 0.8, points, polygons);
|
||||
|
||||
// save output indexed surface mesh to file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
// save output indexed surface mesh to file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,37 +1,43 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/Implicit_cartesian_grid_domain.h>
|
||||
#include <CGAL/Marching_cubes_3.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/boost/graph/IO/OFF.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = typename Kernel::FT;
|
||||
using Vector = typename Kernel::Vector_3;
|
||||
using Point = typename Kernel::Point_3;
|
||||
|
||||
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> >;
|
||||
|
||||
int main() {
|
||||
const CGAL::Bbox_3 bbox{-1.0, -1.0, -1.0, 1.0, 1.0, 1.0};
|
||||
const FT spacing = 0.04;
|
||||
const Vector vec_spacing(spacing, spacing, spacing);
|
||||
int main()
|
||||
{
|
||||
const CGAL::Bbox_3 bbox { -1.0, -1.0, -1.0, 1.0, 1.0, 1.0 };
|
||||
const FT spacing = 0.04;
|
||||
const Vector vec_spacing(spacing, spacing, spacing);
|
||||
|
||||
// Euclidean distance function to the origin
|
||||
auto sphere_function = [&](const Point& p) { return std::sqrt(p.x() * p.x() + p.y() * p.y() + p.z() * p.z()); };
|
||||
// Euclidean distance function to the origin
|
||||
auto sphere_function = [&](const Point& p)
|
||||
{
|
||||
return std::sqrt(p.x() * p.x() + p.y() * p.y() + p.z() * p.z());
|
||||
};
|
||||
|
||||
// create a domain with given bounding box and grid spacing
|
||||
auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, vec_spacing, sphere_function);
|
||||
// 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);
|
||||
|
||||
// prepare collections for the output indexed mesh
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
// prepare collections for the output indexed mesh
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// execute marching cubes with an isovalue of 0.8
|
||||
CGAL::Isosurfacing::marching_cubes(domain, 0.8, points, polygons);
|
||||
// execute marching cubes with an isovalue of 0.8
|
||||
CGAL::Isosurfacing::marching_cubes(domain, 0.8, points, polygons);
|
||||
|
||||
// save ouput indexed mesh to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
// save ouput indexed mesh to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,45 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/Cartesian_grid_3.h>
|
||||
#include <CGAL/Explicit_cartesian_grid_domain.h>
|
||||
#include <CGAL/Marching_cubes_3.h>
|
||||
#include <CGAL/Simple_cartesian.h>
|
||||
|
||||
#include <CGAL/boost/graph/IO/OFF.h>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
typedef CGAL::Cartesian_grid_3<Kernel> Grid;
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using Point = typename Kernel::Point_3;
|
||||
using Grid = CGAL::Cartesian_grid_3<Kernel>;
|
||||
|
||||
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> >;
|
||||
|
||||
int main() {
|
||||
int main()
|
||||
{
|
||||
const std::string fname = CGAL::data_file_path("images/skull_2.9.inr");
|
||||
|
||||
const std::string fname = CGAL::data_file_path("images/skull_2.9.inr");
|
||||
// load volumetric image from a file
|
||||
CGAL::Image_3 image;
|
||||
if(!image.read(fname))
|
||||
{
|
||||
std::cerr << "Error: Cannot read image file " << fname << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// load volumetric image from a file
|
||||
CGAL::Image_3 image;
|
||||
if (!image.read(fname)) {
|
||||
std::cerr << "Error: Cannot read image file " << fname << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
// convert image to a cartesian grid
|
||||
std::shared_ptr<Grid> grid = std::make_shared<Grid>(image);
|
||||
|
||||
// convert image to a cartesian grid
|
||||
std::shared_ptr<Grid> grid = std::make_shared<Grid>(image);
|
||||
// create a domain from the grid
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
|
||||
// create a domain from the grid
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
// prepare collections for the output indexed mesh
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// prepare collections for the output indexed mesh
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
// execute marching cubes with an isovalue of 2.9
|
||||
CGAL::Isosurfacing::marching_cubes(domain, 2.9, points, polygons);
|
||||
|
||||
// execute marching cubes with an isovalue of 2.9
|
||||
CGAL::Isosurfacing::marching_cubes(domain, 2.9, points, polygons);
|
||||
// save output indexed mesh to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
|
||||
// save output indexed mesh to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_traits.h>
|
||||
#include <CGAL/AABB_tree.h>
|
||||
|
|
@ -5,95 +8,96 @@
|
|||
#include <CGAL/Explicit_cartesian_grid_domain.h>
|
||||
#include <CGAL/Marching_cubes_3.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 <iostream>
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using FT = typename Kernel::FT;
|
||||
using Point = typename Kernel::Point_3;
|
||||
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;
|
||||
typedef CGAL::AABB_traits<Kernel, Primitive> Traits;
|
||||
typedef CGAL::AABB_tree<Traits> Tree;
|
||||
|
||||
typedef std::vector<Point> Point_range;
|
||||
typedef std::vector<std::vector<std::size_t>> Polygon_range;
|
||||
using Primitive = CGAL::AABB_face_graph_triangle_primitive<Mesh>;
|
||||
using Traits = CGAL::AABB_traits<Kernel, Primitive>;
|
||||
using Tree = CGAL::AABB_tree<Traits>;
|
||||
|
||||
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
|
||||
// via the AABB tree data structure
|
||||
inline Kernel::FT distance_to_mesh(const Tree& tree, const Point& p) {
|
||||
const Point& x = tree.closest_point(p);
|
||||
return std::sqrt((p - x).squared_length());
|
||||
inline Kernel::FT distance_to_mesh(const Tree& tree,
|
||||
const Point& p)
|
||||
{
|
||||
const Point& x = tree.closest_point(p);
|
||||
return std::sqrt((p - x).squared_length());
|
||||
}
|
||||
|
||||
int main() {
|
||||
const std::string input_name = CGAL::data_file_path("meshes/cross.off");
|
||||
const int n_voxels = 20;
|
||||
const FT offset_value = 0.2;
|
||||
int main()
|
||||
{
|
||||
const std::string input_name = CGAL::data_file_path("meshes/cross.off");
|
||||
const int n_voxels = 20;
|
||||
const FT offset_value = 0.2;
|
||||
|
||||
// load input mesh
|
||||
Mesh mesh_input;
|
||||
if (!CGAL::IO::read_OFF(input_name, mesh_input)) {
|
||||
std::cerr << "Could not read input mesh" << std::endl;
|
||||
exit(-1);
|
||||
// load input mesh
|
||||
Mesh mesh_input;
|
||||
if(!CGAL::IO::read_OFF(input_name, mesh_input))
|
||||
{
|
||||
std::cerr << "Could not read input mesh" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// compute loose bounding box of the mesh
|
||||
CGAL::Bbox_3 aabb_grid = CGAL::Polygon_mesh_processing::bbox(mesh_input);
|
||||
const FT loose_offset = offset_value + 0.01;
|
||||
Vector aabb_increase_vec = Vector(loose_offset, loose_offset, loose_offset);
|
||||
aabb_grid += (Point(aabb_grid.xmax(), aabb_grid.ymax(), aabb_grid.zmax()) + aabb_increase_vec).bbox();
|
||||
aabb_grid += (Point(aabb_grid.xmin(), aabb_grid.ymin(), aabb_grid.zmin()) - aabb_increase_vec).bbox();
|
||||
|
||||
// construct AABB tree and functor to address inside/outside point queries
|
||||
Tree tree(mesh_input.faces_begin(), mesh_input.faces_end(), mesh_input);
|
||||
CGAL::Side_of_triangle_mesh<Mesh, CGAL::GetGeomTraits<Mesh>::type> sotm(mesh_input);
|
||||
|
||||
// create 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 y=0; y<grid->ydim(); ++y) {
|
||||
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_y = y * grid->get_spacing()[1] + grid->get_bbox().ymin();
|
||||
const FT pos_z = z * grid->get_spacing()[2] + grid->get_bbox().zmin();
|
||||
const Point p(pos_x, pos_y, pos_z);
|
||||
|
||||
// compute unsigned distance to input mesh
|
||||
grid->value(x, y, z) = distance_to_mesh(tree, p);
|
||||
|
||||
// sign distance so that it is negative inside the mesh
|
||||
const bool is_inside = (sotm(p) == CGAL::ON_BOUNDED_SIDE);
|
||||
if(is_inside)
|
||||
grid->value(x, y, z) *= -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// compute loose bounding box of the mesh
|
||||
CGAL::Bbox_3 aabb_grid = CGAL::Polygon_mesh_processing::bbox(mesh_input);
|
||||
const FT loose_offset = offset_value + 0.01;
|
||||
Vector aabb_increase_vec = Vector(loose_offset, loose_offset, loose_offset);
|
||||
aabb_grid += (Point(aabb_grid.xmax(), aabb_grid.ymax(), aabb_grid.zmax()) + aabb_increase_vec).bbox();
|
||||
aabb_grid += (Point(aabb_grid.xmin(), aabb_grid.ymin(), aabb_grid.zmin()) - aabb_increase_vec).bbox();
|
||||
// create domain from the grid
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
|
||||
// construct AABB tree and functor to address inside/outside point queries
|
||||
Tree tree(mesh_input.faces_begin(), mesh_input.faces_end(), mesh_input);
|
||||
CGAL::Side_of_triangle_mesh<Mesh, CGAL::GetGeomTraits<Mesh>::type> sotm(mesh_input);
|
||||
// containers for output indexed triangle soup
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// create grid
|
||||
std::shared_ptr<Grid> grid = std::make_shared<Grid>(n_voxels, n_voxels, n_voxels, aabb_grid);
|
||||
// execute marching cubes with an isovalue equating offset
|
||||
CGAL::Isosurfacing::marching_cubes(domain, offset_value, points, polygons);
|
||||
|
||||
for (std::size_t z = 0; z < grid->zdim(); z++) {
|
||||
for (std::size_t y = 0; y < grid->ydim(); y++) {
|
||||
for (std::size_t x = 0; x < grid->xdim(); x++) {
|
||||
// save output indexed triangle soup to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("output.off", points, polygons);
|
||||
|
||||
const FT pos_x = x * grid->get_spacing()[0] + grid->get_bbox().xmin();
|
||||
const FT pos_y = y * grid->get_spacing()[1] + grid->get_bbox().ymin();
|
||||
const FT pos_z = z * grid->get_spacing()[2] + grid->get_bbox().zmin();
|
||||
const Point p(pos_x, pos_y, pos_z);
|
||||
|
||||
// compute unsigned distance to input mesh
|
||||
grid->value(x, y, z) = distance_to_mesh(tree, p);
|
||||
|
||||
// sign distance so that it is negative inside the mesh
|
||||
const bool is_inside = (sotm(p) == CGAL::ON_BOUNDED_SIDE);
|
||||
if (is_inside) {
|
||||
grid->value(x, y, z) *= -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create domain from the grid
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
|
||||
// containers for output indexed triangle soup
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// execute marching cubes with an isovalue equating offset
|
||||
CGAL::Isosurfacing::marching_cubes(domain, offset_value, points, polygons);
|
||||
|
||||
// save output indexed triangle soup to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("output.off", points, polygons);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,244 +31,268 @@ namespace CGAL {
|
|||
*
|
||||
* \tparam GeomTraits the traits type
|
||||
*/
|
||||
template <class GeomTraits>
|
||||
class Cartesian_grid_3 {
|
||||
template <typename GeomTraits>
|
||||
class Cartesian_grid_3
|
||||
{
|
||||
public:
|
||||
typedef GeomTraits Geom_traits;
|
||||
typedef typename Geom_traits::FT FT;
|
||||
typedef typename Geom_traits::Vector_3 Vector;
|
||||
using Geom_traits = GeomTraits;
|
||||
using FT = typename Geom_traits::FT;
|
||||
using Vector = typename Geom_traits::Vector_3;
|
||||
|
||||
typedef Isosurfacing::internal::Grid_topology::Vertex_descriptor VertexDescriptor;
|
||||
using VertexDescriptor = Isosurfacing::internal::Grid_topology::Vertex_descriptor;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Create a grid with `xdim * ydim * zdim` grid points.
|
||||
* The grid covers the space described by a bounding box.
|
||||
*
|
||||
* \param xdim the number of grid points in x direction
|
||||
* \param ydim the number of grid points in y direction
|
||||
* \param zdim the number of grid points in z direction
|
||||
* \param bbox the bounding box
|
||||
*/
|
||||
Cartesian_grid_3(const std::size_t xdim, const std::size_t ydim, const std::size_t zdim, const Bbox_3& bbox)
|
||||
: sizes{xdim, ydim, zdim}, bbox(bbox) {
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Create a grid with `xdim * ydim * zdim` grid points.
|
||||
* The grid covers the space described by a bounding box.
|
||||
*
|
||||
* \param xdim the number of grid points in x direction
|
||||
* \param ydim the number of grid points in y direction
|
||||
* \param zdim the number of grid points in z direction
|
||||
* \param bbox the bounding box
|
||||
*/
|
||||
Cartesian_grid_3(const std::size_t xdim,
|
||||
const std::size_t ydim,
|
||||
const std::size_t zdim,
|
||||
const Bbox_3& bbox)
|
||||
: sizes{xdim, ydim, zdim},
|
||||
bbox(bbox)
|
||||
{
|
||||
// pre-allocate memory
|
||||
values.resize(xdim * ydim * zdim);
|
||||
gradients.resize(xdim * ydim * zdim);
|
||||
|
||||
// pre-allocate memory
|
||||
values.resize(xdim * ydim * zdim);
|
||||
gradients.resize(xdim * ydim * zdim);
|
||||
// calculate grid spacing
|
||||
const FT d_x = bbox.x_span() / (xdim - 1);
|
||||
const FT d_y = bbox.y_span() / (ydim - 1);
|
||||
const FT d_z = bbox.z_span() / (zdim - 1);
|
||||
spacing = Vector(d_x, d_y, d_z);
|
||||
}
|
||||
|
||||
// calculate grid spacing
|
||||
const FT d_x = bbox.x_span() / (xdim - 1);
|
||||
const FT d_y = bbox.y_span() / (ydim - 1);
|
||||
const FT d_z = bbox.z_span() / (zdim - 1);
|
||||
spacing = Vector(d_x, d_y, d_z);
|
||||
}
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Create a grid from an `Image_3`.
|
||||
* The dimensions and bounding box are read from the image.
|
||||
* The values stored in the image must be of type `Geom_traits::FT` or implicitly convertible to it.
|
||||
*
|
||||
* \param image the image providing the data
|
||||
*/
|
||||
Cartesian_grid_3(const Image_3& image)
|
||||
{
|
||||
from_image(image);
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Create a grid from an `Image_3`.
|
||||
* The dimensions and bounding box are read from the image.
|
||||
* The values stored in the image must be of type `Geom_traits::FT` or implicitly convertible to it.
|
||||
*
|
||||
* \param image the image providing the data
|
||||
*/
|
||||
Cartesian_grid_3(const Image_3& image) {
|
||||
from_image(image);
|
||||
}
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Get the value stored in the grid at the grid point described by the vertex.
|
||||
*
|
||||
* \param v the vertex descriptor of the vertex
|
||||
*
|
||||
* \return the stored value
|
||||
*/
|
||||
FT operator()(const VertexDescriptor& v) const
|
||||
{
|
||||
return values[linear_index(v[0], v[1], v[2])];
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Get the value stored in the grid at the grid point described by the vertex.
|
||||
*
|
||||
* \param v the vertex descriptor of the vertex
|
||||
*
|
||||
* \return the stored value
|
||||
*/
|
||||
FT operator()(const VertexDescriptor& v) const {
|
||||
return values[linear_index(v[0], v[1], v[2])];
|
||||
}
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Get the value stored in the grid at the given indices.
|
||||
*
|
||||
* \param x the index in x direction
|
||||
* \param y the index in y direction
|
||||
* \param z the index in z direction
|
||||
*
|
||||
* \return the stored value
|
||||
*/
|
||||
FT value(const std::size_t x,
|
||||
const std::size_t y,
|
||||
const std::size_t z) const
|
||||
{
|
||||
return values[linear_index(x, y, z)];
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Get the value stored in the grid at the given indices.
|
||||
*
|
||||
* \param x the index in x direction
|
||||
* \param y the index in y direction
|
||||
* \param z the index in z direction
|
||||
*
|
||||
* \return the stored value
|
||||
*/
|
||||
FT value(const std::size_t x, const std::size_t y, const std::size_t z) const {
|
||||
return values[linear_index(x, y, z)];
|
||||
}
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Get a reference to the value stored in the grid at the given indices.
|
||||
* Can be used to set values of the grid.
|
||||
*
|
||||
* \param x the index in x direction
|
||||
* \param y the index in y direction
|
||||
* \param z the index in z direction
|
||||
*
|
||||
* \return a reference to the stored value
|
||||
*/
|
||||
FT& value(const std::size_t x,
|
||||
const std::size_t y,
|
||||
const std::size_t z)
|
||||
{
|
||||
return values[linear_index(x, y, z)];
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Get a reference to the value stored in the grid at the given indices.
|
||||
* Can be used to set values of the grid.
|
||||
*
|
||||
* \param x the index in x direction
|
||||
* \param y the index in y direction
|
||||
* \param z the index in z direction
|
||||
*
|
||||
* \return a reference to the stored value
|
||||
*/
|
||||
FT& value(const std::size_t x, const std::size_t y, const std::size_t z) {
|
||||
return values[linear_index(x, y, z)];
|
||||
}
|
||||
Vector gradient(const std::size_t x,
|
||||
const std::size_t y,
|
||||
const std::size_t z) const
|
||||
{
|
||||
return gradients[linear_index(x, y, z)];
|
||||
}
|
||||
|
||||
Vector gradient(const std::size_t x, const std::size_t y, const std::size_t z) const {
|
||||
return gradients[linear_index(x, y, z)];
|
||||
}
|
||||
Vector& gradient(const std::size_t x,
|
||||
const std::size_t y,
|
||||
const std::size_t z)
|
||||
{
|
||||
return gradients[linear_index(x, y, z)];
|
||||
}
|
||||
|
||||
Vector& gradient(const std::size_t x, const std::size_t y, const std::size_t z) {
|
||||
return gradients[linear_index(x, y, z)];
|
||||
}
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \return the number of grid points in x direction
|
||||
*/
|
||||
std::size_t xdim() const
|
||||
{
|
||||
return sizes[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \return the number of grid points in x direction
|
||||
*/
|
||||
std::size_t xdim() const {
|
||||
return sizes[0];
|
||||
}
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \return the number of grid points in y direction
|
||||
*/
|
||||
std::size_t ydim() const
|
||||
{
|
||||
return sizes[1];
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \return the number of grid points in y direction
|
||||
*/
|
||||
std::size_t ydim() const {
|
||||
return sizes[1];
|
||||
}
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \return the number of grid points in z direction
|
||||
*/
|
||||
std::size_t zdim() const
|
||||
{
|
||||
return sizes[2];
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \return the number of grid points in z direction
|
||||
*/
|
||||
std::size_t zdim() const {
|
||||
return sizes[2];
|
||||
}
|
||||
const Bbox_3& get_bbox() const
|
||||
{
|
||||
return bbox;
|
||||
}
|
||||
|
||||
const Bbox_3& get_bbox() const {
|
||||
return bbox;
|
||||
}
|
||||
|
||||
const Vector& get_spacing() const {
|
||||
return spacing;
|
||||
}
|
||||
const Vector& get_spacing() const
|
||||
{
|
||||
return spacing;
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t linear_index(const std::size_t x, const std::size_t y, const std::size_t z) const {
|
||||
// convert x, y, z into a linear index to access the vector
|
||||
return (z * ydim() + y) * xdim() + x;
|
||||
}
|
||||
std::size_t linear_index(const std::size_t x,
|
||||
const std::size_t y,
|
||||
const std::size_t z) const
|
||||
{
|
||||
// convert x, y, z into a linear index to access the vector
|
||||
return (z * ydim() + y) * xdim() + x;
|
||||
}
|
||||
|
||||
void from_image(const Image_3& image);
|
||||
Image_3 to_image() const;
|
||||
void from_image(const Image_3& image);
|
||||
Image_3 to_image() const;
|
||||
|
||||
private:
|
||||
std::vector<FT> values;
|
||||
std::vector<Vector> gradients;
|
||||
std::vector<FT> values;
|
||||
std::vector<Vector> gradients;
|
||||
|
||||
std::array<std::size_t, 3> sizes;
|
||||
std::array<std::size_t, 3> sizes;
|
||||
|
||||
Bbox_3 bbox;
|
||||
Vector spacing;
|
||||
Bbox_3 bbox;
|
||||
Vector spacing;
|
||||
};
|
||||
|
||||
template <typename GeomTraits>
|
||||
void Cartesian_grid_3<GeomTraits>::from_image(const Image_3& image) {
|
||||
// compute bounding box
|
||||
const FT max_x = image.tx() + (image.xdim() - 1) * image.vx();
|
||||
const FT max_y = image.ty() + (image.ydim() - 1) * image.vy();
|
||||
const FT max_z = image.tz() + (image.zdim() - 1) * image.vz();
|
||||
bbox = Bbox_3(image.tx(), image.ty(), image.tz(), max_x, max_y, max_z);
|
||||
void
|
||||
Cartesian_grid_3<GeomTraits>::
|
||||
from_image(const Image_3& image)
|
||||
{
|
||||
// compute bounding box
|
||||
const FT max_x = image.tx() + (image.xdim() - 1) * image.vx();
|
||||
const FT max_y = image.ty() + (image.ydim() - 1) * image.vy();
|
||||
const FT max_z = image.tz() + (image.zdim() - 1) * image.vz();
|
||||
bbox = Bbox_3(image.tx(), image.ty(), image.tz(), max_x, max_y, max_z);
|
||||
|
||||
// get spacing
|
||||
spacing = Vector(image.vx(), image.vy(), image.vz());
|
||||
// get spacing
|
||||
spacing = Vector(image.vx(), image.vy(), image.vz());
|
||||
|
||||
// get sizes
|
||||
sizes[0] = image.xdim();
|
||||
sizes[1] = image.ydim();
|
||||
sizes[2] = image.zdim();
|
||||
// get sizes
|
||||
sizes[0] = image.xdim();
|
||||
sizes[1] = image.ydim();
|
||||
sizes[2] = image.zdim();
|
||||
|
||||
// pre-allocate
|
||||
values.resize(xdim() * ydim() * zdim());
|
||||
gradients.resize(xdim() * ydim() * zdim());
|
||||
// pre-allocate
|
||||
values.resize(xdim() * ydim() * zdim());
|
||||
gradients.resize(xdim() * ydim() * zdim());
|
||||
|
||||
// copy values
|
||||
for (std::size_t x = 0; x < sizes[0]; x++) {
|
||||
for (std::size_t y = 0; y < sizes[1]; y++) {
|
||||
for (std::size_t z = 0; z < sizes[2]; z++) {
|
||||
|
||||
value(x, y, z) = image.value(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy values
|
||||
for(std::size_t x=0; x<sizes[0]; ++x)
|
||||
for(std::size_t y=0; y<sizes[1]; ++y)
|
||||
for(std::size_t z=0; z<sizes[2]; ++z)
|
||||
value(x, y, z) = image.value(x, y, z);
|
||||
}
|
||||
|
||||
template <typename GeomTraits>
|
||||
Image_3 Cartesian_grid_3<GeomTraits>::to_image() const {
|
||||
// select the number type
|
||||
WORD_KIND wordkind;
|
||||
if (std::is_floating_point<FT>::value)
|
||||
wordkind = WK_FLOAT;
|
||||
else
|
||||
wordkind = WK_FIXED;
|
||||
Image_3
|
||||
Cartesian_grid_3<GeomTraits>::
|
||||
to_image() const
|
||||
{
|
||||
// select the number type
|
||||
WORD_KIND wordkind;
|
||||
if(std::is_floating_point<FT>::value)
|
||||
wordkind = WK_FLOAT;
|
||||
else
|
||||
wordkind = WK_FIXED;
|
||||
|
||||
// select signed or unsigned
|
||||
SIGN sign;
|
||||
if (std::is_signed<FT>::value)
|
||||
sign = SGN_SIGNED;
|
||||
else
|
||||
sign = SGN_UNSIGNED;
|
||||
// select signed or unsigned
|
||||
SIGN sign;
|
||||
if(std::is_signed<FT>::value)
|
||||
sign = SGN_SIGNED;
|
||||
else
|
||||
sign = SGN_UNSIGNED;
|
||||
|
||||
// get spacing
|
||||
const double vx = spacing()[0];
|
||||
const double vy = spacing()[1];
|
||||
const double vz = spacing()[2];
|
||||
// get spacing
|
||||
const double vx = spacing()[0];
|
||||
const double vy = spacing()[1];
|
||||
const double vz = spacing()[2];
|
||||
|
||||
// create image
|
||||
_image* im = _createImage(xdim(), ydim(), zdim(),
|
||||
1, // vectorial dimension
|
||||
vx, vy, vz, // voxel size
|
||||
sizeof(FT), // image word size in bytes
|
||||
wordkind, // image word kind WK_FIXED, WK_FLOAT, WK_UNKNOWN
|
||||
sign); // image word sign
|
||||
// create image
|
||||
_image* im = _createImage(xdim(), ydim(), zdim(),
|
||||
1, // vectorial dimension
|
||||
vx, vy, vz, // voxel size
|
||||
sizeof(FT), // image word size in bytes
|
||||
wordkind, // image word kind WK_FIXED, WK_FLOAT, WK_UNKNOWN
|
||||
sign); // image word sign
|
||||
|
||||
// error handling
|
||||
if (im == nullptr || im->data == nullptr) {
|
||||
throw std::bad_alloc(); // TODO: idk?
|
||||
}
|
||||
// error handling
|
||||
if(im == nullptr || im->data == nullptr)
|
||||
throw std::bad_alloc(); // @todo idk?
|
||||
|
||||
// set min coordinates
|
||||
im->tx = bbox.xmin();
|
||||
im->ty = bbox.ymin();
|
||||
im->tz = bbox.zmin();
|
||||
// set min coordinates
|
||||
im->tx = bbox.xmin();
|
||||
im->ty = bbox.ymin();
|
||||
im->tz = bbox.zmin();
|
||||
|
||||
// copy data
|
||||
FT* data = (FT*)im->data;
|
||||
for (std::size_t x = 0; x < xdim(); x++) {
|
||||
for (std::size_t y = 0; y < ydim(); y++) {
|
||||
for (std::size_t z = 0; z < zdim(); z++) {
|
||||
// copy data
|
||||
FT* data = (FT*)im->data;
|
||||
for(std::size_t x=0; x<xdim(); ++x)
|
||||
for(std::size_t y=0; y<ydim(); ++y)
|
||||
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
|
||||
|
|
|
|||
|
|
@ -48,43 +48,49 @@ namespace Isosurfacing {
|
|||
* \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
|
||||
*/
|
||||
template <typename Concurrency_tag = Sequential_tag, class Domain_, class PointRange, class PolygonRange,
|
||||
class 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()) {
|
||||
template <typename Concurrency_tag = Sequential_tag,
|
||||
typename Domain_,
|
||||
typename PointRange,
|
||||
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
|
||||
internal::Dual_contouring_vertex_positioning<Domain_, Positioning> pos_func(domain, isovalue, positioning);
|
||||
domain.template iterate_cells<Concurrency_tag>(pos_func);
|
||||
|
||||
// create vertices in each relevant cell
|
||||
internal::Dual_contouring_vertex_positioning<Domain_, Positioning> pos_func(domain, isovalue, positioning);
|
||||
domain.template iterate_cells<Concurrency_tag>(pos_func);
|
||||
// connect vertices around an edge to form a face
|
||||
internal::Dual_contouring_face_generation<Domain_> face_generation(domain, isovalue);
|
||||
domain.template iterate_edges<Concurrency_tag>(face_generation);
|
||||
|
||||
// connect vertices around an edge to form a face
|
||||
internal::Dual_contouring_face_generation<Domain_> face_generation(domain, isovalue);
|
||||
domain.template iterate_edges<Concurrency_tag>(face_generation);
|
||||
// copy vertices to point range
|
||||
points.resize(pos_func.points_counter);
|
||||
for(const auto& vtop : pos_func.map_voxel_to_point)
|
||||
points[pos_func.map_voxel_to_point_id[vtop.first]] = vtop.second;
|
||||
|
||||
// copy vertices to point range
|
||||
points.resize(pos_func.points_counter);
|
||||
for (const auto& vtop : pos_func.map_voxel_to_point) {
|
||||
points[pos_func.map_voxel_to_point_id[vtop.first]] = vtop.second;
|
||||
// copy faces to polygon range
|
||||
polygons.reserve(face_generation.faces.size());
|
||||
for(const auto& q : face_generation.faces)
|
||||
{
|
||||
std::vector<std::size_t> vertex_ids;
|
||||
for(const auto& v_id : q.second)
|
||||
{
|
||||
// ignore voxels that are outside the valid region and are not stored in the map
|
||||
if(pos_func.map_voxel_to_point_id.count(v_id) > 0)
|
||||
vertex_ids.push_back(pos_func.map_voxel_to_point_id[v_id]);
|
||||
}
|
||||
|
||||
// copy faces to polygon range
|
||||
polygons.reserve(face_generation.faces.size());
|
||||
for (const auto& q : face_generation.faces) {
|
||||
std::vector<std::size_t> vertex_ids;
|
||||
for (const auto& v_id : q.second) {
|
||||
// ignore voxels that are outside the valid region and are not stored in the map
|
||||
if (pos_func.map_voxel_to_point_id.count(v_id) > 0) {
|
||||
vertex_ids.push_back(pos_func.map_voxel_to_point_id[v_id]);
|
||||
}
|
||||
}
|
||||
// ignore degenerated faces
|
||||
if (vertex_ids.size() > 2) {
|
||||
polygons.push_back(vertex_ids);
|
||||
}
|
||||
}
|
||||
// ignore degenerated faces
|
||||
if(vertex_ids.size() > 2)
|
||||
polygons.push_back(vertex_ids);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_DUAL_CONTOURING_3_H
|
||||
#endif // CGAL_DUAL_CONTOURING_3_H
|
||||
|
|
|
|||
|
|
@ -30,13 +30,17 @@ namespace Isosurfacing {
|
|||
* `IsosurfacingDomainWithGradient`.
|
||||
*
|
||||
* \tparam GeomTraits the traits type
|
||||
* \tparam Gradient_ the type of the gradient functor. It must implement `GeomTraits::Vector operator()(const
|
||||
* GeomTraits::Point& point) const`.
|
||||
* \tparam Gradient_ the type of the gradient functor. It must implement
|
||||
* `GeomTraits::Vector operator()(const GeomTraits::Point& point) const`.
|
||||
*/
|
||||
template <class GeomTraits, typename Gradient_>
|
||||
template <typename GeomTraits,
|
||||
typename Gradient_>
|
||||
using Explicit_cartesian_grid_domain =
|
||||
internal::Base_domain<GeomTraits, internal::Grid_topology, internal::Cartesian_grid_geometry<GeomTraits>,
|
||||
Cartesian_grid_3<GeomTraits>, Gradient_>;
|
||||
internal::Base_domain<GeomTraits,
|
||||
internal::Grid_topology,
|
||||
internal::Cartesian_grid_geometry<GeomTraits>,
|
||||
Cartesian_grid_3<GeomTraits>,
|
||||
Gradient_>;
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
|
|
@ -52,34 +56,37 @@ using Explicit_cartesian_grid_domain =
|
|||
*
|
||||
* \return a new `Explicit_cartesian_grid_domain`
|
||||
*/
|
||||
template <class GeomTraits, typename Gradient_ = Zero_gradient<GeomTraits>>
|
||||
Explicit_cartesian_grid_domain<GeomTraits, Gradient_> create_explicit_cartesian_grid_domain(
|
||||
const std::shared_ptr<Cartesian_grid_3<GeomTraits>> grid, const Gradient_& gradient = Gradient_()) {
|
||||
template <typename GeomTraits,
|
||||
typename Gradient_ = Zero_gradient<GeomTraits> >
|
||||
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;
|
||||
typedef typename Domain::Topology Topology;
|
||||
typedef typename Domain::Geometry Geometry;
|
||||
typedef typename Domain::Function Function;
|
||||
typedef typename Domain::Gradient Gradient;
|
||||
using Topology = typename Domain::Topology ;
|
||||
using Geometry = typename Domain::Geometry;
|
||||
using Function = typename Domain::Function;
|
||||
using Gradient = typename Domain::Gradient;
|
||||
|
||||
const std::size_t size_i = grid->xdim();
|
||||
const std::size_t size_j = grid->ydim();
|
||||
const std::size_t size_k = grid->zdim();
|
||||
const std::size_t size_i = grid->xdim();
|
||||
const std::size_t size_j = grid->ydim();
|
||||
const std::size_t size_k = grid->zdim();
|
||||
|
||||
const Bbox_3& bbox = grid->get_bbox();
|
||||
const typename GeomTraits::Vector_3 offset(bbox.xmin(), bbox.ymin(), bbox.zmin());
|
||||
const typename GeomTraits::Vector_3 spacing = grid->get_spacing();
|
||||
const Bbox_3& bbox = grid->get_bbox();
|
||||
const typename GeomTraits::Vector_3 offset(bbox.xmin(), bbox.ymin(), bbox.zmin());
|
||||
const typename GeomTraits::Vector_3 spacing = grid->get_spacing();
|
||||
|
||||
// create copies as shared_ptr for safe memory management
|
||||
const Topology topo = std::make_shared<Topology::element_type>(size_i, size_j, size_k);
|
||||
const Geometry geom = std::make_shared<Geometry::element_type>(offset, spacing);
|
||||
const Function func = grid;
|
||||
const Gradient grad = std::make_shared<Gradient::element_type>(gradient);
|
||||
// create copies as shared_ptr for safe memory management
|
||||
const Topology topo = std::make_shared<Topology::element_type>(size_i, size_j, size_k);
|
||||
const Geometry geom = std::make_shared<Geometry::element_type>(offset, spacing);
|
||||
const Function func = grid;
|
||||
const Gradient grad = std::make_shared<Gradient::element_type>(gradient);
|
||||
|
||||
return Domain(topo, geom, func, grad);
|
||||
return Domain(topo, geom, func, grad);
|
||||
}
|
||||
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_EXPLICIT_CARTESIAN_GRID_DOMAIN_H
|
||||
#endif // CGAL_EXPLICIT_CARTESIAN_GRID_DOMAIN_H
|
||||
|
|
|
|||
|
|
@ -29,92 +29,96 @@ namespace Isosurfacing {
|
|||
*
|
||||
* \tparam GeomTraits the traits for this gradient.
|
||||
*/
|
||||
template <class GeomTraits>
|
||||
class Explicit_cartesian_grid_gradient {
|
||||
template <typename GeomTraits>
|
||||
class Explicit_cartesian_grid_gradient
|
||||
{
|
||||
public:
|
||||
typedef GeomTraits Geom_traits;
|
||||
typedef typename Geom_traits::FT FT;
|
||||
typedef typename Geom_traits::Point_3 Point;
|
||||
typedef typename Geom_traits::Vector_3 Vector;
|
||||
using Geom_traits = GeomTraits;
|
||||
using FT = typename Geom_traits::FT;
|
||||
using Point = typename Geom_traits::Point_3;
|
||||
using Vector = typename Geom_traits::Vector_3;
|
||||
|
||||
typedef std::shared_ptr<Cartesian_grid_3<Geom_traits>> Grid;
|
||||
using Grid = std::shared_ptr<Cartesian_grid_3<Geom_traits> >;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Create a new instance of this gradient.
|
||||
*
|
||||
* \param grid the cartesian grid that stores the gradient
|
||||
*/
|
||||
Explicit_cartesian_grid_gradient(const Grid& grid) : grid(grid) {}
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Create a new instance of this gradient.
|
||||
*
|
||||
* \param grid the cartesian grid that stores the gradient
|
||||
*/
|
||||
Explicit_cartesian_grid_gradient(const Grid& grid)
|
||||
: grid(grid)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Evaluate the gradient at a point in space.
|
||||
*
|
||||
* \param point the point at which the gradient is computed
|
||||
*/
|
||||
Vector operator()(const Point& point) const {
|
||||
// trilinear interpolation of stored gradients
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Evaluate the gradient at a point in space.
|
||||
*
|
||||
* \param point the point at which the gradient is computed
|
||||
*/
|
||||
Vector operator()(const Point& point) const
|
||||
{
|
||||
// trilinear interpolation of stored gradients
|
||||
|
||||
const Bbox_3& bbox = grid->get_bbox();
|
||||
const Vector& spacing = grid->get_spacing();
|
||||
const Bbox_3& bbox = grid->get_bbox();
|
||||
const Vector& spacing = grid->get_spacing();
|
||||
|
||||
// calculate min index including border case
|
||||
std::size_t min_i = (point.x() - bbox.xmin()) / spacing.x();
|
||||
std::size_t min_j = (point.y() - bbox.ymin()) / spacing.y();
|
||||
std::size_t min_k = (point.z() - bbox.zmin()) / spacing.z();
|
||||
if (min_i == grid->xdim() - 1) {
|
||||
min_i--;
|
||||
}
|
||||
if (min_j == grid->ydim() - 1) {
|
||||
min_j--;
|
||||
}
|
||||
if (min_k == grid->zdim() - 1) {
|
||||
min_k--;
|
||||
}
|
||||
// calculate min index including border case
|
||||
std::size_t min_i = (point.x() - bbox.xmin()) / spacing.x();
|
||||
std::size_t min_j = (point.y() - bbox.ymin()) / spacing.y();
|
||||
std::size_t min_k = (point.z() - bbox.zmin()) / spacing.z();
|
||||
if(min_i == grid->xdim() - 1)
|
||||
--min_i;
|
||||
|
||||
// calculate coordinates of min index
|
||||
const FT min_x = min_i * spacing.x() + bbox.xmin();
|
||||
const FT min_y = min_j * spacing.y() + bbox.ymin();
|
||||
const FT min_z = min_k * spacing.z() + bbox.zmin();
|
||||
if(min_j == grid->ydim() - 1)
|
||||
--min_j;
|
||||
|
||||
// interpolation factors between 0 and 1
|
||||
const FT f_i = (point.x() - min_x) / spacing.x();
|
||||
const FT f_j = (point.y() - min_y) / spacing.y();
|
||||
const FT f_k = (point.z() - min_z) / spacing.z();
|
||||
if(min_k == grid->zdim() - 1)
|
||||
--min_k;
|
||||
|
||||
// read the gradient at all 8 corner points
|
||||
const Vector g000 = grid->gradient(min_i + 0, min_j + 0, min_k + 0);
|
||||
const Vector g001 = grid->gradient(min_i + 0, min_j + 0, min_k + 1);
|
||||
const Vector g010 = grid->gradient(min_i + 0, min_j + 1, min_k + 0);
|
||||
const Vector g011 = grid->gradient(min_i + 0, min_j + 1, min_k + 1);
|
||||
const Vector g100 = grid->gradient(min_i + 1, min_j + 0, min_k + 0);
|
||||
const Vector g101 = grid->gradient(min_i + 1, min_j + 0, min_k + 1);
|
||||
const Vector g110 = grid->gradient(min_i + 1, min_j + 1, min_k + 0);
|
||||
const Vector g111 = grid->gradient(min_i + 1, min_j + 1, min_k + 1);
|
||||
|
||||
// interpolate along all axes by weighting the corner points
|
||||
const Vector g0 = g000 * (1 - f_i) * (1 - f_j) * (1 - f_k);
|
||||
const Vector g1 = g001 * (1 - f_i) * (1 - f_j) * f_k;
|
||||
const Vector g2 = g010 * (1 - f_i) * f_j * (1 - f_k);
|
||||
const Vector g3 = g011 * (1 - f_i) * f_j * f_k;
|
||||
const Vector g4 = g100 * f_i * (1 - f_j) * (1 - f_k);
|
||||
const Vector g5 = g101 * f_i * (1 - f_j) * f_k;
|
||||
const Vector g6 = g110 * f_i * f_j * (1 - f_k);
|
||||
const Vector g7 = g111 * f_i * f_j * f_k;
|
||||
// calculate coordinates of min index
|
||||
const FT min_x = min_i * spacing.x() + bbox.xmin();
|
||||
const FT min_y = min_j * spacing.y() + bbox.ymin();
|
||||
const FT min_z = min_k * spacing.z() + bbox.zmin();
|
||||
|
||||
// add weighted corners
|
||||
return g0 + g1 + g2 + g3 + g4 + g5 + g6 + g7;
|
||||
}
|
||||
// interpolation factors between 0 and 1
|
||||
const FT f_i = (point.x() - min_x) / spacing.x();
|
||||
const FT f_j = (point.y() - min_y) / spacing.y();
|
||||
const FT f_k = (point.z() - min_z) / spacing.z();
|
||||
|
||||
// read the gradient at all 8 corner points
|
||||
const Vector g000 = grid->gradient(min_i + 0, min_j + 0, min_k + 0);
|
||||
const Vector g001 = grid->gradient(min_i + 0, min_j + 0, min_k + 1);
|
||||
const Vector g010 = grid->gradient(min_i + 0, min_j + 1, min_k + 0);
|
||||
const Vector g011 = grid->gradient(min_i + 0, min_j + 1, min_k + 1);
|
||||
const Vector g100 = grid->gradient(min_i + 1, min_j + 0, min_k + 0);
|
||||
const Vector g101 = grid->gradient(min_i + 1, min_j + 0, min_k + 1);
|
||||
const Vector g110 = grid->gradient(min_i + 1, min_j + 1, min_k + 0);
|
||||
const Vector g111 = grid->gradient(min_i + 1, min_j + 1, min_k + 1);
|
||||
|
||||
// interpolate along all axes by weighting the corner points
|
||||
const Vector g0 = g000 * (1 - f_i) * (1 - f_j) * (1 - f_k);
|
||||
const Vector g1 = g001 * (1 - f_i) * (1 - f_j) * f_k;
|
||||
const Vector g2 = g010 * (1 - f_i) * f_j * (1 - f_k);
|
||||
const Vector g3 = g011 * (1 - f_i) * f_j * f_k;
|
||||
const Vector g4 = g100 * f_i * (1 - f_j) * (1 - f_k);
|
||||
const Vector g5 = g101 * f_i * (1 - f_j) * f_k;
|
||||
const Vector g6 = g110 * f_i * f_j * (1 - f_k);
|
||||
const Vector g7 = g111 * f_i * f_j * f_k;
|
||||
|
||||
// add weighted corners
|
||||
return g0 + g1 + g2 + g3 + g4 + g5 + g6 + g7;
|
||||
}
|
||||
|
||||
private:
|
||||
const Grid grid;
|
||||
const Grid grid;
|
||||
};
|
||||
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_EXPLICIT_CARTESIAN_GRID_GRADIENT_H
|
||||
#endif // CGAL_EXPLICIT_CARTESIAN_GRID_GRADIENT_H
|
||||
|
|
|
|||
|
|
@ -30,56 +30,62 @@ namespace Isosurfacing {
|
|||
* \tparam PointFunction the type of the implicit function. It must implement `GeomTraits::FT operator()(const
|
||||
* GeomTraits::Point& point) const`.
|
||||
*/
|
||||
template <class GeomTraits, typename PointFunction>
|
||||
class Finite_difference_gradient {
|
||||
template <typename GeomTraits,
|
||||
typename PointFunction>
|
||||
class Finite_difference_gradient
|
||||
{
|
||||
public:
|
||||
typedef GeomTraits Geom_traits;
|
||||
typedef typename Geom_traits::FT FT;
|
||||
typedef typename Geom_traits::Point_3 Point;
|
||||
typedef typename Geom_traits::Vector_3 Vector;
|
||||
using Geom_traits = GeomTraits;
|
||||
using FT = typename Geom_traits::FT;
|
||||
using Point = typename Geom_traits::Point_3;
|
||||
using Vector = typename Geom_traits::Vector_3;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Create a new instance of this gradient.
|
||||
*
|
||||
* \param point_function the function with a point as argument
|
||||
* \param delta the distance for calculating the finite differences
|
||||
*/
|
||||
Finite_difference_gradient(const PointFunction& point_function, const FT delta = 0.001)
|
||||
: func(point_function), delta(delta) {}
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Create a new instance of this gradient.
|
||||
*
|
||||
* \param point_function the function with a point as argument
|
||||
* \param delta the distance for calculating the finite differences
|
||||
*/
|
||||
Finite_difference_gradient(const PointFunction& point_function,
|
||||
const FT delta = 0.001)
|
||||
: func(point_function),
|
||||
delta(delta)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Evaluate the gradient at a point in space.
|
||||
*
|
||||
* \param point the point at which the gradient is computed
|
||||
*/
|
||||
Vector operator()(const Point& point) const {
|
||||
// compute the gradient by sampling the function with finite differences
|
||||
// at six points with distance delta around the query point
|
||||
const Point p0 = point + Vector(delta, 0, 0);
|
||||
const Point p1 = point - Vector(delta, 0, 0);
|
||||
const Point p2 = point + Vector(0, delta, 0);
|
||||
const Point p3 = point - Vector(0, delta, 0);
|
||||
const Point p4 = point + Vector(0, 0, delta);
|
||||
const Point p5 = point - Vector(0, 0, delta);
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Evaluate the gradient at a point in space.
|
||||
*
|
||||
* \param point the point at which the gradient is computed
|
||||
*/
|
||||
Vector operator()(const Point& point) const
|
||||
{
|
||||
// compute the gradient by sampling the function with finite differences
|
||||
// at six points with distance delta around the query point
|
||||
const Point p0 = point + Vector(delta, 0, 0);
|
||||
const Point p1 = point - Vector(delta, 0, 0);
|
||||
const Point p2 = point + Vector(0, delta, 0);
|
||||
const Point p3 = point - Vector(0, delta, 0);
|
||||
const Point p4 = point + Vector(0, 0, delta);
|
||||
const Point p5 = point - Vector(0, 0, delta);
|
||||
|
||||
const FT gx = (func(p0) - func(p1)) / (2 * delta);
|
||||
const FT gy = (func(p2) - func(p3)) / (2 * delta);
|
||||
const FT gz = (func(p4) - func(p5)) / (2 * delta);
|
||||
const FT gx = (func(p0) - func(p1)) / (2 * delta);
|
||||
const FT gy = (func(p2) - func(p3)) / (2 * delta);
|
||||
const FT gz = (func(p4) - func(p5)) / (2 * delta);
|
||||
|
||||
return Vector(gx, gy, gz);
|
||||
}
|
||||
return Vector(gx, gy, gz);
|
||||
}
|
||||
|
||||
private:
|
||||
const PointFunction func;
|
||||
FT delta;
|
||||
const PointFunction func;
|
||||
FT delta;
|
||||
};
|
||||
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_FINITE_DIFFERENCE_GRADIENT_H
|
||||
#endif // CGAL_FINITE_DIFFERENCE_GRADIENT_H
|
||||
|
|
|
|||
|
|
@ -31,15 +31,22 @@ namespace Isosurfacing {
|
|||
* `IsosurfacingDomainWithGradient`.
|
||||
*
|
||||
* \tparam GeomTraits the traits type
|
||||
* \tparam PointFunction the type of the implicit function. It must implement `GeomTraits::FT operator()(const
|
||||
* GeomTraits::Point& point) const`. \tparam Gradient_ the type of the gradient functor. It must implement
|
||||
* `GeomTraits::Vector operator()(const GeomTraits::Point& point) const`.
|
||||
* \tparam PointFunction the type of the implicit function. It must implement
|
||||
* `GeomTraits::FT operator()(const GeomTraits::Point& point) const`.
|
||||
* \tparam Gradient_ the type of the gradient functor. It must implement
|
||||
* `GeomTraits::Vector operator()(const GeomTraits::Point& point) const`.
|
||||
*/
|
||||
template <class GeomTraits, typename PointFunction, typename Gradient_>
|
||||
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_>;
|
||||
template <typename GeomTraits,
|
||||
typename PointFunction,
|
||||
typename Gradient_>
|
||||
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_>;
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
|
|
@ -61,36 +68,41 @@ using Implicit_cartesian_grid_domain = internal::Base_domain<
|
|||
*
|
||||
* \return a new `Implicit_cartesian_grid_domain`
|
||||
*/
|
||||
template <class GeomTraits, typename PointFunction, typename Gradient_ = Zero_gradient<GeomTraits>>
|
||||
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_()) {
|
||||
template <typename GeomTraits,
|
||||
typename PointFunction,
|
||||
typename Gradient_ = Zero_gradient<GeomTraits> >
|
||||
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;
|
||||
typedef typename Domain::Topology Topology;
|
||||
typedef typename Domain::Geometry Geometry;
|
||||
typedef typename Domain::Function Function;
|
||||
typedef typename Domain::Gradient Gradient;
|
||||
typedef typename Function::element_type::Point_function Point_function;
|
||||
using Topology = typename Domain::Topology;
|
||||
using Geometry = typename Domain::Geometry;
|
||||
using Function = typename Domain::Function;
|
||||
using Gradient = typename Domain::Gradient;
|
||||
using Point_function = typename Function::element_type::Point_function;
|
||||
|
||||
// calculate grid dimensions
|
||||
const std::size_t size_i = std::ceil(bbox.x_span() / spacing.x()) + 1;
|
||||
const std::size_t size_j = std::ceil(bbox.y_span() / spacing.y()) + 1;
|
||||
const std::size_t size_k = std::ceil(bbox.z_span() / spacing.z()) + 1;
|
||||
// calculate grid dimensions
|
||||
const std::size_t size_i = std::ceil(bbox.x_span() / spacing.x()) + 1;
|
||||
const std::size_t size_j = std::ceil(bbox.y_span() / spacing.y()) + 1;
|
||||
const std::size_t size_k = std::ceil(bbox.z_span() / spacing.z()) + 1;
|
||||
|
||||
const typename GeomTraits::Vector_3 offset(bbox.xmin(), bbox.ymin(), bbox.zmin());
|
||||
const typename GeomTraits::Vector_3 offset(bbox.xmin(), bbox.ymin(), bbox.zmin());
|
||||
|
||||
// create copies as shared_ptr for safe memory management
|
||||
const Topology topo = std::make_shared<Topology::element_type>(size_i, size_j, size_k);
|
||||
const Geometry geom = std::make_shared<Geometry::element_type>(offset, spacing);
|
||||
const Point_function point_func = std::make_shared<Point_function::element_type>(point_function);
|
||||
const Function func = std::make_shared<Function::element_type>(geom, point_func);
|
||||
const Gradient grad = std::make_shared<Gradient::element_type>(gradient);
|
||||
// create copies as shared_ptr for safe memory management
|
||||
const Topology topo = std::make_shared<Topology::element_type>(size_i, size_j, size_k);
|
||||
const Geometry geom = std::make_shared<Geometry::element_type>(offset, spacing);
|
||||
const Point_function point_func = std::make_shared<Point_function::element_type>(point_function);
|
||||
const Function func = std::make_shared<Function::element_type>(geom, point_func);
|
||||
const Gradient grad = std::make_shared<Gradient::element_type>(gradient);
|
||||
|
||||
return Domain(topo, geom, func, grad);
|
||||
return Domain(topo, geom, func, grad);
|
||||
}
|
||||
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_IMPLICIT_CARTESIAN_GRID_DOMAIN_H
|
||||
#endif // CGAL_IMPLICIT_CARTESIAN_GRID_DOMAIN_H
|
||||
|
|
|
|||
|
|
@ -24,37 +24,46 @@
|
|||
namespace CGAL {
|
||||
namespace Isosurfacing {
|
||||
|
||||
template <typename GeomTraits,
|
||||
typename PointFunction,
|
||||
typename Gradient_>
|
||||
using Implicit_octree_domain =
|
||||
internal::Base_domain<GeomTraits,
|
||||
internal::Octree_topology<GeomTraits>,
|
||||
internal::Octree_geometry<GeomTraits>,
|
||||
internal::Implicit_function_with_geometry<GeomTraits,
|
||||
internal::Octree_geometry<GeomTraits>,
|
||||
PointFunction>,
|
||||
Gradient_>;
|
||||
|
||||
template <class GeomTraits, typename PointFunction, typename Gradient_>
|
||||
using Implicit_octree_domain = internal::Base_domain<
|
||||
GeomTraits, internal::Octree_topology<GeomTraits>, internal::Octree_geometry<GeomTraits>,
|
||||
internal::Implicit_function_with_geometry<GeomTraits, internal::Octree_geometry<GeomTraits>, PointFunction>,
|
||||
Gradient_>;
|
||||
template <typename GeomTraits,
|
||||
typename PointFunction,
|
||||
typename Gradient_ = Zero_gradient<GeomTraits> >
|
||||
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_>;
|
||||
|
||||
template <class GeomTraits, typename PointFunction, typename Gradient_ = Zero_gradient<GeomTraits>>
|
||||
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 Topology = typename Domain::Topology;
|
||||
using Geometry = typename Domain::Geometry;
|
||||
using Function = typename Domain::Function;
|
||||
using Gradient = typename Domain::Gradient;
|
||||
using Point_function = typename Function::element_type::Point_function;
|
||||
using Octree = typename Topology::element_type::Octree;
|
||||
|
||||
typedef Implicit_octree_domain<GeomTraits, PointFunction, Gradient_> Domain;
|
||||
typedef typename Domain::Topology Topology;
|
||||
typedef typename Domain::Geometry Geometry;
|
||||
typedef typename Domain::Function Function;
|
||||
typedef typename Domain::Gradient Gradient;
|
||||
typedef typename Function::element_type::Point_function Point_function;
|
||||
typedef typename Topology::element_type::Octree Octree;
|
||||
const Octree oct = octree;
|
||||
const Topology topo = std::make_shared<Topology::element_type>(oct);
|
||||
const Geometry geom = std::make_shared<Geometry::element_type>(oct);
|
||||
const Point_function point_func = std::make_shared<Point_function::element_type>(point_function);
|
||||
const Function func = std::make_shared<Function::element_type>(geom, point_func);
|
||||
const Gradient grad = std::make_shared<Gradient::element_type>(gradient);
|
||||
|
||||
const Octree oct = octree;
|
||||
const Topology topo = std::make_shared<Topology::element_type>(oct);
|
||||
const Geometry geom = std::make_shared<Geometry::element_type>(oct);
|
||||
const Point_function point_func = std::make_shared<Point_function::element_type>(point_function);
|
||||
const Function func = std::make_shared<Function::element_type>(geom, point_func);
|
||||
const Gradient grad = std::make_shared<Gradient::element_type>(gradient);
|
||||
|
||||
return Domain(topo, geom, func, grad);
|
||||
return Domain(topo, geom, func, grad);
|
||||
}
|
||||
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_IMPLICIT_OCTREE_DOMAIN_H
|
||||
#endif // CGAL_IMPLICIT_OCTREE_DOMAIN_H
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
//
|
||||
// Author(s) : Julian Stahl
|
||||
|
||||
#ifndef CGAL_BASE_DOMAIN_H
|
||||
#define CGAL_BASE_DOMAIN_H
|
||||
#ifndef CGAL_ISOSURFACING_3_INTERNAL_BASE_DOMAIN_H
|
||||
#define CGAL_ISOSURFACING_3_INTERNAL_BASE_DOMAIN_H
|
||||
|
||||
#include <CGAL/license/Isosurfacing_3.h>
|
||||
|
||||
|
|
@ -22,101 +22,124 @@ namespace CGAL {
|
|||
namespace Isosurfacing {
|
||||
namespace internal {
|
||||
|
||||
// A wrapper class to puzzle a domain together from different combinations of topology, geometry, function, and
|
||||
// gradient.
|
||||
template <class GeomTraits, typename Topology_, typename Geometry_, typename Function_, typename Gradient_>
|
||||
class Base_domain {
|
||||
// A wrapper class to puzzle a domain together from different combinations of topology,
|
||||
// geometry, function, and gradient.
|
||||
template <typename GeomTraits,
|
||||
typename Topology_,
|
||||
typename Geometry_,
|
||||
typename Function_,
|
||||
typename Gradient_>
|
||||
class Base_domain
|
||||
{
|
||||
public:
|
||||
typedef GeomTraits Geom_traits;
|
||||
typedef typename Geom_traits::FT FT;
|
||||
typedef typename Geom_traits::Point_3 Point;
|
||||
typedef typename Geom_traits::Vector_3 Vector;
|
||||
using Geom_traits = GeomTraits;
|
||||
|
||||
typedef std::shared_ptr<Topology_> Topology;
|
||||
typedef typename Topology_::Vertex_descriptor Vertex_descriptor;
|
||||
typedef typename Topology_::Edge_descriptor Edge_descriptor;
|
||||
typedef typename Topology_::Cell_descriptor Cell_descriptor;
|
||||
using FT = typename Geom_traits::FT;
|
||||
using Point = typename Geom_traits::Point_3;
|
||||
using Vector = typename Geom_traits::Vector_3;
|
||||
|
||||
static constexpr Cell_type CELL_TYPE = Topology_::CELL_TYPE;
|
||||
static constexpr std::size_t VERTICES_PER_CELL = Topology_::VERTICES_PER_CELL;
|
||||
static constexpr std::size_t EDGES_PER_CELL = Topology_::EDGES_PER_CELL;
|
||||
using Topology = std::shared_ptr<Topology_>;
|
||||
using Vertex_descriptor = typename Topology_::Vertex_descriptor;
|
||||
using Edge_descriptor = typename Topology_::Edge_descriptor;
|
||||
using Cell_descriptor = typename Topology_::Cell_descriptor;
|
||||
|
||||
typedef typename Topology_::Vertices_incident_to_edge Vertices_incident_to_edge;
|
||||
typedef typename Topology_::Cells_incident_to_edge Cells_incident_to_edge;
|
||||
typedef typename Topology_::Cell_vertices Cell_vertices;
|
||||
typedef typename Topology_::Cell_edges Cell_edges;
|
||||
using Vertices_incident_to_edge = typename Topology_::Vertices_incident_to_edge;
|
||||
using Cells_incident_to_edge = typename Topology_::Cells_incident_to_edge;
|
||||
using Cell_vertices = typename Topology_::Cell_vertices;
|
||||
using Cell_edges = typename Topology_::Cell_edges;
|
||||
|
||||
typedef std::shared_ptr<Geometry_> Geometry;
|
||||
typedef std::shared_ptr<Function_> Function;
|
||||
typedef std::shared_ptr<Gradient_> Gradient;
|
||||
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 std::size_t VERTICES_PER_CELL = Topology_::VERTICES_PER_CELL;
|
||||
static constexpr std::size_t EDGES_PER_CELL = Topology_::EDGES_PER_CELL;
|
||||
|
||||
public:
|
||||
// Create a base_domain from a topology, geometry, input function, and gradient
|
||||
Base_domain(const Topology& topo, const Geometry& geom, const Function& func, const Gradient& grad)
|
||||
: topo(topo), geom(geom), func(func), grad(grad) {}
|
||||
// Create a base_domain from a topology, geometry, input function, and gradient
|
||||
Base_domain(const Topology& topo,
|
||||
const Geometry& geom,
|
||||
const Function& func,
|
||||
const Gradient& grad)
|
||||
: topo(topo),
|
||||
geom(geom),
|
||||
func(func),
|
||||
grad(grad)
|
||||
{ }
|
||||
|
||||
// Get the position of vertex v
|
||||
Point position(const Vertex_descriptor& v) const {
|
||||
return geom->operator()(v);
|
||||
}
|
||||
// Get the position of vertex v
|
||||
Point position(const Vertex_descriptor& v) const
|
||||
{
|
||||
return geom->operator()(v);
|
||||
}
|
||||
|
||||
// Get the value of the function at vertex v
|
||||
FT value(const Vertex_descriptor& v) const {
|
||||
return func->operator()(v);
|
||||
}
|
||||
// Get the value of the function at vertex v
|
||||
FT value(const Vertex_descriptor& v) const
|
||||
{
|
||||
return func->operator()(v);
|
||||
}
|
||||
|
||||
// Get the gradient at vertex v
|
||||
Vector gradient(const Point& p) const {
|
||||
return grad->operator()(p);
|
||||
}
|
||||
// Get the gradient at vertex v
|
||||
Vector gradient(const Point& p) const
|
||||
{
|
||||
return grad->operator()(p);
|
||||
}
|
||||
|
||||
// Get a container with the two vertices incident to the edge e
|
||||
Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const {
|
||||
return topo->edge_vertices(e);
|
||||
}
|
||||
// Get a container with the two vertices incident to the edge e
|
||||
Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const
|
||||
{
|
||||
return topo->edge_vertices(e);
|
||||
}
|
||||
|
||||
// Get a container with all cells incident to the edge e
|
||||
Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const {
|
||||
return topo->cells_incident_to_edge(e);
|
||||
}
|
||||
// Get a container with all cells incident to the edge e
|
||||
Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const
|
||||
{
|
||||
return topo->cells_incident_to_edge(e);
|
||||
}
|
||||
|
||||
// Get a container with all vertices of the cell c
|
||||
Cell_vertices cell_vertices(const Cell_descriptor& c) const {
|
||||
return topo->cell_vertices(c);
|
||||
}
|
||||
// Get a container with all vertices of the cell c
|
||||
Cell_vertices cell_vertices(const Cell_descriptor& c) const
|
||||
{
|
||||
return topo->cell_vertices(c);
|
||||
}
|
||||
|
||||
// Get a container with all edges of the cell c
|
||||
Cell_edges cell_edges(const Cell_descriptor& c) const {
|
||||
return topo->cell_edges(c);
|
||||
}
|
||||
// Get a container with all edges of the cell c
|
||||
Cell_edges cell_edges(const Cell_descriptor& c) const
|
||||
{
|
||||
return topo->cell_edges(c);
|
||||
}
|
||||
|
||||
// Iterate over all vertices v calling f(v) on every one
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_vertices(Functor& f) const {
|
||||
topo->iterate_vertices(f, Concurrency_tag());
|
||||
}
|
||||
// Iterate over all vertices v calling f(v) on every one
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_vertices(Functor& f) const
|
||||
{
|
||||
topo->iterate_vertices(f, Concurrency_tag());
|
||||
}
|
||||
|
||||
// Iterate over all edges e calling f(e) on every one
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_edges(Functor& f) const {
|
||||
topo->iterate_edges(f, Concurrency_tag());
|
||||
}
|
||||
// Iterate over all edges e calling f(e) on every one
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_edges(Functor& f) const
|
||||
{
|
||||
topo->iterate_edges(f, Concurrency_tag());
|
||||
}
|
||||
|
||||
// Iterate over all cells c calling f(c) on every one
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_cells(Functor& f) const {
|
||||
topo->iterate_cells(f, Concurrency_tag());
|
||||
}
|
||||
// Iterate over all cells c calling f(c) on every one
|
||||
template <typename Concurrency_tag, typename Functor>
|
||||
void iterate_cells(Functor& f) const
|
||||
{
|
||||
topo->iterate_cells(f, Concurrency_tag());
|
||||
}
|
||||
|
||||
private:
|
||||
const Topology topo;
|
||||
const Geometry geom;
|
||||
const Function func;
|
||||
const Gradient grad;
|
||||
const Topology topo;
|
||||
const Geometry geom;
|
||||
const Function func;
|
||||
const Gradient grad;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_BASE_DOMAIN_H
|
||||
#endif // CGAL_ISOSURFACING_3_INTERNAL_BASE_DOMAIN_H
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
//
|
||||
// Author(s) : Julian Stahl
|
||||
|
||||
#ifndef CGAL_CARTESIAN_GRID_GEOMETRY_H
|
||||
#define CGAL_CARTESIAN_GRID_GEOMETRY_H
|
||||
#ifndef CGAL_ISOSURFACING_3_INTERNAL_CARTESIAN_GRID_GEOMETRY_H
|
||||
#define CGAL_ISOSURFACING_3_INTERNAL_CARTESIAN_GRID_GEOMETRY_H
|
||||
|
||||
#include <CGAL/license/Isosurfacing_3.h>
|
||||
|
||||
|
|
@ -22,32 +22,40 @@ namespace internal {
|
|||
|
||||
// Describes the geometry of a regular cartesian grid. Positions are not stored but calculated
|
||||
// from an offset and grid spacing.
|
||||
template <class GeomTraits>
|
||||
class Cartesian_grid_geometry {
|
||||
template <typename GeomTraits>
|
||||
class Cartesian_grid_geometry
|
||||
{
|
||||
public:
|
||||
typedef GeomTraits Geom_traits;
|
||||
typedef typename Geom_traits::Point_3 Point;
|
||||
typedef typename Geom_traits::Vector_3 Vector;
|
||||
using Geom_traits = GeomTraits;
|
||||
using Point = typename Geom_traits::Point_3;
|
||||
using Vector = typename Geom_traits::Vector_3;
|
||||
|
||||
typedef typename Grid_topology::Vertex_descriptor Vertex_descriptor;
|
||||
using Vertex_descriptor = typename Grid_topology::Vertex_descriptor;
|
||||
|
||||
public:
|
||||
// Create a regular grid geometry where offset is the position of the vertex with index (0, 0, 0)
|
||||
// and spacing the distance between two connected vertices in each dimension.
|
||||
Cartesian_grid_geometry(const Vector& offset, const Vector& spacing) : offset(offset), spacing(spacing) {}
|
||||
// Create a regular grid geometry where offset is the position of the vertex with index (0, 0, 0)
|
||||
// and spacing the distance between two connected vertices in each dimension.
|
||||
Cartesian_grid_geometry(const Vector& offset,
|
||||
const Vector& spacing)
|
||||
: offset(offset),
|
||||
spacing(spacing)
|
||||
{ }
|
||||
|
||||
// Get the position of vertex v
|
||||
Point operator()(const Vertex_descriptor& v) const {
|
||||
return Point(v[0] * spacing[0], v[1] * spacing[1], v[2] * spacing[2]) + offset;
|
||||
}
|
||||
// Get the position of vertex v
|
||||
Point operator()(const Vertex_descriptor& v) const
|
||||
{
|
||||
return Point(v[0] * spacing[0],
|
||||
v[1] * spacing[1],
|
||||
v[2] * spacing[2]) + offset;
|
||||
}
|
||||
|
||||
private:
|
||||
Vector offset;
|
||||
Vector spacing;
|
||||
Vector offset;
|
||||
Vector spacing;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_CARTESIAN_GRID_GEOMETRY_H
|
||||
#endif // CGAL_ISOSURFACING_3_INTERNAL_CARTESIAN_GRID_GEOMETRY_H
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
//
|
||||
// Author(s) : Julian Stahl
|
||||
|
||||
#ifndef CGAL_DOMAIN_CELL_TYPE
|
||||
#define CGAL_DOMAIN_CELL_TYPE
|
||||
#ifndef CGAL_ISOSURFACING_3_INTERNAL_DOMAIN_CELL_TYPE
|
||||
#define CGAL_ISOSURFACING_3_INTERNAL_DOMAIN_CELL_TYPE
|
||||
|
||||
#include <CGAL/license/Isosurfacing_3.h>
|
||||
|
||||
|
|
@ -19,17 +19,16 @@
|
|||
namespace CGAL {
|
||||
namespace Isosurfacing {
|
||||
|
||||
|
||||
// Was supposed to check if an algorithm can handle a specific domain. Not used right now.
|
||||
typedef std::size_t Cell_type;
|
||||
using Cell_type = std::size_t;
|
||||
|
||||
static constexpr Cell_type ANY_CELL = (std::numeric_limits<Cell_type>::max)();
|
||||
|
||||
static constexpr Cell_type POLYHERDAL_CELL = ((Cell_type)1) << 0;
|
||||
static constexpr Cell_type TETRAHEDRAL_CELL = ((Cell_type)1) << 1;
|
||||
static constexpr Cell_type CUBICAL_CELL = ((Cell_type)1) << 2;
|
||||
static constexpr Cell_type POLYHERDAL_CELL = (Cell_type(1) << 0);
|
||||
static constexpr Cell_type TETRAHEDRAL_CELL = (Cell_type(1) << 1);
|
||||
static constexpr Cell_type CUBICAL_CELL = (Cell_type(1) << 2);
|
||||
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_DOMAIN_CELL_TYPE
|
||||
#endif // CGAL_ISOSURFACING_3_INTERNAL_DOMAIN_CELL_TYPE
|
||||
|
|
@ -10,16 +10,17 @@
|
|||
// Author(s) : Daniel Zint
|
||||
// Julian Stahl
|
||||
|
||||
#ifndef CGAL_DUAL_CONTOURING_3_INTERNAL_DUAL_CONTOURING_3_H
|
||||
#define CGAL_DUAL_CONTOURING_3_INTERNAL_DUAL_CONTOURING_3_H
|
||||
#ifndef CGAL_ISOSURFACING_3_INTERNAL_DUAL_CONTOURING_INTERNAL_H
|
||||
#define CGAL_ISOSURFACING_3_INTERNAL_DUAL_CONTOURING_INTERNAL_H
|
||||
|
||||
#include <CGAL/license/Isosurfacing_3.h>
|
||||
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/Origin.h>
|
||||
#include <CGAL/centroid.h>
|
||||
#include <CGAL/Origin.h>
|
||||
|
||||
#include <Eigen/SVD>
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
|
@ -30,11 +31,12 @@ namespace Isosurfacing {
|
|||
namespace internal {
|
||||
|
||||
namespace Positioning {
|
||||
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Computes the vertex position for a point in Dual Contouring using Quadric Error Metrics and the SVD pseudo
|
||||
* inverse.
|
||||
* \brief Computes the vertex position for a point in Dual Contouring
|
||||
* using Quadric Error Metrics and the SVD pseudo inverse.
|
||||
*
|
||||
* \details
|
||||
*
|
||||
|
|
@ -42,109 +44,120 @@ namespace Positioning {
|
|||
*
|
||||
*/
|
||||
template <bool use_bbox = false>
|
||||
class QEM_SVD {
|
||||
class QEM_SVD
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Computes the vertex position for a point in Dual Contouring.
|
||||
*
|
||||
* \details
|
||||
*
|
||||
* \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`.
|
||||
*
|
||||
* \param domain the domain providing input data and its topology
|
||||
* \param isovalue value of the isosurface
|
||||
* \param cell the cell within the domain for which the vertex position ins computed
|
||||
* \param point the point position of the vertex that belongs to that cell
|
||||
*
|
||||
* \return true, if the voxel intersects the isosurface
|
||||
*/
|
||||
template <class Domain_>
|
||||
bool position(const Domain_& domain, const typename Domain_::FT isovalue,
|
||||
const typename Domain_::Cell_descriptor& cell, typename Domain_::Point& point) const {
|
||||
typedef typename Domain_::Point Point;
|
||||
typedef typename Domain_::Geom_traits::Vector_3 Vector;
|
||||
typedef typename Domain_::FT FT;
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Computes the vertex position for a point in Dual Contouring.
|
||||
*
|
||||
* \details
|
||||
*
|
||||
* \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`.
|
||||
*
|
||||
* \param domain the domain providing input data and its topology
|
||||
* \param isovalue value of the isosurface
|
||||
* \param cell the cell within the domain for which the vertex position ins computed
|
||||
* \param point the point position of the vertex that belongs to that cell
|
||||
*
|
||||
* \return true, if the voxel intersects the isosurface
|
||||
*/
|
||||
template <typename Domain_>
|
||||
bool position(const Domain_& domain,
|
||||
const typename Domain_::FT isovalue,
|
||||
const typename Domain_::Cell_descriptor& cell,
|
||||
typename Domain_::Point& point) const
|
||||
{
|
||||
using Point = typename Domain_::Point;
|
||||
using Vector = typename Domain_::Geom_traits::Vector_3;
|
||||
using FT = typename Domain_::FT;
|
||||
|
||||
typename Domain_::Cell_vertices vertices = domain.cell_vertices(cell);
|
||||
typename Domain_::Cell_vertices vertices = domain.cell_vertices(cell);
|
||||
|
||||
std::vector<Point> pos(vertices.size());
|
||||
std::transform(vertices.begin(), vertices.end(), pos.begin(),
|
||||
[&](const auto& v) { return domain.position(v); });
|
||||
std::vector<Point> pos(vertices.size());
|
||||
std::transform(vertices.begin(), vertices.end(), pos.begin(),
|
||||
[&](const auto& v) { return domain.position(v); });
|
||||
|
||||
point = CGAL::centroid(pos.begin(), pos.end(), CGAL::Dimension_tag<0>()); // set point to cell center
|
||||
// set point to cell center
|
||||
point = CGAL::centroid(pos.begin(), pos.end(), CGAL::Dimension_tag<0>());
|
||||
|
||||
// compute edge intersections
|
||||
std::vector<Point> edge_intersections;
|
||||
std::vector<Vector> edge_intersection_normals;
|
||||
// compute edge intersections
|
||||
std::vector<Point> edge_intersections;
|
||||
std::vector<Vector> edge_intersection_normals;
|
||||
|
||||
for (const auto& edge : domain.cell_edges(cell)) {
|
||||
const auto& edge_vertices = domain.edge_vertices(edge);
|
||||
const auto& v0 = edge_vertices[0];
|
||||
const auto& v1 = edge_vertices[1];
|
||||
for(const auto& edge : domain.cell_edges(cell))
|
||||
{
|
||||
const auto& edge_vertices = domain.edge_vertices(edge);
|
||||
const auto& v0 = edge_vertices[0];
|
||||
const auto& v1 = edge_vertices[1];
|
||||
|
||||
const auto& val0 = domain.value(v0);
|
||||
const auto& val1 = domain.value(v1);
|
||||
const auto& val0 = domain.value(v0);
|
||||
const auto& val1 = domain.value(v1);
|
||||
|
||||
const auto& p0 = domain.position(v0);
|
||||
const auto& p1 = domain.position(v1);
|
||||
const auto& p0 = domain.position(v0);
|
||||
const auto& p1 = domain.position(v1);
|
||||
|
||||
if ((val0 <= isovalue) != (val1 <= isovalue)) { // this edge is intersected by the isosurface
|
||||
const FT u = (val0 - isovalue) / (val0 - val1);
|
||||
const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN));
|
||||
edge_intersections.push_back(p_lerp);
|
||||
edge_intersection_normals.push_back(domain.gradient(p_lerp));
|
||||
}
|
||||
}
|
||||
|
||||
if (edge_intersections.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// SVD QEM
|
||||
Eigen::Matrix3d A;
|
||||
A.setZero();
|
||||
Eigen::Vector3d rhs;
|
||||
rhs.setZero();
|
||||
for (std::size_t i = 0; i < edge_intersections.size(); ++i) {
|
||||
Eigen::Vector3d n_k = {edge_intersection_normals[i].x(), edge_intersection_normals[i].y(),
|
||||
edge_intersection_normals[i].z()};
|
||||
Eigen::Vector3d p_k = {edge_intersections[i].x(), edge_intersections[i].y(), edge_intersections[i].z()};
|
||||
double d_k = n_k.transpose() * p_k;
|
||||
|
||||
Eigen::Matrix3d A_k = n_k * n_k.transpose();
|
||||
Eigen::Vector3d b_k = d_k * n_k;
|
||||
A += A_k;
|
||||
rhs += b_k;
|
||||
}
|
||||
|
||||
Eigen::JacobiSVD<Eigen::MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
|
||||
// set threshold as in Peter Lindstrom's paper, "Out-of-Core
|
||||
// Simplification of Large Polygonal Models"
|
||||
svd.setThreshold(1e-3);
|
||||
|
||||
// Init x hat
|
||||
Eigen::Vector3d x_hat;
|
||||
x_hat << point.x(), point.y(), point.z();
|
||||
|
||||
// Lindstrom formula for QEM new position for singular matrices
|
||||
Eigen::VectorXd v_svd = x_hat + svd.solve(rhs - A * x_hat);
|
||||
|
||||
point = Point(v_svd[0], v_svd[1], v_svd[2]);
|
||||
|
||||
// bbox
|
||||
if (use_bbox) {
|
||||
CGAL::Bbox_3 bbox = pos[0].bbox() + pos[7].bbox(); // TODO remove[0],[7]
|
||||
|
||||
FT x = (std::min<FT>)((std::max<FT>)(point.x(), bbox.xmin()), bbox.xmax());
|
||||
FT y = (std::min<FT>)((std::max<FT>)(point.y(), bbox.ymin()), bbox.ymax());
|
||||
FT z = (std::min<FT>)((std::max<FT>)(point.z(), bbox.zmin()), bbox.zmax());
|
||||
point = Point(x, y, z);
|
||||
}
|
||||
|
||||
return true;
|
||||
if((val0 <= isovalue) != (val1 <= isovalue))
|
||||
{
|
||||
// this edge is intersected by the isosurface
|
||||
const FT u = (val0 - isovalue) / (val0 - val1);
|
||||
const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN));
|
||||
edge_intersections.push_back(p_lerp);
|
||||
edge_intersection_normals.push_back(domain.gradient(p_lerp));
|
||||
}
|
||||
}
|
||||
|
||||
if(edge_intersections.empty())
|
||||
return false;
|
||||
|
||||
// SVD QEM
|
||||
Eigen::Matrix3d A;
|
||||
A.setZero();
|
||||
Eigen::Vector3d rhs;
|
||||
rhs.setZero();
|
||||
for(std::size_t i=0; i<edge_intersections.size(); ++i)
|
||||
{
|
||||
Eigen::Vector3d n_k = { edge_intersection_normals[i].x(),
|
||||
edge_intersection_normals[i].y(),
|
||||
edge_intersection_normals[i].z() };
|
||||
Eigen::Vector3d p_k = { edge_intersections[i].x(),
|
||||
edge_intersections[i].y(),
|
||||
edge_intersections[i].z() };
|
||||
double d_k = n_k.transpose() * p_k;
|
||||
|
||||
Eigen::Matrix3d A_k = n_k * n_k.transpose();
|
||||
Eigen::Vector3d b_k = d_k * n_k;
|
||||
A += A_k;
|
||||
rhs += b_k;
|
||||
}
|
||||
|
||||
Eigen::JacobiSVD<Eigen::MatrixXd> svd(A, Eigen::ComputeThinU | Eigen::ComputeThinV);
|
||||
// set threshold as in Peter Lindstrom's paper, "Out-of-Core Simplification of Large Polygonal Models"
|
||||
svd.setThreshold(1e-3);
|
||||
|
||||
// Init x hat
|
||||
Eigen::Vector3d x_hat;
|
||||
x_hat << point.x(), point.y(), point.z();
|
||||
|
||||
// Lindstrom formula for QEM new position for singular matrices
|
||||
Eigen::VectorXd v_svd = x_hat + svd.solve(rhs - A * x_hat);
|
||||
|
||||
point = Point(v_svd[0], v_svd[1], v_svd[2]);
|
||||
|
||||
// bbox
|
||||
if(use_bbox)
|
||||
{
|
||||
CGAL::Bbox_3 bbox = pos[0].bbox() + pos[7].bbox(); // TODO remove[0],[7]
|
||||
|
||||
FT x = (std::min<FT>)((std::max<FT>)(point.x(), bbox.xmin()), bbox.xmax());
|
||||
FT y = (std::min<FT>)((std::max<FT>)(point.y(), bbox.ymin()), bbox.ymax());
|
||||
FT z = (std::min<FT>)((std::max<FT>)(point.z(), bbox.zmin()), bbox.zmax());
|
||||
point = Point(x, y, z);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -152,53 +165,59 @@ public:
|
|||
*
|
||||
* \brief Returns cell center.
|
||||
*/
|
||||
class Cell_center {
|
||||
class Cell_center
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Computes the vertex position for a point in Dual Contouring.
|
||||
*
|
||||
* \details
|
||||
*
|
||||
* \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`.
|
||||
*
|
||||
* \param domain the domain providing input data and its topology
|
||||
* \param isovalue value of the isosurface
|
||||
* \param cell the cell within the domain for which the vertex position ins computed
|
||||
* \param point the point position of the vertex that belongs to that cell
|
||||
*
|
||||
* \return true, if the voxel intersects the isosurface
|
||||
*/
|
||||
template <class Domain_>
|
||||
bool position(const Domain_& domain, const typename Domain_::FT isovalue,
|
||||
const typename Domain_::Cell_descriptor& vh, typename Domain_::Point& point) const {
|
||||
typedef typename Domain_::Point Point;
|
||||
typedef typename Domain_::Geom_traits::Vector_3 Vector;
|
||||
typedef typename Domain_::FT FT;
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Computes the vertex position for a point in Dual Contouring.
|
||||
*
|
||||
* \details
|
||||
*
|
||||
* \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`.
|
||||
*
|
||||
* \param domain the domain providing input data and its topology
|
||||
* \param isovalue value of the isosurface
|
||||
* \param cell the cell within the domain for which the vertex position ins computed
|
||||
* \param point the point position of the vertex that belongs to that cell
|
||||
*
|
||||
* \return true, if the voxel intersects the isosurface
|
||||
*/
|
||||
template <typename Domain_>
|
||||
bool position(const Domain_& domain,
|
||||
const typename Domain_::FT isovalue,
|
||||
const typename Domain_::Cell_descriptor& vh,
|
||||
typename Domain_::Point& point) const
|
||||
{
|
||||
using Point = typename Domain_::Point;
|
||||
using Vector = typename Domain_::Geom_traits::Vector_3;
|
||||
using FT = typename Domain_::FT;
|
||||
|
||||
typename Domain_::Cell_vertices vertices = domain.cell_vertices(vh);
|
||||
typename Domain_::Cell_vertices vertices = domain.cell_vertices(vh);
|
||||
|
||||
std::vector<Point> pos(vertices.size());
|
||||
std::transform(vertices.begin(), vertices.end(), pos.begin(),
|
||||
[&](const auto& v) { return domain.position(v); });
|
||||
std::vector<Point> pos(vertices.size());
|
||||
std::transform(vertices.begin(), vertices.end(), pos.begin(),
|
||||
[&](const auto& v) { return domain.position(v); });
|
||||
|
||||
point = CGAL::centroid(pos.begin(), pos.end(), CGAL::Dimension_tag<0>()); // set point to cell center
|
||||
// set point to cell center
|
||||
point = CGAL::centroid(pos.begin(), pos.end(), CGAL::Dimension_tag<0>());
|
||||
|
||||
bool allSmaller = true;
|
||||
bool allGreater = true;
|
||||
for (const auto& v : vertices) {
|
||||
const bool& b = domain.value(v) <= isovalue;
|
||||
allSmaller = allSmaller && b;
|
||||
allGreater = allGreater && !b;
|
||||
}
|
||||
|
||||
if (allSmaller || allGreater) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
bool allSmaller = true;
|
||||
bool allGreater = true;
|
||||
for(const auto& v : vertices)
|
||||
{
|
||||
const bool& b = domain.value(v) <= isovalue;
|
||||
allSmaller = allSmaller && b;
|
||||
allGreater = allGreater && !b;
|
||||
}
|
||||
|
||||
if(allSmaller || allGreater)
|
||||
return false;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -206,146 +225,170 @@ public:
|
|||
*
|
||||
* \brief Computes the centroid of all cell edge intersections with the isosurface.
|
||||
*/
|
||||
class Centroid_of_edge_intersections {
|
||||
class Centroid_of_edge_intersections
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Computes the vertex position for a point in Dual Contouring.
|
||||
*
|
||||
* \details
|
||||
*
|
||||
* \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`.
|
||||
*
|
||||
* \param domain the domain providing input data and its topology
|
||||
* \param isovalue value of the isosurface
|
||||
* \param cell the cell within the domain for which the vertex position ins computed
|
||||
* \param point the point position of the vertex that belongs to that cell
|
||||
*
|
||||
* \return true, if the voxel intersects the isosurface
|
||||
*/
|
||||
template <class Domain_>
|
||||
bool position(const Domain_& domain, const typename Domain_::FT isovalue,
|
||||
const typename Domain_::Cell_descriptor& cell, typename Domain_::Point& point) const {
|
||||
typedef typename Domain_::Point Point;
|
||||
typedef typename Domain_::Geom_traits::Vector_3 Vector;
|
||||
typedef typename Domain_::FT FT;
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Computes the vertex position for a point in Dual Contouring.
|
||||
*
|
||||
* \details
|
||||
*
|
||||
* \tparam Domain_ must be a model of `IsosurfacingDomainWithGradient`.
|
||||
*
|
||||
* \param domain the domain providing input data and its topology
|
||||
* \param isovalue value of the isosurface
|
||||
* \param cell the cell within the domain for which the vertex position ins computed
|
||||
* \param point the point position of the vertex that belongs to that cell
|
||||
*
|
||||
* \return true, if the voxel intersects the isosurface
|
||||
*/
|
||||
template <typename Domain_>
|
||||
bool position(const Domain_& domain,
|
||||
const typename Domain_::FT isovalue,
|
||||
const typename Domain_::Cell_descriptor& cell,
|
||||
typename Domain_::Point& point) const
|
||||
{
|
||||
using Point = typename Domain_::Point;
|
||||
using Vector = typename Domain_::Geom_traits::Vector_3;
|
||||
using FT = typename Domain_::FT;
|
||||
|
||||
typename Domain_::Cell_vertices vertices = domain.cell_vertices(cell);
|
||||
typename Domain_::Cell_vertices vertices = domain.cell_vertices(cell);
|
||||
|
||||
// compute edge intersections
|
||||
std::vector<Point> edge_intersections;
|
||||
// compute edge intersections
|
||||
std::vector<Point> edge_intersections;
|
||||
|
||||
for (const auto& edge : domain.cell_edges(cell)) {
|
||||
const auto& edge_vertices = domain.edge_vertices(edge);
|
||||
const auto& v0 = edge_vertices[0];
|
||||
const auto& v1 = edge_vertices[1];
|
||||
for(const auto& edge : domain.cell_edges(cell))
|
||||
{
|
||||
const auto& edge_vertices = domain.edge_vertices(edge);
|
||||
const auto& v0 = edge_vertices[0];
|
||||
const auto& v1 = edge_vertices[1];
|
||||
|
||||
const auto& val0 = domain.value(v0);
|
||||
const auto& val1 = domain.value(v1);
|
||||
const auto& val0 = domain.value(v0);
|
||||
const auto& val1 = domain.value(v1);
|
||||
|
||||
const auto& p0 = domain.position(v0);
|
||||
const auto& p1 = domain.position(v1);
|
||||
const auto& p0 = domain.position(v0);
|
||||
const auto& p1 = domain.position(v1);
|
||||
|
||||
if ((val0 <= isovalue) != (val1 <= isovalue)) { // this edge is intersected by the isosurface
|
||||
const FT u = (val0 - isovalue) / (val0 - val1);
|
||||
const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN));
|
||||
edge_intersections.push_back(p_lerp);
|
||||
}
|
||||
}
|
||||
|
||||
if (edge_intersections.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
point = CGAL::centroid(edge_intersections.begin(), edge_intersections.end(),
|
||||
CGAL::Dimension_tag<0>()); // set point to center of edge intersections
|
||||
|
||||
return true;
|
||||
if((val0 <= isovalue) != (val1 <= isovalue))
|
||||
{
|
||||
// this edge is intersected by the isosurface
|
||||
const FT u = (val0 - isovalue) / (val0 - val1);
|
||||
const Point p_lerp = CGAL::ORIGIN + ((1 - u) * (p0 - CGAL::ORIGIN) + u * (p1 - CGAL::ORIGIN));
|
||||
edge_intersections.push_back(p_lerp);
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace Positioning
|
||||
|
||||
template <class Domain_, class Positioning_>
|
||||
class Dual_contouring_vertex_positioning {
|
||||
if(edge_intersections.empty())
|
||||
return false;
|
||||
|
||||
point = CGAL::centroid(edge_intersections.begin(), edge_intersections.end(),
|
||||
CGAL::Dimension_tag<0>()); // set point to center of edge intersections
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Positioning
|
||||
|
||||
template <typename Domain_,
|
||||
typename Positioning_>
|
||||
class Dual_contouring_vertex_positioning
|
||||
{
|
||||
private:
|
||||
typedef Domain_ Domain;
|
||||
typedef Positioning_ Positioning;
|
||||
using Domain = Domain_;
|
||||
using Positioning = Positioning_;
|
||||
|
||||
typedef typename Domain::FT FT;
|
||||
typedef typename Domain::Point Point;
|
||||
typedef typename Domain::Cell_descriptor Cell_descriptor;
|
||||
using FT = typename Domain::FT;
|
||||
using Point = typename Domain::Point;
|
||||
using Cell_descriptor = typename Domain::Cell_descriptor;
|
||||
|
||||
public:
|
||||
Dual_contouring_vertex_positioning(const Domain& domain, FT isovalue, const Positioning& positioning)
|
||||
: domain(domain), isovalue(isovalue), positioning(positioning), points_counter(0) {}
|
||||
Dual_contouring_vertex_positioning(const Domain& domain,
|
||||
const FT isovalue,
|
||||
const Positioning& positioning)
|
||||
: domain(domain),
|
||||
isovalue(isovalue),
|
||||
positioning(positioning),
|
||||
points_counter(0)
|
||||
{ }
|
||||
|
||||
void operator()(const Cell_descriptor& v) {
|
||||
// compute dc-vertices
|
||||
Point p;
|
||||
if (positioning.position(domain, isovalue, v, p)) {
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
map_voxel_to_point[v] = p;
|
||||
map_voxel_to_point_id[v] = points_counter++;
|
||||
}
|
||||
void operator()(const Cell_descriptor& v)
|
||||
{
|
||||
// compute dc-vertices
|
||||
Point p;
|
||||
if(positioning.position(domain, isovalue, v, p))
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
map_voxel_to_point[v] = p;
|
||||
map_voxel_to_point_id[v] = points_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
// private:
|
||||
const Domain& domain;
|
||||
FT isovalue;
|
||||
const Positioning& positioning;
|
||||
// private: // @todo
|
||||
const Domain& domain;
|
||||
FT isovalue;
|
||||
const Positioning& positioning;
|
||||
|
||||
std::map<Cell_descriptor, std::size_t> map_voxel_to_point_id;
|
||||
std::map<Cell_descriptor, Point> map_voxel_to_point;
|
||||
std::size_t points_counter;
|
||||
std::map<Cell_descriptor, std::size_t> map_voxel_to_point_id;
|
||||
std::map<Cell_descriptor, Point> map_voxel_to_point;
|
||||
std::size_t points_counter;
|
||||
|
||||
std::mutex mutex;
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
template <class Domain_>
|
||||
class Dual_contouring_face_generation {
|
||||
template <typename Domain_>
|
||||
class Dual_contouring_face_generation
|
||||
{
|
||||
private:
|
||||
typedef Domain_ Domain;
|
||||
using Domain = Domain_;
|
||||
|
||||
typedef typename Domain_::FT FT;
|
||||
typedef typename Domain_::Edge_descriptor Edge_descriptor;
|
||||
typedef typename Domain_::Cell_descriptor Cell_descriptor;
|
||||
using FT = typename Domain_::FT;
|
||||
using Edge_descriptor = typename Domain_::Edge_descriptor;
|
||||
using Cell_descriptor = typename Domain_::Cell_descriptor;
|
||||
|
||||
public:
|
||||
Dual_contouring_face_generation(const Domain& domain, FT isovalue) : domain(domain), isovalue(isovalue) {}
|
||||
Dual_contouring_face_generation(const Domain& domain,
|
||||
FT isovalue)
|
||||
: domain(domain),
|
||||
isovalue(isovalue)
|
||||
{ }
|
||||
|
||||
void operator()(const Edge_descriptor& e) {
|
||||
// save all faces
|
||||
const auto& vertices = domain.edge_vertices(e);
|
||||
const FT s0 = domain.value(vertices[0]);
|
||||
const FT s1 = domain.value(vertices[1]);
|
||||
void operator()(const Edge_descriptor& e)
|
||||
{
|
||||
// save all faces
|
||||
const auto& vertices = domain.edge_vertices(e);
|
||||
const FT s0 = domain.value(vertices[0]);
|
||||
const FT s1 = domain.value(vertices[1]);
|
||||
|
||||
if (s0 <= isovalue && s1 > isovalue) {
|
||||
const auto& voxels = domain.cells_incident_to_edge(e);
|
||||
if(s0 <= isovalue && s1 > isovalue)
|
||||
{
|
||||
const auto& voxels = domain.cells_incident_to_edge(e);
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
faces[e].insert(faces[e].begin(), voxels.begin(), voxels.end());
|
||||
|
||||
} else if (s1 <= isovalue && s0 > isovalue) {
|
||||
const auto& voxels = domain.cells_incident_to_edge(e);
|
||||
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
faces[e].insert(faces[e].begin(), voxels.rbegin(), voxels.rend());
|
||||
}
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
faces[e].insert(faces[e].begin(), voxels.begin(), voxels.end());
|
||||
}
|
||||
else if(s1 <= isovalue && s0 > isovalue)
|
||||
{
|
||||
const auto& voxels = domain.cells_incident_to_edge(e);
|
||||
|
||||
// private:
|
||||
std::map<Edge_descriptor, std::vector<Cell_descriptor>> faces;
|
||||
std::lock_guard<std::mutex> lock(mutex);
|
||||
faces[e].insert(faces[e].begin(), voxels.rbegin(), voxels.rend());
|
||||
}
|
||||
}
|
||||
|
||||
const Domain& domain;
|
||||
FT isovalue;
|
||||
// private: // @todo
|
||||
std::map<Edge_descriptor, std::vector<Cell_descriptor>> faces;
|
||||
|
||||
std::mutex mutex;
|
||||
const Domain& domain;
|
||||
FT isovalue;
|
||||
|
||||
std::mutex mutex;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_DUAL_CONTOURING_3_INTERNAL_DUAL_CONTOURING_3_H
|
||||
#endif // CGAL_ISOSURFACING_3_INTERNAL_DUAL_CONTOURING_INTERNAL_H
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
//
|
||||
// Author(s) : Julian Stahl
|
||||
|
||||
#ifndef CGAL_GRID_TOPOLOGY_H
|
||||
#define CGAL_GRID_TOPOLOGY_H
|
||||
#ifndef CGAL_ISOSURFACING_3_INTERNAL_GRID_TOPOLOGY_H
|
||||
#define CGAL_ISOSURFACING_3_INTERNAL_GRID_TOPOLOGY_H
|
||||
|
||||
#include <CGAL/license/Isosurfacing_3.h>
|
||||
|
||||
|
|
@ -22,197 +22,214 @@
|
|||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <tbb/parallel_for.h>
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
|
||||
namespace CGAL {
|
||||
namespace Isosurfacing {
|
||||
namespace internal {
|
||||
|
||||
// The topology of a cartesian grid. All elements are created with the help of the cube tables.
|
||||
class Grid_topology {
|
||||
class Grid_topology
|
||||
{
|
||||
public:
|
||||
// identify a vertex by its (i, j, k) indices
|
||||
typedef std::array<std::size_t, 3> Vertex_descriptor;
|
||||
// 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;
|
||||
// identify a cell by its corner vertex with the smallest (i, j, k) index
|
||||
typedef std::array<std::size_t, 3> Cell_descriptor;
|
||||
// identify a vertex by its (i, j, k) indices
|
||||
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
|
||||
using Edge_descriptor = std::array<std::size_t, 4>;
|
||||
// identify a cell by its corner vertex with the smallest (i, j, k) index
|
||||
using Cell_descriptor = std::array<std::size_t, 3>;
|
||||
|
||||
static constexpr Cell_type CELL_TYPE = CUBICAL_CELL;
|
||||
static constexpr std::size_t VERTICES_PER_CELL = 8;
|
||||
static constexpr std::size_t EDGES_PER_CELL = 12;
|
||||
static constexpr Cell_type CELL_TYPE = CUBICAL_CELL;
|
||||
static constexpr std::size_t VERTICES_PER_CELL = 8;
|
||||
static constexpr std::size_t EDGES_PER_CELL = 12;
|
||||
|
||||
typedef std::array<Vertex_descriptor, 2> Vertices_incident_to_edge;
|
||||
typedef std::array<Cell_descriptor, 4> Cells_incident_to_edge;
|
||||
typedef std::array<Vertex_descriptor, VERTICES_PER_CELL> Cell_vertices;
|
||||
typedef std::array<Edge_descriptor, EDGES_PER_CELL> Cell_edges;
|
||||
using Vertices_incident_to_edge = std::array<Vertex_descriptor, 2>;
|
||||
using Cells_incident_to_edge = std::array<Cell_descriptor, 4>;
|
||||
using Cell_vertices = std::array<Vertex_descriptor, VERTICES_PER_CELL>;
|
||||
using Cell_edges = std::array<Edge_descriptor, EDGES_PER_CELL>;
|
||||
|
||||
public:
|
||||
// Create the topology of a grid with size_i, size_j, and size_k vertices in the respective dimensions.
|
||||
Grid_topology(const std::size_t size_i, const std::size_t size_j, const std::size_t size_k)
|
||||
: size_i(size_i), size_j(size_j), size_k(size_k) {}
|
||||
// Create the topology of a grid with size_i, size_j, and size_k vertices in the respective dimensions.
|
||||
Grid_topology(const std::size_t size_i,
|
||||
const std::size_t size_j,
|
||||
const std::size_t size_k)
|
||||
: size_i(size_i),
|
||||
size_j(size_j),
|
||||
size_k(size_k)
|
||||
{ }
|
||||
|
||||
// Get a container with the two vertices incident to the edge e
|
||||
Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const {
|
||||
Vertices_incident_to_edge ev;
|
||||
ev[0] = {e[0], e[1], e[2]}; // start vertex
|
||||
ev[1] = {e[0], e[1], e[2]}; // end vertex
|
||||
ev[1][e[3]] += 1; // one position further in the direction of the edge
|
||||
return ev;
|
||||
// Get a container with the two vertices incident to the edge e
|
||||
Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const
|
||||
{
|
||||
Vertices_incident_to_edge ev;
|
||||
ev[0] = { e[0], e[1], e[2] }; // start vertex
|
||||
ev[1] = { e[0], e[1], e[2] }; // end vertex
|
||||
ev[1][e[3]] += 1; // one position further in the direction of the edge
|
||||
return ev;
|
||||
}
|
||||
|
||||
// Get a container with all cells incident to the edge e
|
||||
Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const
|
||||
{
|
||||
// lookup the neighbor cells relative to the edge
|
||||
const int local = internal::Cube_table::edge_store_index[e[3]];
|
||||
auto neighbors = internal::Cube_table::edge_to_voxel_neighbor[local];
|
||||
|
||||
Cells_incident_to_edge cite;
|
||||
for(std::size_t i=0; i<cite.size(); ++i)
|
||||
{
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// Get a container with all cells incident to the edge e
|
||||
Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const {
|
||||
// lookup the neighbor cells relative to the edge
|
||||
const int local = internal::Cube_table::edge_store_index[e[3]];
|
||||
auto neighbors = internal::Cube_table::edge_to_voxel_neighbor[local];
|
||||
return cite;
|
||||
}
|
||||
|
||||
Cells_incident_to_edge cite;
|
||||
for (std::size_t i = 0; i < cite.size(); i++) {
|
||||
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
|
||||
}
|
||||
// Get a container with all vertices of the cell c
|
||||
Cell_vertices cell_vertices(const Cell_descriptor& c) const
|
||||
{
|
||||
Cell_vertices cv;
|
||||
for(std::size_t i=0; i<cv.size(); ++i)
|
||||
{
|
||||
for(std::size_t j=0; j<c.size(); ++j)
|
||||
{
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
|
||||
return cv;
|
||||
}
|
||||
|
||||
// Get a container with all edges of the cell c
|
||||
Cell_edges cell_edges(const Cell_descriptor& c) const
|
||||
{
|
||||
Cell_edges ce;
|
||||
for(std::size_t i=0; i<ce.size(); ++i)
|
||||
{
|
||||
for(std::size_t j=0; j<c.size(); ++j)
|
||||
{
|
||||
// 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];
|
||||
}
|
||||
// set the direction of the edge
|
||||
ce[i][3] = internal::Cube_table::global_edge_id[i][3];
|
||||
}
|
||||
|
||||
return ce;
|
||||
}
|
||||
|
||||
// Iterate sequentially over all vertices v calling f(v) on every one
|
||||
template <typename Functor>
|
||||
void iterate_vertices(Functor& f, Sequential_tag) const
|
||||
{
|
||||
for(std::size_t i=0; i<size_i; ++i)
|
||||
for(std::size_t j=0; j<size_j; ++j)
|
||||
for(std::size_t k=0; k<size_k; ++k)
|
||||
f({i, j, k});
|
||||
}
|
||||
|
||||
// Iterate sequentially over all edges e calling f(e) on every one
|
||||
template <typename Functor>
|
||||
void iterate_edges(Functor& f, Sequential_tag) const
|
||||
{
|
||||
for(std::size_t i=0; i<size_i-1; ++i) {
|
||||
for(std::size_t j=0; j<size_j-1; ++j) {
|
||||
for(std::size_t k=0; k<size_k-1; ++k)
|
||||
{
|
||||
// all three edges starting at vertex (i, j, k)
|
||||
f({i, j, k, 0});
|
||||
f({i, j, k, 1});
|
||||
f({i, j, k, 2});
|
||||
}
|
||||
return cite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get a container with all vertices of the cell c
|
||||
Cell_vertices cell_vertices(const Cell_descriptor& c) const {
|
||||
Cell_vertices cv;
|
||||
for (std::size_t i = 0; i < cv.size(); i++) {
|
||||
for (std::size_t j = 0; j < c.size(); j++) {
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
return cv;
|
||||
}
|
||||
|
||||
// Get a container with all edges of the cell c
|
||||
Cell_edges cell_edges(const Cell_descriptor& c) const {
|
||||
Cell_edges ce;
|
||||
for (std::size_t i = 0; i < ce.size(); i++) {
|
||||
for (std::size_t j = 0; j < c.size(); j++) {
|
||||
// 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];
|
||||
}
|
||||
// set the direction of the edge
|
||||
ce[i][3] = internal::Cube_table::global_edge_id[i][3];
|
||||
}
|
||||
return ce;
|
||||
}
|
||||
|
||||
// Iterate sequentially over all vertices v calling f(v) on every one
|
||||
template <typename Functor>
|
||||
void iterate_vertices(Functor& f, Sequential_tag) const {
|
||||
for (std::size_t i = 0; i < size_i; i++) {
|
||||
for (std::size_t j = 0; j < size_j; j++) {
|
||||
for (std::size_t k = 0; k < size_k; k++) {
|
||||
f({i, j, k});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate sequentially over all edges e calling f(e) on every one
|
||||
template <typename Functor>
|
||||
void iterate_edges(Functor& f, Sequential_tag) const {
|
||||
for (std::size_t i = 0; i < size_i - 1; i++) {
|
||||
for (std::size_t j = 0; j < size_j - 1; j++) {
|
||||
for (std::size_t k = 0; k < size_k - 1; k++) {
|
||||
// all three edges starting at vertex (i, j, k)
|
||||
f({i, j, k, 0});
|
||||
f({i, j, k, 1});
|
||||
f({i, j, k, 2});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate sequentially over all cells c calling f(c) on every one
|
||||
template <typename Functor>
|
||||
void iterate_cells(Functor& f, Sequential_tag) const {
|
||||
for (std::size_t i = 0; i < size_i - 1; i++) {
|
||||
for (std::size_t j = 0; j < size_j - 1; j++) {
|
||||
for (std::size_t k = 0; k < size_k - 1; k++) {
|
||||
f({i, j, k});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Iterate sequentially over all cells c calling f(c) on every one
|
||||
template <typename Functor>
|
||||
void iterate_cells(Functor& f, Sequential_tag) const
|
||||
{
|
||||
for(std::size_t i=0; i<size_i-1; ++i)
|
||||
for(std::size_t j=0; j<size_j-1; ++j)
|
||||
for(std::size_t k=0; k<size_k-1; ++k)
|
||||
f({i, j, k});
|
||||
}
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
// Iterate in parallel over all vertices v calling f(v) on every one
|
||||
template <typename Functor>
|
||||
void iterate_vertices(Functor& f, Parallel_tag) const {
|
||||
const std::size_t sj = size_j;
|
||||
const std::size_t sk = size_k;
|
||||
// Iterate in parallel over all vertices v calling f(v) on every one
|
||||
template <typename Functor>
|
||||
void iterate_vertices(Functor& f, Parallel_tag) const
|
||||
{
|
||||
const std::size_t sj = size_j;
|
||||
const std::size_t sk = size_k;
|
||||
|
||||
// for now only parallelize outer loop
|
||||
auto iterator = [&f, sj, sk](const tbb::blocked_range<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 k = 0; k < sk; k++) {
|
||||
f({i, j, k});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
// for now only parallelize outer loop
|
||||
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 k=0; k<sk; ++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);
|
||||
}
|
||||
|
||||
// Iterate in parallel over all edges e calling f(e) on every one
|
||||
template <typename Functor>
|
||||
void iterate_edges(Functor& f, Parallel_tag) const {
|
||||
const std::size_t sj = size_j;
|
||||
const std::size_t sk = size_k;
|
||||
// Iterate in parallel over all edges e calling f(e) on every one
|
||||
template <typename Functor>
|
||||
void iterate_edges(Functor& f, Parallel_tag) const
|
||||
{
|
||||
const std::size_t sj = size_j;
|
||||
const std::size_t sk = size_k;
|
||||
|
||||
// for now only parallelize outer loop
|
||||
auto iterator = [&f, sj, sk](const tbb::blocked_range<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 k = 0; k < sk - 1; k++) {
|
||||
f({i, j, k, 0});
|
||||
f({i, j, k, 1});
|
||||
f({i, j, k, 2});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
// for now only parallelize outer loop
|
||||
auto iterator = [&f, sj, sk](const tbb::blocked_range<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 k=0; k<sk - 1; ++k)
|
||||
{
|
||||
f({i, j, k, 0});
|
||||
f({i, j, k, 1});
|
||||
f({i, j, k, 2});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Iterate in parallel over all cells c calling f(c) on every one
|
||||
template <typename Functor>
|
||||
void iterate_cells(Functor& f, Parallel_tag) const {
|
||||
const std::size_t sj = size_j;
|
||||
const std::size_t sk = size_k;
|
||||
// Iterate in parallel over all cells c calling f(c) on every one
|
||||
template <typename Functor>
|
||||
void iterate_cells(Functor& f, Parallel_tag) const
|
||||
{
|
||||
const std::size_t sj = size_j;
|
||||
const std::size_t sk = size_k;
|
||||
|
||||
// for now only parallelize outer loop
|
||||
auto iterator = [&f, sj, sk](const tbb::blocked_range<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 k = 0; k < sk - 1; k++) {
|
||||
f({i, j, k});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
// for now only parallelize outer loop
|
||||
auto iterator = [&f, sj, sk](const tbb::blocked_range<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 k=0; k<sk - 1; ++k)
|
||||
f({i, j, k});
|
||||
};
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, size_i - 1), iterator);
|
||||
}
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, size_i - 1), iterator);
|
||||
}
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
|
||||
private:
|
||||
std::size_t size_i;
|
||||
std::size_t size_j;
|
||||
std::size_t size_k;
|
||||
std::size_t size_i;
|
||||
std::size_t size_j;
|
||||
std::size_t size_k;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_GRID_TOPOLOGY_H
|
||||
#endif // CGAL_ISOSURFACING_3_INTERNAL_GRID_TOPOLOGY_H
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
//
|
||||
// Author(s) : Julian Stahl
|
||||
|
||||
#ifndef CGAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H
|
||||
#define CGAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H
|
||||
#ifndef CGAL_ISOSURFACING_3_INTERNAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H
|
||||
#define CGAL_ISOSURFACING_3_INTERNAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H
|
||||
|
||||
#include <CGAL/license/Isosurfacing_3.h>
|
||||
|
||||
|
|
@ -23,32 +23,40 @@ namespace internal {
|
|||
// Wrapper for an implicit function that can only be evaluated at a position and not at a vertex.
|
||||
// Evaluates the geometry to get the vertex position and passes that to the function.
|
||||
// Works for all VertexDescriptor types.
|
||||
template <class GeomTraits, typename Geometry_, typename PointFunction>
|
||||
class Implicit_function_with_geometry {
|
||||
template <typename GeomTraits,
|
||||
typename Geometry_,
|
||||
typename PointFunction>
|
||||
class Implicit_function_with_geometry
|
||||
{
|
||||
public:
|
||||
typedef GeomTraits Geom_traits;
|
||||
typedef typename Geom_traits::FT FT;
|
||||
using Geom_traits = GeomTraits;
|
||||
using FT = typename Geom_traits::FT;
|
||||
|
||||
typedef std::shared_ptr<Geometry_> Geometry;
|
||||
typedef std::shared_ptr<PointFunction> Point_function;
|
||||
using Geometry = std::shared_ptr<Geometry_>;
|
||||
using Point_function = std::shared_ptr<PointFunction>;
|
||||
|
||||
public:
|
||||
// Create a function that uses the geometry to evaluate the function at vertex positions.
|
||||
Implicit_function_with_geometry(const Geometry& geom, const Point_function& func) : geom(geom), func(func) {}
|
||||
// Create a function that uses the geometry to evaluate the function at vertex positions.
|
||||
Implicit_function_with_geometry(const Geometry& geom,
|
||||
const Point_function& func)
|
||||
: geom(geom),
|
||||
func(func)
|
||||
{ }
|
||||
|
||||
// Get the value of the function at vertex v
|
||||
template <typename VertexDescriptor>
|
||||
FT operator()(const VertexDescriptor& v) const {
|
||||
return func->operator()(geom->operator()(v));
|
||||
}
|
||||
// Get the value of the function at vertex v
|
||||
template <typename VertexDescriptor>
|
||||
FT operator()(const VertexDescriptor& v) const
|
||||
{
|
||||
return func->operator()(geom->operator()(v));
|
||||
}
|
||||
|
||||
private:
|
||||
const Geometry geom;
|
||||
const Point_function func;
|
||||
const Geometry geom;
|
||||
const Point_function func;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H
|
||||
#endif // CGAL_ISOSURFACING_3_INTERNAL_IMPLICIT_FUNCTION_WITH_GEOMETRY_H
|
||||
|
|
|
|||
|
|
@ -38,12 +38,13 @@
|
|||
// https://github.com/rogrosso/tmc available on 15th of September 2022.
|
||||
//
|
||||
|
||||
#ifndef CGAL_MARCHING_CUBES_3_INTERNAL_MARCHING_CUBES_3_H
|
||||
#define CGAL_MARCHING_CUBES_3_INTERNAL_MARCHING_CUBES_3_H
|
||||
#ifndef CGAL_ISOSURFACING_3_INTERNAL_MARCHING_CUBES_3_INTERNAL_H
|
||||
#define CGAL_ISOSURFACING_3_INTERNAL_MARCHING_CUBES_3_INTERNAL_H
|
||||
|
||||
#include <CGAL/license/Isosurfacing_3.h>
|
||||
|
||||
#include <CGAL/Isosurfacing_3/internal/Tables.h>
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <tbb/concurrent_vector.h>
|
||||
#else
|
||||
|
|
@ -61,164 +62,203 @@ namespace Isosurfacing {
|
|||
namespace internal {
|
||||
|
||||
// Interpolate linearly between two vertex positions v0, v1 with values d0 and d1 according to the isovalue
|
||||
template <class Point_3, typename FT>
|
||||
Point_3 vertex_interpolation(const Point_3& p0, const Point_3& p1, const FT d0, const FT d1, const FT isovalue) {
|
||||
template <typename Point_3,
|
||||
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
|
||||
if(abs(d1 - d0) < 0.000001) // @todo
|
||||
mu = 0.5; // if both points have the same value, assume isolevel is in the middle
|
||||
else
|
||||
mu = (isovalue - d0) / (d1 - d0);
|
||||
|
||||
// don't divide by 0
|
||||
if (abs(d1 - d0) < 0.000001) {
|
||||
mu = 0.5; // if both points have the same value, assume isolevel is in the middle
|
||||
} else {
|
||||
mu = (isovalue - d0) / (d1 - d0);
|
||||
}
|
||||
assert(mu >= 0.0 || mu <= 1.0);
|
||||
|
||||
assert(mu >= 0.0 || mu <= 1.0);
|
||||
|
||||
// linear interpolation
|
||||
return Point_3(p1.x() * mu + p0.x() * (1 - mu), p1.y() * mu + p0.y() * (1 - mu), p1.z() * mu + p0.z() * (1 - mu));
|
||||
// linear interpolation
|
||||
return { p1.x() * mu + p0.x() * (1 - mu),
|
||||
p1.y() * mu + p0.y() * (1 - mu),
|
||||
p1.z() * mu + p0.z() * (1 - mu) };
|
||||
}
|
||||
|
||||
// Retrieve the corner vertices and their values of a cell and return the lookup index
|
||||
template <class Domain_, typename Corners_, typename Values_>
|
||||
std::size_t get_cell_corners(const Domain_& domain, const typename Domain_::Cell_descriptor& cell,
|
||||
const typename Domain_::FT isovalue, Corners_& corners, Values_& values) {
|
||||
template <typename Domain_,
|
||||
typename Corners_,
|
||||
typename Values_>
|
||||
std::size_t get_cell_corners(const Domain_& domain,
|
||||
const typename Domain_::Cell_descriptor& cell,
|
||||
const typename Domain_::FT isovalue,
|
||||
Corners_& corners,
|
||||
Values_& values)
|
||||
{
|
||||
using Vertex_descriptor = typename Domain_::Vertex_descriptor;
|
||||
|
||||
typedef typename Domain_::Vertex_descriptor Vertex_descriptor;
|
||||
// collect function values and build index
|
||||
std::size_t v_id = 0;
|
||||
std::bitset<Domain_::VERTICES_PER_CELL> index = 0;
|
||||
for(const Vertex_descriptor& v : domain.cell_vertices(cell))
|
||||
{
|
||||
// collect scalar values and computex index
|
||||
corners[v_id] = domain.position(v);
|
||||
values[v_id] = domain.value(v);
|
||||
|
||||
// collect function values and build index
|
||||
std::size_t v_id = 0;
|
||||
std::bitset<Domain_::VERTICES_PER_CELL> index = 0;
|
||||
for (const Vertex_descriptor& v : domain.cell_vertices(cell)) {
|
||||
// collect scalar values and computex index
|
||||
corners[v_id] = domain.position(v);
|
||||
values[v_id] = domain.value(v);
|
||||
if(values[v_id] >= isovalue)
|
||||
index.set(v_id);
|
||||
|
||||
if (values[v_id] >= isovalue) {
|
||||
index.set(v_id);
|
||||
}
|
||||
// next cell vertex
|
||||
v_id++;
|
||||
}
|
||||
// next cell vertex
|
||||
++v_id;
|
||||
}
|
||||
|
||||
return static_cast<std::size_t>(index.to_ullong());
|
||||
return static_cast<std::size_t>(index.to_ullong());
|
||||
}
|
||||
|
||||
// Create the vertices on the edges of one cell
|
||||
template <class CellEdges, typename FT, 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) {
|
||||
template <typename CellEdges,
|
||||
typename FT,
|
||||
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
|
||||
std::size_t flag = 1;
|
||||
std::size_t e_id = 0;
|
||||
|
||||
// compute for this case the vertices
|
||||
std::size_t flag = 1;
|
||||
std::size_t e_id = 0;
|
||||
for(const auto& edge : cell_edges)
|
||||
{
|
||||
(void)edge; // @todo
|
||||
|
||||
for (const auto& edge : cell_edges) {
|
||||
(void)edge; // TODO
|
||||
if(flag & Cube_table::intersected_edges[i_case])
|
||||
{
|
||||
// generate vertex here, do not care at this point if vertex already exist
|
||||
|
||||
if (flag & Cube_table::intersected_edges[i_case]) {
|
||||
const int v0 = Cube_table::edge_to_vertex[e_id][0];
|
||||
const int v1 = Cube_table::edge_to_vertex[e_id][1];
|
||||
|
||||
// generate vertex here, do not care at this point if vertex already exist
|
||||
|
||||
const int v0 = Cube_table::edge_to_vertex[e_id][0];
|
||||
const int v1 = Cube_table::edge_to_vertex[e_id][1];
|
||||
|
||||
vertices[e_id] = vertex_interpolation(corners[v0], corners[v1], values[v0], values[v1], isovalue);
|
||||
}
|
||||
flag <<= 1;
|
||||
e_id++;
|
||||
vertices[e_id] = vertex_interpolation(corners[v0], corners[v1], values[v0], values[v1], isovalue);
|
||||
}
|
||||
|
||||
flag <<= 1;
|
||||
++e_id;
|
||||
}
|
||||
}
|
||||
|
||||
// Connect the vertices of one cell to form triangles
|
||||
template <typename Vertices_, class TriangleList>
|
||||
void mc_construct_triangles(const int i_case, const Vertices_& vertices, TriangleList& triangles) {
|
||||
// construct triangles
|
||||
for (int t = 0; t < 16; t += 3) {
|
||||
template <typename Vertices_,
|
||||
typename TriangleList>
|
||||
void mc_construct_triangles(const int i_case,
|
||||
const Vertices_& vertices,
|
||||
TriangleList& triangles)
|
||||
{
|
||||
// construct triangles
|
||||
for(int t=0; t<16; t+=3)
|
||||
{
|
||||
const int t_index = i_case * 16 + t;
|
||||
|
||||
const int t_index = i_case * 16 + t;
|
||||
// if (e_tris_list[t_index] == 0x7f)
|
||||
if (Cube_table::triangle_cases[t_index] == -1) break;
|
||||
// if(e_tris_list[t_index] == 0x7f)
|
||||
if(Cube_table::triangle_cases[t_index] == -1)
|
||||
break;
|
||||
|
||||
const int eg0 = Cube_table::triangle_cases[t_index + 0]; // TODO: move more of this stuff into the table
|
||||
const int eg1 = Cube_table::triangle_cases[t_index + 1];
|
||||
const int eg2 = Cube_table::triangle_cases[t_index + 2];
|
||||
const int eg0 = Cube_table::triangle_cases[t_index + 0]; // TODO: move more of this stuff into the table
|
||||
const int eg1 = Cube_table::triangle_cases[t_index + 1];
|
||||
const int eg2 = Cube_table::triangle_cases[t_index + 2];
|
||||
|
||||
// insert new triangle in list
|
||||
triangles.push_back({vertices[eg0], vertices[eg1], vertices[eg2]});
|
||||
}
|
||||
// insert new triangle in list
|
||||
triangles.push_back({vertices[eg0], vertices[eg1], vertices[eg2]});
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the triangle list to an indexed face set
|
||||
template <class TriangleList, class PointRange, class 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();
|
||||
template <typename TriangleList,
|
||||
typename PointRange,
|
||||
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();
|
||||
|
||||
points.push_back(triangle[0]);
|
||||
points.push_back(triangle[1]);
|
||||
points.push_back(triangle[2]);
|
||||
points.push_back(triangle[0]);
|
||||
points.push_back(triangle[1]);
|
||||
points.push_back(triangle[2]);
|
||||
|
||||
// simply use increasing indices
|
||||
polygons.push_back({id + 2, id + 1, id + 0});
|
||||
}
|
||||
// simply use increasing indices
|
||||
polygons.push_back({id + 2, id + 1, id + 0});
|
||||
}
|
||||
}
|
||||
|
||||
// Marching Cubes implemented as a functor that runs on every cell of the grid
|
||||
template <class Domain_>
|
||||
class Marching_cubes_3 {
|
||||
template <typename Domain_>
|
||||
class Marching_cubes_3
|
||||
{
|
||||
private:
|
||||
typedef Domain_ Domain;
|
||||
typedef typename Domain::FT FT;
|
||||
typedef typename Domain::Point Point;
|
||||
typedef typename Domain::Cell_descriptor Cell_descriptor;
|
||||
using Domain = Domain_;
|
||||
using FT = typename Domain::FT;
|
||||
using Point = typename Domain::Point;
|
||||
using Cell_descriptor = typename Domain::Cell_descriptor;
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
typedef tbb::concurrent_vector<std::array<Point, 3>> Triangle_list;
|
||||
using Triangle_list = tbb::concurrent_vector<std::array<Point, 3> >;
|
||||
#else
|
||||
typedef std::vector<std::array<Point, 3>> Triangle_list;
|
||||
using Triangle_list = std::vector<std::array<Point, 3> >;
|
||||
#endif
|
||||
|
||||
public:
|
||||
// Create a Marching Cubes functor for a domain and iso value
|
||||
Marching_cubes_3(const Domain& domain, const FT isovalue) : domain(domain), isovalue(isovalue) {}
|
||||
// Create a Marching Cubes functor for a domain and iso value
|
||||
Marching_cubes_3(const Domain& domain,
|
||||
const FT isovalue)
|
||||
: domain(domain),
|
||||
isovalue(isovalue)
|
||||
{ }
|
||||
|
||||
// Compute one cell
|
||||
void operator()(const Cell_descriptor& cell) {
|
||||
// Compute one cell
|
||||
void operator()(const Cell_descriptor& cell)
|
||||
{
|
||||
// @todo: maybe better checks if the domain can be processed?
|
||||
assert(domain.cell_vertices(cell).size() == 8);
|
||||
assert(domain.cell_edges(cell).size() == 12);
|
||||
|
||||
// TODO: maybe better checks if the domain can be processed?
|
||||
assert(domain.cell_vertices(cell).size() == 8);
|
||||
assert(domain.cell_edges(cell).size() == 12);
|
||||
FT values[8];
|
||||
Point corners[8];
|
||||
const int i_case = get_cell_corners(domain, cell, isovalue, corners, values);
|
||||
|
||||
FT values[8];
|
||||
Point corners[8];
|
||||
const int i_case = get_cell_corners(domain, cell, isovalue, corners, values);
|
||||
const int all_bits_set = (1 << (8 + 1)) - 1; // last 8 bits are 1
|
||||
if(i_case == 0 || i_case == all_bits_set)
|
||||
return; // skip empty cells
|
||||
|
||||
const int all_bits_set = (1 << (8 + 1)) - 1; // last 8 bits are 1
|
||||
if (i_case == 0 || i_case == all_bits_set) {
|
||||
return; // skip empty cells
|
||||
}
|
||||
std::array<Point, 12> vertices;
|
||||
mc_construct_vertices(domain.cell_edges(cell), isovalue, i_case, corners, values, vertices);
|
||||
|
||||
std::array<Point, 12> vertices;
|
||||
mc_construct_vertices(domain.cell_edges(cell), isovalue, i_case, corners, values, vertices);
|
||||
mc_construct_triangles(i_case, vertices, triangle_list);
|
||||
}
|
||||
|
||||
mc_construct_triangles(i_case, vertices, triangle_list);
|
||||
}
|
||||
|
||||
// Get the created triangle list
|
||||
const Triangle_list& triangles() const {
|
||||
return triangle_list;
|
||||
}
|
||||
// Get the created triangle list
|
||||
const Triangle_list& triangles() const
|
||||
{
|
||||
return triangle_list;
|
||||
}
|
||||
|
||||
private:
|
||||
const Domain& domain;
|
||||
FT isovalue;
|
||||
const Domain& domain;
|
||||
FT isovalue;
|
||||
|
||||
Triangle_list triangle_list;
|
||||
Triangle_list triangle_list;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_MARCHING_CUBES_3_INTERNAL_MARCHING_CUBES_3_H
|
||||
#endif // CGAL_ISOSURFACING_3_INTERNAL_MARCHING_CUBES_3_INTERNAL_H
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
//
|
||||
// Author(s) : Julian Stahl
|
||||
|
||||
#ifndef CGAL_OCTREE_GEOMETRY_H
|
||||
#define CGAL_OCTREE_GEOMETRY_H
|
||||
#ifndef CGAL_ISOSURFACING_3_INTERNAL_OCTREE_GEOMETRY_H
|
||||
#define CGAL_ISOSURFACING_3_INTERNAL_OCTREE_GEOMETRY_H
|
||||
|
||||
#include <CGAL/license/Isosurfacing_3.h>
|
||||
|
||||
|
|
@ -23,29 +23,33 @@ namespace CGAL {
|
|||
namespace Isosurfacing {
|
||||
namespace internal {
|
||||
|
||||
template <class GeomTraits>
|
||||
class Octree_geometry {
|
||||
template <typename GeomTraits>
|
||||
class Octree_geometry
|
||||
{
|
||||
public:
|
||||
typedef GeomTraits Geom_traits;
|
||||
typedef typename Geom_traits::Point_3 Point;
|
||||
using Geom_traits = GeomTraits;
|
||||
using Point = typename Geom_traits::Point_3;
|
||||
|
||||
typedef std::shared_ptr<Octree_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:
|
||||
Octree_geometry(const Octree& octree) : octree(octree) {}
|
||||
Octree_geometry(const Octree& octree)
|
||||
: octree(octree)
|
||||
{ }
|
||||
|
||||
Point operator()(const Vertex_descriptor& v) const {
|
||||
return octree->point(v);
|
||||
}
|
||||
Point operator()(const Vertex_descriptor& v) const
|
||||
{
|
||||
return octree->point(v);
|
||||
}
|
||||
|
||||
private:
|
||||
const Octree octree;
|
||||
const Octree octree;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_OCTREE_GEOMETRY_H
|
||||
#endif // CGAL_ISOSURFACING_3_INTERNAL_OCTREE_GEOMETRY_H
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
//
|
||||
// Author(s) : Julian Stahl
|
||||
|
||||
#ifndef CGAL_OCTREE_TOPOLOGY_H
|
||||
#define CGAL_OCTREE_TOPOLOGY_H
|
||||
#ifndef CGAL_ISOSURFACING_3_INTERNAL_OCTREE_TOPOLOGY_H
|
||||
#define CGAL_ISOSURFACING_3_INTERNAL_OCTREE_TOPOLOGY_H
|
||||
|
||||
#include <CGAL/license/Isosurfacing_3.h>
|
||||
|
||||
|
|
@ -20,118 +20,128 @@
|
|||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
#include <tbb/parallel_for.h>
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
|
||||
namespace CGAL {
|
||||
namespace Isosurfacing {
|
||||
namespace internal {
|
||||
|
||||
template <class GeomTraits> // TODO: should not be necessary
|
||||
class Octree_topology {
|
||||
template <typename GeomTraits> // @todo should not be necessary
|
||||
class Octree_topology
|
||||
{
|
||||
public:
|
||||
typedef GeomTraits Geom_traits;
|
||||
typedef Octree_wrapper<Geom_traits> Octree_;
|
||||
typedef std::shared_ptr<Octree_wrapper<Geom_traits>> Octree;
|
||||
typedef typename Octree_::Vertex_handle Vertex_descriptor;
|
||||
typedef typename Octree_::Edge_handle Edge_descriptor;
|
||||
typedef typename Octree_::Voxel_handle Cell_descriptor;
|
||||
using Geom_traits = GeomTraits;
|
||||
using Octree_ = Octree_wrapper<Geom_traits>;
|
||||
using Octree = std::shared_ptr<Octree_wrapper<Geom_traits> >;
|
||||
using Vertex_descriptor = typename Octree_::Vertex_handle;
|
||||
using Edge_descriptor = typename Octree_::Edge_handle;
|
||||
using Cell_descriptor = typename Octree_::Voxel_handle;
|
||||
|
||||
static constexpr Cell_type CELL_TYPE = CUBICAL_CELL;
|
||||
static constexpr std::size_t VERTICES_PER_CELL = 8;
|
||||
static constexpr std::size_t EDGES_PER_CELL = 12;
|
||||
static constexpr Cell_type CELL_TYPE = CUBICAL_CELL;
|
||||
static constexpr std::size_t VERTICES_PER_CELL = 8;
|
||||
static constexpr std::size_t EDGES_PER_CELL = 12;
|
||||
|
||||
typedef std::array<Vertex_descriptor, 2> Vertices_incident_to_edge;
|
||||
typedef std::array<Cell_descriptor, 4> Cells_incident_to_edge; // TODO: not always 4
|
||||
typedef std::array<Vertex_descriptor, 8> Cell_vertices;
|
||||
typedef std::array<Edge_descriptor, 12> Cell_edges;
|
||||
using Vertices_incident_to_edge = std::array<Vertex_descriptor, 2>;
|
||||
using Cells_incident_to_edge = std::array<Cell_descriptor, 4>; // @todo: not always 4
|
||||
using Cell_vertices = std::array<Vertex_descriptor, 8>;
|
||||
using Cell_edges = std::array<Edge_descriptor, 12>;
|
||||
|
||||
public:
|
||||
Octree_topology(const Octree& octree) : octree(octree) {}
|
||||
Octree_topology(const Octree& octree)
|
||||
: octree(octree)
|
||||
{ }
|
||||
|
||||
Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const {
|
||||
return octree->edge_vertices(e);
|
||||
}
|
||||
Vertices_incident_to_edge edge_vertices(const Edge_descriptor& e) const
|
||||
{
|
||||
return octree->edge_vertices(e);
|
||||
}
|
||||
|
||||
Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const {
|
||||
return octree->edge_voxels(e);
|
||||
}
|
||||
Cells_incident_to_edge cells_incident_to_edge(const Edge_descriptor& e) const
|
||||
{
|
||||
return octree->edge_voxels(e);
|
||||
}
|
||||
|
||||
Cell_vertices cell_vertices(const Cell_descriptor& c) const {
|
||||
return octree->voxel_vertices(c);
|
||||
}
|
||||
Cell_vertices cell_vertices(const Cell_descriptor& c) const
|
||||
{
|
||||
return octree->voxel_vertices(c);
|
||||
}
|
||||
|
||||
Cell_edges cell_edges(const Cell_descriptor& c) const {
|
||||
return octree->voxel_edges(c);
|
||||
}
|
||||
Cell_edges cell_edges(const Cell_descriptor& c) const
|
||||
{
|
||||
return octree->voxel_edges(c);
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
void iterate_vertices(Functor& f, Sequential_tag) const {
|
||||
for (const Vertex_descriptor& v : octree->leaf_vertices()) {
|
||||
f(v);
|
||||
}
|
||||
}
|
||||
template <typename Functor>
|
||||
void iterate_vertices(Functor& f, Sequential_tag) const
|
||||
{
|
||||
for(const Vertex_descriptor& v : octree->leaf_vertices())
|
||||
f(v);
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
void iterate_edges(Functor& f, Sequential_tag) const {
|
||||
for (const Edge_descriptor& e : octree->leaf_edges()) {
|
||||
f(e);
|
||||
}
|
||||
}
|
||||
template <typename Functor>
|
||||
void iterate_edges(Functor& f, Sequential_tag) const
|
||||
{
|
||||
for(const Edge_descriptor& e : octree->leaf_edges())
|
||||
f(e);
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
void iterate_cells(Functor& f, Sequential_tag) const {
|
||||
for (const Cell_descriptor& v : octree->leaf_voxels()) {
|
||||
f(v);
|
||||
}
|
||||
}
|
||||
template <typename Functor>
|
||||
void iterate_cells(Functor& f, Sequential_tag) const
|
||||
{
|
||||
for(const Cell_descriptor& v : octree->leaf_voxels())
|
||||
f(v);
|
||||
}
|
||||
|
||||
#ifdef CGAL_LINKED_WITH_TBB
|
||||
template <typename Functor>
|
||||
void iterate_vertices(Functor& f, Parallel_tag) const {
|
||||
const auto& vertices = octree->leaf_vertices();
|
||||
template <typename Functor>
|
||||
void iterate_vertices(Functor& f, Parallel_tag) const
|
||||
{
|
||||
const auto& vertices = octree->leaf_vertices();
|
||||
|
||||
auto iterator = [&](const tbb::blocked_range<std::size_t>& r) {
|
||||
for (std::size_t i = r.begin(); i != r.end(); i++) {
|
||||
f(vertices[i]);
|
||||
}
|
||||
};
|
||||
auto iterator = [&](const tbb::blocked_range<std::size_t>& r)
|
||||
{
|
||||
for(std::size_t i = r.begin(); i != r.end(); ++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>
|
||||
void iterate_edges(Functor& f, Parallel_tag) const {
|
||||
const auto& edges = octree->leaf_edges();
|
||||
template <typename Functor>
|
||||
void iterate_edges(Functor& f, Parallel_tag) const
|
||||
{
|
||||
const auto& edges = octree->leaf_edges();
|
||||
|
||||
auto iterator = [&](const tbb::blocked_range<std::size_t>& r) {
|
||||
for (std::size_t i = r.begin(); i != r.end(); i++) {
|
||||
f(edges[i]);
|
||||
}
|
||||
};
|
||||
auto iterator = [&](const tbb::blocked_range<std::size_t>& r)
|
||||
{
|
||||
for(std::size_t i = r.begin(); i != r.end(); ++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>
|
||||
void iterate_cells(Functor& f, Parallel_tag) const {
|
||||
const auto& cells = octree->leaf_voxels();
|
||||
template <typename Functor>
|
||||
void iterate_cells(Functor& f, Parallel_tag) const
|
||||
{
|
||||
const auto& cells = octree->leaf_voxels();
|
||||
|
||||
auto iterator = [&](const tbb::blocked_range<std::size_t>& r) {
|
||||
for (std::size_t i = r.begin(); i != r.end(); i++) {
|
||||
f(cells[i]);
|
||||
}
|
||||
};
|
||||
auto iterator = [&](const tbb::blocked_range<std::size_t>& r)
|
||||
{
|
||||
for(std::size_t i = r.begin(); i != r.end(); ++i)
|
||||
f(cells[i]);
|
||||
};
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, cells.size()), iterator);
|
||||
}
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
tbb::parallel_for(tbb::blocked_range<std::size_t>(0, cells.size()), iterator);
|
||||
}
|
||||
#endif // CGAL_LINKED_WITH_TBB
|
||||
|
||||
private:
|
||||
const Octree octree;
|
||||
const Octree octree;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace internal
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_OCTREE_TOPOLOGY_H
|
||||
#endif // CGAL_ISOSURFACING_3_INTERNAL_OCTREE_TOPOLOGY_H
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -44,24 +44,34 @@ namespace Isosurfacing {
|
|||
* \param triangles each element in the vector describes a triangle using the indices of the points in `points`
|
||||
* \param topologically_correct decides whether the topologically correct variant of Marching Cubes should be used
|
||||
*/
|
||||
template <typename Concurrency_tag = Sequential_tag, class Domain_, class PointRange, class TriangleRange>
|
||||
void marching_cubes(const Domain_& domain, const typename Domain_::FT isovalue, PointRange& points,
|
||||
TriangleRange& triangles, bool topologically_correct = true) {
|
||||
template <typename Concurrency_tag = Sequential_tag,
|
||||
typename Domain_,
|
||||
typename PointRange,
|
||||
typename TriangleRange>
|
||||
void marching_cubes(const Domain_& domain,
|
||||
const typename Domain_::FT isovalue,
|
||||
PointRange& points,
|
||||
TriangleRange& triangles,
|
||||
bool topologically_correct = true)
|
||||
{
|
||||
if(topologically_correct)
|
||||
{
|
||||
// run TMC and directly write the result to points and triangles
|
||||
internal::TMC_functor<Domain_, PointRange, TriangleRange> functor(domain, isovalue, points, triangles);
|
||||
domain.template iterate_cells<Concurrency_tag>(functor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// run MC
|
||||
internal::Marching_cubes_3<Domain_> functor(domain, isovalue);
|
||||
domain.template iterate_cells<Concurrency_tag>(functor);
|
||||
|
||||
if (topologically_correct) {
|
||||
// run TMC and directly write the result to points and triangles
|
||||
internal::TMC_functor<Domain_, PointRange, TriangleRange> functor(domain, isovalue, points, triangles);
|
||||
domain.template iterate_cells<Concurrency_tag>(functor);
|
||||
} else {
|
||||
// run MC
|
||||
internal::Marching_cubes_3<Domain_> functor(domain, isovalue);
|
||||
domain.template iterate_cells<Concurrency_tag>(functor);
|
||||
// copy the result to points and triangles
|
||||
internal::to_indexed_face_set(functor.triangles(), points, triangles);
|
||||
}
|
||||
// copy the result to points and triangles
|
||||
internal::to_indexed_face_set(functor.triangles(), points, triangles);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_MARCHING_CUBES_3_H
|
||||
#endif // CGAL_MARCHING_CUBES_3_H
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -26,30 +26,32 @@ namespace Isosurfacing {
|
|||
*
|
||||
* \tparam GeomTraits the traits for this gradient.
|
||||
*/
|
||||
template <class GeomTraits>
|
||||
class Zero_gradient {
|
||||
template <typename GeomTraits>
|
||||
class Zero_gradient
|
||||
{
|
||||
public:
|
||||
typedef GeomTraits Geom_traits;
|
||||
typedef typename Geom_traits::Point_3 Point;
|
||||
typedef typename Geom_traits::Vector_3 Vector;
|
||||
using Geom_traits = GeomTraits;
|
||||
using Point = typename Geom_traits::Point_3;
|
||||
using Vector = typename Geom_traits::Vector_3;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Evaluate the gradient at a point in space.
|
||||
*
|
||||
* \param point the point at which the gradient is computed
|
||||
*/
|
||||
Vector operator()(const Point& point) const {
|
||||
return zero;
|
||||
}
|
||||
/**
|
||||
* \ingroup PkgIsosurfacing3Ref
|
||||
*
|
||||
* \brief Evaluate the gradient at a point in space.
|
||||
*
|
||||
* \param point the point at which the gradient is computed
|
||||
*/
|
||||
Vector operator()(const Point& point) const
|
||||
{
|
||||
return zero;
|
||||
}
|
||||
|
||||
private:
|
||||
const Vector zero = Vector(0, 0, 0);
|
||||
const Vector zero = Vector(0, 0, 0);
|
||||
};
|
||||
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
} // namespace Isosurfacing
|
||||
} // namespace CGAL
|
||||
|
||||
#endif // CGAL_ZERO_GRADIENT_H
|
||||
#endif // CGAL_ZERO_GRADIENT_H
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ public:
|
|||
}
|
||||
|
||||
~ScopeTimer() {
|
||||
if (running) {
|
||||
if(running) {
|
||||
TimePoint end = Clock::now();
|
||||
int64_t duration = std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();
|
||||
std::cout << msg << ": " << duration << " ms" << std::endl;
|
||||
|
|
@ -35,4 +35,4 @@ private:
|
|||
bool running;
|
||||
};
|
||||
|
||||
#endif // SCOPE_TIMER_H
|
||||
#endif // SCOPE_TIMER_H
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
#include <CGAL/Simple_cartesian.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Cartesian_grid_3.h>
|
||||
#include <CGAL/Dual_contouring_3.h>
|
||||
#include <CGAL/Explicit_cartesian_grid_domain.h>
|
||||
|
|
@ -5,80 +8,83 @@
|
|||
#include <CGAL/Marching_cubes_3.h>
|
||||
#include <CGAL/Octree_wrapper.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/Finite_difference_gradient.h>
|
||||
|
||||
#include "Timer.h"
|
||||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
using Kernel = CGAL::Simple_cartesian<double>;
|
||||
using Vector = typename Kernel::Vector_3;
|
||||
using Point = typename Kernel::Point_3;
|
||||
|
||||
typedef CGAL::Surface_mesh<Point> Mesh;
|
||||
typedef CGAL::Cartesian_grid_3<Kernel> Grid;
|
||||
using Mesh = CGAL::Surface_mesh<Point>;
|
||||
using Grid CGAL::Cartesian_grid_3<Kernel>;
|
||||
|
||||
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> >;
|
||||
|
||||
int main() {
|
||||
const Vector spacing(0.002, 0.002, 0.02);
|
||||
const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1};
|
||||
int main()
|
||||
{
|
||||
const Vector spacing(0.002, 0.002, 0.02);
|
||||
const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1};
|
||||
|
||||
auto sphere_function = [](const Point& point) {
|
||||
return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z());
|
||||
};
|
||||
auto sphere_function = [](const Point& point)
|
||||
{
|
||||
return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z());
|
||||
};
|
||||
|
||||
typedef CGAL::Isosurfacing::Finite_difference_gradient<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>(
|
||||
bbox, spacing, sphere_function, Gradient(sphere_function, 0.0001));
|
||||
auto implicit_domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(
|
||||
bbox, spacing, sphere_function, Gradient(sphere_function, 0.0001));
|
||||
|
||||
const std::size_t nx = static_cast<std::size_t>(2.0 / spacing.x());
|
||||
const std::size_t ny = static_cast<std::size_t>(2.0 / spacing.y());
|
||||
const std::size_t nz = static_cast<std::size_t>(2.0 / spacing.z());
|
||||
const std::size_t nx = static_cast<std::size_t>(2.0 / spacing.x());
|
||||
const std::size_t ny = static_cast<std::size_t>(2.0 / spacing.y());
|
||||
const std::size_t nz = static_cast<std::size_t>(2.0 / spacing.z());
|
||||
|
||||
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 y = 0; y < grid->ydim(); y++) {
|
||||
for (std::size_t z = 0; z < grid->zdim(); z++) {
|
||||
for(std::size_t x=0; x<grid->xdim(); ++x) {
|
||||
for(std::size_t y=0; y<grid->ydim(); ++y) {
|
||||
for(std::size_t z=0; z<grid->zdim(); ++z)
|
||||
{
|
||||
const Point pos(x * spacing.x() + bbox.xmin(),
|
||||
y * spacing.y() + bbox.ymin(),
|
||||
z * spacing.z() + bbox.zmin());
|
||||
|
||||
const Point pos(x * spacing.x() + bbox.xmin(), y * spacing.y() + bbox.ymin(),
|
||||
z * spacing.z() + bbox.zmin());
|
||||
|
||||
grid->value(x, y, z) = sphere_function(pos);
|
||||
}
|
||||
}
|
||||
grid->value(x, y, z) = sphere_function(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const std::string fname = "../data/skull_2.9.inr";
|
||||
// Load image
|
||||
// CGAL::Image_3 image;
|
||||
// if (!image.read(fname)) {
|
||||
// std::cerr << "Error: Cannot read file " << fname << std::endl;
|
||||
// return EXIT_FAILURE;
|
||||
//}
|
||||
// Grid grid(image);
|
||||
const std::string fname = "../data/skull_2.9.inr";
|
||||
|
||||
auto grid_domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
// Load image
|
||||
// CGAL::Image_3 image;
|
||||
// if(!image.read(fname)) {
|
||||
// std::cerr << "Error: Cannot read file " << fname << std::endl;
|
||||
// return EXIT_FAILURE;
|
||||
//}
|
||||
// Grid grid(image);
|
||||
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
auto grid_domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
|
||||
{
|
||||
ScopeTimer timer;
|
||||
CGAL::Isosurfacing::dual_contouring<CGAL::Parallel_tag>(implicit_domain, 0.8f, points, polygons);
|
||||
}
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// TODO: compare results with mesh_3
|
||||
{
|
||||
ScopeTimer timer;
|
||||
CGAL::Isosurfacing::dual_contouring<CGAL::Parallel_tag>(implicit_domain, 0.8f, points, polygons);
|
||||
}
|
||||
|
||||
// Mesh mesh;
|
||||
// CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, mesh);
|
||||
// @todo compare results with mesh_3
|
||||
|
||||
// CGAL::IO::write_OFF("result.off", mesh);
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
// Mesh mesh;
|
||||
// CGAL::Polygon_mesh_processing::polygon_soup_to_polygon_mesh(points, polygons, mesh);
|
||||
|
||||
return 0;
|
||||
// CGAL::IO::write_OFF("result.off", mesh);
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,92 +5,102 @@
|
|||
|
||||
#define WRITE_OFF
|
||||
|
||||
struct Sphere_function {
|
||||
FT operator()(const Point& point) const {
|
||||
return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z());
|
||||
}
|
||||
struct Sphere_function
|
||||
{
|
||||
FT operator()(const Point& point) const
|
||||
{
|
||||
return std::sqrt(point.x() * point.x() + point.y() * point.y() + point.z() * point.z());
|
||||
}
|
||||
};
|
||||
|
||||
template <class Domain_>
|
||||
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);
|
||||
template <typename Domain_>
|
||||
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);
|
||||
}
|
||||
|
||||
void test_implicit_sphere() {
|
||||
const std::string test_name = "test_implicit_sphere()";
|
||||
void test_implicit_sphere()
|
||||
{
|
||||
const std::string test_name = "test_implicit_sphere()";
|
||||
|
||||
const Vector spacing(0.2, 0.2, 0.2);
|
||||
const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1};
|
||||
const Vector spacing(0.2, 0.2, 0.2);
|
||||
const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1};
|
||||
|
||||
auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, spacing, Sphere_function());
|
||||
auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, spacing, Sphere_function());
|
||||
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
run(domain, 0.8, points, polygons);
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
run(domain, 0.8, points, polygons);
|
||||
|
||||
#ifdef WRITE_OFF
|
||||
CGAL::IO::write_OFF(test_name + ".off", points, polygons);
|
||||
CGAL::IO::write_OFF(test_name + ".off", points, polygons);
|
||||
#endif
|
||||
|
||||
assert(is_polygon_mesh(polygons));
|
||||
Mesh m = to_mesh(points, polygons);
|
||||
assert(is_polygon_mesh(polygons));
|
||||
Mesh m = to_mesh(points, polygons);
|
||||
|
||||
assert(is_manifold(m));
|
||||
assert(!has_degenerate_faces(m));
|
||||
assert(is_manifold(m));
|
||||
assert(!has_degenerate_faces(m));
|
||||
|
||||
std::cout << "Test passed: " << test_name << std::endl;
|
||||
std::cout << "Test passed: " << test_name << std::endl;
|
||||
}
|
||||
|
||||
void test_grid_sphere(const std::size_t n) {
|
||||
const std::string test_name = "test_grid_sphere(" + std::to_string(n) + ")";
|
||||
void test_grid_sphere(const std::size_t n)
|
||||
{
|
||||
const std::string test_name = "test_grid_sphere(" + std::to_string(n) + ")";
|
||||
|
||||
const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1};
|
||||
const Vector spacing(2.0 / (n - 1), 2.0 / (n - 1), 2.0 / (n - 1));
|
||||
const CGAL::Bbox_3 bbox = {-1, -1, -1, 1, 1, 1};
|
||||
const Vector spacing(2.0 / (n - 1), 2.0 / (n - 1), 2.0 / (n - 1));
|
||||
|
||||
Sphere_function sphere_function;
|
||||
Sphere_function sphere_function;
|
||||
|
||||
std::shared_ptr<Grid> 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 y = 0; y < grid->ydim(); y++) {
|
||||
for (std::size_t z = 0; z < grid->zdim(); z++) {
|
||||
for(std::size_t x=0; x<grid->xdim(); ++x) {
|
||||
for(std::size_t y=0; y<grid->ydim(); ++y) {
|
||||
for(std::size_t z=0; z<grid->zdim(); ++z)
|
||||
{
|
||||
const Point pos(x * spacing.x() + bbox.xmin(),
|
||||
y * spacing.y() + bbox.ymin(),
|
||||
z * spacing.z() + bbox.zmin());
|
||||
|
||||
const Point pos(x * spacing.x() + bbox.xmin(), y * spacing.y() + bbox.ymin(),
|
||||
z * spacing.z() + bbox.zmin());
|
||||
|
||||
grid->value(x, y, z) = sphere_function(pos);
|
||||
}
|
||||
}
|
||||
grid->value(x, y, z) = sphere_function(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
run(domain, 0.777, points, polygons);
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
run(domain, 0.777, points, polygons);
|
||||
|
||||
#ifdef WRITE_OFF
|
||||
CGAL::IO::write_OFF(test_name + ".off", points, polygons);
|
||||
CGAL::IO::write_OFF(test_name + ".off", points, polygons);
|
||||
#endif
|
||||
|
||||
assert(is_polygon_mesh(polygons));
|
||||
Mesh m = to_mesh(points, polygons);
|
||||
assert(is_polygon_mesh(polygons));
|
||||
Mesh m = to_mesh(points, polygons);
|
||||
|
||||
assert(is_manifold(m));
|
||||
assert(!has_degenerate_faces(m));
|
||||
assert(is_manifold(m));
|
||||
assert(!has_degenerate_faces(m));
|
||||
|
||||
std::cout << "Test passed: " << test_name << std::endl;
|
||||
std::cout << "Test passed: " << test_name << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_implicit_sphere();
|
||||
test_grid_sphere(2);
|
||||
test_grid_sphere(3);
|
||||
test_grid_sphere(10);
|
||||
test_grid_sphere(11);
|
||||
test_grid_sphere(100);
|
||||
int main()
|
||||
{
|
||||
test_implicit_sphere();
|
||||
test_grid_sphere(2);
|
||||
test_grid_sphere(3);
|
||||
test_grid_sphere(10);
|
||||
test_grid_sphere(11);
|
||||
test_grid_sphere(100);
|
||||
|
||||
std::cout << "All tests passed" << std::endl;
|
||||
std::cout << "All tests passed" << std::endl;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
#ifndef 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/Surface_mesh.h>
|
||||
|
||||
#include <CGAL/Cartesian_grid_3.h>
|
||||
#include <CGAL/Explicit_cartesian_grid_domain.h>
|
||||
#include <CGAL/Implicit_cartesian_grid_domain.h>
|
||||
#include <CGAL/Polygon_mesh_processing/distance.h>
|
||||
|
|
@ -10,60 +12,67 @@
|
|||
#include <CGAL/Polygon_mesh_processing/polygon_soup_to_polygon_mesh.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair.h>
|
||||
#include <CGAL/Polygon_mesh_processing/repair_polygon_soup.h>
|
||||
#include <CGAL/Surface_mesh.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
|
||||
typedef typename Kernel::FT FT;
|
||||
typedef typename Kernel::Vector_3 Vector;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel;
|
||||
using FT = typename Kernel::FT;
|
||||
using Vector = typename Kernel::Vector_3;
|
||||
using Point = typename Kernel::Point_3;
|
||||
|
||||
typedef CGAL::Surface_mesh<Point> Mesh;
|
||||
typedef CGAL::Cartesian_grid_3<Kernel> Grid;
|
||||
using Mesh = CGAL::Surface_mesh<Point>;
|
||||
using Grid = CGAL::Cartesian_grid_3<Kernel>;
|
||||
|
||||
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> >;
|
||||
|
||||
namespace PMP = CGAL::Polygon_mesh_processing;
|
||||
|
||||
bool has_duplicate_points(Point_range points, Polygon_range polygons) {
|
||||
return PMP::merge_duplicate_points_in_polygon_soup(points, polygons) != 0;
|
||||
bool has_duplicate_points(Point_range points, Polygon_range polygons)
|
||||
{
|
||||
return PMP::merge_duplicate_points_in_polygon_soup(points, polygons) != 0;
|
||||
}
|
||||
|
||||
bool has_duplicate_polygons(Point_range points, Polygon_range polygons) {
|
||||
return PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons) != 0;
|
||||
bool has_duplicate_polygons(Point_range points, Polygon_range polygons)
|
||||
{
|
||||
return PMP::merge_duplicate_polygons_in_polygon_soup(points, polygons) != 0;
|
||||
}
|
||||
|
||||
bool has_isolated_vertices(Point_range points, Polygon_range polygons) {
|
||||
return PMP::remove_isolated_points_in_polygon_soup(points, polygons) != 0;
|
||||
bool has_isolated_vertices(Point_range points, Polygon_range polygons)
|
||||
{
|
||||
return PMP::remove_isolated_points_in_polygon_soup(points, polygons) != 0;
|
||||
}
|
||||
|
||||
bool is_polygon_mesh(const Polygon_range& polygons) {
|
||||
return PMP::is_polygon_soup_a_polygon_mesh(polygons);
|
||||
bool is_polygon_mesh(const Polygon_range& polygons)
|
||||
{
|
||||
return PMP::is_polygon_soup_a_polygon_mesh(polygons);
|
||||
}
|
||||
|
||||
Mesh to_mesh(const Point_range& points, const Polygon_range& polygons) {
|
||||
Mesh m;
|
||||
PMP::polygon_soup_to_polygon_mesh(points, polygons, m);
|
||||
return m;
|
||||
Mesh to_mesh(const Point_range& points, const Polygon_range& polygons)
|
||||
{
|
||||
Mesh m;
|
||||
PMP::polygon_soup_to_polygon_mesh(points, polygons, m);
|
||||
return m;
|
||||
}
|
||||
|
||||
bool is_manifold(Mesh& m) {
|
||||
return PMP::duplicate_non_manifold_vertices(m, CGAL::parameters::dry_run(true)) == 0;
|
||||
bool is_manifold(Mesh& m)
|
||||
{
|
||||
return PMP::duplicate_non_manifold_vertices(m, CGAL::parameters::dry_run(true)) == 0;
|
||||
}
|
||||
|
||||
bool has_degenerate_faces(Mesh& m) {
|
||||
return PMP::remove_connected_components_of_negligible_size(
|
||||
m, CGAL::parameters::dry_run(true).area_threshold(std::numeric_limits<FT>::epsilon())) != 0;
|
||||
bool has_degenerate_faces(Mesh& m)
|
||||
{
|
||||
return PMP::remove_connected_components_of_negligible_size(
|
||||
m, CGAL::parameters::dry_run(true).area_threshold(std::numeric_limits<FT>::epsilon())) != 0;
|
||||
}
|
||||
|
||||
bool check_mesh_distance(const Mesh& m0, const Mesh& m1) {
|
||||
auto dist = PMP::approximate_Hausdorff_distance<CGAL::Sequential_tag>(
|
||||
m0, m1, CGAL::parameters::number_of_points_per_area_unit(4000));
|
||||
std::cout << dist << std::endl;
|
||||
return true;
|
||||
bool check_mesh_distance(const Mesh& m0, const Mesh& m1)
|
||||
{
|
||||
auto dist = PMP::approximate_Hausdorff_distance<CGAL::Sequential_tag>(
|
||||
m0, m1, CGAL::parameters::number_of_points_per_area_unit(4000));
|
||||
std::cout << dist << std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // CGAL_ISOSURFACING_TEST_UTIL_H
|
||||
#endif // CGAL_ISOSURFACING_TEST_UTIL_H
|
||||
|
|
|
|||
Loading…
Reference in New Issue