Skip to content
Open
Show file tree
Hide file tree
Changes from 60 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
ccc58fc
Ball Merge Surface Reconstruction
afabri Dec 1, 2023
16a096b
Add original code
afabri Dec 4, 2023
abcfd74
add missing typename
sloriot Feb 22, 2024
3cea793
update from Amal's 24/01/31 email
sloriot Feb 22, 2024
0e21941
using CGAL IO function
amaldevp Feb 22, 2024
8f1949f
make attic compilable
amaldevp Feb 22, 2024
b20696a
set option
amaldevp Feb 22, 2024
e4610c4
fix doc
sloriot Feb 22, 2024
c2fb8a3
fix parameter passing and clean up
amaldevp Feb 22, 2024
d1b1011
address comments
amaldevp Feb 22, 2024
d4b78ff
Replacing group with a vector
amaldevp Feb 22, 2024
fd23864
consistent orientation of faces
amaldevp Feb 22, 2024
6619636
get rid of pair and use CGAL io function
amaldevp Feb 22, 2024
46240a0
add free functions for both versions
amaldevp Feb 22, 2024
4d77229
hide the class
amaldevp Feb 22, 2024
bb04afc
Edits from Amal
amaldevp Feb 26, 2024
b9cb9e3
clean up
sloriot Feb 27, 2024
e0f62d0
add new package
sloriot Feb 27, 2024
6c7f5df
update legal info
sloriot Feb 27, 2024
541ad50
fix bibtex and whitespaces
sloriot Feb 27, 2024
b79e70e
rename
sloriot Feb 27, 2024
a523925
fix for CI
sloriot Feb 27, 2024
d33cfd6
fix tests/examples
sloriot Feb 27, 2024
a1dff78
workaround for the CI
sloriot Feb 27, 2024
a370f0b
resize
sloriot Feb 27, 2024
ea6498b
add missing deps file
sloriot Feb 27, 2024
f1cb0d1
Change in variable name and updated the documentation
amaldevp Feb 27, 2024
46b542c
make signature more generic + fix doxygen doc
sloriot Apr 24, 2024
1274daf
add traits as template param
sloriot Apr 24, 2024
edf2908
update parameter name
sloriot Apr 24, 2024
89939cd
Merge remote-tracking branch 'cgal/master'
sloriot Apr 24, 2024
31d5700
Add a data set that fails on an assertion
afabri Jun 14, 2024
fe4175b
cleanup
afabri Jun 14, 2024
2577218
improvements after review
sloriot Jul 23, 2024
ba91ce0
more comments in exemples
sloriot Jul 23, 2024
7b367f6
typo
sloriot Jul 23, 2024
a04bd50
use named parameters
sloriot Jul 23, 2024
affac8b
Update Ball_merge_surface_reconstruction.txt
amaldevp Dec 2, 2024
9f94eab
Update Ball_merge_surface_reconstruction/doc/Ball_merge_surface_recon…
amaldevp Dec 2, 2024
bd94453
Update Ball_merge_surface_reconstruction/doc/Ball_merge_surface_recon…
amaldevp Dec 2, 2024
62fc9a4
Update Ball_merge_surface_reconstruction/test/Ball_merge_surface_reco…
amaldevp Dec 2, 2024
343e9f5
fix typo
sloriot Feb 12, 2025
dce6a30
spell checking
sloriot Feb 12, 2025
752f928
move concurrency_tag to named parameters
sloriot Feb 12, 2025
86dacfb
document class
sloriot Feb 12, 2025
ba2f400
gt in np
sloriot Feb 12, 2025
dd41166
only one cc is expected
sloriot Feb 12, 2025
5e4d16f
remove local version from the doc and add automatic parameter estimation
sloriot Apr 16, 2025
26fef3b
add safe exit
sloriot Apr 16, 2025
fc35fc8
group algorithm, member variable prefix and some clean up
sloriot Apr 16, 2025
e5158cb
clean up
sloriot Apr 16, 2025
e626f8c
split impl for global and local
sloriot Apr 16, 2025
77a7b8f
Merge cgal/master
afabri Jul 16, 2025
36df052
update after round 2
sloriot Sep 23, 2025
a596524
global pass
sloriot Sep 23, 2025
024782f
fix typos
sloriot Sep 24, 2025
217978f
Merge remote-tracking branch 'cgal/main' into Ball_merge_reconstruction
sloriot Sep 24, 2025
97de708
add first version of CHANGES
sloriot Sep 24, 2025
e5cac32
precision on the output
sloriot Sep 25, 2025
77fe6e0
cleanup
sloriot Sep 25, 2025
a0dc486
more update after review
sloriot Oct 21, 2025
8d2eb2f
typos
sloriot Oct 22, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
namespace CGAL {
/*!

\mainpage User Manual
\anchor Chapter_Ball_merge_surface_reconstruction

\cgalAutoToc
\author Amal Dev Parakkat, Stefan Ohrhallinger, Elmar Eisemann, Pooran Memari


This \cgal component implements a surface reconstruction method that takes an unoriented set of 3D points as input and computes a piecewise linear approximation of the sampled surface. In simple words, the method tries to classify the medial balls (computed from the 3D Delaunay triangulation of the input points) into interior and exterior and returns the interface between them.

The detailed description of the algorithm can be seen in \cgalCite{parakkat2024ballmerge}.


\section secBMSRdefinitions Definitions

The method is built upon the fact that whenever a discrete set of sample points approximates a continuous surface, the Voronoi balls (interior/exterior) intersect along the boundary with a ratio inversely proportional to the sampling density (similar to the observation of Amenta et al. \cgalCite{ack-pcubm-01}). Based on this, we define an \em intersection \em ratio between adjacent Voronoi balls as follows:

\f$ ir(B_0,B_1) = max((r_0+r_1-d)/r_0,(r_0+r_1-d)/r_1) \f$

Where \f$ B_0 \f$ and \f$ B_1 \f$ are two adjacent Voronoi balls with radius \f$ r_0 \f$ and \f$ r_1 \f$ respectively, and \f$ d \f$ is the distance between it's circumcenters.

Using this ratio, we can say that if the intersection ratio between two adjacent Voronoi balls is small,
they likely correspond to a pair of interior and exterior balls sharing a thin overlapping region along the underlying surface
(a 2D case is illustrated in \cgalFigureRef{figBMSRillus}). In other words, given a threshold \f$ \delta \f$, a triangle is said
to belong to a set \f$ \mathrm{BallMerge}(\delta) \f$ if its corresponding adjacent Voronoi balls have an intersection ratio less than \f$ \delta \f$.
By definition, \f$ \mathrm{BallMerge}(\delta) \f$ is a subcomplex of the Delaunay triangulation of the sample points. It is easy to see that \f$ \mathrm{BallMerge}(0) \f$ is empty,
while \f$ \mathrm{BallMerge}(\delta) \f$, for any \f$ \delta \gt 2 \f$ contains all the triangles of the Delaunay triangulation.

\cgalFigureBegin{figBMSRillus,BMSRIllustration.png}
Top: The interior (red) and exterior (green) medial balls of a point set with decreasing point density from l.t.r. Bottom: Corresponding \f$ \delta \f$-merged components on Delaunay triangulation.
\cgalFigureEnd

\cgal provides the global variant of the ball merge algorithm as described in \cgalCite{parakkat2024ballmerge}.

`ball_merge_surface_reconstruction()`: Given a threshold \f$ \delta \f$, two Delaunay simplices are called \f$ \delta\f$-merged either
if their corresponding Voronoi balls are adjacent with an intersection ratio \f$ > \delta \f$ or if there exists another Delaunay simplex,
which is \f$ \delta\f$-merged with both of them. Following a procedure similar to classical connected component computation, the algorithm
starts by visiting \f$ \delta\f$-merged simplices from an arbitrary seed simplex (the procedure is order independent) and tag them
with the current component label until no more \f$ \delta\f$-merged simplices remain. The procedure is then restarted with any yet
unvisited simplex until all have been visited, and output the simplices with the most frequent label. The reconstructed surface is then computed from the boundary of this output.


\subsection secBMSRChoose Input Requirements and Output Format

This method expects as input a 3D point cloud sampled a manifold close surface with a single connected component.
As the algorithm attempts to close the surface, it can tolerate some missing data and can handle little outliers and noise.
If there are some significant gaps in the data, the internal flooding algorithm will generate triangle faces from points visible from inside the input surface.

The output is of the form two triangle soups. It features the two largest components extracted from the flooding algorithm.
One of them is always a manifold surface mesh, while the second might features some non-manifold edges.
The fonction `CGAL::Polygon_mesh_processing::is_polygon_soup_a_polygon_mesh()` can be used to test them.

\subsection secBMSRPar Parameter Settings

The main parameter used in \f$ \mathrm{BallMerge} \f$ is the intersection ratio \f$\delta\f$. By definition, \f$\delta\f$ ranges from 0 to 2, with \f$ \mathrm{BallMerge}(0) \f$
being empty and \f$ \mathrm{BallMerge}(2) \f$ containing all the triangles of the Delaunay triangulation.
Experiments show that the \f$ > \delta \f$ value usually lies between 1.5 and 1.95, with 1.8 or 1.85 yielding the best results in most cases.
Thanks to the useful properties of this intersection ratio, tuning this parameter can be done using the following rule:
if the reconstructed surface has missing parts, the threshold should be lowered, conversely, if the reconstructed surface has additional parts, the threshold should be increased.

If no value is provided to the reconstruction function, the \f$\delta\f$ parameter is automatically estimated using the following method:
Starting from the maximal value 2, we iteratively decrease \f$\delta\f$ until the reconstructed surface undergoes a sudden vertex-count drop (10% of the total number of input points).
This indicates that a large number of interior/exterior medial balls have become \f$\delta\f$-merged, causing that part of
the reconstructed surface to collapse. Consequently, the value from the previous iteration is used to generate the output.
The \f$\delta\f$ value used is always returned by the functions.

\section secBMSRexamples Examples

`ball_merge_surface_reconstruction()` has the following arguments: The set of input points, two output parameters where the resulting meshes will be stored, and optionally the parameter \f$ \delta \f$.
The function returns two meshes - the largest and second-largest components as sometimes the expected shape will be the second-largest component after merging.
A sample program showing how to use this function is given below, together with the output reconstructions.

\cgalFigureBegin{figBMSKitten,kitten_ball_merged.png}
Results of the run of the ball merge algorithm with automatic delta parameter estimation.
From left to right: Input point cloud (no normal required); one of the two output containing the expected triangle mesh; the second output representing the non desired part, that is actually a triangle soup with non-manifold edges (shown in red). The `delta` parameter that is automatically estimated is `1`.
\cgalFigureEnd

\cgalExample{Ball_merge_surface_reconstruction/ball_merge_reconstruction.cpp}

Ideally, the current implementation takes a dense point cloud as input (plain x,y,z coordinates without any additional information like normal or texture) sampled over a smooth surface. Thanks to the "intersection ratio", the algorithm can also handle a few challenging cases with mild noise, outliers or missing data up to an extent.
It is worth noting that outliers sometimes create deep cavities over the surface, and an increased amount of noise shrinks and sometimes misses important features.

Finally, the algorithm is efficient, requiring minimal computation resources relative to the input size, as it completes two swift linear-time passes over the 3D Delaunay triangulation.

\section secBMSRhistory Implementation History

This package is based on the original code from the research article \cgalCite{parakkat2024ballmerge} and has been turned into a \cgal package by Amal Dev Parakkat and Sébastien Loriot.

*/
} /* namespace CGAL */

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@INCLUDE = ${CGAL_DOC_PACKAGE_DEFAULTS}
PROJECT_NAME = "CGAL ${CGAL_DOC_VERSION} - Ball Merge Surface Reconstruction"
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/// \defgroup PkgBallMergeRef Ball Merge Surface Reconstruction Reference

/*!
\addtogroup PkgBallMergeRef

\cgalPkgDescriptionBegin{Ball Merge Surface Reconstruction,PkgBallMerge}
\cgalPkgPicture{pkgBMR-small.png}
\cgalPkgSummaryBegin
\cgalPkgAuthors{Amal Dev Parakkat, Stefan Ohrhallinger, Elmar Eisemann, Pooran Memari}
\cgalPkgDesc{The package provides a Delaunay triangulation based surface reconstruction algorithm from an unorganized point set. The reconstructed surface consists of the interface between Voronoi balls, which
approximate the interior and exterior medial balls. This package contains the so-called global variant of the ball merge algorithm,
which is carefully designed to reconstruct a watertight surface from real-world scanned data sets, exhibiting mild noise, outliers, and small gaps in the data.}
\cgalPkgManuals{Chapter_Ball_merge_surface_reconstruction,PkgBallMergeRef}
\cgalPkgSummaryEnd
\cgalPkgShortInfoBegin
\cgalPkgSince{6.2}
\cgalPkgDependsOn{\ref PkgTriangulation3}
\cgalPkgBib{cgal:poem-bmsr}
\cgalPkgLicense{\ref licensesGPL "GPL"}
\cgalPkgShortInfoEnd
\cgalPkgDescriptionEnd

\cgalClassifedRefPages

\cgalCRPSection{Concepts}

\cgalCRPSection{Functions}
- `CGAL::ball_merge_surface_reconstruction()`

\cgalCRPSection{Class}
- `CGAL::Ball_merge_surface_reconstruction`

*/
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Manual
Kernel_23
STL_Extension
Algebraic_foundations
Circulator
Stream_support
Triangulation_3
Polygon_mesh_processing
BGL
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/*!
\example Ball_merge_surface_reconstruction/ball_merge_reconstruction.cpp
*/
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Created by the script cgal_create_cmake_script
# This is the CMake script for compiling a CGAL application.

