Thursday, April 26, 2012

Calculating distance between lat/lng points in MvvmCross


Currently mvvmcross has deliberately not included lat/lng calculations.
The motivation for this was:
  • to keep the code size down - not every app needs those calculations
  • further I have in my mind that some calculations are better done by native libraries rather than generic C# - e.g. some polygon calculations would benefit from native hardware acceleration. This type of thought is there not only for geo-calcuations, but also for other areas - e.g. whereever things like image manipulation are required, then using native acceleration makes sense.
It may be that mvvmcross provides an "official" location helper IoC plugin (or set of extension methods) at some point in the future... e.g. it maybe that we build an IoC plugin around http://xamarin.com/mobileapi... and I'm also very happy for others to build and publish them too.
So....
At a very simple level, working out the distance between two lat/lng points is easy to do in C# - there are heaps of fairly simple code example available like the excellent javascript ones at http://www.movable-type.co.uk/scripts/latlong.html - and there are heaps of libraries on github and codeplex likehttp://sharpmap.codeplex.com/
In RunSat (including on iPhone) I use:
using System;

namespace Cirrious.NewRunSat.Core.Models.Utils
{
    public class DistanceCalcs
    {
        /// 
        /// Calculates the distance between two points of latitude and longitude.
        /// Great Link - http://www.movable-type.co.uk/scripts/latlong.html
        /// 
        /// 
First coordinate.
        /// 
First coordinate.
        /// 
Second coordinate.
        /// 
Second coordinate.
        /// the distance in metres
        public static Double DistanceInMetres(double lat1, double lon1, double lat2, double lon2)
        {

            if (lat1 == lat2 && lon1 == lon2)
                return 0.0;

            var theta = lon1 - lon2;

            var distance = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) +
                           Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) *
                           Math.Cos(deg2rad(theta));

            distance = Math.Acos(distance);
            if (double.IsNaN(distance))
                return 0.0;

            distance = rad2deg(distance);
            distance = distance * 60.0 * 1.1515 * 1609.344;

            return (distance);
        }

        private static double deg2rad(double deg) {
          return (deg * Math.PI / 180.0);
        }

        private static double rad2deg(double rad) {
          return (rad / Math.PI * 180.0);
        }
    }
}
Note that the license on this snippet is CC attribution - because its derived from movable type -http://www.movable-type.co.uk/scripts/latlong.html:
I offer these formulæ & scripts for free use and adaptation as my contribution to the open-source info-sphere from which I have received so much. You are welcome to re-use these scripts [under a simple attribution license, without any warranty express or implied] provided solely that you retain my copyright notice and a reference to this page.

No comments:

Post a Comment