Ramer-Douglas-Peucker line simplification: Difference between revisions

m
m (Fixed spelling error)
m (→‎{{header|Wren}}: Minor tidy)
 
(22 intermediate revisions by 14 users not shown)
Line 18:
:*   the Wikipedia article:   [https://en.wikipedia.org/wiki/Ramer%E2%80%93Douglas%E2%80%93Peucker_algorithm Ramer-Douglas-Peucker algorithm].
<br><br>
 
=={{header|11l}}==
{{trans|Go}}
 
<syntaxhighlight lang="11l">F rdp(l, ε) -> [(Float, Float)]
V x = 0
V dMax = -1.0
V p1 = l[0]
V p2 = l.last
V p21 = p2 - p1
 
L(p) l[1.<(len)-1]
V d = abs(cross(p, p21) + cross(p2, p1))
I d > dMax
x = L.index + 1
dMax = d
I dMax > ε
R rdp(l[0..x], ε) [+] rdp(l[x..], ε)[1..]
 
R [l[0], l.last]
 
print(rdp([(0.0, 0.0),
(1.0, 0.1),
(2.0,-0.1),
(3.0, 5.0),
(4.0, 6.0),
(5.0, 7.0),
(6.0, 8.1),
(7.0, 9.0),
(8.0, 9.0),
(9.0, 9.0)], 1.0))</syntaxhighlight>
 
{{out}}
<pre>
[(0, 0), (2, -0.1), (3, 5), (7, 9), (9, 9)]
</pre>
 
=={{header|ALGOL 68}}==
{{trans|Go}}
<syntaxhighlight lang="algol68">
BEGIN # Ramer Douglas Peucker algotithm - translated from the Go sample #
 
MODE POINT = STRUCT( REAL x, y );
 
PRIO APPEND = 1;
OP APPEND = ( []POINT a, b )[]POINT: # append two POINT arrays #
BEGIN
INT len a = ( UPB a - LWB a ) + 1;
INT len b = ( UPB b - LWB b ) + 1;
[ 1 : lena + len b ]POINT result;
result[ : len a ] := a;
result[ len a + 1 : ] := b;
result
END # APPEND # ;
 
PROC rdp = ( []POINT l, REAL epsilon )[]POINT: # Ramer Douglas Peucker #
BEGIN # algorithm #
INT x := 0;
REAL d max := -1;
POINT p1 = l[ LWB l ];
POINT p2 = l[ UPB l ];
REAL x21 = x OF p2 - x OF p1;
REAL y21 = y OF p2 - y OF p1;
REAL p2xp1y = x OF p2 * y OF p1;
REAL p2yp1x = y OF p2 * x OF p1;
FOR i FROM LWB l TO UPB l DO
POINT p = l[ i ];
IF REAL d := ABS ( y21 * x OF p - x21 * y OF p + p2xp1y - p2yp1x); d > d max
THEN
x := i;
d max := d
FI
OD;
IF d max > epsilon THEN
rdp( l[ : x ], epsilon ) APPEND rdp( l[ x + 1 : ], epsilon )
ELSE
[]POINT( l[ LWB l ], l[ UPB l ] )
FI
END # rdp # ;
 
OP FMT = ( REAL v )STRING: # formsts v with up to 2 decimals #
BEGIN
STRING result := fixed( ABS v, 0, 2 );
IF result[ LWB result ] = "." THEN "0" +=: result FI;
WHILE result[ UPB result ] = "0" DO result := result[ : UPB result - 1 ] OD;
IF result[ UPB result ] = "." THEN result := result[ : UPB result - 1 ] FI;
IF v < 0 THEN "-" + result ELSE result FI
END # FMT # ;
OP SHOW = ( []POINT a )VOID: # prints an array of points #
BEGIN
print( ( "[" ) );
FOR i FROM LWB a TO UPB a DO
print( ( " ( ", FMT x OF a[ i ], ", ", FMT y OF a[ i ], " )" ) )
OD;
print( ( " ]" ) )
END # SHOW # ;
 
SHOW rdp( ( ( 0, 0 ), ( 1, 0.1 ), ( 2, -0.1 ), ( 3, 5 ), ( 4, 6 )
, ( 5, 7 ), ( 6, 8.1 ), ( 7, 9 ), ( 8, 9 ), ( 9, 9 )
)
, 1
)
END
</syntaxhighlight>
{{out}}
<pre>
[ ( 0, 0 ) ( 2, -0.1 ) ( 3, 5 ) ( 7, 9 ) ( 8, 9 ) ( 9, 9 ) ]
</pre>
 
=={{header|C}}==
<langsyntaxhighlight lang="c">#include <assert.h>
#include <math.h>
#include <stdio.h>
Line 89 ⟶ 198:
print_points(out, n);
return 0;
}</langsyntaxhighlight>
 
{{out}}
Line 98 ⟶ 207:
=={{header|C sharp|C#}}==
{{trans|Java}}
<langsyntaxhighlight lang="csharp">using System;
using System.Collections.Generic;
using System.Linq;
Line 187 ⟶ 296:
}
}
}</langsyntaxhighlight>
{{out}}
<pre>Points remaining after simplification:
Line 198 ⟶ 307:
=={{header|C++}}==
 
<langsyntaxhighlight lang="cpp">#include <iostream>
#include <cmath>
#include <utility>
Line 306 ⟶ 415:
 
return 0;
}</langsyntaxhighlight>
 
{{out}}
Line 318 ⟶ 427:
=={{header|D}}==
{{trans|C++}}
<langsyntaxhighlight Dlang="d">import std.algorithm;
import std.exception : enforce;
import std.math;
Line 406 ⟶ 515:
output ~= pointList[end];
}
}</langsyntaxhighlight>
 
