diff --git a/doc/sphinx/source/user_guide/complex_shape.png b/doc/sphinx/source/user_guide/complex_shape.png
new file mode 100644
index 0000000000..7663a553a3
Binary files /dev/null and b/doc/sphinx/source/user_guide/complex_shape.png differ
diff --git a/doc/sphinx/source/user_guide/gcs_graphics.rst b/doc/sphinx/source/user_guide/gcs_graphics.rst
new file mode 100644
index 0000000000..f3530903de
--- /dev/null
+++ b/doc/sphinx/source/user_guide/gcs_graphics.rst
@@ -0,0 +1,149 @@
+.. user_guide flight_plan
+
+================
+GCS map graphics
+================
+
+GCS map can be enriched with intruders and shapes.
+
+Intruders
+---------
+
+Intruders represents vehicules that are not managed by paparazzi. They are updated with the `INTRUDER` message.
+
+Intruders positions are transmitted by the server to the ACs with ACINFO messages.
+
+.. image:: intruder.png
+
+
+The **INTRUDER** message is defined as follow:
+
+.. code-block:: xml
+
+
+
+
+
+
+ altitude above WGS84 reference ellipsoid
+
+
+
+
+
+
+Latitudes and longitudes are integers in 1e7deg: ``43.123456`` become ``431234560``.
+
+.. note::
+
+ You can use the **OpenSky-Network Intruders** tool (in the paparazzi center: Tools->OpenSky-Network Intruders) to view ADS-B aircrafts near your ACs.
+
+ The **id** field will be the aircraft's hexadecimal ICAO 24 bits address, and the **name** field its callsign.
+
+
+
+Shapes
+------
+
+Shapes can be drawn in the GCS by sending the **SHAPE** message defined below.
+
+.. image:: shapes.png
+
+.. code-block:: xml
+
+
+
+ The SHAPE message used to draw shapes onto the Paparazzi GCS.
+ Field name shape is used to define the type of shape i.e. Circle, Polygon, Line, or Text.
+ This is indexed from 0-3 respectively.
+
+ Each shape drawn must have an id number associated with it.
+ This id number in conjuction with the shapetype will be needed to update or delete the shape.
+ A circle can be defined with the same id as a polygon but since they have different shape types they are considered unique.
+
+ linecolor and fillcolor take in a color string ie: "red", "blue"
+
+ opacity will change the level of transparency of the fill.
+ 0 - Transparent
+ 1 - Light Fill
+ 2 - Medium Fill
+ 3 - Opaque
+
+ Passing a status of 0 will create or update the shape specified by id and type.
+ Passing a status of 1 will delete the shape specified by id and type.
+
+ latarr is an array of coordinates that contain the latitude coordinate for each point in the shape.
+ The array is comma separated.
+ lonarr is similar to latarr but contain the longitude coordinate for each point in the shape.
+
+ Circle and Text type will take the first coordinates given to place the shape.
+ Polygon will take all the coordinates given.
+ Line will take the first two coordinates given.
+
+ Radius is only used for the circle.
+
+ Text will always be populated with each message using the first set of coordinates.
+ The text field can not be blank or have spaces.
+ If text is not desired for a shape then pass "NULL" into the text field.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+The embedded documentation is pretty explicit here.
+
+
+
+How is this different from sectors, and which one should I choose?
+__________________________________________________________________
+
+Sectors are defined in the flight plan with waypoints, and are embedded in the aircraft. The aircraft can react to it even if telemetry is down.
+It is advised to keep the number of waypoints low, so this limits the sector "resolution".
+
+Shapes, on the other hand, are simply drawn in the GCS. It means that the aircraft has no knowledge of their existence, so it can't react to them by itself.
+Being purely on the ground station also means that the number of waypoints can be much higher, allowing to draw e.g. detailled curved zones.
+
+.. image:: complex_shape.png
+
+Example
+_______
+
+This is the python script that was used to draw the 3 shapes on the first example.
+
+.. literalinclude:: shapes_example.py
+
+Draw shapes from the AC
+-----------------------
+
+A future feature will be the addition of a DRAW message to the telemetry, that will be translated to a SHAPE message by the server.
+This will allow to draw shapes on the GCS directly from the AC.
+
+
+GCS position
+------------
+
+The GCS displays its position on the map when receiving a ``FLIGHT_PARAM`` message with the **ac_id** set to ``GCS``.
+
+This is used by the *rtcm2ivy* tool, that transmit the RTK corrections of a base station, and by the *GPSd position display* tool, dedicated to this task.
+
+Plumes
+------
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
diff --git a/doc/sphinx/source/user_guide/index_user_guide.rst b/doc/sphinx/source/user_guide/index_user_guide.rst
index 34bfed7e6f..443a8468d3 100644
--- a/doc/sphinx/source/user_guide/index_user_guide.rst
+++ b/doc/sphinx/source/user_guide/index_user_guide.rst
@@ -15,5 +15,6 @@ Start conquering the wolrd, by making incredible :doc:`flight_plans`!
flight_plans
communication
radio
+ gcs_graphics
directories_structure
diff --git a/doc/sphinx/source/user_guide/intruder.png b/doc/sphinx/source/user_guide/intruder.png
new file mode 100644
index 0000000000..7378742afc
Binary files /dev/null and b/doc/sphinx/source/user_guide/intruder.png differ
diff --git a/doc/sphinx/source/user_guide/shapes.png b/doc/sphinx/source/user_guide/shapes.png
new file mode 100644
index 0000000000..93f270f998
Binary files /dev/null and b/doc/sphinx/source/user_guide/shapes.png differ
diff --git a/doc/sphinx/source/user_guide/shapes_example.py b/doc/sphinx/source/user_guide/shapes_example.py
new file mode 100755
index 0000000000..9818cfb71f
--- /dev/null
+++ b/doc/sphinx/source/user_guide/shapes_example.py
@@ -0,0 +1,104 @@
+#!/usr/bin/python3
+
+import sys
+from os import path, getenv
+import time
+from enum import Enum
+
+PPRZ_HOME = getenv("PAPARAZZI_HOME", path.normpath(path.dirname(path.abspath(__file__))))
+sys.path.append(PPRZ_HOME + "/var/lib/python")
+sys.path.append(PPRZ_HOME + "/sw/lib/python")
+
+from pprzlink.ivy import IvyMessagesInterface
+from pprzlink.message import PprzMessage
+from pprz_connect import PprzConnect
+
+
+class Shape(Enum):
+ CIRCLE = 0
+ POLYGON = 1
+ LINE = 2
+ TEXT = 3
+
+
+class Opacity(Enum):
+ TRANSPARENT = 0
+ LIGHT_FILL = 1
+ MEDIUM_FILL = 2
+ OPAQUE = 3
+
+
+class Status(Enum):
+ CREATE = 0
+ DELETE = 1
+
+
+POLYGON_COORDS = [
+ (43.462, 1.272),
+ (43.4622, 1.2684),
+ (43.4628, 1.2686),
+ (43.464, 1.2710),
+ (43.4657, 1.2714),
+ (43.4656, 1.2738)
+]
+
+
+def polygon(shape_id):
+ msg_shape = PprzMessage("ground", "SHAPE")
+ msg_shape['id'] = shape_id
+ msg_shape['linecolor'] = 'red'
+ msg_shape['fillcolor'] = 'red'
+ msg_shape['opacity'] = Opacity.LIGHT_FILL.value
+ msg_shape['shape'] = Shape.POLYGON.value
+ msg_shape['status'] = Status.CREATE.value
+ lonarr = []
+ latarr = []
+ for coord in POLYGON_COORDS:
+ latarr.append(int(coord[0] * 1e7))
+ lonarr.append(int(coord[1] * 1e7))
+ msg_shape['latarr'] = latarr
+ msg_shape['lonarr'] = lonarr
+ msg_shape['text'] = "Crop"
+ return msg_shape
+
+def circle(shape_id):
+ msg_shape = PprzMessage("ground", "SHAPE")
+ msg_shape['id'] = shape_id
+ msg_shape['linecolor'] = 'green'
+ msg_shape['fillcolor'] = 'yellow'
+ msg_shape['opacity'] = Opacity.MEDIUM_FILL.value
+ msg_shape['shape'] = Shape.CIRCLE.value
+ msg_shape['status'] = Status.CREATE.value
+ msg_shape['latarr'] = [int(43.4640*1e7)]
+ msg_shape['lonarr'] = [int(1.275*1e7)]
+ msg_shape['radius'] = int(100)
+ msg_shape['text'] = "hello"
+ return msg_shape
+
+def line(shape_id):
+ msg_shape = PprzMessage("ground", "SHAPE")
+ msg_shape['id'] = shape_id
+ msg_shape['linecolor'] = 'purple'
+ msg_shape['shape'] = Shape.LINE.value
+ msg_shape['status'] = Status.CREATE.value
+ msg_shape['latarr'] = [int(43.46296*1e7), int(43.46216*1e7)]
+ msg_shape['lonarr'] = [int(1.272*1e7), int(1.2744*1e7)]
+ msg_shape['text'] = "runway"
+ return msg_shape
+
+if __name__ == '__main__':
+ ivy = IvyMessagesInterface("Shape drawer")
+ # wait for ivy to be correctly started
+ time.sleep(0.1)
+
+ msg = polygon(1)
+ ivy.send(msg)
+
+ msg = circle(2)
+ ivy.send(msg)
+
+ msg = line(3)
+ ivy.send(msg)
+
+ ivy.shutdown()
+