Skip to content

Commit

Permalink
Merge pull request #1 from muktihari/fix/rdp-calculation
Browse files Browse the repository at this point in the history
fix: rdp calculation
  • Loading branch information
muktihari authored Sep 5, 2024
2 parents 36888ff + 75fd031 commit 964c2c3
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 7 deletions.
26 changes: 19 additions & 7 deletions rdp/rdp.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type Point struct {
// Note: The resulting slice is a reslice of given points (it shares the same underlying array) for efficiency.
// It works similar to append, so the input points should not be used after this call, use only the returned value.
func Simplify(points []Point, epsilon float64) []Point {
if len(points) < 2 {
if len(points) <= 2 {
return points
}

Expand All @@ -38,19 +38,31 @@ func Simplify(points []Point, epsilon float64) []Point {
return append(points[:0], first, last)
}

firstHalf, lastHalf := points[:index], points[index:]
// Move index to avoids infinite recursive as slice input
// for next operation is never changed if we keep it as is.
if index == 0 || index == len(points) {
index++
}

left, right := points[:index], points[index:]

return append(Simplify(firstHalf, epsilon), Simplify(lastHalf, epsilon)...)
return append(Simplify(left, epsilon), Simplify(right, epsilon)...)
}

// perpendicularDistance calculates the perpendicular distance from a point to a line segment
func perpendicularDistance(p, start, end Point) float64 {
if start.X == end.X && start.Y == end.Y {
return euclidean(start, end)
// Find distance between p and (start or end)
return euclidean(p, start)
}
numerator := math.Abs((end.Y-start.Y)*p.X - (end.X-start.X)*p.Y + end.X*start.Y - end.Y*start.X)
denominator := euclidean(start, end)
return numerator / denominator

// Standard Form: Ax + Bx + C = 0
A := end.Y - start.Y
B := start.X - end.X
C := (end.X * start.Y) - (start.X * end.Y)

// d = | Ax + By + C = 0 | / ✓(A²+B²)
return math.Abs(A*p.X+B*p.Y+C) / math.Sqrt(A*A+B*B)
}

// euclidean calculates the distance between two points.
Expand Down
40 changes: 40 additions & 0 deletions rdp/rdp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"flag"
"fmt"
"io"
"math"
"math/rand"
"os"
"strconv"
Expand Down Expand Up @@ -85,6 +86,45 @@ func TestSimplify(t *testing.T) {
}
}

func TestPerpendicularDistance(t *testing.T) {
tt := []struct {
name string
p Point
start Point
end Point
d float64
prec float64
}{
{
name: "valid result",
p: Point{X: 5, Y: 6},
start: Point{X: 0, Y: -1.3333333333333333},
end: Point{X: 2, Y: 0},
d: 3.328,
prec: 1000,
},
{
name: "zero result",
p: Point{X: 5, Y: 6},
start: Point{X: 2, Y: 0},
end: Point{X: 2, Y: 0},
d: 6.708, // euclidean((5,6), (2,0))
prec: 1000,
},
}

for i, tc := range tt {
t.Run(fmt.Sprintf("[%d] %s", i, tc.name), func(t *testing.T) {
d := perpendicularDistance(tc.p, tc.start, tc.end)
d = math.Round(d*tc.prec) / tc.prec
tc.d = math.Round(tc.d*tc.prec) / tc.prec
if d != tc.d {
t.Fatalf("expected: %g, got: %g", tc.d, d)
}
})
}
}

var update = flag.Bool("update", false, "update the test file")

func BenchmarkSimplify(b *testing.B) {
Expand Down

0 comments on commit 964c2c3

Please sign in to comment.