{{out}}
Line 415 ⟶ 524:
7,9
9,9</pre>
 
 
=={{header|EasyLang}}==
{{trans|C}}
<syntaxhighlight>
func perpdist px py p1x p1y p2x p2y .
dx = p2x - p1x
dy = p2y - p1y
d = sqrt (dx * dx + dy * dy)
return abs (px * dy - py * dx + p2x * p1y - p2y * p1x) / d
.
proc peucker eps . ptx[] pty[] outx[] outy[] .
n = len ptx[]
idx = 1
for i = 2 to n - 1
dist = perpdist ptx[i] pty[i] ptx[1] pty[1] ptx[n] pty[n]
if dist > dmax
dmax = dist
idx = i
.
.
if dmax > eps
for i to idx
px[] &= ptx[i]
py[] &= pty[i]
.
peucker eps px[] py[] outx[] outy[]
#
for i = idx to n
p2x[] &= ptx[i]
p2y[] &= pty[i]
.
peucker eps p2x[] p2y[] ox[] oy[]
for i = 2 to len ox[]
outx[] &= ox[i]
outy[] &= oy[i]
.
else
outx[] = [ ptx[1] ptx[n] ]
outy[] = [ pty[1] pty[n] ]
.
.
proc prpts px[] py[] . .
for i to len px[]
write "(" & px[i] & " " & py[i] & ") "
.
print ""
.
px[] = [ 0 1 2 3 4 5 6 7 8 9 ]
py[] = [ 0 0.1 -0.1 5 6 7 8.1 9 9 9 ]
peucker 1 px[] py[] ox[] oy[]
prpts ox[] oy[]
</syntaxhighlight>
 
=={{header|FreeBASIC}}==
{{trans|Yabasic}}
<syntaxhighlight lang="freebasic">
Function DistanciaPerpendicular(tabla() As Double, i As Integer, ini As Integer, fin As Integer) As Double
Dim As Double dx, dy, mag, pvx, pvy, pvdot, dsx, dsy, ax, ay
dx = tabla(fin, 1) - tabla(ini, 1)
dy = tabla(fin, 2) - tabla(ini, 2)
'Normaliza
mag = (dx^2 + dy^2)^0.5
If mag > 0 Then dx /= mag : dy /= mag
pvx = tabla(i, 1) - tabla(ini, 1)
pvy = tabla(i, 2) - tabla(ini, 2)
'Producto escalado (proyecto pv en dirección normalizada)
pvdot = dx * pvx + dy * pvy
'Vector de dirección de línea de escala
dsx = pvdot * dx
dsy = pvdot * dy
'Reste esto de pv
ax = pvx - dsx
ay = pvy - dsy
Return (ax^2 + ay^2)^0.5
End Function
 
Sub DRDP(ListaDePuntos() As Double, ini As Integer, fin As Integer, epsilon As Double)
Dim As Double dmax, d
Dim As Integer indice, i
' Encuentra el punto con la distancia máxima
If Ubound(ListaDePuntos) < 2 Then Print "No hay suficientes puntos para simplificar " : Sleep : End
For i = ini + 1 To fin
d = DistanciaPerpendicular(ListaDePuntos(), i, ini, fin)
If d > dmax Then indice = i : dmax = d
Next
' Si la distancia máxima es mayor que épsilon, simplifique de forma recursiva
If dmax > epsilon Then
ListaDePuntos(indice, 3) = True
DRDP(ListaDePuntos(), ini, indice, epsilon)
DRDP(ListaDePuntos(), indice, fin, epsilon)
End If
End Sub
 
Dim As Double matriz(1 To 10, 1 To 3)
Data 0, 0, 1, 0.1, 2, -0.1, 3, 5, 4, 6, 5, 7, 6, 8.1, 7, 9, 8, 9, 9, 9
For i As Integer = Lbound(matriz) To Ubound(matriz)
Read matriz(i, 1), matriz(i, 2)
Next i
 
DRDP(matriz(), 1, 10, 1)
 
