/**

\page tutorial-display-pcl Tutorial: Threaded PCL viewer
\tableofcontents

\section pcl_viewer_intro Introduction

This tutorial shows how to use the `vpDisplayPCL` class.

In the next section you will find an example that shows how to use a threaded display to display two point clouds,
with one suffering some noise.

The program first generate a polynomial surface, whose coordinates are expressed in the object frame.
Then, a second surface is generated. It corresponds to the first surface, moved in another coordinates frame.
Some noise is added to this second surface if requested by the user (by default it is not activated), to simulate sensor innacuracy. Finally, the point clouds are displayed using the `vpDisplayPCL`.

\section pcl_viewer_requirements Requirements

To enable `vpDisplayPCL` class usage, and thus use this tutorial, you need to have a version of ViSP build with PCL. To see how to install PCL library,
please refer to the \ref soft_tool_pcl section.

\section pcl_viewer_howtorun How to run the tutorial

To see the different options of the tutorial, please run the following commands:
```
cd $VISP_WS/visp-build/tutorial/gui/pcl-visualizer/
$ ./tutorial-display-pcl -h
```

You should see a new windows that shows something similar to. It shows
our two point clouds.

\image html img-tutorial-display-pcl.png

To run the program without adding noise to the second point cloud, you can run:
```
$ ./tutorial-display-pcl
```
To stop the program, please click in the viewer window and press the `q` key.

\section pcl_viewer_example Point clouds visualization example explained

For this tutorial, we use the main program tutorial-display-pcl.cpp.

It uses the following class, which generates 3D coordinates and relies on the `vpDisplayPCL` to visualize data.

\include ClassUsingDisplayPCL.h

\subsection pcl_viewer_main Main code explained

Let us first have a look at the main program.

First, we include the class that uses the `vpDisplayPCL` object to display different point clouds:

\snippet tutorial-display-pcl.cpp Class include

Then, we define the default value of the program arguments.

\snippet tutorial-display-pcl.cpp Default arguments values

The following program arguments are available:

\snippet tutorial-display-pcl.cpp Arguments of the program

Let us look with more details into these arguments:

- `noise` represents the intensity of noise along the Z-axis, expressed in the object frame, has to be added to the original surface.
- `order` represents the order of the polynomial surface the user wants to use running the demo.
- `x-lim` and `y-lim` represents reciproquely the X-axis and Y-axis minimum and maximum values of the polynomial surface, expressed in the object frame.
- `reso` represents the number of points along the X-axis and Y-axis, expressed in the object frame, are used to generate the first surface.

Then, we parse the program arguments that permit to the user to change part of the behavior
of the program.

\snippet tutorial-display-pcl.cpp Arguments parser

\subsection pcl_viewer_class Code of the example class explained

\subsubsection pcl_viewer_class_generation Generation of the polynomial surfaces used in this example

For this example, we decided to modelize a polynomial 3D surface. The Z coordinate
is computed from the X and Y coordinates thanks to the following method.

\snippet ClassUsingDisplayPCL.cpp Z coordinates computation

The constructor initializes the minimum and maximum X and Y coordinates of the polynomial
surface, along with the number of points in each direction it contains. It also constructs
the vpDisplayPCL object, naming the window that will open.

\snippet ClassUsingDisplayPCL.cpp Constructor

The following method generate two polynomial surface. If the user asked to, noise will be added
to the displaced surface.

\snippet ClassUsingDisplayPCL.cpp Surface generator

\subsubsection pcl_viewer_class_usage How to use the vpDisplayPCL class to display the point clouds

To use the `vpDisplayPCL` class, you must first add the surfaces you want to display. For a textureless point cloud,
you can either choose the color to use to render it
or you can use the default color. Please refer to \ref vpDisplayPCL::addPointCloud for more information.

\snippet ClassUsingDisplayPCL.cpp Inserting point clouds

To update the surfaces over time, please use the following lines of codes:

\snippet ClassUsingDisplayPCL.cpp Updating point clouds used by display thread

As you can see, you don't have to do anything to the `vpDisplayPCL` class, but you have
to lock the mutex in order to avoid concurrency access.

Finally, if you decided to run the visualizer in monothread mode, you have to call the `vpDIsplayPCL::display()`
method to refresh the visualizer:

\snippet ClassUsingDisplayPCL.cpp Display monothread

\section pcl_viewer_known_issues Known issues

\subsection pcl_viewer_issues_MacOs Known issue on MacOS

On MacOS, you can face the following error:
\code
tutorial-display-pcl *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'NSWindow drag regions should only be invalidated on the Main Thread!'
libc++abi: terminating due to uncaught exception of type NSException
\endcode
This problem seems to be due to VTK library that does not like to be run in a non-main thread on MacOS.
You can use the vpDisplayPCL class in monothread mode using the method vpDisplayPCL::display. See the
[PCL issue](https://github.com/PointCloudLibrary/pcl/issues/253#issuecomment-29716100) for more details.

\subsection pcl_viewer_issues_ubuntu Known issue on Ubuntu 22.04

On Ubuntu 22.04, you can face the following error:
\code
Thread 2 "tutorial-pcl-vi" received signal SIGSEGV, Segmentation fault.
0x00007ffff7304b10 in _XEventsQueued () from /lib/x86_64-linux-gnu/libX11.so.6
0x00007ffff7304b10 in _XEventsQueued () at /lib/x86_64-linux-gnu/libX11.so.6
0x00007ffff72f11a1 in XPending () at /lib/x86_64-linux-gnu/libX11.so.6
0x00007fffecf65b8f in vtkXRenderWindowInteractor::StartEventLoop() () at /lib/x86_64-linux-gnu/libvtkRenderingUI-9.1.so.1
0x00007ffff6ee3f8c in pcl::visualization::PCLVisualizer::spinOnce(int, bool) () at /lib/x86_64-linux-gnu/libpcl_visualization.so.1.12
0x00007ffff7fa5c49 in vpPclVisualizer::loopThread() (this=0x7fffffffd720) at /usr/include/c++/11/bits/shared_ptr_base.h:1295
\endcode
This is a [known compatibility issue](https://github.com/PointCloudLibrary/pcl/issues/5237) between PCL library and VTK library.

The vpDisplayPCL can be used in monothread mode, or you may try to install PCL from source and then recompile
ViSP.

\subsection pcl_viewer_issues_xserver Known issue when using VTK and the server X backends

When the PCL library relies on the VTK library and X11 library as backends for the viewer, you
may face the following error if you create either two viewers in threaded mode or one viewer in
threaded mode and another one in the main thread:

\code
X Error of failed request:  BadAccess (attempt to access private resource denied)
  Major opcode of failed request:  152 (GLX)
  Minor opcode of failed request:  5 (X_GLXMakeCurrent)
  Serial number of failed request:  407
  Current serial number in output stream:  407
\endcode

*/
