using System; using System.Linq; using System.Diagnostics; using System.ComponentModel; namespace CoordinateSharp { /// /// Military Grid Reference System (MGRS). Uses the WGS 84 Datum. /// Relies upon values from the UniversalTransverseMercator class /// [Serializable] public class MilitaryGridReferenceSystem : INotifyPropertyChanged { /// /// Create an MGRS object with WGS84 datum /// /// Lat Zone /// Long Zone /// Digraph /// Easting /// Northing public MilitaryGridReferenceSystem(string latz, int longz, string d, double e, double n) { string digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ"; string digraphLettersN = "ABCDEFGHJKLMNPQRSTUV"; if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); } if (!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); } if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); } if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); } if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); } if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); } latZone = latz; longZone = longz; digraph = d; easting = e; northing = n; //WGS84 equatorialRadius = 6378137.0; inverseFlattening = 298.257223563; } /// /// Create an MGRS object with custom datum /// /// Lat Zone /// Long Zone /// Digraph /// Easting /// Northing /// Equatorial Radius /// Inverse Flattening public MilitaryGridReferenceSystem(string latz, int longz, string d, double e, double n,double rad, double flt) { string digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ"; string digraphLettersN = "ABCDEFGHJKLMNPQRSTUV"; if (longz < 1 || longz > 60) { Debug.WriteLine("Longitudinal zone out of range", "UTM longitudinal zones must be between 1-60."); } if (!Verify_Lat_Zone(latz)) { throw new ArgumentException("Latitudinal zone invalid", "UTM latitudinal zone was unrecognized."); } if (n < 0 || n > 10000000) { throw new ArgumentOutOfRangeException("Northing out of range", "Northing must be between 0-10,000,000."); } if (d.Count() < 2 || d.Count() > 2) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); } if (digraphLettersE.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[0].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); } if (digraphLettersN.ToCharArray().ToList().Where(x => x.ToString() == d.ToUpper()[1].ToString()).Count() == 0) { throw new ArgumentException("Digraph invalid", "MGRS Digraph was unrecognized."); } latZone = latz; longZone = longz; digraph = d; easting = e; northing = n; equatorialRadius = rad; inverseFlattening = flt; } private double equatorialRadius; private double inverseFlattening; private string latZone; private int longZone; private double easting; private double northing; private string digraph; private bool withinCoordinateSystemBounds=true; private bool Verify_Lat_Zone(string l) { if (LatZones.longZongLetters.Where(x => x == l.ToUpper()).Count() != 1) { return false; } return true; } /// /// MGRS Zone Letter /// public string LatZone { get { return latZone; } } /// /// MGRS Zone Number /// public int LongZone { get { return longZone; } } /// /// MGRS Easting /// public double Easting { get { return easting; } } /// /// MGRS Northing /// public double Northing { get { return northing; } } /// /// MGRS Digraph /// public string Digraph { get { return digraph; } } /// /// Is MGRS conversion within the coordinate system's accurate boundaries after conversion from Lat/Long. /// public bool WithinCoordinateSystemBounds { get { return withinCoordinateSystemBounds; } } internal MilitaryGridReferenceSystem(UniversalTransverseMercator utm) { ToMGRS(utm); } internal void ToMGRS(UniversalTransverseMercator utm) { Digraphs digraphs = new Digraphs(); string digraph1 = digraphs.getDigraph1(utm.LongZone, utm.Easting); string digraph2 = digraphs.getDigraph2(utm.LongZone, utm.Northing); digraph = digraph1 + digraph2; latZone = utm.LatZone; longZone = utm.LongZone; //String easting = String.valueOf((int)_easting); string e = ((int)utm.Easting).ToString(); if (e.Length < 5) { e = "00000" + ((int)utm.Easting).ToString(); } e = e.Substring(e.Length - 5); easting = Convert.ToInt32(e); string n = ((int)utm.Northing).ToString(); if (n.Length < 5) { n = "0000" + ((int)utm.Northing).ToString(); } n = n.Substring(n.Length - 5); northing = Convert.ToInt32(n); equatorialRadius = utm.equatorial_radius; inverseFlattening = utm.inverse_flattening; withinCoordinateSystemBounds = utm.WithinCoordinateSystemBounds; } /// /// Creates a Coordinate object from an MGRS/NATO UTM Coordinate /// /// MilitaryGridReferenceSystem /// Coordinate object public static Coordinate MGRStoLatLong(MilitaryGridReferenceSystem mgrs) { string latz = mgrs.LatZone; string digraph = mgrs.Digraph; char eltr = digraph[0]; char nltr = digraph[1]; string digraphLettersE = "ABCDEFGHJKLMNPQRSTUVWXYZ"; string digraphLettersN = "ABCDEFGHJKLMNPQRSTUV"; string digraphLettersAll=""; for (int lt = 1; lt < 25; lt++) { digraphLettersAll += "ABCDEFGHJKLMNPQRSTUV"; } var eidx = digraphLettersE.IndexOf(eltr); var nidx = digraphLettersN.IndexOf(nltr); if (mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0)) { nidx -= 5; // correction for even numbered zones } var ebase = 100000 * (1 + eidx - 8 * Math.Floor(Convert.ToDouble(eidx) / 8)); var latBand = digraphLettersE.IndexOf(latz); var latBandLow = 8 * latBand - 96; var latBandHigh = 8 * latBand - 88; if (latBand < 2) { latBandLow = -90; latBandHigh = -80; } else if (latBand == 21) { latBandLow = 72; latBandHigh = 84; } else if (latBand > 21) { latBandLow = 84; latBandHigh = 90; } var lowLetter = Math.Floor(100 + 1.11 * latBandLow); var highLetter = Math.Round(100 + 1.11 * latBandHigh); string latBandLetters = null; int l = Convert.ToInt32(lowLetter); int h = Convert.ToInt32(highLetter); if (mgrs.LongZone / 2.0 == Math.Floor(mgrs.LongZone / 2.0)) { latBandLetters = digraphLettersAll.Substring(l + 5, h + 5).ToString(); } else { latBandLetters = digraphLettersAll.Substring(l, h).ToString(); } var nbase = 100000 * (lowLetter + latBandLetters.IndexOf(nltr)); //latBandLetters.IndexOf(nltr) value causing incorrect Northing below -80 var x = ebase + mgrs.Easting; var y = nbase + mgrs.Northing; if (y > 10000000) { y = y - 10000000; } if (nbase >= 10000000) { y = nbase + mgrs.northing - 10000000; } var southern = nbase < 10000000; UniversalTransverseMercator utm = new UniversalTransverseMercator(mgrs.LatZone, mgrs.LongZone, x, y); utm.equatorial_radius = mgrs.equatorialRadius; utm.inverse_flattening = mgrs.inverseFlattening; Coordinate c = UniversalTransverseMercator.ConvertUTMtoLatLong(utm); c.Set_Datum(mgrs.equatorialRadius, mgrs.inverseFlattening); return c; } /// /// MGRS Default String Format /// /// MGRS Formatted Coordinate String public override string ToString() { if (!withinCoordinateSystemBounds) { return ""; }//MGRS Coordinate is outside its reliable boundaries. Return empty. return longZone.ToString() + LatZone + " " + digraph + " " + ((int)easting).ToString("00000") + " " + ((int)northing).ToString("00000"); } /// /// Property changed event /// public event PropertyChangedEventHandler PropertyChanged; /// /// Notify property changed /// /// Property name public void NotifyPropertyChanged(string propName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propName)); } } } }