Algorithme de Douglas-Peucker
En informatique, plus précisément en algorithmique, plus précisément en algorithmique géométrique, l’algorithme de Douglas-Peucker, aussi connu sous le nom d'algorithme de Ramer-Douglas-Peucker, sert à simplifier un polygone ou une ligne brisée en supprimant des points. L'algorithme a été publié par David H. Douglas et Thomas K. Peucker en 1973[1]. Il est utilisé en compression de données vectorielles et en généralisation cartographique.
Principe
L'algorithme part du principe suivant. Considérons une ligne brisée (aussi appelée polyligne dans le jargon de l'algorithmique géométrique). On décide de simplifier la ligne brisée et de la remplacer par une ligne simple (deux points), si la distance de son points le plus éloigné de la droite formée par les extrémités de la ligne brisée est inférieure à un certain seuil.
L'algorithme travaille de manière récursive par la méthode « diviser pour régner ».
À l'initialisation on sélectionne le premier et le dernier point (cas d'une polyligne), ou un point quelconque (cas d'un polygone). Ce sont les bornes initiales.
À chaque étape on parcourt tous les points entre les bornes et on sélectionne le point le plus éloigné du segment formé par les bornes :
- s'il n'y a aucun point entre les bornes l'algorithme se termine,
- si cette distance est inférieure à un certain seuil on supprime tous les point entre les bornes,
- si elle est supérieure la polyligne n'est pas directement simplifiable. On appelle de manière récursive l'algorithme sur deux sous-parties de la polyligne : de la première borne au point distant, et du point distant à la borne finale.
Pseudo-code
fonction DouglasPeucker(points[1..n], ε)
// Trouve l'indice du point le plus éloigné du segment
dmax = 0
index = 0
pour i = 2 à n - 1
d = distance du points[i] au segment [points[1], points[n])
si d > dmax
index = i
dmax = d
// Si la distance dmax est supérieure au seuil, appels récursifs
si dmax > ε
// Appel récursif de la fonction
recPoints1[1..k] = DouglasPeucker(points[1…index], ε)
recPoints2[1..m] = DouglasPeucker(points[index…n], ε)
// Construit la liste des résultats à partir des résultats partiels
renvoie la concaténation de recPoints1[1…k-1] et recResults2[1…m]
sinon // Tous les points sont proches → renvoie un segment avec les extrémités
renvoie [points[1], points[n]]
Complexité
On remarquera que l'algorithme se finit forcément puisque dans le pire des cas la polyligne (ou le polygone) n'est pas simplifiable et chaque branche formée par la récursion s'achèvera lorsque les bornes ne seront pas séparées par un nœud (cas 1).
Dans le meilleur des cas, la complexité est en puisqu'à chaque itération le nombre de branches de récursion est multiplié par deux et tous les points sont visités. Le pire des cas est en car il correspond au cas où chaque segment est coupé au niveau du deuxième point. On parcourt donc n-2 points à la première itération, n-3 à la seconde, etc.
En utilisant une structure de données dynamique pour représenter une enveloppe convexe, l'algorithme peut s'implémenter en dans le pire cas[2].
Voir aussi
L'algorithme de Visvalingam (1992) donne aussi de très bons résultats, voire meilleurs
cf cette description simple
ou cet article complet
Notes et références
- David H Douglas et Thomas K. Peucker, « Algorithms for the reduction of the number of points required to represent a digitized line or its caricature », Cartographica: The International Journal for Geographic Information and Geovisualization, University of Toronto Press, vol. 10, no 2, , p. 112-122
- Hershberger, John; Snoeyink, Jack (1992). Speeding Up the Douglas-Peucker Line-Simplification Algorithm (PDF) (Technical report).