Home > C#, MVVM, WinRT > A converter to show the distance to a given position in a Windows Store app

A converter to show the distance to a given position in a Windows Store app

18/04/2013

Many app that provide location aware information show also an indication of how far away is a certain place from us. If we’are using the MVVM pattern to develop our C# Windows Store app, we can easily obtain the same feature using a value converter:

public class PositionToDistanceConverter : IValueConverter
{
    private const double METRE_TO_MILES_FACTOR = 1609.344;

    public object Convert(object value, Type targetType, object parameter, string language)
    {
        if (value == null || !(value is Point))
            return null;

        // Retrieves current position (i.e., reading it from a class that holds the last
        // known position).
        var currentPosition = /* */;
        if (currentPosition == null)
            return null;

        var otherPosition = (Point)value;

        var distance = Math.Round(
            this.CalculateDistance(currentPosition.Latitude, currentPosition.Longitude,
            otherPosition.Y, otherPosition.X), 0);

        var distanceString = string.Empty;
        var unitType = System.Convert.ToString(parameter).ToUpperInvariant();
        switch (unitType)
        {
            case "KM":
                distanceString = Math.Round(distance / 1000, 2) + "km";
                break;

            case "MI":
                distanceString = Math.Round(distance / METRE_TO_MILES_FACTOR, 2) + "mi";
                break;

            case "M":
            default:
                distanceString = distance + "m";
                break;
        }

        return distanceString;
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        string language)
    {
        throw new NotImplementedException();
    }

    private double CalculateDistance(double lat1, double lon1, double lat2, double lon2)
    {
        const double degreesToRadians = (Math.PI / 180.0);
        const double earthRadius = 6371; // kilometers

        // convert latitude and longitude values to radians
        var radLat1 = lat1 * degreesToRadians;
        var radLon1 = lon1 * degreesToRadians;
        var radLat2 = lat2 * degreesToRadians;
        var radLon2 = lon2 * degreesToRadians;

        // calculate radian delta between each position.
        var radDeltaLat = radLat2 - radLat1;
        var radDeltaLong = radLon2 - radLon1;

        // calculate distance
        var expr1 = (Math.Sin(radDeltaLat / 2.0) *
                     Math.Sin(radDeltaLat / 2.0)) +
                    (Math.Cos(radLat1) *
                     Math.Cos(radLat2) *
                     Math.Sin(radDeltaLong / 2.0) *
                     Math.Sin(radDeltaLong / 2.0));

        var expr2 = 2.0 * Math.Atan2(Math.Sqrt(expr1),
                                     Math.Sqrt(1 - expr1));

        var distance = (earthRadius * expr2);
        return distance * 1000;  // return results as meters
    }
}

One important thing: on line 12, we need to retrieve our current position, that can be saved for example in a static class, so it can be accessed without problem.

The Convert method takes a Point object that contains latitude and longitude of the position to use to calculate the distance. We determine the distance value, in metres, in the CalculateDistance method, then we use the converter parameter, if any, to decide how to format the distance string that will be returned. In this version, we can retrieve the distance in kilometres, miles and metres, but it is very easy to add other units.

Using this converter is straightforward:

<TextBlock Text="{Binding OtherPosition,
    Converter={StaticResource PositionToDistanceConverter},
    ConverterParameter='KM'}"></TextBlock>

OtherPosition is a ViewModel property that holds the longitude and the latitudine, respectively, in its X and Y property.

Categories: C#, MVVM, WinRT
%d bloggers like this: