ConvertCoordinate to coordinate notation strings

1387
6
05-19-2017 05:32 AM
BjørnarSundsbø1
Occasional Contributor II

I'm used to seeing a position as  59° 25' 09.28" N 9° 28' 56.59" E, but ConvertCoordinate.ToDegreesMinutesSeconds returns 59 25 09.28 N 009 28 56.59  I'm wondering about the lack of symbols inside the string, as well as 0-padding of values. I'm not a GIS-person, so I assume there is a reason behind this, and I suppose both styles are correct, though I personally find it easier to read the former format for display purposes, though perhaps not if doing user input. Is there an easy way I can get the "pretty print" from my first example out of the box?

I also experience that no matter the UTM SRS (Zone 31-35) i pass to ToUtm, the return value is always in UTM 32. 

0 Kudos
6 Replies
BjørnarSundsbø1
Occasional Contributor II

Anyone?

0 Kudos
ChadYoder1
Occasional Contributor II

Could try something like, where _centerPt is the map point project to WGS84:

_centerPt = (MapPoint)GeometryEngine.Project (mapPt, SpatialReferences.Wgs84);

//Convert the X
int xdeg;
int xmin;
int xsec;
ConvertDecimalToDegMinSec (_centerPt.X, out xdeg, out xmin, out xsec);
 
//Convert the Y
int ydeg;
int ymin;
int ysec;
ConvertDecimalToDegMinSec (_centerPt.Y, out ydeg, out ymin, out ysec);
 
//Check for -
string ns = "N";
if (ydeg < 0)
   ns = "S";
string we = "E";
if (xdeg < 0)
   we = "W";
 
//Set the string
coordString = "Latitude:  " + Math.Abs (ydeg) + "° " + ymin + "′ " + ysec + "″ " + ns;
coordString += "\nLongitude:  " + Math.Abs (xdeg) + "° " + xmin + "′ " + xsec + "″ " + we;

        /// <summary>
         /// Converts the decimal to degrees minutes seconds.
         /// </summary>
         /// <returns>The decimal to deg minimum sec.</returns>
         /// <param name="value">Value.</param>
         /// <param name="deg">Deg.</param>
         /// <param name="min">Minimum.</param>
         /// <param name="sec">Sec.</param>
         private double ConvertDecimalToDegMinSec(double value, out int deg, out int min, out int sec)
         {
             deg = (int)value;
             value = Math.Abs(value - deg);
             min = (int)(value * 60);
             value = value - (double)min / 60;
             sec = (int)(value * 3600);
             value = value - (double)sec / 3600;
             return value;
         }
marceloctorres
Esri Contributor

If you are using Xamarin.Forms maybe this code can be usefull:

using System;
using System.Globalization;
using Xamarin.Forms;

namespace GeonetPost.Xamarin.Converters
{
  /// <summary>
  /// 
  /// </summary>
  public class GeographicCoordinateConverter : IValueConverter
  {
    /// <summary>
    /// 
    /// </summary>
    /// <param name="value"></param>
    /// <param name="targetType"></param>
    /// <param name="parameter"></param>
    /// <param name="culture"></param>
    /// <returns></returns>
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
      if (value.GetType() == typeof(double) && targetType == typeof(string))
      {
        return ToDMS((double)value, (string)parameter);
      }
      return value;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="valor"></param>
    /// <param name="eje"></param>
    /// <returns></returns>

    private string ToDMS(double valor, string eje)
    {
      var cSigno = string.Empty;
      var signo = Math.Sign(valor);
      valor = Math.Abs(valor);

      if (!string.IsNullOrEmpty(eje))
      {
        cSigno = eje.ToUpper() == "X" ? signo > 0 ? "E" : "W" : signo > 0 ? "N" : "S";
        signo = 1;
      }

      var grados = Math.Floor(valor);
      var minutos = Math.Floor((valor - grados) * 60);
      var segundos = ((valor - grados) * 60 - minutos) * 60;

      return string.Format("{0:0}°{1:00}'{2:00.000}\" {3}", signo * grados, minutos, segundos, cSigno);
    }


    /// <summary>
    /// 
    /// </summary>
    /// <param name="value"></param>
    /// <param name="targetType"></param>
    /// <param name="parameter"></param>
    /// <param name="culture"></param>
    /// <returns></returns>
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
      throw new NotImplementedException();
    }
  }
}

In XAML code you can use the converter like in the next code:

  <ContentPage.Resources>
    <ResourceDictionary>
      <cv:GeographicCoordinateConverter x:Key="GeoCoorConverter" />
    </ResourceDictionary>
  </ContentPage.Resources>

      <StackLayout Orientation="Vertical"
                   Margin="10"
                   HeightRequest="100">
        <Label Text="{Binding UpdatedViewpoint.TargetGeometry.XMin, 
          Converter={StaticResource GeoCoorConverter}, 
          ConverterParameter='X', 
          StringFormat='XMin = {0}'}" />
        <Label Text="{Binding UpdatedViewpoint.TargetGeometry.YMin, 
          Converter={StaticResource GeoCoorConverter}, 
          ConverterParameter='Y', 
          StringFormat='YMin = {0}'}" />
        <Label Text="{Binding UpdatedViewpoint.TargetGeometry.XMax, 
          Converter={StaticResource GeoCoorConverter}, 
          ConverterParameter='X', 
          StringFormat='XMax = {0}'}" />
        <Label Text="{Binding UpdatedViewpoint.TargetGeometry.YMax, 
          Converter={StaticResource GeoCoorConverter}, 
          ConverterParameter='Y', 
          StringFormat='YMax = {0}'}" />
      </StackLayout>

To see the complete sample code visit:

https://github.com/marceloctorres/GeonetPost.Xamarin (Xamarin sample) or https://github.com/marceloctorres/GeonetPost.WPF (WPF sample).

Marcelo César Torres
0 Kudos
BjørnarSundsbø1
Occasional Contributor II

Thank you both. I already have the logic you presented in some other form, so the conversion problem has been addressed. My main question is if there is a way to get this behavior with degree, minute and second symbol being displayed by using the CoordinateConverter; out of the box without writing specialized converters. 

The second part is if the default format is a standard format, with arguments to why use that one compared to the pretty print version we are all used to.

Second, how come the ToUtm only return an UTM 32 string if UTM 34 is passed as argument. If any other SR, I can understand defaulting back to 32, but not when the input position is in 34.

0 Kudos
ChadYoder1
Occasional Contributor II

I don't see a way to get the "pretty" version without using a converter.  

Also, I don't see anything that will convert to UTM, are you using v. 100?  

You could try GeometryEngine.Project Method 

0 Kudos
BjørnarSundsbø1
Occasional Contributor II

I use 10.2.7. They should really add that, but I'll manage.

For UTM I use ConvertCoordinate.ToUtm Method (MapPoint, UtmConversionMode, Boolean) 

I've tried using GeometryEngine.Project Method (Geometry, SpatialReference) into different UTM epsg codes before converting ToUtm, but no matter which one, I end up with the same result in all string value.

0 Kudos