namespace CGAL {
/*!
\mainpage User Manual
\anchor Chapter_3D_SurfaceSegmentation

\cgalAutoToc
\author Ilker %O. Yaz and Sébastien Loriot

\cgalFigureBegin{Segmentation_Elephant_main,elephant_sdf_partition.png}
The shape diameter function applied to the elephant and the corresponding segmentation (using 6 clusters).
\cgalFigureEnd

\section Surface_mesh_segmentationIntroduction Introduction
Mesh segmentation is the process of decomposing a mesh into smaller and meaningful sub-meshes.
This process is used in applications such as modeling, rigging, texturing, shape-retrieval, deformation ...
We refer to a comprehensive survey on mesh segmentation \cgalCite{Shamir2008SegmentationSurvey} for different segmentation techniques.

This package provides an implementation of the algorithm relying on the <em>Shape Diameter Function</em> \cgalCite{Shapira2008Consistent} (SDF).
Given a triangulated surface mesh (simply <em>mesh</em> in the following) bounding a 3D solid object,
the SDF provides an estimate of the local object diameter for each facet of the mesh (the SDF values).
The segmentation algorithm first applies a soft clustering on the facets using the associated SDF values.
The final segmentation is then obtained via a graph-cut algorithm that considers surface-based features (dihedral-angle and concavity)
together with the result of the soft clustering.

This package offers the computation of the SDF values and the mesh segmentation result as independent functions.
This allows an alternative implementation of the SDF to be directly plugged into the segmentation algorithm,
and also to reuse the SDF values several times with different parameters for the segmentation algorithm.

\section Surface_mesh_segmentationOverviewoftheSegmentation Overview of the Segmentation Process

\subsection Surface_mesh_segmentationShapeDiameterFunction Shape Diameter Function
The Shape Diameter Function provides a connection between the surface mesh and the volume of the subtended 3D bounded object.
More specifically, the SDF is a scalar-valued function defined on facets of the mesh that measures the corresponding local object diameter.
The SDF is used to distinguish between thin and thick parts by adding a local notion of thickness to the facets.
In addition, the SDF is pose-invariant: SDF values remain largely unaffected after changes of pose (see \cgalFigureRef{Segmentation_pose_changes}).

\cgalFigureBegin{Segmentation_pose_changes,pose_changes_sdf_low_3.png}
Influence of pose changes over SDF values and the segmentation.
\cgalFigureEnd

\subsubsection Surface_mesh_segmentationRawSDF Computing Raw SDF Values
For a given input mesh, the raw SDF values are computed by processing each facet one by one. For each facet,
several rays are sampled in a cone constructed using the centroid of the facet as apex and inward-normal of the facet as axis.
Each ray is truncated into a segment, its endpoints being the apex of the cone and the first mesh facet intersection point.
Using the lengths of these truncated rays, which intuitively correspond to a local volume sampling,
the raw SDF value is computed by first applying an outlier removal procedure and then taking the average of the lengths.

The raw SDF values are computed through function `sdf_values()`, setting `postprocess` to `false`.

\note This package also accepts input meshes with holes. In such a case, rays that can not be truncated to segments,
or rays that form an obtuse angle with the inward-normal of the first intersected facet are ignored.
Only facets having no ray get no raw SDF values

\subsubsection Surface_mesh_segmentationPostprocessing Post-processing of Raw SDF Values
After having calculated the raw SDF value for each facet, the SDF values used in the segmentation algorithm are
the result of several post-processing steps:

- Facets with no raw SDF values are assigned the average raw SDF value of their edge-adjacent neighbors. If there is still a facet having no SDF value,
the minimum amongst all the SDF values is assigned to it (this is a deviation from the description of the algorithm in \cgalCite{Shapira2008Consistent}).
The main reason for not assigning 0 to facets with no SDF values is that it can obstruct log-normalization process done at the beginning of `segmentation_from_sdf_values()`.

- A bilateral smoothing \cgalCite{Tomasi1998Bilateral} is applied.
  This smoothing technique removes the noise while trying to keep fast changes on SDF values unchanged since they are natural candidates for segment boundaries.
  The bilateral smoothing \cgalCite{Tomasi1998Bilateral} has three parameters that are set as follows:
  -\f$ w = \lfloor\sqrt{  |F| / 2000}\rfloor + 1 \f$, the window size (i.e. maximum level for breadth-first neighbor selection), where \f$ F \f$ denotes the set of facets
  -\f$ \sigma_s = w / 2 \f$, the spatial parameter
  -\f$ \sigma_{r_i} = \sqrt{1/|w_i| \sum_{f_j \in w_i}(SDF(f_j) - SDF(f_i))^2} \f$, the range parameter set for each facet \f$ f_i \f$; \f$ w_i \f$ denotes the set of neighboring facets of \f$ f_i \f$ collected using \f$ w \f$ in the facet neighbor breadth-first search

  Large window sizes are more effective at eliminating noise but may over-smooth SDF values along segment boundaries.
  Large range parameters make smoothing closer to Gaussian smoothing and may also lead to over-smoothed SDF values.
- SDF values are linearly normalized between [0,1].

These post-processing steps can be applied to raw SDF values (or an alternative set of similar scalar values associated with facets) using the function `sdf_values_postprocessing()`.

\subsection Surface_mesh_segmentationSoftClustering Soft Clustering

Given a number \f$ k \f$  of clusters, the soft clustering is a Gaussian mixture model that consists in fitting \f$ k \f$
Gaussian distributions to the distribution of the SDF values of the facets. It is initialized with k-means++ \cgalCite{Arthur2007Kmeans}, and run multiple times with random seeds.
Among these runs, the best result is used for initializing the expectation-maximization algorithm for fitting the Gaussian distributions.

\note There is no direct relationship between the number of clusters (parameter for soft clustering) and the  final number of segments.
Intuitively, the number of clusters represents the number of levels of a segmentation by clustering facets that have close SDF values
without considering their connectivity.  However, a large number of clusters is likely to result in detailed segmentation of the mesh
with a large number of segments, see \cgalFigureRef{Segmentation_levels}.

\cgalFigureBegin{Segmentation_levels,effect_of_levels.png}
Influence of the number of clusters over the segmentation. The number of clusters are set to 4, 3, and 2 respectively.
\cgalFigureEnd

The output of this procedure is a matrix that contains probability values for each facet to belong to each cluster.
These probability values are used as input to the hard clustering.

\subsection Surface_mesh_segmentationGraphCut Hard clustering

The hard clustering yields the final segmentation of the input mesh and results from minimizing an energy function
combining the aforementioned probability matrix and geometric surface features.

The energy function minimized using alpha-expansion graph cut algorithm \cgalCite{Boykov2001FastApproximate} is defined as follows:

  <table border="0">
  <tr>
	 <td>
		\f$ E(\bar{x}) = \sum\limits_{f \in F} e_1(f, x_f) + \lambda \sum\limits_{ \{f,g\} \in N} e_2(x_f, x_g) \f$

		\f$ e_1(f, x_f) = -log(max(P(f|x_f), \epsilon)) \f$

		\f$ e_2(x_f, x_g) =
		\left \{
		\begin{array}{rl}
			-log(\theta(f,g)/\pi) &\mbox{ $x_f \ne x_g$} \\
			0 &\mbox{ $x_f = x_g$}
		\end{array}
		\right \} \f$
	 </td>
     <td>
where:
  - \f$F\f$ denotes the set of facets,
  - \f$N\f$ denotes the set of pairs of neighboring facets,
  - \f$x_f\f$ denotes the cluster assigned to facet \f$f\f$,
  - \f$P(f|x_p)\f$ denotes the probability of assigning facet \f$f\f$ to cluster \f$x_p\f$,
  - \f$\theta(f,g)\f$ denotes the dihedral angle between neighboring facets \f$f\f$ and \f$g\f$:
	 concave angles and convex angles are weighted by 1 and 0.1 respectively,
  - \f$\epsilon\f$ denotes the minimal probability threshold,
  - \f$\lambda \in [0,1]\f$ denotes a smoothness parameter.
	 </td>
  </tr>
  </table>

The first term of the energy function provides the contribution of the soft clustering probabilities.
The second term of the energy function is a geometric criterion that is larger when two adjacent facets sharing a sharp and concave edge are in the same cluster.
The smoothness parameter makes this geometric criteria more or less prevalent.

Assigning a high value to the smoothness parameter results in a small number of segments (since constructing a segment boundary would be expensive).
In other words, merging facets that are placed under different clusters is less expensive than separating them and creating boundaries.
On the contrary, assigning smaller values to smoothness parameter results in a high number of segments, by getting closer to the result of the soft clustering
(notice that setting \f$ \lambda=0 \f$ provides the result of the soft clustering). \cgalFigureRef{Segmentation_lambdas} depicts the influence of the smoothness parameter.

\cgalFigureBegin{Segmentation_lambdas,dino_different_lambda_small.png}
Influence of the smoothness parameter lambda over the segmentation (using 10 clusters). Smoothness parameters are set to 0.0, 0.1, 0.25, 0.5 and 1.0 respectively. The coloring reflects the segmentation result before assigning each connected component to its own segment.
\cgalFigureEnd

The hard clustering assigns a cluster id to each facet (see \cgalFigureRef{Cluster_vs_segment} (a)).
A segment consists in a set of connected facets in the same cluster (see \cgalFigureRef{Cluster_vs_segment} (b)).
By default the function `segmentation_from_sdf_values()` assigns to each facet the id of its segment.
It assigns to each facet the id of its cluster when `output_cluster_ids` is set to `true`.


\cgalFigureBegin{Cluster_vs_segment,cluster_vs_segment.png}
Clusters and segments. The input number of clusters is set to 5. <b>(a)</b> Result of the hard-clustering. <b>(b)</b> Segments are extracted from the computed clusters.
\cgalFigureEnd



\subsection Surface_mesh_segmentationAPI Summary
Four functions are provided:
	- `sdf_values()` : computes the SDF value of each facet of an input mesh in either raw or post-processed form.
           SDF values are associated to facets using a property map (see \ref Chapter_CGAL_and_Boost_Property_Maps
"CGAL and Boost Property Maps").
	- `sdf_values_postprocessing()` : post-processes raw SDF values. The post-processing is decoupled from
             the function `sdf_values()` to allow the use of alternative methods to compute SDF values or additional post-processing step.
	- `segmentation_from_sdf_values()` : computes the mesh segmentation from the SDF values of the facets of an input mesh.
            The input SDF values can be any set of scalar values associated to each facet as long as they have been normalized between 0 and 1.
            This function allows using the same SDF values with different parameters for the segmentation stage.
            The segment or cluster ids are associated to the facets using a property map.
	- `segmentation_via_sdf_values()` : combines the three functions above.

These functions expect as input a triangulated surface mesh bounding a 3D solid object, with
the following properties:
- Combinatorially 2-manifold;
- The vertices of the facets are oriented counterclockwise when seen from outside of the object;
- Intersection-free;
- Boundary free.

\note The current implementation executes fine on meshes that do not match
some of these properties but may produce unreliable or meaningless segmentations.

The current implementation of the computation of the SDF values relies on the \ref PkgAABBTree package.
This operation is reliable when the `AABBTraits` model provided has exact predicates.
`::CGAL::Exact_predicates_inexact_constructions_kernel` is recommended as geometric traits for this algorithm.

\section SDFExamples Examples

\subsection Example_1 Example: Computation of SDF Values
\cgalExample{Surface_mesh_segmentation/sdf_values_example.cpp}

\subsection Example_2 Example: Segmentation from SDF Values
\cgalExample{Surface_mesh_segmentation/segmentation_from_sdf_values_example.cpp}

\subsubsection Example_3 Computation of SDF Values and Segmentation
The function `segmentation_via_sdf_values()` combines the computation of sdf values, the post-processing and the segmentation.
Note that when computing several segmentations of a mesh with different parameters (i.e. number of levels, and smoothing lambda),
it is advised to first compute the SDF values using `sdf_values()` and use them in calls of the function `segmentation_from_sdf_values()`.

\cgalExample{Surface_mesh_segmentation/segmentation_via_sdf_values_example.cpp}

\subsection Surface_mesh_segmentationUsingapolyhedron Using a Polyhedron with an ID per Facet
The previous examples use a `std::map` as property maps for storing the SDF values and the segmentation results. This example uses
a polyhedron type with a facet type storing an extra ID field, together with a vector, as underlying data structure in the property maps.
The main advantage is to decrease from log to constant the complexity for accessing the data associated to facets.

\cgalExample{Surface_mesh_segmentation/segmentation_with_facet_ids_example.cpp}


\subsection Surface_mesh_segmentationUsingSM Using a Surface_mesh
When using a `Surface_mesh`, you can use the built-in property mechanism. 

\cgalExample{Surface_mesh_segmentation/segmentation_from_sdf_values_SM_example.cpp}

\subsection Surface_mesh_segmentationIndependantmeshpersegment Independant TriangleMesh per Segment
 It is possible to consider each segment as an independant triangle mesh, like in the following example, where the area of each segment is computed.

\cgalExample{Surface_mesh_segmentation/extract_segmentation_into_mesh_example.cpp}

<BR>
\section Performances Performances
<!-- \subsection SMSRuntime Runtime of the functions sdf_values() and segmentation_from_sdf_values() -->

The following tables provide the runtime of the functions `sdf_values()` and `segmentation_from_sdf_values()`.
The results were produced with the release 4.4 of \cgal, on an Intel i7 3.2 Ghz laptop with 8 GB RAM, compiled by Visual C++ 2010 with /O2 option.
The polyhedron types are using `Polyhedron_items_with_id_3` as item class.
The models used for the benchmarks are the <i>dinosaur</i> model with 7,828 facets,  the <i>bear</i> model with 20,188 facets and the <i>elephant</i> model with 88,928 facets.

Runtime in seconds of `sdf_values()` with 25 rays showing the cost of the robustness:

<center>
Number of triangles  | `%Simple_cartesian<double>` | `%Exact_predicates_inexact_constructions_kernel` (`EPICK`)
---------------------| -------------------------:  | --------------------------------------------------------:
  7,828              |  2.3                        |  3.8
 20,188              |  6.1                        |  9.5
 88,928              | 46.1                        | 62.3
</center>

<!-- This is only to keep the results, the flag is not documented
<center>
Number of triangles  | `%Simple_cartesian<double>` | `%Exact_predicates_inexact_constructions_kernel` (`EPICK`) | `EPICK` with `Fast_sdf_calculation_mode = false`
---------------------| -------------------------:  | --------------------------------------------------------:  | -----------------------------------------------:
  5,558              |  1.6                        |  3.9                                                       |   8.4
 34,986              | 13.6                        | 26.2                                                       |  63.9
100,332              | 48.7                        | 88.1                                                       | 169.2
</center>
-->

Runtime in milliseconds of `segmentation_from_sdf_values()` (using `%Simple_cartesian<double>` or `EPICK` gives the same results),
the graph-cut part is using the library <a href="http://pub.ist.ac.at/~vnk/software.html">MaxFlow</a> v2.21:

<center>
Number of triangles  | Number of cluster = 2 | Number of cluster = 5 | Number of cluster = 10 | Number of cluster = 15
---------------------| -------------------:  | -------------------:  | --------------------:  | ---------------------:
7,828                |    38                 |    61                 |    141                 |     204
20,188               |    50                 |   163                 |    483                 |     608
88,928               |   314                 | 1,260                 |  2,736                 |   4,239
</center>


<!-- Internal for developers:
These are the runtimes in case CGAL_DO_NOT_USE_BOYKOV_KOLMOGOROV_MAXFLOW_SOFTWARE is defined, in which
case boost::boykov_kolmogorov_max_flow is used instead of MaxFlow
<center>
Number of triangles  | Number of cluster = 2 | Number of cluster = 5 | Number of cluster = 10 | Number of cluster = 15
---------------------| -------------------:  | -------------------:  | --------------------:  | -------------------:
5,558                |    55                 |   215                 |    538                 |     847
34,986               |   351                 | 1,279                 |  3,551                 |   5,875
100,332              | 1,112                 | 4,227                 | 11,850                 |  23,408
</center>

\section ImplementationDetails Implementation Details
\subsection RaySamplingInShapeDiameterFunction Ray Sampling in Shape Diameter Function
\cgalFigureBegin{Segmentation_vogel,vogel_uniform_biased.png}
Comparison of biased toward the center and uniform disk sampling for 64 rays.
\cgalFigureEnd

We generate a set of sample points in a unit circle and place it tangent to the cone, with it supporting plane orthogonal to the cone direction. Then we combine each point with the apex of the cone to construct the rays.
The sampling method is biased toward the center \cite Vogel1979Sampling in order to make the sampling uniform to the angle.
As a result, we do not use the weighting scheme from the original algorithm in order to reduce the contributions of rays with larger angles.
A comparison with biased and uniform sampling of points can be seen in \cgalFigureRef{Segmentation_vogel}. The final SDF value of a facet is then calculated by averaging the ray lengths falling into 1.5 Median Absolute Deviation (MAD) from the median of all lengths.
-->

<!--
\subsection SMSBench Mesh Segmentation Benchmark
The mesh segmentation problem being ill-posed, the mesh segmentation community have proposed some benchmarks to evaluate the
quality of a given algorithm. A benchmark is composed of a set of models and a software responsible for scoring
the results. On a particular benchmark \cite Chen2009SegmentationBenchmark, the current implementation obtains the
score of XXX. The code used in the benchmark is provided as an exemple XXX.
\todo Add the score and the source code used for the benchmark
-->


\section Surface_mesh_segmentationImplementationhistory Design and Implementation History
The initial implementation of this package is the result of the work of Ilker O. Yaz during the 2012 season
of the Google Summer of Code. He has been mentored by Sébastien Loriot who also contributed to the documentation
and the API definition.

*/
} /* namespace CGAL */
