mirror of https://github.com/CGAL/cgal
massaging examples and doc (work in progress)
This commit is contained in:
parent
97beade7ef
commit
d381e38296
|
|
@ -17,34 +17,38 @@ Different isovalues of a bunny.
|
|||
|
||||
\section secmyintroduction Introduction
|
||||
|
||||
This package provides methods to compute a surface mesh representing an isosurface of a 3-dimensional scalar field.
|
||||
An isosurface is defined as the surface on which the value of this field is equal to a given constant, i.e. the isovalue.
|
||||
Depending on the isosurfacing method and the input data structure, the result is either a triangular, quadrilateral, or higher order polygonal indexed face set.
|
||||
|
||||
This package provides algorithms to compute a surface mesh approximating an isosurface of a 3-dimensional scalar field defined over an input 3D domain.
|
||||
An isosurface is defined as the surface on which the value of this scalar field equates a given constant, i.e. a user-defined isovalue.
|
||||
Depending on the isosurfacing method and the input data structure, the ouput is either a triangular, quadrilateral,
|
||||
or higher order polygonal surface mesh represented as an indexed face set. The output can be empty when the isovalue is absent in the input domain.
|
||||
\section secmyalgorithms Algorithms
|
||||
|
||||
There are multiple algorithms to extract isosurfaces.
|
||||
This package contains Marching Cubes, topologically correct Marching Cubes, and Dual Contouring.
|
||||
There is a variety of algorithms to extract isosurfaces.
|
||||
This package offers Marching Cubes, topologically correct Marching Cubes and Dual Contouring.
|
||||
|
||||
\subsection subsecmc Marching Cubes (MC)
|
||||
MC processes all cells of the input domain individually.
|
||||
MC runs over a 3D grid, i.e. a 3D domain partitioned into hexahedral cells.
|
||||
It processes all cells of the input domain individually.
|
||||
Each cell corner gets a sign (+/-) to indicate if it is above or below the isovalue.
|
||||
A new vertex is created on every cell edge where the sign changes, i.e. the isosurface is intersected.
|
||||
The vertex position is computed via linear interpolation of the scalar values of the incident corners.
|
||||
Depending on the configuration of signs at the corners the resulting vertices are connected to form triangles within the cell.
|
||||
A vertex is created on every cell edge where the sign changes, i.e. where the edge intersects the isosurface.
|
||||
The vertex position is computed via linear interpolation of the scalar values evaluated at the cell corners forming the edge.
|
||||
Depending on the configuration of signs at the cell corners, the resulting vertices are connected to form triangles within the cell.
|
||||
|
||||
MC can process any input data structure that consists of hexahedral cells.
|
||||
In case of a conforming grid, MC produces a triangle mesh that is manifold in most scenarios.
|
||||
If the mesh is manifold and the isosurface does not intersect the domain boundaries, the mesh is also watertight.
|
||||
Compared to other approaches the algorithm often generates more and many thin triangles with acute angles.
|
||||
MC does not preserve sharp features of the input data.
|
||||
The proposed implementation is generic in that it can process any grid-based data structure that consists of hexahedral cells.
|
||||
In case of a conforming grid, MC generates as output a surface triangle mesh that is 2-manifold in most scenarios. [TODO: reformulate, as
|
||||
it is either strict or not - precise in which cases it is not, and say whether you talk about just combinatorially 2-manifold, or truly 2-manifold]
|
||||
If the mesh is manifold and the isosurface does not intersect the domain boundaries, then the output mesh is also watertight.
|
||||
|
||||
Compared to other approaches such a Delaunay refinement (TODO: add link to component), the MC algorithm often generates more triangles,
|
||||
and triangles with small angles.
|
||||
MC does not preserve the sharp features present in the isovalue of the input scalar field.
|
||||
|
||||
\cgalFigureAnchor{isosurfacing_mc_cases}
|
||||
<center>
|
||||
<img src="mc_cases.png" style="max-width:70%;"/>
|
||||
</center>
|
||||
\cgalFigureCaptionBegin{isosurfacing_mc_cases}
|
||||
Some example cases of Marching Cubes.
|
||||
Ouputs of Marching Cubes over a variety of input domains.
|
||||
\cgalFigureCaptionEnd
|
||||
|
||||
\subsection subsectmc Topologically correct Marching Cubes (TMC)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
\cgalPkgPicture{isosurfacing3_ico.png}
|
||||
\cgalPkgSummaryBegin
|
||||
\cgalPkgAuthor{Julian Stahl and Daniel Zint}
|
||||
\cgalPkgDesc{This package implements isosurfacing algorithms to generate a mesh from a scalar field. The algorithms provide different guarantees for the output and should be chosen depending on the use-case. The representations of input data is flexible and includes explicit and implicit formats. }
|
||||
\cgalPkgDesc{This package implements isosurfacing algorithms to generate a surface mesh from a 3D scalar field. The algorithms provide different guarantees for the output and should be chosen depending on each use case. The possible format for the input data is flexible and includes explicit as well as implicit representations. }
|
||||
\cgalPkgManuals{Chapter_Isosurfacing3,PkgIsosurfacing3Ref}
|
||||
\cgalPkgSummaryEnd
|
||||
\cgalPkgShortInfoBegin
|
||||
|
|
@ -20,9 +20,9 @@
|
|||
\cgalPkgDescriptionEnd
|
||||
|
||||
This package provides algorithms to extract isosurfaces from different inputs.
|
||||
The input is represented as a domain and can be an implicit function, a cartesion grid, or an octree.
|
||||
The input is represented as a 3D domain and can be an implicit function, a cartesion grid or an octree.
|
||||
The output is an indexed face set that stores an isosurface in the form of a surface mesh.
|
||||
Available algorithms include Marching Cubes, topologically correct Marching Cubes, and Dual Contouring.
|
||||
Available algorithms include Marching Cubes, topologically correct Marching Cubes and Dual Contouring.
|
||||
|
||||
\cgalClassifedRefPages
|
||||
|
||||
|
|
|
|||
|
|
@ -15,13 +15,14 @@ typedef CGAL::Cartesian_grid_3<Kernel> Grid;
|
|||
typedef std::vector<Point> Point_range;
|
||||
typedef std::vector<std::vector<std::size_t>> Polygon_range;
|
||||
|
||||
// return 1.0 if value has positive sign, and -1.0 otherwise
|
||||
FT sign(FT value) {
|
||||
return (value > 0) - (value < 0);
|
||||
return (value > 0.0) - (value < 0.0);
|
||||
}
|
||||
|
||||
int main() {
|
||||
// create a cartesian grid with 100^3 grid points and the bounding box [-1, 1]^3
|
||||
const CGAL::Bbox_3 bbox(-1, -1, -1, 1, 1, 1);
|
||||
// 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
|
||||
|
|
@ -39,19 +40,20 @@ int main() {
|
|||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
Vector g(0.0, 0.0, 0.0);
|
||||
if (max_value == std::abs(p.x())) {
|
||||
g += Vector(sign(p.x()), 0, 0);
|
||||
g += Vector(sign(p.x()), 0.0, 0.0);
|
||||
}
|
||||
if (max_value == std::abs(p.y())) {
|
||||
g += Vector(0, sign(p.y()), 0);
|
||||
g += Vector(0.0, sign(p.y()), 0.0);
|
||||
}
|
||||
if (max_value == std::abs(p.z())) {
|
||||
g += Vector(0, 0, sign(p.z()));
|
||||
g += Vector(0.0, 0.0, sign(p.z()));
|
||||
}
|
||||
const FT length_sq = g.squared_length();
|
||||
if (length_sq > 0.00001) {
|
||||
|
|
@ -60,18 +62,19 @@ int main() {
|
|||
return g;
|
||||
};
|
||||
|
||||
// create a domain from the grid
|
||||
// create domain from given grid and gradient
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid, cube_gradient);
|
||||
|
||||
// prepare collections for the results
|
||||
// containers for output indexed surface meshes
|
||||
Point_range points_mc, points_dc;
|
||||
Polygon_range polygons_mc, polygons_dc;
|
||||
|
||||
// execute topologically correct marching cubes and dual contouring with an isovalue of 0.8
|
||||
CGAL::Isosurfacing::marching_cubes(domain, 0.88, points_mc, polygons_mc);
|
||||
CGAL::Isosurfacing::dual_contouring(domain, 0.88, points_dc, 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 the results in the OFF format
|
||||
// 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,19 +37,20 @@ int main() {
|
|||
return Vector(gx, gy, gz);
|
||||
};
|
||||
|
||||
const CGAL::Bbox_3 bbox{-1, -1, -1, 1, 1, 1};
|
||||
const Vector spacing(0.05f, 0.05f, 0.05f);
|
||||
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 bounding box [-1, 1]^3 and grid spacing 0.02
|
||||
// create a domain with given bounding box and grid spacing
|
||||
auto domain =
|
||||
CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, spacing, iwp_value, iwp_gradient);
|
||||
CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, vec_spacing, iwp_value, iwp_gradient);
|
||||
|
||||
// prepare collections for the result
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// execute marching cubes with an isovalue of 0
|
||||
CGAL::Isosurfacing::dual_contouring(domain, 0.0f, points, polygons);
|
||||
// execute 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);
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ 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;
|
||||
typedef std::vector<std::vector<std::size_t> > Polygon_range;
|
||||
|
||||
int main() {
|
||||
const std::string input_name = CGAL::data_file_path("meshes/cross.off");
|
||||
|
|
@ -32,7 +32,7 @@ int main() {
|
|||
|
||||
Mesh mesh_input;
|
||||
if (!CGAL::IO::read_OFF(input_name, mesh_input)) {
|
||||
std::cerr << "Could not read mesh" << std::endl;
|
||||
std::cerr << "Could not read input mesh" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
|
|
@ -47,7 +47,7 @@ int main() {
|
|||
|
||||
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());
|
||||
|
|
@ -55,18 +55,20 @@ int main() {
|
|||
|
||||
auto mesh_normal = [&tree](const Point& p) {
|
||||
const Point& x = tree.closest_point(p);
|
||||
const Vector n = p - x;
|
||||
return n / std::sqrt(n.squared_length());
|
||||
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 bounding box [-1, 1]^3 and grid spacing 0.02
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ typedef std::vector<std::vector<std::size_t>> Polygon_range;
|
|||
|
||||
int main() {
|
||||
// create a cartesian grid with 100^3 grid points and the bounding box [-1, 1]^3
|
||||
const CGAL::Bbox_3 bbox(-1, -1, -1, 1, 1, 1);
|
||||
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);
|
||||
|
||||
// calculate the value at all grid points
|
||||
// calculate 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++) {
|
||||
|
|
@ -28,7 +28,7 @@ int main() {
|
|||
const FT pos_y = y * grid->get_spacing()[1] + bbox.ymin();
|
||||
const FT pos_z = z * grid->get_spacing()[2] + bbox.zmin();
|
||||
|
||||
// distance to the origin
|
||||
// Euclidean distance to the origin
|
||||
grid->value(x, y, z) = std::sqrt(pos_x * pos_x + pos_y * pos_y + pos_z * pos_z);
|
||||
}
|
||||
}
|
||||
|
|
@ -44,6 +44,6 @@ int main() {
|
|||
// execute marching cubes with an isovalue of 0.8
|
||||
CGAL::Isosurfacing::marching_cubes(domain, 0.8f, points, polygons);
|
||||
|
||||
// save the result in the OFF format
|
||||
// save the result to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
#include <CGAL/Bbox_3.h>
|
||||
#include <CGAL/Implicit_cartesian_grid_domain.h>
|
||||
#include <CGAL/Marching_cubes_3.h>
|
||||
|
|
@ -6,28 +5,31 @@
|
|||
#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;
|
||||
|
||||
typedef std::vector<Point> Point_range;
|
||||
typedef std::vector<std::vector<std::size_t>> Polygon_range;
|
||||
typedef std::vector<std::vector<std::size_t> > Polygon_range;
|
||||
|
||||
int main() {
|
||||
const CGAL::Bbox_3 bbox{-1, -1, -1, 1, 1, 1};
|
||||
const Vector spacing(0.04f, 0.04f, 0.04f);
|
||||
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()); };
|
||||
|
||||
// create a domain with bounding box [-1, 1]^3 and grid spacing 0.02
|
||||
auto domain = CGAL::Isosurfacing::create_implicit_cartesian_grid_domain<Kernel>(bbox, 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 result
|
||||
// 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.8f, points, polygons);
|
||||
CGAL::Isosurfacing::marching_cubes(domain, 0.8, points, polygons);
|
||||
|
||||
// save the result in the OFF format
|
||||
// save ouput indexed mesh to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
typedef CGAL::Simple_cartesian<double> Kernel;
|
||||
typedef typename Kernel::Point_3 Point;
|
||||
|
||||
typedef CGAL::Cartesian_grid_3<Kernel> Grid;
|
||||
|
||||
typedef std::vector<Point> Point_range;
|
||||
|
|
@ -16,26 +15,26 @@ int main() {
|
|||
|
||||
const std::string fname = CGAL::data_file_path("images/skull_2.9.inr");
|
||||
|
||||
// load the image
|
||||
// load volumetric image from a file
|
||||
CGAL::Image_3 image;
|
||||
if (!image.read(fname)) {
|
||||
std::cerr << "Error: Cannot read file " << fname << std::endl;
|
||||
std::cerr << "Error: Cannot read image file " << fname << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// convert it to a cartesian grid
|
||||
// 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);
|
||||
|
||||
// prepare collections for the result
|
||||
// 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);
|
||||
|
||||
// save the result in the OFF format
|
||||
// save output indexed mesh to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ typedef std::vector<Point> Point_range;
|
|||
typedef std::vector<std::vector<std::size_t>> Polygon_range;
|
||||
|
||||
|
||||
// computes the distance of a point p from the mesh with the use of a AABB_tree
|
||||
// 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());
|
||||
|
|
@ -39,25 +40,25 @@ int main() {
|
|||
const int n_voxels = 20;
|
||||
const FT offset_value = 0.2;
|
||||
|
||||
// load the original mesh
|
||||
// load input mesh
|
||||
Mesh mesh_input;
|
||||
if (!CGAL::IO::read_OFF(input_name, mesh_input)) {
|
||||
std::cerr << "Could not read mesh" << std::endl;
|
||||
std::cerr << "Could not read input mesh" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// compute the new bounding box
|
||||
// compute loose bounding box of the mesh
|
||||
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);
|
||||
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
|
||||
// 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 the grid
|
||||
// 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++) {
|
||||
|
|
@ -69,28 +70,28 @@ int main() {
|
|||
const FT pos_z = z * grid->get_spacing()[2] + grid->get_bbox().zmin();
|
||||
const Point p(pos_x, pos_y, pos_z);
|
||||
|
||||
// compute the distance
|
||||
// compute unsigned distance to input mesh
|
||||
grid->value(x, y, z) = distance_to_mesh(tree, p);
|
||||
|
||||
// flip the sign, so the distance is negative inside the mesh
|
||||
// sign distance so that it is negative inside the mesh
|
||||
const bool is_inside = (sotm(p) == CGAL::ON_BOUNDED_SIDE);
|
||||
if (is_inside) {
|
||||
grid->value(x, y, z) *= -1;
|
||||
grid->value(x, y, z) *= -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// create a domain from the grid
|
||||
// create domain from the grid
|
||||
auto domain = CGAL::Isosurfacing::create_explicit_cartesian_grid_domain<Kernel>(grid);
|
||||
|
||||
// prepare collections for the result
|
||||
// prepare collections for output indexed surface mesh
|
||||
Point_range points;
|
||||
Polygon_range polygons;
|
||||
|
||||
// execute marching cubes with an isovalue equal to the offset
|
||||
// execute marching cubes with an isovalue equating offset
|
||||
CGAL::Isosurfacing::marching_cubes(domain, offset_value, points, polygons);
|
||||
|
||||
// save the result in the OFF format
|
||||
// save output indexed surface mesh to a file, in the OFF format
|
||||
CGAL::IO::write_OFF("result.off", points, polygons);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
INRIA Sophia-Antipolis (France)
|
||||
Inria Sophia-Antipolis (France)
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
3D Isosurfacing Algorithms
|
||||
The 3D Isosurfacing package provides several isosurfacing algorithms (marching cubes, dual contouring) to generate surface triangle and quadrangle surface meshes from an input 3D domain and a user-defined isovalue.
|
||||
|
|
@ -1 +1 @@
|
|||
Various implementation of the marching cube algorithms to generate triangle surfaces
|
||||
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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue