An implementation of a signed distance function based on Mauch's Closest Point Transform (CPT) employing the GNU Triangulated Surface Library.
The signed distance function between an arbitrary point in 3D space and a given closed surface returns the minimum distance from that point to the collection of triangles representing the surface. By convention, the sign is positive if the point is outside and negative if the point is inside the region determined by the surface.
In Computational Fluid Dynamics, the signed distance function is useful to:
- Locate the separation interface between two fluids (zero level-set surface)
- Determine instantaneous mass density and viscosity for each Eulerian grid point
- C++17 compatible compiler (GCC 8+, Clang 7+)
- GTS Library - GNU Triangulated Surface Library
- GLib 2.0 - Required by GTS
- Silo - For mesh output (optional, for VisIt visualization)
sudo pacman -S gts silosudo apt install libgts-dev silo-binmake clean && makeThe binary will be created at debug/gts-cpt.
The Makefile uses these default flags:
-std=c++17- C++17 standard-Wall -pedantic- Enable warnings-O3 -funroll-loops -ftree-vectorize- Optimizations
./debug/gts-cpt [OPTIONS] < input_file.gtsAll mesh boundary and size parameters must be specified:
| Option | Description |
|---|---|
--begin-x VALUE |
Minimum X coordinate of Eulerian mesh |
--begin-y VALUE |
Minimum Y coordinate of Eulerian mesh |
--begin-z VALUE |
Minimum Z coordinate of Eulerian mesh |
--end-x VALUE |
Maximum X coordinate of Eulerian mesh |
--end-y VALUE |
Maximum Y coordinate of Eulerian mesh |
--end-z VALUE |
Maximum Z coordinate of Eulerian mesh |
--size-x N |
Number of cells along X axis |
--size-y N |
Number of cells along Y axis |
--size-z N |
Number of cells along Z axis |
| Flag | Description |
|---|---|
--normalize |
Fit surface in a unit cube centered at origin |
--verbose |
Print statistics and progress |
--help |
Display help message |
# Using a sphere with geodesic order 4
./debug/gts-cpt --verbose \
--begin-x -1.5 --begin-y -1.5 --begin-z -1.5 \
--end-x 1.5 --end-y 1.5 --end-z 1.5 \
--size-x 100 --size-y 100 --size-z 100 \
< sphere20.gts# Process a GTS file with custom extents
./debug/gts-cpt --verbose --normalize \
--begin-x -2.0 --begin-y -2.0 --begin-z -2.0 \
--end-x 2.0 --end-y 2.0 --end-z 2.0 \
--size-x 50 --size-y 50 --size-z 50 \
< my_mesh.gts# The 'run' script simplifies execution
./run sphere20.gts
# Or with STL files (auto-converted)
./run my_model.stlThe program creates output in the out/ directory:
| File | Format | Description |
|---|---|---|
eulerianmesh.silo |
Silo | Distance function for VisIt visualization |
surface.vtk |
VTK | Surface mesh for visualization |
Using VisIt:
visit -o out/eulerianmesh.siloUsing ParaView:
paraview out/surface.vtkThe test suite covers critical algorithms and safety checks:
cd tests && make check| Test File | Coverage |
|---|---|
test_sign.cpp |
Sign function (zero, bounds, subnormals) |
test_safe_mesh_size.cpp |
Overflow detection, zero handling |
test_cpt_math.cpp |
min/max, vector angle, distance thresholds |
gts-cpt/
├── include/
│ ├── gtscpt.h # Main header, SignedDistance class
│ ├── cpt.h # CPT function declarations
│ ├── export.h # Export function declarations
│ ├── gtstools.h # GTS utility declarations
│ ├── array3d.h # Legacy array template (unused)
│ └── gts-cpp/ # C++ RAII wrappers
│ ├── gts_wrapper.hpp # Template deleters for GTS objects
│ ├── surface.hpp # gts::Surface RAII wrapper
│ ├── vertex.hpp # gts::Vertex, gts::Edge wrappers
│ └── callbacks.hpp # Callback utilities
├── src/
│ ├── main.cpp # Entry point, CLI parsing
│ ├── cpt.cpp # CPT algorithm implementation
│ ├── export.cpp # Silo/VTK export functions
│ ├── gtstools.cpp # GTS utility functions
│ └── gts-cpp/ # C++ wrapper implementations
│ └── surface.cpp
├── tests/
│ ├── Makefile
│ ├── test_sign.cpp
│ ├── test_safe_mesh_size.cpp
│ └── test_cpt_math.cpp
├── docs/plans/
│ └── *.md # Design and implementation plans
├── Makefile
├── run # Execution helper script
└── README.md
This codebase has been modernized from C++98 to C++17 with the following fixes:
-
Memory Safety
- RAII wrapper for
SignedDistanceclass gts::Surfacewrapper withstd::unique_ptrownership- Template
GtsDeleter<T>for automatic GTS object cleanup std::unique_ptrandstd::vectorfor automatic cleanup- Overflow-safe mesh size allocation
- RAII wrapper for
-
Undefined Behavior Fixes
- Safe
sign()function usingstd::copysign(no division by zero) - Division by zero protection in
cpt_point_angle()with epsilon check - File I/O error handling with NULL checks
- Proper exception handling
- Safe
-
Code Quality
- Const correctness for utility functions
noexceptfor simple functions- Proper include guards
- Removed dead code and declarations
- Clean compile with
-Werror
- GTS - Native GTS triangulated surface format
- STL - STL format (converted via
stl2gtsin run script)
For surfaces where the number of Lagrangian points (triangle vertices) is less than N*log(N) of Eulerian grid points, the CPT algorithm provides:
- Linear complexity in geometric elements
- O(1) proportion constant per element
Download GTS sample files from:
Note: The program requires closed manifold surfaces. Non-manifold surfaces may produce incorrect results.
If you use this implementation, please cite:
-
Ceniceros and Roma 2005: "A study of the long-time dynamics of a three-dimensional drop rising through a matching-density medium"
- Journal of Computational Physics, Vol. 205, Issue 2, May 2005, Pages 391-400
- DOI: 10.1016/j.jcp.2004.11.013
-
Ceniceros et al. 2009: "A fast, robust, and accurate adaptive method for the simulation of surface tension flows"
- Commun. Comput. Phys., Vol. 8, 2010, Pages 51-94
- DOI: 10.4208/cicp.050509.141009a
-
Mauch's Algorithm: Closest Point Transform
- Thiago P. Macedo - Original implementation and maintenance
- Prof. Alexandre M. Roma - Supervision
- Instituto de Matemática e Estatística, Universidade de São Paulo (IME-USP)
See LICENSE file for details.
Please report issues to:
- Thiago P. Macedo (tmacedo@usp.br)