From 151ae31317e64e5be9ea8278c3678a3972310c45 Mon Sep 17 00:00:00 2001 From: Paul Mach Date: Thu, 11 Nov 2021 20:02:47 -0800 Subject: [PATCH] style: cleanup tests --- geo/distance.go | 31 +++---- geo/distance_test.go | 205 +++++++++++++++++++++++-------------------- 2 files changed, 128 insertions(+), 108 deletions(-) diff --git a/geo/distance.go b/geo/distance.go index a04aa9b..f7aed9e 100644 --- a/geo/distance.go +++ b/geo/distance.go @@ -79,14 +79,13 @@ func PointAtBearingAndDistance(p orb.Point, bearing, distance float64) orb.Point distanceRatio := distance / orb.EarthRadius bLat := math.Asin(math.Sin(aLat)*math.Cos(distanceRatio) + math.Cos(aLat)*math.Sin(distanceRatio)*math.Cos(bearingRadians)) - bLon := aLon + math.Atan2(math.Sin(bearingRadians)*math.Sin(distanceRatio)*math.Cos(aLat), math.Cos(distanceRatio)-math.Sin(aLat)*math.Sin(bLat)) + bLon := aLon + + math.Atan2( + math.Sin(bearingRadians)*math.Sin(distanceRatio)*math.Cos(aLat), + math.Cos(distanceRatio)-math.Sin(aLat)*math.Sin(bLat), + ) - r := orb.Point{ - rad2deg(bLon), - rad2deg(bLat), - } - - return r + return orb.Point{rad2deg(bLon), rad2deg(bLat)} } func PointAtDistanceAlongLine(ls orb.LineString, distance float64) (orb.Point, float64) { @@ -98,14 +97,17 @@ func PointAtDistanceAlongLine(ls orb.LineString, distance float64) (orb.Point, f return ls[0], 0.0 } - travelled := 0.0 - i := 1 - var from, to orb.Point - for ; i < len(ls); i++ { - from = ls[i-1] - to = ls[i] + var ( + travelled = 0.0 + from, to orb.Point + ) + + for i := 1; i < len(ls); i++ { + from, to = ls[i-1], ls[i] + actualSegmentDistance := DistanceHaversine(from, to) expectedSegmentDistance := distance - travelled + if expectedSegmentDistance < actualSegmentDistance { bearing := Bearing(from, to) return PointAtBearingAndDistance(from, bearing, expectedSegmentDistance), bearing @@ -113,6 +115,5 @@ func PointAtDistanceAlongLine(ls orb.LineString, distance float64) (orb.Point, f travelled += actualSegmentDistance } - bearing := Bearing(from, to) - return to, bearing + return to, Bearing(from, to) } diff --git a/geo/distance_test.go b/geo/distance_test.go index f13933e..051ad66 100644 --- a/geo/distance_test.go +++ b/geo/distance_test.go @@ -91,27 +91,119 @@ func TestMidpoint(t *testing.T) { } func TestPointAtBearingAndDistance(t *testing.T) { - expected := orb.Point{-0.841153, 52.68179432} - bearing := 127.373 - distance := 85194.89 - actual := PointAtBearingAndDistance(orb.Point{-1.8444, 53.1506}, bearing, distance) - - if d := DistanceHaversine(actual, expected); d > 1 { - t.Errorf("expected %v, got %v (%vm away)", expected, actual, d) - } + cases := []struct { + name string + point orb.Point + bearing float64 + distance float64 + expected orb.Point + }{ + { + name: "simple", + point: orb.Point{-1.8444, 53.1506}, + bearing: 127.373, + distance: 85194.89, + expected: orb.Point{-0.841153, 52.68179432}, + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + actual := PointAtBearingAndDistance(tc.point, tc.bearing, tc.distance) + + if d := DistanceHaversine(actual, tc.expected); d > 1 { + t.Errorf("expected %v, got %v (%vm away)", tc.expected, actual, d) + } + }) + } + + t.Run("midpoint", func(t *testing.T) { + a := orb.Point{-1.8444, 53.1506} + b := orb.Point{0.1406, 52.2047} + bearing := Bearing(a, b) + distance := DistanceHaversine(a, b) + + p1 := PointAtBearingAndDistance(a, bearing, distance/2) + p2 := Midpoint(a, b) + + if d := DistanceHaversine(p1, p2); d > epsilon { + t.Errorf("expected %v to be within %vm of %v", p1, epsilon, p2) + } + }) } -func TestMidpointAgainstPointAtBearingAndDistance(t *testing.T) { - a := orb.Point{-1.8444, 53.1506} - b := orb.Point{0.1406, 52.2047} - bearing := Bearing(a, b) - distance := DistanceHaversine(a, b) - acceptableTolerance := 1e-06 // unit is meters - - p1 := PointAtBearingAndDistance(a, bearing, distance/2) - p2 := Midpoint(a, b) - - if d := DistanceHaversine(p1, p2); d > acceptableTolerance { - t.Errorf("expected %v to be within %vm of %v", p1, acceptableTolerance, p2) + +func TestPointAtDistanceAlongLineWithSinglePoint(t *testing.T) { + cases := []struct { + name string + line orb.LineString + distance float64 + expectedPoint orb.Point + expectedBearing float64 + }{ + { + name: "with single point", + line: orb.LineString{ + orb.Point{-1.8444, 53.1506}, + }, + distance: 9000, + expectedPoint: orb.Point{-1.8444, 53.1506}, + expectedBearing: 0, + }, + { + name: "with minimal points", + line: orb.LineString{ + orb.Point{-1.8444, 53.1506}, + orb.Point{0.1406, 52.2047}, + }, + distance: 85194.89, + expectedPoint: orb.Point{-0.841153, 52.68179432}, + expectedBearing: Bearing( + orb.Point{-1.8444, 53.1506}, + orb.Point{0.1406, 52.2047}, + ), + }, + { + name: "with single point", + line: orb.LineString{ + orb.Point{-1.8444, 53.1506}, + orb.Point{-0.8411, 52.6817}, + orb.Point{0.1406, 52.2047}, + }, + distance: 90000, + expectedPoint: orb.Point{-0.78526, 52.65506}, + expectedBearing: Bearing( + orb.Point{-0.8411, 52.6817}, + orb.Point{0.1406, 52.2047}, + ), + }, + { + name: "past end of line", + line: orb.LineString{ + orb.Point{-1.8444, 53.1506}, + orb.Point{-0.8411, 52.6817}, + orb.Point{0.1406, 52.2047}, + }, + distance: 200000, + expectedPoint: orb.Point{0.1406, 52.2047}, + expectedBearing: Bearing( + orb.Point{-0.8411, 52.6817}, + orb.Point{0.1406, 52.2047}, + ), + }, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + actualPoint, actualBearing := PointAtDistanceAlongLine(tc.line, tc.distance) + + if d := DistanceHaversine(actualPoint, tc.expectedPoint); d > 1 { + t.Errorf("point %v != %v", actualPoint, tc.expectedPoint) + } + + if d := math.Abs(actualBearing - tc.expectedBearing); d > 1 { + t.Errorf("bearing %v != %v", tc.expectedBearing, actualBearing) + } + }) } } @@ -125,76 +217,3 @@ func TestPointAtDistanceAlongLineWithEmptyLineString(t *testing.T) { line := orb.LineString{} PointAtDistanceAlongLine(line, 90000) } - -func TestPointAtDistanceAlongLineWithSinglePoint(t *testing.T) { - expectedPoint := orb.Point{-1.8444, 53.1506} - line := orb.LineString{ - expectedPoint, - } - actualPoint, actualBearing := PointAtDistanceAlongLine(line, 90000) - - if actualPoint != expectedPoint { - t.Errorf("expected %v but got %v", expectedPoint, actualPoint) - } - if actualBearing != 0.0 { - t.Errorf("expected %v but got %v", actualBearing, 0.0) - } -} - -func TestPointAtDistanceAlongLineWithMinimalPoints(t *testing.T) { - expected := orb.Point{-0.841153, 52.68179432} - acceptableDistanceTolerance := 1.0 // unit is meters - line := orb.LineString{ - orb.Point{-1.8444, 53.1506}, - orb.Point{0.1406, 52.2047}, - } - acceptableBearingTolerance := 0.01 // unit is degrees - expectedBearing := Bearing(line[0], line[1]) - actual, actualBearing := PointAtDistanceAlongLine(line, 85194.89) - - if d := DistanceHaversine(expected, actual); d > acceptableDistanceTolerance { - t.Errorf("expected %v to be within %vm of %v (%vm away)", actual, acceptableDistanceTolerance, expected, d) - } - if b := math.Abs(actualBearing - expectedBearing); b > acceptableBearingTolerance { - t.Errorf("expected bearing %v to be within %v degrees of %v", actualBearing, acceptableBearingTolerance, expectedBearing) - } -} - -func TestPointAtDistanceAlongLineWithMultiplePoints(t *testing.T) { - expected := orb.Point{-0.78526, 52.65506} - acceptableTolerance := 1.0 // unit is meters - line := orb.LineString{ - orb.Point{-1.8444, 53.1506}, - orb.Point{-0.8411, 52.6817}, - orb.Point{0.1406, 52.2047}, - } - acceptableBearingTolerance := 0.01 // unit is degrees - expectedBearing := Bearing(line[1], line[2]) - actualPoint, actualBearing := PointAtDistanceAlongLine(line, 90000) - - if d := DistanceHaversine(expected, actualPoint); d > acceptableTolerance { - t.Errorf("expected %v to be within %vm of %v (%vm away)", expected, acceptableTolerance, actualPoint, d) - } - if b := math.Abs(actualBearing - expectedBearing); b > acceptableBearingTolerance { - t.Errorf("expected bearing %v to be within %v degrees of %v", actualBearing, acceptableBearingTolerance, expectedBearing) - } -} - -func TestPointAtDistanceAlongLinePastEndOfLine(t *testing.T) { - expected := orb.Point{0.1406, 52.2047} - line := orb.LineString{ - orb.Point{-1.8444, 53.1506}, - orb.Point{-0.8411, 52.6817}, - expected, - } - acceptableBearingTolerance := 0.01 // unit is degrees - expectedBearing := Bearing(line[1], line[2]) - actualPoint, actualBearing := PointAtDistanceAlongLine(line, 200000) - - if actualPoint != expected { - t.Errorf("expected %v but got %v", expected, actualPoint) - } - if b := math.Abs(actualBearing - expectedBearing); b > acceptableBearingTolerance { - t.Errorf("expected bearing %v to be within %v degrees of %v", actualBearing, acceptableBearingTolerance, expectedBearing) - } -}