/// <summary> /// Computes the forward transformation. /// </summary> /// <param name="coordinate">The coordinate.</param> /// <returns>The transformed coordinate.</returns> protected override String ComputeForward(GeoCoordinate coordinate) { // source: http://en.wikipedia.org/wiki/MGRS Int32 xZoneNumber, yZoneNumber, columnNumber, rowNumber, columnMeters, rowMeters; Char yZoneChar, rowChar, columnChar; if (coordinate.Latitude > Angle.FromDegree(84)) // north pole { // apply projection Coordinate projectedCoordinate = ProjectedCoordinateReferenceSystems.WGS84_UPSN_EN.Projection.Forward(coordinate); // compute row and column (for coordinates) columnNumber = Convert.ToInt32(Math.Floor(projectedCoordinate.X) / _columnWidth); rowNumber = Convert.ToInt32(Math.Floor(projectedCoordinate.Y) / _rowHeight); // compute metre precision columnMeters = Convert.ToInt32(Math.Floor(projectedCoordinate.X) % _columnWidth); rowMeters = Convert.ToInt32(Math.Floor(projectedCoordinate.Y) % _rowHeight); // compute string yZoneChar = (coordinate.Longitude.BaseValue >= 0) ? 'Z' : 'Y'; columnChar = _polarColumnSigns[(columnNumber - 20 + _polarColumnSigns.Count) % _polarColumnSigns.Count]; rowChar = _polarRowSigns[rowNumber - 13]; return(yZoneChar.ToString() + columnChar + rowChar + columnMeters.ToString("D5") + rowMeters.ToString("D5")); } else if (coordinate.Latitude < Angle.FromDegree(-80)) // south pole { // apply projection Coordinate projectedCoordinate = ProjectedCoordinateReferenceSystems.WGS84_UPSS_EN.Projection.Forward(coordinate); // compute row and column (for coordinates) columnNumber = Convert.ToInt32(Math.Floor(projectedCoordinate.X) / _columnWidth); rowNumber = Convert.ToInt32(Math.Floor(projectedCoordinate.Y) / _rowHeight); // compute metre precision columnMeters = Convert.ToInt32(Math.Floor(projectedCoordinate.X) % _columnWidth); rowMeters = Convert.ToInt32(Math.Floor(projectedCoordinate.Y) % _rowHeight); // compute string yZoneChar = (coordinate.Longitude.BaseValue >= 0) ? 'Z' : 'Y'; columnChar = _polarColumnSigns[(columnNumber - 20 + _polarColumnSigns.Count) % _polarColumnSigns.Count]; rowChar = _polarRowSigns[rowNumber - 13]; return(yZoneChar.ToString() + columnChar + rowChar + columnMeters.ToString("D5") + rowMeters.ToString("D5")); } else { // apply projection to the specific zone CoordinateProjection projection = CoordinateProjectionFactory.UniversalTransverseMercatorZone(Ellipsoids.WGS1984, coordinate.Longitude, coordinate.Latitude.BaseValue >= 0 ? EllipsoidHemisphere.North : EllipsoidHemisphere.South); Coordinate projectedCoordinate = projection.Forward(coordinate); // compute the zone (from the original coordinates) xZoneNumber = Convert.ToInt32(Math.Floor(Math.Round((coordinate.Longitude.BaseValue + Constants.PI) / _zoneWidth, 4))) % 60 + 1; yZoneNumber = Convert.ToInt32(Math.Floor(Math.Round((coordinate.Latitude.BaseValue + Constants.PI / 2 - 2 * Constants.DegreeToRadian) / _zoneHeight, 4))) + 1; // compute row and column (for coordinates) columnNumber = (xZoneNumber - 1) * 8 + Convert.ToInt32(Math.Floor(Math.Round(projectedCoordinate.X, 4) / _columnWidth)) - 1; rowNumber = Convert.ToInt32(Math.Floor(Math.Round(projectedCoordinate.Y, 4) / _rowHeight)); if (xZoneNumber % 2 == 0) { rowNumber += 5; } // compute metre precision columnMeters = Convert.ToInt32(Math.Round(projectedCoordinate.X)) % _columnWidth; rowMeters = Convert.ToInt32(Math.Round(projectedCoordinate.Y)) % _rowHeight; // compute string yZoneChar = _gridSigns[yZoneNumber]; columnChar = _columnSigns[columnNumber % _columnSigns.Count]; rowChar = _rowSigns[rowNumber % _rowSigns.Count]; return(xZoneNumber.ToString() + yZoneChar + columnChar + rowChar + columnMeters.ToString("D5") + rowMeters.ToString("D5")); } }
/// <summary> /// Computes the reverse transformation. /// </summary> /// <param name="coordinate">The coordinate.</param> /// <returns>The transformed coordinate.</returns> protected override GeoCoordinate ComputeReverse(String coordinate) { // source: http://en.wikipedia.org/wiki/MGRS if (coordinate == null) { throw new ArgumentNullException("coordinate", "The coordinate is null."); } if (!Regex.IsMatch(coordinate, "^[0-9]{1,2}[A-Z]{1,3}[0-9]{2,10}")) { throw new ArgumentException("The coordinate is not a valid MGRS string.", "coordinate"); } Int32 xZoneNumber = 0, yZoneNumber = 0, columnNumber = 0, rowNumber = 0, columnMeters = 0, rowMeters = 0, precision = 0; // compute the main zone if (Regex.IsMatch(coordinate, "^[0-9]{1,2}[A-Z]{1}")) { if (Char.IsDigit(coordinate[1])) { xZoneNumber = Int32.Parse(coordinate.Substring(0, 2)); yZoneNumber = _gridSigns.IndexOf(coordinate[2]); } else { xZoneNumber = Int32.Parse(coordinate.Substring(0, 1)); yZoneNumber = _gridSigns.IndexOf(coordinate[1]); } } // compute the latitude and longitude for the main zone Double longitudeBase = (xZoneNumber - 1) * _zoneWidth - Constants.PI; Double latitudeBase = (yZoneNumber - 2) * _zoneHeight - 80 * Constants.DegreeToRadian; // compute the subzone if (Regex.IsMatch(coordinate, "^[0-9]{1,2}[A-Z]{3}")) { if (xZoneNumber >= 10) { columnNumber = _columnSigns.IndexOf(coordinate[3]); // compute the relative row and column rowNumber = _rowSigns.IndexOf(coordinate[4]); } else { columnNumber = _columnSigns.IndexOf(coordinate[2]); rowNumber = _rowSigns.IndexOf(coordinate[3]); } } // compute metre precision if (Regex.IsMatch(coordinate, "^[0-9]{1,2}[A-Z]{1,3}[0-9]{2,10}")) { if (xZoneNumber >= 10) { if ((coordinate.Length - 5) % 2 != 0) { throw new ArgumentException("The coordinate is not a valid MGRS string.", "coordinate"); } precision = (coordinate.Length - 5) / 2; columnMeters = Int32.Parse(coordinate.Substring(5, precision)) * Convert.ToInt32(Calculator.Pow(10, 5 - precision)); rowMeters = Int32.Parse(coordinate.Substring(5 + precision, precision)) * Convert.ToInt32(Calculator.Pow(10, 5 - precision)); } else { if ((coordinate.Length - 4) % 2 != 0) { throw new ArgumentException("The coordinate is not a valid MGRS string.", "coordinate"); } precision = (coordinate.Length - 4) / 2; columnMeters = Int32.Parse(coordinate.Substring(4, precision)) * Convert.ToInt32(Calculator.Pow(10, 5 - precision)); rowMeters = Int32.Parse(coordinate.Substring(4 + precision, precision)) * Convert.ToInt32(Calculator.Pow(10, 5 - precision)); } } CoordinateProjection projection = CoordinateProjectionFactory.UniversalTransverseMercatorZone(Ellipsoids.WGS1984, xZoneNumber, latitudeBase >= 0 ? EllipsoidHemisphere.North : EllipsoidHemisphere.South); Coordinate coordinateBase = projection.Forward(new GeoCoordinate(latitudeBase, longitudeBase)); // row number correction if (xZoneNumber % 2 == 0) { rowNumber = (rowNumber + _rowSigns.Count - 5) % _rowSigns.Count; } Int32 rowNumberBase = Convert.ToInt32(Math.Floor(coordinateBase.Y / _rowHeight)); // compute the number inside the zone if (rowNumberBase / _rowSigns.Count * _rowSigns.Count + rowNumber < rowNumberBase) { rowNumber += (rowNumberBase / _rowSigns.Count + 1) * _rowSigns.Count; } else { rowNumber += rowNumberBase / _rowSigns.Count * _rowSigns.Count; } if (rowNumber >= 190) // handle overflow { rowNumber -= _rowSigns.Count; } // compute metre precision Double coordinateX = (columnNumber % 8 + 1) * _columnWidth + columnMeters; Double coordinateY = rowNumber * _rowHeight + rowMeters; // apply projection return(projection.Reverse(new Coordinate(coordinateX, coordinateY))); }