cmake_minimum_required(VERSION 3.1...3.23)
project(Ball_merge_surface_reconstruction_Examples)

find_package(CGAL REQUIRED)

create_single_source_cgal_program("ball_merge_reconstruction.cpp")

find_package(TBB QUIET)
include(CGAL_TBB_support)
if(TARGET CGAL::TBB_support)
target_link_libraries(ball_merge_reconstruction PUBLIC CGAL::TBB_support)
else()
message(STATUS "NOTICE: Intel TBB was not found. Parallel code will not be used.")
endif()
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
#include <CGAL/Ball_merge_surface_reconstruction.h>
#include <CGAL/IO/polygon_soup_io.h>
#include <CGAL/IO/read_points.h>

#include <string>

typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
typedef K::Point_3 Point;

namespace params=CGAL::parameters;

int main(int argc, char **argv)
{
// reading input points and parameters
const std::string inFilename=argc>1?argv[1]:CGAL::data_file_path("points_3/kitten.xyz");

std::vector<Point> points;
CGAL::IO::read_points(inFilename, std::back_inserter(points));

if (points.empty())
{
std::cerr << inFilename << " cannot be read correctly or is empty.\n";
return 1;
}

//vectors for storing output triangle indices
std::vector<std::array<int,3>> meshFaceIndices1, meshFaceIndices2;

double delta = argc > 2
// run the reconstruction with user passed delta parameter
? CGAL::ball_merge_surface_reconstruction(points,
meshFaceIndices1, meshFaceIndices2,
params::delta(atof(argv[2]))
.concurrency_tag(CGAL::Parallel_if_available_tag()))

// run the reconstruction with automatic parameter estimation
: CGAL::ball_merge_surface_reconstruction(points,
meshFaceIndices1, meshFaceIndices2,
params::concurrency_tag(CGAL::Parallel_if_available_tag()));

// write output triangle soups
CGAL::IO::write_polygon_soup("BMOut1.ply", points, meshFaceIndices1); //The first resulting mesh
CGAL::IO::write_polygon_soup("BMOut2.ply", points, meshFaceIndices2); //The second resulting mesh

std::cout << "delta parameter used = " << delta << "\n";

return 0;
}
Loading