Print "Puntos restantes tras de simplificar:"
matriz(1, 3) = True : matriz(10, 3) = True
For i As Integer = Lbound(matriz) To Ubound(matriz)
If matriz(i, 3) Then Print "(";matriz(i, 1);", "; matriz(i, 2);") ";
Next i
Sleep
</syntaxhighlight>
{{out}}
<pre>
Puntos restantes tras de simplificar:
( 0, 0) ( 2, -0.1) ( 3, 5) ( 7, 9) ( 9, 9)
</pre>
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 449 ⟶ 682:
fmt.Println(RDP([]point{{0, 0}, {1, 0.1}, {2, -0.1},
{3, 5}, {4, 6}, {5, 7}, {6, 8.1}, {7, 9}, {8, 9}, {9, 9}}, 1))
}</langsyntaxhighlight>
{{out}}
<pre>
Line 457 ⟶ 690:
=={{header|J}}==
'''Solution:'''
<langsyntaxhighlight lang="j">mp=: +/ .* NB. matrix product
norm=: +/&.:*: NB. vector norm
normalize=: (% norm)^:(0 < norm)
Line 480 ⟶ 713:
({. ,: {:) points
end.
)</langsyntaxhighlight>
'''Example Usage:'''
<langsyntaxhighlight lang="j"> Points=: 0 0,1 0.1,2 _0.1,3 5,4 6,5 7,6 8.1,7 9,8 9,:9 9
1.0 rdp Points
0 0
Line 488 ⟶ 721:
3 5
7 9
9 9</langsyntaxhighlight>
 
=={{header|Java}}==
{{trans|Kotlin}}
{{works with|Java|9}}
<langsyntaxhighlight Javalang="java">import javafx.util.Pair;
 
import java.util.ArrayList;
Line 587 ⟶ 820:
pointListOut.forEach(System.out::println);
}
}</langsyntaxhighlight>
{{out}}
<pre>Points remaining after simplification:
Line 598 ⟶ 831:
=={{header|JavaScript}}==
{{trans|Go}}
<syntaxhighlight lang="javascript">/**
<lang JavaScript>/**
* @typedef {{
* x: (!number),
Line 642 ⟶ 875:
{x: 9, y: 9}];
 
console.log(RDP(points, 1));</langsyntaxhighlight>
{{out}}
<pre>[{x: 0, y: 0},
Line 654 ⟶ 887:
{{trans|C++}}
 
<langsyntaxhighlight lang="julia">const Point = Vector{Float64}
 
function perpdist(pt::Point, lnstart::Point, lnend::Point)
Line 695 ⟶ 928:
plist = Point[[0.0, 0.0], [1.0, 0.1], [2.0, -0.1], [3.0, 5.0], [4.0, 6.0], [5.0, 7.0], [6.0, 8.1], [7.0, 9.0], [8.0, 9.0], [9.0, 9.0]]
@show plist
@show rdp(plist)</langsyntaxhighlight>
 
{{out}}
Line 703 ⟶ 936:
=={{header|Kotlin}}==
{{trans|C++}}
<langsyntaxhighlight lang="scala">// version 1.1.0
 
typealias Point = Pair<Double, Double>
Line 778 ⟶ 1,011:
println("Points remaining after simplification:")
for (p in pointListOut) println(p)
}</langsyntaxhighlight>
 
{{out}}
Line 791 ⟶ 1,024:
 
=={{header|Nim}}==
<langsyntaxhighlight lang="nim">import math
 
type
Line 828 ⟶ 1,061:
var line: seq[Point] = @[(0.0, 0.0), (1.0, 0.1), (2.0, -0.1), (3.0, 5.0), (4.0, 6.0),
(5.0, 7.0), (6.0, 8.1), (7.0, 9.0), (8.0, 9.0), (9.0, 9.0)]
echo rdp(line, line.low, line.high)</langsyntaxhighlight>
 
{{out}}
<pre>@[(x: 0.0, y: 0.0), (x: 2.0, y: -0.1), (x: 3.0, y: 5.0), (x: 7.0, y: 9.0), (x: 9.0, y: 9.0)]</pre>
 
=={{header|ooRexx}}==
<syntaxhighlight lang="oorexx">
/*REXX program uses the Ramer-Douglas-Peucker (RDP) line simplification algorithm for*/
/*--------------------------- reducing the number of points used to define its shape. */
Parse Arg epsilon pl /*obtain optional arguments from the CL*/
If epsilon='' | epsilon=',' then epsilon= 1 /*Not specified? Then use the default.*/
If pl='' Then pl= '(0,0) (1,0.1) (2,-0.1) (3,5) (4,6) (5,7) (6,8.1) (7,9) (8,9) (9,9)'
Say ' error threshold:' epsilon
Say ' points specified:' pl
Say 'points simplified:' dlp(pl)
Exit
dlp: Procedure Expose epsilon
Parse Arg pl
plc=pl
Do i=1 By 1 While plc<>''
Parse Var plc '(' X ',' y ')' plc
p.i=.point~new(x,y)
End
end=i-1
dmax=0
index=0
Do i=2 To end-1
d=distpg(p.i,.line~new(p.1,p.end))
If d>dmax Then Do
index=i
dmax=d
End
End
If dmax>epsilon Then Do
rla=dlp(subword(pl,1,index))
rlb=dlp(subword(pl,index,end))
rl=subword(rla,1,words(rla)-1) rlb
End
Else
rl=word(pl,1) word(pl,end)
Return rl
 
::CLASS point public
::ATTRIBUTE X
::ATTRIBUTE Y
::METHOD init PUBLIC
Expose X Y
Use Arg X,Y
 
::CLASS line public
::ATTRIBUTE A
::ATTRIBUTE B
::METHOD init PUBLIC
Expose A B
Use Arg A,B
If A~x=B~x & A~y=B~y Then Do
Say 'not a line'
Return .nil
End
 
::METHOD k PUBLIC
Expose A B
ax=A~x; ay=A~y; bx=B~x; by=B~y
If ax=bx Then
res='infinite'
Else
res=(by-ay)/(bx-ax)
Return res
 
::METHOD d PUBLIC
Expose A B
ax=A~x; ay=A~y
If self~k='infinite' Then
res='indeterminate'
Else
res=round(ay-ax*self~k)
Return res
 
::ROUTINE distpg PUBLIC --Compute the distance from a point to a line
/***********************************************************************
* Compute the distance from a point to a line
***********************************************************************/
Use Arg A,g
ax=A~x; ay=A~y
k=g~k
If k='infinite' Then Do
Parse Value g~kxd With 'x='gx
res=gx-ax
End
Else
res=(ay-k*ax-g~d)/rxCalcsqrt(1+k**2)
Return abs(res)
 
::ROUTINE round PUBLIC --Round a number to 3 decimal digits
/***********************************************************************
* Round a nmber to 3 decimal digits
***********************************************************************/
Use Arg z,d
Numeric Digits 30
res=z+0
If d>'' Then
res=format(res,9,6)
Return strip(res)
 
::requires rxMath library
</syntaxhighlight>
 
{{out}}
<pre> error threshold: 1
points specified: (0,0) (1,0.1) (2,-0.1) (3,5) (4,6) (5,7) (6,8.1) (7,9) (8,9) (9,9)
points simplified: (0,0) (2,-0.1) (3,5) (7,9) (9,9)</pre>
 
=={{header|Openscad}}==
Line 838 ⟶ 1,178:
{{works with|Openscad|2019.05}}
 
<langsyntaxhighlight lang="openscad">function slice(a, v) = [ for (i = v) a[i] ];
 
// Find the distance from the point to the line
Line 913 ⟶ 1,253:
$fn=16;
points = [[0,0], [1,0.1], [2,-0.1], [3,5], [4,6], [5,7], [6,8.1], [7,9], [8,9], [9,9]];
demo(points);</langsyntaxhighlight>
 
{{out}}
Line 920 ⟶ 1,260:
=={{header|Perl}}==
{{trans|Raku}}
<langsyntaxhighlight lang="perl">use strict;
use warnings;
use feature 'say';
Line 963 ⟶ 1,303:
 
say '(' . join(' ', @$_) . ') '
for Ramer_Douglas_Peucker( [0,0],[1,0.1],[2,-0.1],[3,5],[4,6],[5,7],[6,8.1],[7,9],[8,9],[9,9] )</langsyntaxhighlight>
{{out}}
<pre>(0 0)
Line 973 ⟶ 1,313:
=={{header|Phix}}==
{{trans|Go}}
<!--<syntaxhighlight lang="phix">(phixonline)-->
<lang Phix>function rdp(sequence l, atom e)
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
if length(l)<2 then crash("not enough points to simplify") end if
<span style="color: #008080;">function</span> <span style="color: #000000;">rdp</span><span style="color: #0000FF;">(</span><span style="color: #004080;">sequence</span> <span style="color: #000000;">l</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">e</span><span style="color: #0000FF;">)</span>
integer idx := 0
<span style="color: #008080;">if</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">)<</span><span style="color: #000000;">2</span> <span style="color: #008080;">then</span> <span style="color: #7060A8;">crash</span><span style="color: #0000FF;">(</span><span style="color: #008000;">"not enough points to simplify"</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
atom dMax := -1,
<span style="color: #004080;">integer</span> <span style="color: #000000;">idx</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">0</span>
{p1x,p1y} := l[1],
<span style="color: #004080;">atom</span> <span style="color: #000000;">dMax</span> <span style="color: #0000FF;">:=</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span>
{p2x,p2y} := l[$],
<span style="color: #0000FF;">{</span><span style="color: #000000;">p1x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">p1y</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">l</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span>
x21 := p2x - p1x,
<span style="color: #0000FF;">{</span><span style="color: #000000;">p2x</span><span style="color: #0000FF;">,</span><span style="color: #000000;">p2y</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">l</span><span style="color: #0000FF;">[$],</span>
y21 := p2y - p1y
<span style="color: #000000;">x21</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">p2x</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">p1x</span><span style="color: #0000FF;">,</span>
for i=1 to length(l) do
<span style="color: #000000;">y21</span> <span style="color: #0000FF;">:=</span> <span style="color: #000000;">p2y</span> <span style="color: #0000FF;">-</span> <span style="color: #000000;">p1y</span>
atom {px,py} = l[i],
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #7060A8;">length</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">)</span> <span style="color: #008080;">do</span>
d = abs(y21*px-x21*py + p2x*p1y-p2y*p1x)
<span style="color: #004080;">atom</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">px</span><span style="color: #0000FF;">,</span><span style="color: #000000;">py</span><span style="color: #0000FF;">}</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">l</span><span style="color: #0000FF;">[</span><span style="color: #000000;">i</span><span style="color: #0000FF;">],</span>
if d>dMax then
<span style="color: #000000;">d</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">abs</span><span style="color: #0000FF;">(</span><span style="color: #000000;">y21</span><span style="color: #0000FF;">*</span><span style="color: #000000;">px</span><span style="color: #0000FF;">-</span><span style="color: #000000;">x21</span><span style="color: #0000FF;">*</span><span style="color: #000000;">py</span> <span style="color: #0000FF;">+</span> <span style="color: #000000;">p2x</span><span style="color: #0000FF;">*</span><span style="color: #000000;">p1y</span><span style="color: #0000FF;">-</span><span style="color: #000000;">p2y</span><span style="color: #0000FF;">*</span><span style="color: #000000;">p1x</span><span style="color: #0000FF;">)</span>
idx = i
<span style="color: #008080;">if</span> <span style="color: #000000;">d</span><span style="color: #0000FF;">></span><span style="color: #000000;">dMax</span> <span style="color: #008080;">then</span>
dMax = d
<span style="color: #000000;">idx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">i</span>
end if
<span style="color: #000000;">dMax</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">d</span>
end for
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
if dMax>e then
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
return rdp(l[1..idx], e) & rdp(l[idx..$], e)[2..$]
<span style="color: #008080;">if</span> <span style="color: #000000;">dMax</span><span style="color: #0000FF;">></span><span style="color: #000000;">e</span> <span style="color: #008080;">then</span>
end if
<span style="color: #008080;">return</span> <span style="color: #000000;">rdp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">..</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">e</span><span style="color: #0000FF;">)</span> <span style="color: #0000FF;">&</span> <span style="color: #000000;">rdp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">l</span><span style="color: #0000FF;">[</span><span style="color: #000000;">idx</span><span style="color: #0000FF;">..$],</span> <span style="color: #000000;">e</span><span style="color: #0000FF;">)[</span><span style="color: #000000;">2</span><span style="color: #0000FF;">..$]</span>
return {l[1], l[$]}
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
end function
<span style="color: #008080;">return</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">l</span><span style="color: #0000FF;">[</span><span style="color: #000000;">1</span><span style="color: #0000FF;">],</span> <span style="color: #000000;">l</span><span style="color: #0000FF;">[$]}</span>
 
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
sequence points = {{0, 0}, {1, 0.1}, {2, -0.1}, {3, 5}, {4, 6},
{5, 7}, {6, 8.1}, {7, 9}, {8, 9}, {9, 9}}
<span style="color: #004080;">sequence</span> <span style="color: #000000;">points</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{{</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.1</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">2</span><span style="color: #0000FF;">,</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">0.1</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">3</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">5</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">4</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">6</span><span style="color: #0000FF;">},</span>
?rdp(points, 1)</lang>
<span style="color: #0000FF;">{</span><span style="color: #000000;">5</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">6</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">8.1</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">8</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9</span><span style="color: #0000FF;">},</span> <span style="color: #0000FF;">{</span><span style="color: #000000;">9</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">9</span><span style="color: #0000FF;">}}</span>
<span style="color: #0000FF;">?</span><span style="color: #000000;">rdp</span><span style="color: #0000FF;">(</span><span style="color: #000000;">points</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">1</span><span style="color: #0000FF;">)</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
Line 1,005 ⟶ 1,348:
=={{header|PHP}}==
{{trans|C++}}
<langsyntaxhighlight lang="php">function perpendicular_distance(array $pt, array $line) {
// Calculate the normalized delta x and y of the line.
$dx = $line[1][0] - $line[0][0];
Line 1,077 ⟶ 1,420:
foreach ($result as $point) {
print $point[0] . ',' . $point[1] . "\n";
}</langsyntaxhighlight>
 
{{out}}
Line 1,092 ⟶ 1,435:
{{libheader|Shapely}}
An approach using the shapely library:
<langsyntaxhighlight lang="python">from __future__ import print_function
from shapely.geometry import LineString
if __name__=="__main__":
line = LineString([(0,0),(1,0.1),(2,-0.1),(3,5),(4,6),(5,7),(6,8.1),(7,9),(8,9),(9,9)])
print (line.simplify(1.0, preserve_topology=False))</langsyntaxhighlight>
{{out}}
<pre>LINESTRING (0 0, 2 -0.1, 3 5, 7 9, 9 9)</pre>
Line 1,103 ⟶ 1,446:
=={{header|Racket}}==
 
<langsyntaxhighlight lang="racket">#lang racket
(require math/flonum)
;; points are lists of x y (maybe extensible to z)
Line 1,147 ⟶ 1,490:
(module+ test
(require rackunit)
(check-= ((⊥-distance '(0 0) '(0 1)) '(1 0)) 1 epsilon.0))</langsyntaxhighlight>
 
{{out}}
Line 1,157 ⟶ 1,500:
{{trans|C++}}
 
<syntaxhighlight lang="raku" perl6line>sub norm (*@list) { @list»².sum.sqrt }
 
sub perpendicular-distance (@start, @end where @end !eqv @start, @point) {
Line 1,181 ⟶ 1,524:
say Ramer-Douglas-Peucker(
[(0,0),(1,0.1),(2,-0.1),(3,5),(4,6),(5,7),(6,8.1),(7,9),(8,9),(9,9)]
);</langsyntaxhighlight>
{{out}}
<pre>((0 0) (2 -0.1) (3 5) (7 9) (9 9))</pre>
 
=={{header|REXX}}==
===Version 1===
The computation for the &nbsp; ''perpendicular distance'' &nbsp; was taken from the &nbsp; '''GO''' &nbsp; example.
The computation for the &nbsp; ''perpendicular distance'' &nbsp; was taken from
<lang rexx>/*REXX program uses the Ramer─Douglas─Peucker (RDP) line simplification algorithm for*/
the &nbsp; '''GO''' &nbsp; example.
<syntaxhighlight lang="rexx">/*REXX program uses the Ramer─Douglas─Peucker (RDP) line simplification algorithm for*/
/*───────────────────────────── reducing the number of points used to define its shape. */
parse arg epsilon pts /*obtain optional arguments from the CL*/
Line 1,193 ⟶ 1,538:
if pts='' then pts= '(0,0) (1,0.1) (2,-0.1) (3,5) (4,6) (5,7) (6,8.1) (7,9) (8,9) (9,9)'
pts= space(pts) /*elide all superfluous blanks. */
say ' error threshold: ' epsilon say ' error threshold: ' epsilon /*echo the error threshold to the term.*/
say ' points specified: ' pts say ' points specified: ' pts /* " " shape points " " " */
$= RDP(pts) /*invoke Ramer─Douglas─Peucker function*/
say 'points simplified: ' rez($) say 'points simplified: ' rez($) /*display points with () ───► terminal.*/
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
bld: parse arg _; #= words(_); dMax=-#; idx=1; do j=1 for #; @.j= word(_, j); end; return
px: parse arg _; return word( translate(_, , ','), 1) /*obtain the X coörd.*/
py: parse arg _; return word( translate(_, , ','), 2) /* " " Y " */
reb: parse arg a,b,,_; do k=a to b; _= _ @.k; end; return strip(_)
rez: parse arg z,_; do k=1 for words(z); _= _ '('word(z, k)") "; end; return strip(_)
/*──────────────────────────────────────────────────────────────────────────────────────*/
RDP: procedure expose epsilon; parse arg PT; call bld space( translate(PTarg(1), , ')(][}{') )
L= px(@.#) - px(@.1)
H= py(@.#) - py(@.1) /* [↓] find point IDX with max distance*/
do i=2 to #-1
d= abs(H*px(@.i) - L*py(@.i) + px(@.#)*py(@.1) - py(@.#)*px(@.1) )
if d>dMax then do; idx= i; dMax= d
end
end /*i*/ /* [↑] D is the perpendicular distance*/
 
if dMax>epsilon then do; r= RDP( reb(1, idx) )
return subword(r, 1, words(r) - 1) RDP( reb(idx, #) )
end
return @.1 @.#</langsyntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
Line 1,223 ⟶ 1,568:
points specified: (0,0) (1,0.1) (2,-0.1) (3,5) (4,6) (5,7) (6,8.1) (7,9) (8,9) (9,9)
points simplified: (0,0) (2,-0.1) (3,5) (7,9) (9,9)
</pre>
===Version 2===
{{trans|ooRexx}}
<syntaxhighlight lang="rexx">
/*REXX program uses the Ramer-Douglas-Peucker (RDP) line simplification algorithm for*/
/*--------------------------- reducing the number of points used to define its shape. */
Parse Arg epsilon pl /*obtain optional arguments from the CL*/
If epsilon='' | epsilon=',' then epsilon= 1 /*Not specified? Then use the default.*/
If pl='' Then pl= '(0,0) (1,0.1) (2,-0.1) (3,5) (4,6) (5,7) (6,8.1) (7,9) (8,9) (9,9)'
Say ' error threshold:' epsilon
Say ' points specified:' pl
Say 'points simplified:' dlp(pl)
Exit
dlp: Procedure Expose epsilon
Parse Arg pl
plc=pl
Do i=1 By 1 While plc<>''
Parse Var plc '(' x ',' y ')' plc
p.i=x y
End
end=i-1
dmax=0
index=0
Do i=2 To end-1
d=distpg(p.i,p.1,p.end)
If d>dmax Then Do
index=i
dmax=d
End
End
If dmax>epsilon Then Do
rla=dlp(subword(pl,1,index))
rlb=dlp(subword(pl,index,end))
rl=subword(rla,1,words(rla)-1) rlb
End
Else
rl=word(pl,1) word(pl,end)
Return rl
 
distpg: Procedure
/**********************************************************************
* compute the distance of point P from the line giveb by A and B
**********************************************************************/
Parse Arg P,A,B
Parse Var P px py
Parse Var A ax ay
Parse Var B bx by
If ax=bx Then
res=px-ax
Else Do
k=(by-ay)/(bx-ax)
d=(ay-ax*k)
res=(py-k*px-d)/sqrt(1+k**2)
End
Return abs(res)
sqrt: Procedure
/* REXX ***************************************************************
* EXEC to calculate the square root of a = 2 with high precision
**********************************************************************/
Parse Arg x,prec
If prec<9 Then prec=9
prec1=2*prec
eps=10**(-prec1)
k = 1
Numeric Digits 3
r0= x
r = 1
Do i=1 By 1 Until r=r0 | (abs(r*r-x)<eps)
r0 = r
r = (r + x/r) / 2
k = min(prec1,2*k)
Numeric Digits (k + 5)
End
Numeric Digits prec
r=r+0
Return r
</syntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
error threshold: 1
points specified: (0,0) (1,0.1) (2,-0.1) (3,5) (4,6) (5,7) (6,8.1) (7,9) (8,9) (9,9)
points simplified: (0,0) (2,-0.1) (3,5) (7,9) (9,9)
</pre>
 
=={{header|RPL}}==
{{works with|Halcyon Calc|4.2.9}}
3 PICK - CONJ SWAP ROT
- (0,1) * DUP ABS /
* RE ABS
≫ ≫ '<span style="color:blue">DM→AB</span>' STO
≪ OVER SIZE 0 → points epsilon nb dmax
≪ '''IF''' nb 2 ≤ '''THEN''' points '''ELSE'''
0 points 1 GET points nb GET
2 nb 1 - '''FOR''' j
DUP2 points j GET <span style="color:blue">DM→AB</span>
'''IF''' DUP dmax < '''THEN''' DROP '''ELSE'''
'dmax' STO ROT DROP j ROT ROT '''END'''
'''NEXT'''
'''IF''' dmax epsilon < '''THEN'''
{ } + + SWAP DROP
'''ELSE'''
DROP2 points 1 3 PICK SUB epsilon <span style="color:blue">RDP</span>
points ROT nb SUB epsilon <span style="color:blue">RDP</span> 2 nb SUB +
'''END END'''
≫ ≫ '<span style="color:blue">RDP</span>' STO
 
{ (0,0) (1,0.1) (2,-0.1) (3,5) (4,6) (5,7) (6,8.1) (7,9) (8,9) (9,9) } 1 <span style="color:blue">RDP</span>
{{out}}
<pre>
1: { (0, 0) (2, -0.1) (3, 5) (7, 9) (9, 9) }
</pre>
 
=={{header|Rust}}==
===An implementation of the algorithm===
<langsyntaxhighlight lang="rust">#[derive(Copy, Clone)]
struct Point {
x: f64,
Line 1,295 ⟶ 1,752:
println!("{}", p);
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,309 ⟶ 1,766:
The geo crate contains an implementation of the Ramer-Douglas-Peucker line
simplification algorithm.
<langsyntaxhighlight lang="rust">// [dependencies]
// geo = "0.14"
 
Line 1,331 ⟶ 1,788:
println!("({}, {})", p.x, p.y);
}
}</langsyntaxhighlight>
 
{{out}}
Line 1,341 ⟶ 1,798:
(9, 9)
</pre>
 
 
=={{header|Scala}}==
{{trans|Kotlin}}
 
<syntaxhighlight lang="scala">// version 1.1.0
 
object SimplifyPolyline extends App {
type Point = (Double, Double)
 
def perpendicularDistance(
pt: Point,
lineStart: Point,
lineEnd: Point
): Double = {
var dx = lineEnd._1 - lineStart._1
var dy = lineEnd._2 - lineStart._2
 
// Normalize
val mag = math.hypot(dx, dy)
if (mag > 0.0) { dx /= mag; dy /= mag }
val pvx = pt._1 - lineStart._1
val pvy = pt._2 - lineStart._2
 
// Get dot product (project pv onto normalized direction)
val pvdot = dx * pvx + dy * pvy
 
// Scale line direction vector and subtract it from pv
val ax = pvx - pvdot * dx
val ay = pvy - pvdot * dy
 
math.hypot(ax, ay)
}
 
def RamerDouglasPeucker(
pointList: List[Point],
epsilon: Double
): List[Point] = {
if (pointList.length < 2)
throw new IllegalArgumentException("Not enough points to simplify")
 
// Check if there are points to process
if (pointList.length > 2) {
// Find the point with the maximum distance from the line between the first and last
val (dmax, index) = pointList.zipWithIndex
.slice(1, pointList.length - 1)
.map { case (point, i) =>
(perpendicularDistance(point, pointList.head, pointList.last), i)
}
.maxBy(_._1)
 
// If max distance is greater than epsilon, recursively simplify
if (dmax > epsilon) {
val firstLine = pointList.take(index + 1)
val lastLine = pointList.drop(index)
val recResults1 = RamerDouglasPeucker(firstLine, epsilon)
val recResults2 = RamerDouglasPeucker(lastLine, epsilon)
 
// Combine the results
(recResults1.init ++ recResults2).distinct
} else {
// If no point is further than epsilon, return the endpoints
List(pointList.head, pointList.last)
}
} else {
// If there are only two points, just return them
pointList
}
}
 
val pointList = List(
(0.0, 0.0),
(1.0, 0.1),
(2.0, -0.1),
(3.0, 5.0),
(4.0, 6.0),
(5.0, 7.0),
(6.0, 8.1),
(7.0, 9.0),
(8.0, 9.0),
(9.0, 9.0)
)
 
val simplifiedPointList = RamerDouglasPeucker(pointList, 1.0)
println("Points remaining after simplification:")
simplifiedPointList.foreach(println)
}
</syntaxhighlight>
{{out}}
<pre>
Points remaining after simplification:
(0.0,0.0)
(2.0,-0.1)
(3.0,5.0)
(7.0,9.0)
(9.0,9.0)
 
</pre>
 
 
 
 
=={{header|Sidef}}==
{{trans|Raku}}
<langsyntaxhighlight lang="ruby">func perpendicular_distance(Arr start, Arr end, Arr point) {
((point == start) || (point == end)) && return 0
var (Δx, Δy ) = ( end  »-«  start)...
var (Δpx, Δpy) = (point  »-«  start)...
var h = hypot(Δx, Δy)
[\Δx, \Δy].map { *_ /= h }
(([Δpx, Δpy]  »-«  ([Δx, Δy]  »*» (Δx*Δpx + Δy*Δpy)))  »**» 2).sum.sqrt.round(-20)
}
 
Line 1,362 ⟶ 1,920:
if (d.max > ε) {
var i = d.index(d.max)
return [Ramer_Douglas_Peucker(points.ftfirst(0, i), ε).ftfirst(0, -21)...,
Ramer_Douglas_Peucker(points.ftslice(i), ε)...]
}
 
Line 1,371 ⟶ 1,929:
say Ramer_Douglas_Peucker(
[[0,0],[1,0.1],[2,-0.1],[3,5],[4,6],[5,7],[6,8.1],[7,9],[8,9],[9,9]]
)</langsyntaxhighlight>
{{out}}
<pre>
[[0, 0], [2, -1/10], [3, 5], [7, 9], [9, 9]]
</pre>
 
=={{header|Swift}}==
<syntaxhighlight lang="swift">struct Point: CustomStringConvertible {
let x: Double, y: Double
 
var description: String {
return "(\(x), \(y))"
}
}
 
// Returns the distance from point p to the line between p1 and p2
func perpendicularDistance(p: Point, p1: Point, p2: Point) -> Double {
let dx = p2.x - p1.x
let dy = p2.y - p1.y
let d = (p.x * dy - p.y * dx + p2.x * p1.y - p2.y * p1.x)
return abs(d)/(dx * dx + dy * dy).squareRoot()
}
 
func ramerDouglasPeucker(points: [Point], epsilon: Double) -> [Point] {
var result : [Point] = []
func rdp(begin: Int, end: Int) {
guard end > begin else {
return
}
var maxDist = 0.0
var index = 0
for i in begin+1..<end {
let dist = perpendicularDistance(p: points[i], p1: points[begin],
p2: points[end])
if dist > maxDist {
maxDist = dist
index = i
}
}
if maxDist > epsilon {
rdp(begin: begin, end: index)
rdp(begin: index, end: end)
} else {
result.append(points[end])
}
}
if points.count > 0 && epsilon >= 0.0 {
result.append(points[0])
rdp(begin: 0, end: points.count - 1)
}
return result
}
 
let points = [
Point(x: 0.0, y: 0.0),
Point(x: 1.0, y: 0.1),
Point(x: 2.0, y: -0.1),
Point(x: 3.0, y: 5.0),
Point(x: 4.0, y: 6.0),
Point(x: 5.0, y: 7.0),
Point(x: 6.0, y: 8.1),
Point(x: 7.0, y: 9.0),
Point(x: 8.0, y: 9.0),
Point(x: 9.0, y: 9.0)
]
print("\(ramerDouglasPeucker(points: points, epsilon: 1.0))")</syntaxhighlight>
 
{{out}}
<pre>
[(0.0, 0.0), (2.0, -0.1), (3.0, 5.0), (7.0, 9.0), (9.0, 9.0)]
</pre>
 
=={{header|Wren}}==
{{trans|Go}}
{{libheader|Wren-dynamic}}
<syntaxhighlight lang="wren">import "./dynamic" for Tuple
 
var Point = Tuple.create("Point", ["x", "y"])
 
var rdp // recursive
rdp = Fn.new { |l, eps|
var x = 0
var dMax = -1
var p1 = l[0]
var p2 = l[-1]
var x21 = p2.x - p1.x
var y21 = p2.y - p1.y
var i = 0
for (p in l[1..-1]) {
var d = (y21*p.x - x21*p.y + p2.x*p1.y - p2.y*p1.x).abs
if (d > dMax) {
x = i + 1
dMax = d
}
i = i + 1
}
if (dMax > eps) {
return rdp.call(l[0..x], eps) + rdp.call(l[x..-1], eps)[1..-1]
}
return [l[0], l[-1]]
}
 
var points = [
Point.new(0, 0), Point.new(1, 0.1), Point.new(2, -0.1), Point.new(3, 5), Point.new(4, 6),
Point.new(5, 7), Point.new(6, 8.1), Point.new(7, 9), Point.new(8, 9), Point.new(9, 9)
]
System.print(rdp.call(points, 1))</syntaxhighlight>
 
{{out}}
<pre>
[(0, 0), (2, -0.1), (3, 5), (7, 9), (9, 9)]
</pre>
 
=={{header|XPL0}}==
{{trans|C}}
<syntaxhighlight lang "XPL0">include xpllib; \for PerpDist and Print
 
func RDP(Points, Size, Epsilon, RemPoints);
\Reduce array Points using Ramer-Douglas-Peucker algorithm
\Return array of remaining points in RemPoints and its size
real Points; int Size; real Epsilon, RemPoints;
real Dist, DistMax;
int Index, I, Size1, Size2;
[\Find Index of point farthest from line between first and last points
DistMax:= 0.; Index:= 0;
for I:= 1 to Size-2 do
[Dist:= PerpDist(Points(I), Points(0), Points(Size-1));
if Dist > DistMax then
[DistMax:= Dist;
Index:= I;
];
];
if DistMax <= Epsilon then \replace in-between points with first and last points
[RemPoints(0):= Points(0);
RemPoints(1):= Points(Size-1);
return 2;
]
else \recursively check sub-line-segments
[Size1:= RDP(Points, Index+1, Epsilon, RemPoints);
RemPoints:= @RemPoints(Size1-1); \add retained points to array
Size2:= RDP(@Points(Index), Size-Index, Epsilon, RemPoints);
return Size1 + Size2 - 1; \for point at Index
];
];
 
real Points, RemPoints;
int Size, I;
[Points:= [ [0.0, 0.0], [1.0, 0.1], [2.0, -0.1], [3.0, 5.0], [4.0, 6.0],
[5.0, 7.0], [6.0, 8.1], [7.0, 9.0], [8.0, 9.0], [9.0, 9.0] ];
Size:= 10;
RemPoints:= RlRes(Size);
Size:= RDP(Points, Size, 1.0, RemPoints);
for I:= 0 to Size-1 do
[if I > 0 then Print(", ");
Print("[%1.1g, %1.1g]", RemPoints(I,0), RemPoints(I,1));
];
CrLf(0);
]</syntaxhighlight>
{{out}}
<pre>
[0, 0], [2, -0.1], [3, 5], [7, 9], [9, 9]
</pre>
 
=={{header|Yabasic}}==
<langsyntaxhighlight Yabasiclang="yabasic">sub perpendicularDistance(tabla(), i, ini, fin)
local dx, cy, mag, pvx, pvy, pvdot, dsx, dsy, ax, ay
 
Line 1,437 ⟶ 2,152:
for i = 1 to 10
if matriz(i, 3) print matriz(i, 1), matriz(i, 2)
next</langsyntaxhighlight>
 
=={{header|zkl}}==
{{trans|Raku}}
<langsyntaxhighlight lang="zkl">fcn perpendicularDistance(start,end, point){ // all are tuples: (x,y) -->|d|
dx,dy := end .zipWith('-,start); // deltas
dpx,dpy := point.zipWith('-,start);
Line 1,459 ⟶ 2,174:
RamerDouglasPeucker(points[index,*],epsilon)))
} else return(points[0],points[-1]);
}</langsyntaxhighlight>
<langsyntaxhighlight lang="zkl">RamerDouglasPeucker(
T( T(0.0, 0.0), T(1.0, 0.1), T(2.0, -0.1), T(3.0, 5.0), T(4.0, 6.0),
T(5.0, 7.0), T(6.0, 8.1), T(7.0, 9.0), T(8.0, 9.0), T(9.0, 9.0) ))
.println();</langsyntaxhighlight>
{{out}}
<pre>
9,476

edits