4 people like it.

calculating the distance on earth (with units of measure)

calculating the distance between two locations on earth using haversine formula see http://en.wikipedia.org/wiki/Haversine_formula and implementing it using the posibilities of F#'s unit of measure system to avoid unit-conversion-errors concerning radians convertet the code found here: http://www.movable-type.co.uk/scripts/latlong.html for an concrete implementation

measures and type declerations

1: 
2: 
3: 
4: 
[<Measure>] type rad
[<Measure>] type deg
[<Measure>] type km
type Location = { Latitude : float<deg>; Longitude : float<deg> }

calculation with haversine-formula

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
let GreatCircleDistance<[<Measure>] 'u> (R : float<'u>) (p1 : Location) (p2 : Location) =
    let degToRad (x : float<deg>) = System.Math.PI * x / 180.0<deg/rad>

    let sq x = x * x
    // take the sin of the half and square the result
    let sinSqHf (a : float<rad>) = (System.Math.Sin >> sq) (a / 2.0<rad>)
    let cos (a : float<deg>) = System.Math.Cos (degToRad a / 1.0<rad>)

    let dLat = (p2.Latitude - p1.Latitude) |> degToRad
    let dLon = (p2.Longitude - p1.Longitude) |> degToRad

    let a = sinSqHf dLat + cos p1.Latitude * cos p2.Latitude * sinSqHf dLon
    let c = 2.0 * System.Math.Atan2(System.Math.Sqrt(a), System.Math.Sqrt(1.0-a))

    R * c

using the mean-earth-radius

1: 
let GreatCircleDistanceOnEarth = GreatCircleDistance 6371.0<km>

example

1: 
2: 
3: 
4: 
5: 
let p1 = { Latitude = 53.147222222222222222222222222222<deg>; Longitude = 0.96666666666666666666666666666667<deg> }

let p2 = { Latitude = 52.204444444444444444444444444444<deg>; Longitude = 0.14055555555555555555555555555556<deg> }

GreatCircleDistanceOnEarth p1 p2
Multiple items
type MeasureAttribute =
  inherit Attribute
  new : unit -> MeasureAttribute

Full name: Microsoft.FSharp.Core.MeasureAttribute

--------------------
new : unit -> MeasureAttribute
[<Measure>]
type rad

Full name: Script.rad
[<Measure>]
type deg

Full name: Script.deg
[<Measure>]
type km

Full name: Script.km
type Location =
  {Latitude: float<deg>;
   Longitude: float<deg>;}

Full name: Script.Location
Location.Latitude: float<deg>
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
Location.Longitude: float<deg>
val GreatCircleDistance : R:float<'u> -> p1:Location -> p2:Location -> float<'u>

Full name: Script.GreatCircleDistance
val R : float<'u>
val p1 : Location
val p2 : Location
val degToRad : (float<deg> -> float<rad>)
val x : float<deg>
namespace System
type Math =
  static val PI : float
  static val E : float
  static member Abs : value:sbyte -> sbyte + 6 overloads
  static member Acos : d:float -> float
  static member Asin : d:float -> float
  static member Atan : d:float -> float
  static member Atan2 : y:float * x:float -> float
  static member BigMul : a:int * b:int -> int64
  static member Ceiling : d:decimal -> decimal + 1 overload
  static member Cos : d:float -> float
  ...

Full name: System.Math
field System.Math.PI = 3.14159265359
val sq : (float -> float)
val x : float
val sinSqHf : (float<rad> -> float)
val a : float<rad>
System.Math.Sin(a: float) : float
val cos : (float<deg> -> float)
val a : float<deg>
System.Math.Cos(d: float) : float
val dLat : float<rad>
val dLon : float<rad>
val a : float
val c : float
System.Math.Atan2(y: float, x: float) : float
System.Math.Sqrt(d: float) : float
val GreatCircleDistanceOnEarth : (Location -> Location -> float<km>)

Full name: Script.GreatCircleDistanceOnEarth
val p1 : Location

Full name: Script.p1
val p2 : Location

Full name: Script.p2
Raw view Test code New version

More information

Link:http://fssnip.net/4a
Posted:12 years ago
Author:Carsten König
Tags: geocomputing; haversine formula