namespace Distance [] module Units = open System [] type km [] type rad [] type deg let degToRad (degrees : float) = degrees * Math.PI / 180. [] module Constants = let earthRadius = 6371. let marsRadius = 3397. module GreatCircle = open System /// Calculates the great-circle distance between two Latitude/Longitude positions on a sphere of given radius. let DistanceBetween (radius:float) lat1 long1 lat2 long2 = let lat1r, lat2r, long1r, long2r = lat1 |> degToRad, lat2 |> degToRad, long1 |> degToRad, long2 |> degToRad let deltaLat = lat2r - lat1r let deltaLong = long2r - long1r let a = Math.Sin(deltaLat/2.) ** 2. + (Math.Sin(deltaLong/2.) ** 2. * Math.Cos((double)lat1r) * Math.Cos((double)lat2r)) let c = 2. * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1.-a)) radius * c /// Calculate DistanceBetween for Earth. let DistanceBetweenEarth = DistanceBetween earthRadius /// Calculate DistanceBetween for Mars. let DistanceBetweenMars = DistanceBetween marsRadius module GreatCircleTests = open NUnit.Framework open FsUnit [] type ``Given the DistanceBetween function for Earth``() = // Error margin for non-sphericality of Earth: let ErrorMargin = 0.003; // 0.3% // Travel no distance: [] // Travel along the equator eastwards for 90 degrees: [] // Travel along the equator westwards for 90 degrees: [] // Travel along the equator eastwards for 180 degrees: [] // Travel along the equator westwards for 180 degrees: [] // Travel along the meridian northwards 90 degrees: [] // Travel along the meridian soutwards 90 degrees: [] // Travel from Farnham to Reigate: [] // Travel from London to Sidney Australia: [] member t.``the function returns the right result``(lat1, long1, lat2, long2, expected:float) = let actual = GreatCircle.DistanceBetweenEarth lat1 long1 lat2 long2 let error = expected * ErrorMargin actual |> should (equalWithin error) expected [] type ``Given the DistanceBetween function for Mars``() = // Error margin for non-sphericality of Mars: let ErrorMargin = 0.003; // 0.3% // Travel from Olympus Mons to Pavonis Mons: [] member t.``the function returns the right result``(lat1, long1, lat2, long2, expected:float) = let actual = GreatCircle.DistanceBetweenMars lat1 long1 lat2 long2 let error = expected * ErrorMargin actual |> should (equalWithin error) expected