{"id":607,"date":"2008-12-05T12:19:38","date_gmt":"2008-12-05T11:19:38","guid":{"rendered":"http:\/\/www.navision-blog.de\/2008\/12\/05\/distance-on-the-surface-of-the-earth-in-fsharp\/"},"modified":"2023-01-05T14:06:49","modified_gmt":"2023-01-05T14:06:49","slug":"distance-on-the-surface-of-the-earth-in-fsharp","status":"publish","type":"post","link":"http:\/\/www.navision-blog.de\/blog\/2008\/12\/05\/distance-on-the-surface-of-the-earth-in-fsharp\/","title":{"rendered":"The distance of two cities on the surface of the earth in F#"},"content":{"rendered":"<p>If we want to calculate the distance between two objects, we need some sort of distance function. I recently showed how we can compute the &#8220;edit distance&#8221; between two strings (see <a href=\"http:\/\/www.navision-blog.de\/2008\/10\/31\/damerau-levenshtein-distance-in-fsharp-part-i\/\">Damerau-Levenshtein-Distance in F# &#8211; part I<\/a>, <a href=\"http:\/\/www.navision-blog.de\/2008\/11\/01\/damerau-levenshtein-distance-in-fsharp-part-ii\/\">part II<\/a> and <a href=\"http:\/\/www.navision-blog.de\/2008\/11\/01\/damerau-levenshtein-distance-in-fsharp-part-iii\/\">part III<\/a>). This time I will consider the distance between two points in the plane and on the surface of the earth. <\/p>\n<p>First of all we need some sort of location type, which stores information about the coordinates (I used this type <a href=\"http:\/\/www.navision-blog.de\/2008\/12\/02\/calculate-the-intersection-of-two-lines-in-fsharp-2d\/\">before<\/a>). I will use the &#8220;Units of Measure&#8221;-feature in F# to distinct between &lt;degree&gt; vs. &lt;radian&gt; and &lt;m&gt; vs. &lt;km&gt;. If you are not familiar with this concept see <a href=\"http:\/\/blogs.msdn.com\/andrewkennedy\/archive\/2008\/08\/29\/units-of-measure-in-f-part-one-introducing-units.aspx\">Andrew Kennedy&#8217;s excellent blog series about Units of Measures in F#<\/a>.<\/p>\n<pre class=\"code\"><span style=\"color: blue\">open <\/span>Microsoft.FSharp.Math.SI\n  \n[&lt;Measure&gt;]\n<span style=\"color: blue\">type <\/span>degree\n\n[&lt;Measure&gt;]\n<span style=\"color: blue\">type <\/span>radian =\n  <span style=\"color: blue\">static member <\/span>per_degree = Math.PI\/180.0&lt;degree\/radian&gt;\n  \n[&lt;Measure&gt;]\n<span style=\"color: blue\">type <\/span>km =  \n<span style=\"color: blue\"><font color=\"#f26722\">  <\/font>static member <\/span>per_meter = 1000.&lt;m\/km&gt;<\/pre>\n<pre class=\"code\"><span style=\"color: blue\">type <\/span>Location =\n  {Latitude:float&lt;degree&gt;; \n   Longitude:float&lt;degree&gt; }\n    \n  <span style=\"color: blue\">member <\/span>x.YPos = x.Longitude\n  <span style=\"color: blue\">member <\/span>x.XPos = x.Latitude        \n  <span style=\"color: blue\">member <\/span>x.Longitude_radian = x.Longitude * radian.per_degree  \n  <span style=\"color: blue\">member <\/span>x.Latitude_radian = x.Latitude * radian.per_degree   \n  <span style=\"color: blue\">member <\/span>x.Coordinates = (x.Longitude,x.Latitude)  \n  \n  <span style=\"color: blue\">static member <\/span>CreateLocation(latitude, longitude) = \n    {<span style=\"color: blue\">new <\/span>Location <span style=\"color: blue\">with\n<\/span><span style=\"color: blue\">      <\/span>Latitude = latitude <span style=\"color: blue\">and\n      <\/span>Longitude = longitude}<\/pre>\n<p>Now we can easily compute the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Euclidean_distance\">Euclidean distance<\/a> for two points in the plane.<\/p>\n<pre class=\"code\"><span style=\"color: blue\">let <\/span>sq x = x * x\n<span style=\"color: blue\">let <\/span>CalcEuclideanDistance (s:Location) (t:Location) =\n<p><\/p><span style=\"color: blue\">  let <\/span>d1 = (t.Longitude - s.Longitude) \/ 1.&lt;degree&gt; \n<span style=\"color: blue\">  let <\/span>d2 = (t.Latitude - s.Latitude) \/ 1.&lt;degree&gt;\n  ((sq d1 + sq d2) |&gt; Math.Sqrt) * 1.&lt;m&gt;<\/pre>\n<p>If we want to approximate the distance of two cities on the surface of earth, we can use the &#8220;<a href=\"http:\/\/en.wikipedia.org\/wiki\/Great-circle_distance\">Great circle distance<\/a>&#8220;.<\/p>\n<\/p>\n<blockquote>\n<p>&#8220;The great-circle distance is the shortest distance between any two points on the surface of a sphere measured along a path on the surface of the sphere (as opposed to going through the sphere&#8217;s interior)&#8221; &#8211; <a href=\"http:\/\/en.wikipedia.org\/wiki\/Great-circle_distance\">Wikipedia<\/a><\/p>\n<\/blockquote>\n<pre class=\"code\"><span style=\"color: blue\">let <\/span>kmFactor = 6372.795&lt;km&gt;\n<span style=\"color: blue\">let <\/span>sin_rad x = Math.Sin(x \/ 1.&lt;radian&gt;)\n<span style=\"color: blue\">let <\/span>cos_rad x = Math.Cos(x \/ 1.&lt;radian&gt;)\n\n<span style=\"color: green\">\/\/\/ Great Circle Distance \n<\/span><span style=\"color: blue\">let <\/span>CalcGreatCircleDistance (s:Location) (t:Location)=\n  <span style=\"color: blue\">if <\/span>s = t <span style=\"color: blue\">then\n    <\/span>0.&lt;m&gt;\n  <span style=\"color: blue\">else\n    let <\/span>factor = kmFactor * km.per_meter\n    <span style=\"color: blue\">let <\/span>b =\n         sin_rad s.Latitude_radian * sin_rad t.Latitude_radian +\n         cos_rad s.Latitude_radian * cos_rad t.Latitude_radian *\n           cos_rad (t.Longitude_radian - s.Longitude_radian) \n    Math.Acos(b) * factor<\/pre>\n<div style=\"position:absolute; left:-6161px;\"><a href=\"https:\/\/apotheekpillen.nl\">https:\/\/apotheekpillen.nl<\/a><\/div>\n","protected":false},"excerpt":{"rendered":"<p>If we want to calculate the distance between two objects, we need some sort of distance function. I recently showed how we can compute the &#8220;edit distance&#8221; between two strings (see Damerau-Levenshtein-Distance in F# &#8211; part I, part II and part III). This time I will consider the distance between two points in the plane [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[23,448,8],"tags":[480,482,664,481],"_links":{"self":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/607"}],"collection":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/comments?post=607"}],"version-history":[{"count":4,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/607\/revisions"}],"predecessor-version":[{"id":2054,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/607\/revisions\/2054"}],"wp:attachment":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/media?parent=607"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/categories?post=607"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/tags?post=607"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}