static void Main(string[] args) { try { // See also example-GeoCoords.cpp { // Sample forward calculation double lat = 33.3, lon = 44.4; // Baghdad int zone; bool northp; double x, y; UTMUPS.Forward(lat, lon, out zone, out northp, out x, out y, -1, true); string zonestr = UTMUPS.EncodeZone(zone, northp, true); Console.WriteLine(String.Format("{0} {1} {2}", zonestr, x, y)); } { // Sample reverse calculation string zonestr = "38N"; int zone; bool northp; UTMUPS.DecodeZone(zonestr, out zone, out northp); double x = 444e3, y = 3688e3; double lat, lon; UTMUPS.Reverse(zone, northp, x, y, out lat, out lon, true); Console.WriteLine(String.Format("{0} {1}", lat, lon)); } } catch (GeographicErr e) { Console.WriteLine(String.Format("Caught exception: {0}", e.Message)); } }
static void Main(string[] args) { try { // See also example-GeoCoords.cpp { // Sample forward calculation double lat = 33.3, lon = 44.4; // Baghdad int zone; bool northp; double x, y; UTMUPS.Forward(lat, lon, out zone, out northp, out x, out y, -1, true); string mgrs; MGRS.Forward(zone, northp, x, y, lat, 5, out mgrs); Console.WriteLine(mgrs); } { // Sample reverse calculation string mgrs = "38SMB4488"; int zone, prec; bool northp; double x, y; MGRS.Reverse(mgrs, out zone, out northp, out x, out y, out prec, true); double lat, lon; UTMUPS.Reverse(zone, northp, x, y, out lat, out lon, true); Console.WriteLine(String.Format("Latitude: {0} Longitude: {1}", lat, lon)); } } catch (GeographicErr e) { Console.WriteLine(String.Format("Caught exception: {0}", e.Message)); } }
private void OnValidate(object sender, EventArgs e) { try { string str; int prec, zone, zout; bool northp; double x, y, x1, y1, gamma, k, lat, lon; OSGB.Forward(52.0, -2.0, out x, out y, out gamma, out k); OSGB.Forward(52.0, -2.0, out x1, out y1); if (x != x1 || y != y1) { throw new Exception("Error in OSGB.Forward"); } OSGB.Reverse(x, y, out lat, out lon, out gamma, out k); OSGB.Reverse(x, y, out x1, out y1); if (lat != x1 || lon != y1) { throw new Exception("Error in OSGB.Reverse"); } OSGB.GridReference(x, y, 8, out str); OSGB.GridReference(str, out x1, out y1, out prec, true); UTMUPS.StandardZone(32.0, -80.0, (int)UTMUPS.ZoneSpec.STANDARD); UTMUPS.UTMShift(); UTMUPS.StandardZone(32.0, -86.0, (int)UTMUPS.ZoneSpec.STANDARD); UTMUPS.Forward(32.0, -86.0, out zone, out northp, out x, out y, out gamma, out k, (int)UTMUPS.ZoneSpec.STANDARD, true); UTMUPS.Forward(32.0, -86.0, out zone, out northp, out x1, out y1, (int)UTMUPS.ZoneSpec.STANDARD, true); if (x != x1 || y != y1) { throw new Exception("Error in UTMUPS.Forward"); } UTMUPS.Reverse(zone, northp, x, y, out lat, out lon, out gamma, out k, true); UTMUPS.Reverse(zone, northp, x, y, out x1, out y1, true); if (lat != x1 || lon != y1) { throw new Exception("Error in UTMUPS.Reverse"); } UTMUPS.Transfer(zone, northp, x, y, zone + 1, true, out x1, out y1, out zout); str = UTMUPS.EncodeZone(zone, northp, true); prec = UTMUPS.EncodeEPSG(zone, northp); UTMUPS.DecodeZone(str, out zone, out northp); UTMUPS.DecodeEPSG(prec, out zone, out northp); MGRS.Forward(zone, northp, x, y, 8, out str); MGRS.Forward(zone, northp, x, y, 32.0, 8, out str); MGRS.Reverse(str, out zone, out northp, out x, out y, out prec, true); MessageBox.Show("No errors detected", "OK", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception xcpt) { MessageBox.Show(xcpt.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
/// <summary> /// Perform some checks on the <see cref="UTMUPS"/> coordinates on this ellipsoid. /// Throw an error if any of the assumptions made in the <see cref="MGRS"/> class is not true. /// This check needs to be carried out if the ellipsoid parameters (or the UTM/UPS scales) are ever changed. /// </summary> public static void Check() { double t = tile_; var(_, lon) = UTMUPS.Reverse(31, true, 1 * t, 0 * t); if (!(lon < 0)) { throw new GeographicException("MGRS::Check: equator coverage failure"); } var(lat, _) = UTMUPS.Reverse(31, true, 1 * t, 95 * t); if (!(lat > 84)) { throw new GeographicException("MGRS::Check: UTM doesn't reach latitude = 84"); } (lat, _) = UTMUPS.Reverse(31, false, 1 * t, 10 * t); if (!(lat < -80)) { throw new GeographicException("MGRS::Check: UTM doesn't reach latitude = -80"); } var(_, _, x, _) = UTMUPS.Forward(56, 3, 32); if (!(x > 1 * t)) { throw new GeographicException("MGRS::Check: Norway exception creates a gap"); } (_, _, x, _) = UTMUPS.Forward(72, 21, 35); if (!(x > 1 * t)) { throw new GeographicException("MGRS::Check: Svalbard exception creates a gap"); } (lat, _) = UTMUPS.Reverse(0, true, 20 * t, 13 * t); if (!(lat < 84)) { throw new GeographicException("MGRS::Check: North UPS doesn't reach latitude = 84"); } (lat, _) = UTMUPS.Reverse(0, false, 20 * t, 8 * t); if (!(lat > -80)) { throw new GeographicException("MGRS::Check: South UPS doesn't reach latitude = -80"); } var bandchecks = tab.Length / 3; for (int i = 0; i < bandchecks; ++i) { (lat, _) = UTMUPS.Reverse(38, true, tab[3 * i + 1] * t, tab[3 * i + 2] * t); if (!(LatitudeBand(lat) == tab[3 * i + 0])) { throw new GeographicException( $"MGRS::Check: Band error, b = {tab[3 * i + 0]}, x = {tab[3 * i + 1]}00km, y = {tab[3 * i + 2]}00km"); } } }
public void TestReverse(double lat, double lon, string input) { var(zone, northp, x, y, _) = MGRS.Reverse(input); var(olat, olon) = UTMUPS.Reverse(zone, northp, x, y); Assert.AreEqual(olat, lat, 1e-5); // No need to check longitude when near pole. if (Math.Abs(lat) != 90) { Assert.AreEqual(olon, lon, 1e-5); } }
private void OnConvertMGRS(object sender, EventArgs e) { int zone, prec; bool northp; double x, y, lat, lon; MGRS.Reverse(m_mgrsTextBox.Text, out zone, out northp, out x, out y, out prec, true); m_utmPoleCheckBox.Checked = northp; m_utmXTextBox.Text = x.ToString(); m_utmYTextBox.Text = y.ToString(); m_utmZoneTextBox.Text = zone.ToString(); UTMUPS.Reverse(zone, northp, x, y, out lat, out lon, true); m_latitudeTextBox.Text = lat.ToString(); m_longitudeTextBox.Text = lon.ToString(); }
/// <summary> /// Convert UTM or UPS coordinate to an MGRS coordinate. /// </summary> /// <param name="zone">UTM zone (zero means UPS).</param> /// <param name="northp">hemisphere (<see langword="true"/> means north, <see langword="false"/> means south).</param> /// <param name="x">easting of point (meters).</param> /// <param name="y">northing of point (meters).</param> /// <param name="prec">precision relative to 100 km.</param> /// <returns>A <see cref="MGRS"/> string.</returns> /// <remarks> /// <i>prec</i> specifies the precision of the <see cref="MGRS"/> as follows: /// <list type="bullet"> /// <item><i>prec</i> = -1 (min), only the grid zone is returned</item> /// <item><i>prec</i> = 0, 100km</item> /// <item><i>prec</i> = 1, 10km</item> /// <item><i>prec</i> = 2, 1km</item> /// <item><i>prec</i> = 3, 100m</item> /// <item><i>prec</i> = 4, 10m</item> /// <item><i>prec</i> = 5, 1m</item> /// <item><i>prec</i> = 6, 0.1m</item> /// <item>...</item> /// <item><i>prec</i> = 11 (max), 1μm</item> /// </list> /// <para> /// UTM eastings are allowed to be in the range [100 km, 900 km], /// northings are allowed to be in in [0 km, 9500 km] for the northern hemisphere and in [1000 km, 10000 km] for the southern hemisphere. /// (However UTM northings can be continued across the equator. So the actual limits on the northings are [−9000 km, 9500 km] /// for the "northern" hemisphere and [1000 km, 19500 km] for the "southern" hemisphere.) /// </para> /// <para> /// UPS eastings/northings are allowed to be in the range [1300 km, 2700 km] in the northern hemisphere /// and in [800 km, 3200 km] in the southern hemisphere. /// </para> /// <para> /// The ranges are 100 km more restrictive than for the conversion between geographic coordinates and UTM and UPS given by <see cref="UTMUPS"/>. /// These restrictions are dictated by the allowed letters in <see cref="MGRS"/> coordinates. /// The choice of 9500 km for the maximum northing for northern hemisphere and of 1000 km as the minimum northing for southern hemisphere /// provide at least 0.5 degree extension into standard UPS zones. /// The upper ends of the ranges for the UPS coordinates is dictated by requiring symmetry about the meridians <c>0E</c> and <c>90E</c>. /// </para> /// <para> /// All allowed UTM and UPS coordinates may now be converted to legal <see cref="MGRS"/> coordinates with the proviso that eastings and northings /// on the upper boundaries are silently reduced by about 4 nm (4 nanometers) to place them within the allowed range. /// (This includes reducing a southern hemisphere northing of 10000 km by 4 nm so that it is placed in latitude band <c>M</c>.) /// The UTM or UPS coordinates are truncated to requested precision to determine the <see cref="MGRS"/> coordinate. /// Thus in UTM zone <c>38N</c>, the square area with easting in [444 km, 445 km) and northing in [3688 km, 3689 km) maps to <see cref="MGRS"/> /// coordinate <c>38SMB4488</c> (at <i>prec</i> = 2, 1 km), Khulani Sq., Baghdad. /// </para> /// <para> /// The UTM/UPS selection and the UTM zone is preserved in the conversion to <see cref="MGRS"/> coordinate. /// Thus for <i>zone</i> > 0, the <see cref="MGRS"/> coordinate begins with the zone number followed by one of [<c>C</c>–<c>M</c>] for the southern hemisphere /// and [<c>N</c>–<c>X</c>] for the northern hemisphere. For <i>zone</i> = 0, the <see cref="MGRS"/> coordinates begins with one of [<c>AB</c>] for the /// southern hemisphere and [<c>XY</c>] for the northern hemisphere. /// </para> /// <para> /// The conversion to the <see cref="MGRS"/> is exact for prec in [0, 5] except that a neighboring /// latitude band letter may be given if the point is within 5nm of a band boundary. For <i>prec</i> in [6, 11], the conversion is accurate to roundoff. /// </para> /// <para> /// If <i>prec</i> = −1, then the "grid zone designation", e.g., <c>18T</c>, is returned. /// This consists of the UTM zone number (absent for UPS) and the first letter of the <see cref="MGRS"/> string which labels the latitude band /// for UTM and the hemisphere for UPS. /// </para> /// <para> /// If <i>x</i> or <i>y</i> is <see cref="double.NaN"/> or if zone is <see cref="ZoneSpec.Invalid"/>, the returned <see cref="MGRS"/> string is "INVALID". /// </para> /// </remarks> public static string Forward(int zone, bool northp, double x, double y, int prec) { double lat; if (zone > 0) { // Does a rough estimate for latitude determine the latitude band? var ys = northp ? y : y - utmNshift_; // A cheap calculation of the latitude which results in an "allowed" // latitude band would be // lat = ApproxLatitudeBand(ys) * 8 + 4; // // Here we do a more careful job using the band letter corresponding to // the actual latitude. ys /= tile_; if (Abs(ys) < 1) { lat = 0.9 * ys; // accurate enough estimate near equator } else { double // The poleward bound is a fit from above of lat(x,y) // for x = 500km and y = [0km, 950km] latp = 0.901 * ys + (ys > 0 ? 1 : -1) * 0.135, // The equatorward bound is a fit from below of lat(x,y) // for x = 900km and y = [0km, 950km] late = 0.902 * ys * (1 - 1.85e-6 * ys * ys); if (LatitudeBand(latp) == LatitudeBand(late)) { lat = latp; } else { // bounds straddle a band boundary so need to compute lat accurately (lat, _) = UTMUPS.Reverse(zone, northp, x, y); } } } else { // Latitude isn't needed for UPS specs or for INVALID lat = 0; } return(Forward(zone, northp, x, y, lat, prec)); }
private void OnConvertUTMUPS(object sender, EventArgs e) { try { double lat, lon; string str; double x = Double.Parse(m_utmXTextBox.Text); double y = Double.Parse(m_utmYTextBox.Text); int zone = Int32.Parse(m_utmZoneTextBox.Text); UTMUPS.Reverse(zone, m_utmPoleCheckBox.Checked, x, y, out lat, out lon, true); m_latitudeTextBox.Text = lat.ToString(); m_longitudeTextBox.Text = lon.ToString(); MGRS.Forward(zone, m_utmPoleCheckBox.Checked, x, y, 8, out str); m_mgrsTextBox.Text = str; } catch (Exception xcpt) { MessageBox.Show(xcpt.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }