/// <summary> /// The function convertFromGeodetic converts geodetic (latitude and /// longitude) coordinates to UPS (hemisphere, easting, and northing) /// coordinates, according to the current ellipsoid parameters. /// If any errors occur, an exception is thrown with a description /// of the error. /// </summary> /// <param name="geodeticCoordinates"></param> /// <returns></returns> public UPSCoordinates convertFromGeodetic(GeodeticCoordinates geodeticCoordinates) { /* * latitude : Latitude in radians (input) * longitude : Longitude in radians (input) * hemisphere : Hemisphere either 'N' or 'S' (output) * easting : Easting/X in meters (output) * northing : Northing/Y in meters (output) */ char hemisphere; string errorStatus = ""; double longitude = geodeticCoordinates.longitude; double latitude = geodeticCoordinates.latitude; if ((latitude < -MAX_LAT) || (latitude > MAX_LAT)) { /* latitude out of range */ errorStatus += ErrorMessages.latitude; } else if ((latitude < 0) && (latitude >= (MAX_SOUTH_LAT + EPSILON))) { errorStatus += ErrorMessages.latitude; } else if ((latitude >= 0) && (latitude < (MIN_NORTH_LAT - EPSILON))) { errorStatus += ErrorMessages.latitude; } if ((longitude < -Math.PI) || (longitude > (2 * Math.PI))) { /* longitude out of range */ errorStatus += ErrorMessages.longitude; } if (errorStatus.Length > 0) { throw new ArgumentException(errorStatus); } if (latitude < 0) { //this.UPS_Origin_Latitude = -MAX_ORIGIN_LAT; hemisphere = 'S'; } else { //this.UPS_Origin_Latitude = MAX_ORIGIN_LAT; hemisphere = 'N'; } PolarStereographic polarStereographic = new PolarStereographic(this.semiMajorAxis, this.flattening, this.UPS_Origin_Longitude, 0.994, hemisphere, this.UPS_False_Easting, this.UPS_False_Northing); MapProjectionCoordinates polarStereographicCoordinates = polarStereographic.convertFromGeodetic(geodeticCoordinates); double easting = polarStereographicCoordinates.getEasting(); double northing = polarStereographicCoordinates.getNorthing(); return(new UPSCoordinates(CoordinateType.Enum.universalPolarStereographic, hemisphere, easting, northing)); }
/// <summary> /// The function convertToGeodetic converts Transverse /// Mercator projection (easting and northing) coordinates to geodetic /// (latitude and longitude) coordinates, according to the current ellipsoid /// and Transverse Mercator projection parameters. If any errors occur, /// an exception is thrown with a description of the error. /// </summary> /// <param name="mapProjectionCoordinates"></param> /// <returns></returns> public GeodeticCoordinates convertToGeodetic(MapProjectionCoordinates mapProjectionCoordinates) { /* * easting : Easting/X in meters (input) * northing : Northing/Y in meters (input) * longitude : Longitude in radians (output) * latitude : Latitude in radians (output) */ double c; /* Cosine of latitude */ double de; /* Delta easting - Difference in Easting (easting-Fe) */ double dlam; /* Delta longitude - Difference in Longitude */ double eta1; /* constant - TranMerc_ebs *c *c */ double eta2; double eta3; double eta4; double ftphi; /* Footpoint latitude */ int i; /* Loop iterator */ double s; /* Sine of latitude */ double sn; /* Radius of curvature in the prime vertical */ double sr; /* Radius of curvature in the meridian */ double tan1; /* Tangent of latitude */ double tan2; double tan4; double t10; /* Term in coordinate conversion formula - GP to Y */ double t11; /* Term in coordinate conversion formula - GP to Y */ double t12; /* Term in coordinate conversion formula - GP to Y */ double t13; /* Term in coordinate conversion formula - GP to Y */ double t14; /* Term in coordinate conversion formula - GP to Y */ double t15; /* Term in coordinate conversion formula - GP to Y */ double t16; /* Term in coordinate conversion formula - GP to Y */ double t17; /* Term in coordinate conversion formula - GP to Y */ double tmd; /* True Meridianal distance */ double tmdo; /* True Meridianal distance for latitude of origin */ string errorStatus = ""; double latitude; double longitude; double easting = mapProjectionCoordinates.getEasting(); double northing = mapProjectionCoordinates.getNorthing(); if ((easting < (TranMerc_False_Easting - TranMerc_Delta_Easting)) || (easting > (TranMerc_False_Easting + TranMerc_Delta_Easting))) { /* easting out of range */ errorStatus += ErrorMessages.easting; } if ((northing < (TranMerc_False_Northing - TranMerc_Delta_Northing)) || (northing > (TranMerc_False_Northing + TranMerc_Delta_Northing))) { /* northing out of range */ errorStatus += ErrorMessages.northing; } if (errorStatus.Length > 0) { throw new ArgumentException(errorStatus); } /* True Meridianal Distances for latitude of origin */ tmdo = sphtmd(TranMerc_Origin_Lat); /* Origin */ tmd = tmdo + (northing - TranMerc_False_Northing) / TranMerc_Scale_Factor; /* First Estimate */ sr = sphsr(0.0); ftphi = tmd / sr; for (i = 0; i < 5; i++) { t10 = sphtmd(ftphi); sr = sphsr(ftphi); ftphi += (tmd - t10) / sr; } /* Radius of Curvature in the meridian */ sr = sphsr(ftphi); /* Radius of Curvature in the meridian */ sn = sphsn(ftphi); /* Sine CoMath.Sine terms */ s = Math.Sin(ftphi); c = Math.Cos(ftphi); /* Tangent Value */ tan1 = Math.Tan(ftphi); tan2 = tan1 * tan1; tan4 = tan2 * tan2; eta1 = TranMerc_ebs * Math.Pow(c, 2.0); eta2 = eta1 * eta1; eta3 = eta2 * eta1; eta4 = eta3 * eta1; de = easting - TranMerc_False_Easting; if (Math.Abs(de) < 0.0001) { de = 0.0; } /* Latitude */ t10 = tan1 / (2.0 * sr * sn * Math.Pow(TranMerc_Scale_Factor, 2.0)); t11 = tan1 * (5.0 + 3.0 * tan2 + eta1 - 4.0 * Math.Pow(eta1, 2.0) - 9.0 * tan2 * eta1) / (24.0 * sr * Math.Pow(sn, 3.0) * Math.Pow(this.TranMerc_Scale_Factor, 4.0)); t12 = tan1 * (61.0 + 90.0 * tan2 + 46.0 * eta1 + 45.0 * tan4 - 252.0 * tan2 * eta1 - 3.0 * eta2 + 100.0 * eta3 - 66.0 * tan2 * eta2 - 90.0 * tan4 * eta1 + 88.0 * eta4 + 225.0 * tan4 * eta2 + 84.0 * tan2 * eta3 - 192.0 * tan2 * eta4) / (720.0 * sr * Math.Pow(sn, 5.0) * Math.Pow(this.TranMerc_Scale_Factor, 6.0)); t13 = tan1 * (1385.0 + 3633.0 * tan2 + 4095.0 * tan4 + 1575.0 * Math.Pow(tan1, 6.0)) / (40320.0 * sr * Math.Pow(sn, 7.0) * Math.Pow(TranMerc_Scale_Factor, 8.0)); latitude = ftphi - Math.Pow(de, 2.0) * t10 + Math.Pow(de, 4.0) * t11 - Math.Pow(de, 6.0) * t12 + Math.Pow(de, 8.0) * t13; t14 = 1.0 / (sn * c * this.TranMerc_Scale_Factor); t15 = (1.0 + 2.0 * tan2 + eta1) / (6.0 * Math.Pow(sn, 3.0) * c * Math.Pow(this.TranMerc_Scale_Factor, 3.0)); t16 = (5.0 + 6.0 * eta1 + 28.0 * tan2 - 3.0 * eta2 + 8.0 * tan2 * eta1 + 24.0 * tan4 - 4.0 * eta3 + 4.0 * tan2 * eta2 + 24.0 * tan2 * eta3) / (120.0 * Math.Pow(sn, 5.0) * c * Math.Pow(this.TranMerc_Scale_Factor, 5.0)); t17 = (61.0 + 662.0 * tan2 + 1320.0 * tan4 + 720.0 * Math.Pow(tan1, 6.0)) / (5040.0 * Math.Pow(sn, 7.0) * c * Math.Pow(this.TranMerc_Scale_Factor, 7.0)); /* Difference in Longitude */ dlam = de * t14 - Math.Pow(de, 3.0) * t15 + Math.Pow(de, 5.0) * t16 - Math.Pow(de, 7.0) * t17; /* Longitude */ longitude = this.TranMerc_Origin_Long + dlam; if (Math.Abs(latitude) > PI_OVER_2) { throw new ArgumentException(ErrorMessages.northing); } if (longitude > Math.PI) { longitude -= (2 * Math.PI); if (Math.Abs(longitude) > Math.PI) { throw new ArgumentException(ErrorMessages.easting); } } else if (longitude < -Math.PI) { longitude += (2 * Math.PI); if (Math.Abs(longitude) > Math.PI) { throw new ArgumentException(ErrorMessages.easting); } } if (Math.Abs(dlam) > Math.PI / 20 * Math.Cos(latitude)) { /* Distortion will result if longitude is more than 9 degrees from the Central Meridian at the equator */ /* and decreases to 0 degrees at the poles */ /* As you move towards the poles, distortion will become more significant */ errorStatus += WarningMessages.longitude; } return new GeodeticCoordinates(CoordinateType.Enum.geodetic, longitude, latitude); }
/// <summary> /// The function convertFromGeodetic converts geodetic (latitude and /// longitude) coordinates to UTM projection (zone, hemisphere, easting and /// northing) coordinates according to the current ellipsoid and UTM zone /// zoneOverride parameters. If any errors occur, an exception is thrown with a description /// of the error. /// </summary> /// <param name="geodeticCoordinates"></param> /// <returns></returns> public UTMCoordinates convertFromGeodetic(GeodeticCoordinates geodeticCoordinates) { /* * * longitude : Longitude in radians (input) * latitude : Latitude in radians (input) * zone : UTM zone (output) * hemisphere : North or South hemisphere (output) * easting : Easting (X) in meters (output) * northing : Northing (Y) in meters (output) */ long Lat_Degrees; long Long_Degrees; int temp_zone; char hemisphere; double False_Northing = 0; string errorStatus = ""; double longitude = geodeticCoordinates.longitude; double latitude = geodeticCoordinates.latitude; if ((latitude < (MIN_LAT - EPSILON)) || (latitude >= (MAX_LAT + EPSILON))) { /* latitude out of range */ errorStatus += ErrorMessages.latitude; } if ((longitude < -Math.PI) || (longitude > (2 * Math.PI))) { /* longitude out of range */ errorStatus += ErrorMessages.longitude; } if (errorStatus.Length > 0) { throw new ArgumentException(errorStatus); } if ((latitude > -1.0e-9) && (latitude < 0)) { latitude = 0.0; } if (longitude < 0) { longitude += (2 * Math.PI) + 1.0e-10; } Lat_Degrees = (long)(latitude * 180.0 / Math.PI); Long_Degrees = (long)(longitude * 180.0 / Math.PI); if (longitude < Math.PI) { temp_zone = (int)(31 + ((longitude * 180.0 / Math.PI) / 6.0)); } else { temp_zone = (int)(((longitude * 180.0 / Math.PI) / 6.0) - 29); } if (temp_zone > 60) { temp_zone = 1; } if (zoneOverride > 0) { if ((temp_zone == 1) && (this.zoneOverride == 60)) { temp_zone = (int)this.zoneOverride; } else if ((temp_zone == 60) && (zoneOverride == 1)) { temp_zone = (int)this.zoneOverride; } else if (((temp_zone - 1) <= zoneOverride) && (zoneOverride <= (temp_zone + 1))) { temp_zone = (int)this.zoneOverride; } else { throw new ArgumentException(ErrorMessages.zoneOverride); } } TransverseMercator transverseMercator = getTransverseMercator(temp_zone); if (latitude < 0) { False_Northing = 10000000.0; hemisphere = 'S'; } else { hemisphere = 'N'; } MapProjectionCoordinates transverseMercatorCoordinates = transverseMercator.convertFromGeodetic(new GeodeticCoordinates(CoordinateType.Enum.geodetic, longitude, latitude)); double easting = transverseMercatorCoordinates.getEasting(); double northing = transverseMercatorCoordinates.getNorthing() + False_Northing; if ((easting < MIN_EASTING) || (easting > MAX_EASTING)) { throw new ArgumentException(ErrorMessages.easting); } if ((northing < MIN_NORTHING) || (northing > MAX_NORTHING)) { throw new ArgumentException(ErrorMessages.northing); } return(new UTMCoordinates(CoordinateType.Enum.universalTransverseMercator, temp_zone, hemisphere, easting, northing)); }
/// <summary> /// The function convertToGeodetic converts Polar /// Stereographic coordinates (easting and northing) to geodetic /// coordinates (latitude and longitude) according to the current ellipsoid /// and Polar Stereographic projection Parameters. If any errors occur, /// an exception is thrown with a description of the error. /// </summary> /// <param name="mapProjectionCoordinates"></param> /// <returns></returns> public GeodeticCoordinates convertToGeodetic(MapProjectionCoordinates mapProjectionCoordinates) { /* * easting : Easting (X), in meters (input) * northing : Northing (Y), in meters (input) * longitude : Longitude, in radians (output) * latitude : Latitude, in radians (output) * */ double dy = 0, dx = 0; double rho = 0; double t; double PHI, sin_PHI; double tempPHI = 0.0; double essin; double pow_es; double delta_radius; double longitude, latitude; string errorStatus = ""; double easting = mapProjectionCoordinates.getEasting(); double northing = mapProjectionCoordinates.getNorthing(); double min_easting = this.Polar_False_Easting - this.Polar_Delta_Easting; double max_easting = this.Polar_False_Easting + this.Polar_Delta_Easting; double min_northing = this.Polar_False_Northing - this.Polar_Delta_Northing; double max_northing = this.Polar_False_Northing + this.Polar_Delta_Northing; if (easting > max_easting || easting < min_easting) { /* easting out of range */ errorStatus += ErrorMessages.easting; } if (northing > max_northing || northing < min_northing) { /* northing out of range */ errorStatus += ErrorMessages.northing; } if (errorStatus.Length > 0) { throw new ArgumentException(errorStatus); } dy = northing - this.Polar_False_Northing; dx = easting - this.Polar_False_Easting; /* Radius of point with origin of false easting, false northing */ rho = Math.Sqrt(dx * dx + dy * dy); delta_radius = Math.Sqrt(this.Polar_Delta_Easting * this.Polar_Delta_Easting + this.Polar_Delta_Northing * this.Polar_Delta_Northing); if (rho > delta_radius) { /* Point is outside of projection area */ throw new ArgumentException(ErrorMessages.radius); } if ((dy == 0.0) && (dx == 0.0)) { latitude = PI_OVER_2; longitude = this.Polar_Central_Meridian; } else { if (this.Southern_Hemisphere != 0) { dy *= -1.0; dx *= -1.0; } if (Math.Abs(Math.Abs(this.Polar_Standard_Parallel) - PI_OVER_2) > 1.0e-10) { t = rho * this.Polar_tc / (this.Polar_a_mc); } else { t = rho * Polar_k90 / (two_Polar_a); } PHI = PI_OVER_2 - 2.0 * Math.Atan(t); while (Math.Abs(PHI - tempPHI) > 1.0e-10) { tempPHI = PHI; sin_PHI = Math.Sin(PHI); essin = es * sin_PHI; pow_es = polarPow(essin); PHI = PI_OVER_2 - 2.0 * Math.Atan(t * pow_es); } latitude = PHI; longitude = Polar_Central_Meridian + Math.Atan2(dx, -dy); if (longitude > Math.PI) { longitude -= TWO_PI; } else if (longitude < -Math.PI) { longitude += TWO_PI; } // Force distorted values if (latitude > PI_OVER_2) /* force distorted values to 90, -90 degrees */ { latitude = PI_OVER_2; } else if (latitude < -PI_OVER_2) { latitude = -PI_OVER_2; } if (longitude > Math.PI) /* force distorted values to 180, -180 degrees */ { longitude = Math.PI; } else if (longitude < -Math.PI) { longitude = -Math.PI; } } if (Southern_Hemisphere != 0) { latitude *= -1.0; longitude *= -1.0; } return new GeodeticCoordinates(CoordinateType.Enum.geodetic, longitude, latitude); }
/// <summary> /// The constructor receives the ellipsoid /// parameters and Polar Stereograpic (Standard Parallel) projection parameters as inputs, and /// sets the corresponding state variables. If any errors occur, an /// exception is thrown with a description of the error. /// </summary> /// <param name="ellipsoidSemiMajorAxis">Semi-major axis of ellipsoid, in meters</param> /// <param name="ellipsoidFlattening">Flattening of ellipsoid</param> /// <param name="centralMeridian">Longitude down from pole, in radians</param> /// <param name="standardParallel">Latitude of true scale, in radians</param> /// <param name="falseEasting">Easting (X) at center of projection, in meters</param> /// <param name="falseNorthing">Northing (Y) at center of projection, in meters</param> public PolarStereographic(double ellipsoidSemiMajorAxis, double ellipsoidFlattening, double centralMeridian, double standardParallel, double falseEasting, double falseNorthing) { this.coordinateType = CoordinateType.Enum.polarStereographicStandardParallel; this.es = 0.08181919084262188000; this.es_OVER_2 = .040909595421311; this.Southern_Hemisphere = 0; this.Polar_tc = 1.0; this.Polar_k90 = 1.0033565552493; this.Polar_a_mc = 6378137.0; this.two_Polar_a = 12756274.0; this.Polar_Central_Meridian = 0.0; this.Polar_Standard_Parallel = ((Math.PI * 90) / 180); this.Polar_False_Easting = 0.0; this.Polar_False_Northing = 0.0; this.Polar_Scale_Factor = 1.0; this.Polar_Delta_Easting = 12713601.0; this.Polar_Delta_Northing = 12713601.0; double es2; double slat, sinolat, cosolat; double essin; double one_PLUS_es, one_MINUS_es; double one_PLUS_es_sinolat, one_MINUS_es_sinolat; double pow_es; double inv_f = 1 / ellipsoidFlattening; string errorStatus = ""; if (ellipsoidSemiMajorAxis <= 0.0) { /* Semi-major axis must be greater than zero */ errorStatus += ErrorMessages.semiMajorAxis; } if ((inv_f < 250) || (inv_f > 350)) { /* Inverse flattening must be between 250 and 350 */ errorStatus += ErrorMessages.ellipsoidFlattening; } if ((standardParallel < -PI_OVER_2) || (standardParallel > PI_OVER_2)) { /* Origin Latitude out of range */ errorStatus += ErrorMessages.originLatitude; } if ((centralMeridian < -Math.PI) || (centralMeridian > TWO_PI)) { /* Origin Longitude out of range */ errorStatus += ErrorMessages.centralMeridian; } if (errorStatus.Length > 0) { throw new ArgumentException(errorStatus); } this.semiMajorAxis = ellipsoidSemiMajorAxis; this.flattening = ellipsoidFlattening; two_Polar_a = 2.0 * semiMajorAxis; if (centralMeridian > Math.PI) { centralMeridian -= TWO_PI; } if (standardParallel < 0) { this.Southern_Hemisphere = 1; this.Polar_Standard_Parallel = -standardParallel; this.Polar_Central_Meridian = -centralMeridian; } else { Southern_Hemisphere = 0; this.Polar_Standard_Parallel = standardParallel; this.Polar_Central_Meridian = centralMeridian; } this.Polar_False_Easting = falseEasting; this.Polar_False_Northing = falseNorthing; es2 = 2 * this.flattening - this.flattening * this.flattening; es = Math.Sqrt(es2); es_OVER_2 = es / 2.0; if (Math.Abs(Math.Abs(Polar_Standard_Parallel) - PI_OVER_2) > 1.0e-10) { sinolat = Math.Sin(Polar_Standard_Parallel); essin = es * sinolat; pow_es = polarPow(essin); cosolat = Math.Cos(Polar_Standard_Parallel); double mc = cosolat / Math.Sqrt(1.0 - essin * essin); this.Polar_a_mc = semiMajorAxis * mc; this.Polar_tc = Math.Tan(PI_OVER_4 - Polar_Standard_Parallel / 2.0) / pow_es; } one_PLUS_es = 1.0 + es; one_MINUS_es = 1.0 - es; this.Polar_k90 = Math.Sqrt(Math.Pow(one_PLUS_es, one_PLUS_es) * Math.Pow(one_MINUS_es, one_MINUS_es)); slat = Math.Sin(Math.Abs(standardParallel)); one_PLUS_es_sinolat = 1.0 + es * slat; one_MINUS_es_sinolat = 1.0 - es * slat; this.Polar_Scale_Factor = ((1 + slat) / 2) * (Polar_k90 / Math.Sqrt(Math.Pow(one_PLUS_es_sinolat, one_PLUS_es) * Math.Pow(one_MINUS_es_sinolat, one_MINUS_es))); /* Calculate Radius */ MapProjectionCoordinates tempCoordinates = convertFromGeodetic(new GeodeticCoordinates(CoordinateType.Enum.geodetic, centralMeridian, 0, 0)); this.Polar_Delta_Northing = tempCoordinates.getNorthing(); if (this.Polar_False_Northing != 0) { this.Polar_Delta_Northing -= this.Polar_False_Northing; } if (Polar_Delta_Northing < 0) { this.Polar_Delta_Northing = -this.Polar_Delta_Northing; } this.Polar_Delta_Northing *= 1.01; this.Polar_Delta_Easting = this.Polar_Delta_Northing; }
/// <summary> /// The function convertToGeodetic converts Polar /// Stereographic coordinates (easting and northing) to geodetic /// coordinates (latitude and longitude) according to the current ellipsoid /// and Polar Stereographic projection Parameters. If any errors occur, /// an exception is thrown with a description of the error. /// </summary> /// <param name="mapProjectionCoordinates"></param> /// <returns></returns> public GeodeticCoordinates convertToGeodetic(MapProjectionCoordinates mapProjectionCoordinates) { /* * easting : Easting (X), in meters (input) * northing : Northing (Y), in meters (input) * longitude : Longitude, in radians (output) * latitude : Latitude, in radians (output) * */ double dy = 0, dx = 0; double rho = 0; double t; double PHI, sin_PHI; double tempPHI = 0.0; double essin; double pow_es; double delta_radius; double longitude, latitude; string errorStatus = ""; double easting = mapProjectionCoordinates.getEasting(); double northing = mapProjectionCoordinates.getNorthing(); double min_easting = this.Polar_False_Easting - this.Polar_Delta_Easting; double max_easting = this.Polar_False_Easting + this.Polar_Delta_Easting; double min_northing = this.Polar_False_Northing - this.Polar_Delta_Northing; double max_northing = this.Polar_False_Northing + this.Polar_Delta_Northing; if (easting > max_easting || easting < min_easting) { /* easting out of range */ errorStatus += ErrorMessages.easting; } if (northing > max_northing || northing < min_northing) { /* northing out of range */ errorStatus += ErrorMessages.northing; } if (errorStatus.Length > 0) { throw new ArgumentException(errorStatus); } dy = northing - this.Polar_False_Northing; dx = easting - this.Polar_False_Easting; /* Radius of point with origin of false easting, false northing */ rho = Math.Sqrt(dx * dx + dy * dy); delta_radius = Math.Sqrt(this.Polar_Delta_Easting * this.Polar_Delta_Easting + this.Polar_Delta_Northing * this.Polar_Delta_Northing); if (rho > delta_radius) { /* Point is outside of projection area */ throw new ArgumentException(ErrorMessages.radius); } if ((dy == 0.0) && (dx == 0.0)) { latitude = PI_OVER_2; longitude = this.Polar_Central_Meridian; } else { if (this.Southern_Hemisphere != 0) { dy *= -1.0; dx *= -1.0; } if (Math.Abs(Math.Abs(this.Polar_Standard_Parallel) - PI_OVER_2) > 1.0e-10) { t = rho * this.Polar_tc / (this.Polar_a_mc); } else { t = rho * Polar_k90 / (two_Polar_a); } PHI = PI_OVER_2 - 2.0 * Math.Atan(t); while (Math.Abs(PHI - tempPHI) > 1.0e-10) { tempPHI = PHI; sin_PHI = Math.Sin(PHI); essin = es * sin_PHI; pow_es = polarPow(essin); PHI = PI_OVER_2 - 2.0 * Math.Atan(t * pow_es); } latitude = PHI; longitude = Polar_Central_Meridian + Math.Atan2(dx, -dy); if (longitude > Math.PI) { longitude -= TWO_PI; } else if (longitude < -Math.PI) { longitude += TWO_PI; } // Force distorted values if (latitude > PI_OVER_2) /* force distorted values to 90, -90 degrees */ { latitude = PI_OVER_2; } else if (latitude < -PI_OVER_2) { latitude = -PI_OVER_2; } if (longitude > Math.PI) /* force distorted values to 180, -180 degrees */ { longitude = Math.PI; } else if (longitude < -Math.PI) { longitude = -Math.PI; } } if (Southern_Hemisphere != 0) { latitude *= -1.0; longitude *= -1.0; } return(new GeodeticCoordinates(CoordinateType.Enum.geodetic, longitude, latitude)); }
/// <summary> /// The constructor receives the ellipsoid /// parameters and Polar Stereograpic (Scale Factor) projection parameters as inputs, and /// sets the corresponding state variables. If any errors occur, an /// exception is thrown with a description of the error. /// </summary> /// <param name="ellipsoidSemiMajorAxis">Semi-major axis of ellipsoid, in meters</param> /// <param name="ellipsoidFlattening">Flattening of ellipsoid</param> /// <param name="centralMeridian">Longitude down from pole, in radians</param> /// <param name="scaleFactor">Scale Factor</param> /// <param name="hemisphere">Hemisphere</param> /// <param name="falseEasting">Easting (X) at center of projection, in meters</param> /// <param name="falseNorthing">Northing (Y) at center of projection, in meters</param> public PolarStereographic(double ellipsoidSemiMajorAxis, double ellipsoidFlattening, double centralMeridian, double scaleFactor, char hemisphere, double falseEasting, double falseNorthing) { this.coordinateType = CoordinateType.Enum.polarStereographicScaleFactor; this.es = 0.08181919084262188000; this.es_OVER_2 = .040909595421311; this.Southern_Hemisphere = 0; this.Polar_tc = 1.0; this.Polar_k90 = 1.0033565552493; this.Polar_a_mc = 6378137.0; this.two_Polar_a = 12756274.0; this.Polar_Central_Meridian = 0.0; this.Polar_Standard_Parallel = PI_OVER_2; this.Polar_False_Easting = 0.0; this.Polar_False_Northing = 0.0; this.Polar_Scale_Factor = 1.0; this.Polar_Delta_Easting = 12713601.0; this.Polar_Delta_Northing = 12713601.0; double es2; double sinolat, cosolat; double essin; double pow_es; double mc; double one_PLUS_es, one_MINUS_es; double one_PLUS_es_sk, one_MINUS_es_sk; double sk, sk_PLUS_1; double tolerance = 1.0e-15; int count = 30; double inv_f = 1 / ellipsoidFlattening; string errorStatus = ""; if (ellipsoidSemiMajorAxis <= 0.0) { /* Semi-major axis must be greater than zero */ errorStatus += ErrorMessages.semiMajorAxis; } if ((inv_f < 250) || (inv_f > 350)) { /* Inverse flattening must be between 250 and 350 */ errorStatus += ErrorMessages.ellipsoidFlattening; } if ((scaleFactor < MIN_SCALE_FACTOR) || (scaleFactor > MAX_SCALE_FACTOR)) { errorStatus += ErrorMessages.scaleFactor; } if ((centralMeridian < -Math.PI) || (centralMeridian > TWO_PI)) { /* Origin Longitude out of range */ errorStatus += ErrorMessages.centralMeridian; } if ((hemisphere != 'N') && (hemisphere != 'S')) { errorStatus += ErrorMessages.hemisphere; } if (errorStatus.Length > 0) { // throw CoordinateConversionException(errorStatus); } this.semiMajorAxis = ellipsoidSemiMajorAxis; this.flattening = ellipsoidFlattening; this.Polar_Scale_Factor = scaleFactor; this.Polar_False_Easting = falseEasting; this.Polar_False_Northing = falseNorthing; this.two_Polar_a = 2.0 * this.semiMajorAxis; es2 = 2 * this.flattening - this.flattening * this.flattening; es = Math.Sqrt(es2); es_OVER_2 = es / 2.0; one_PLUS_es = 1.0 + es; one_MINUS_es = 1.0 - es; this.Polar_k90 = Math.Sqrt(Math.Pow(one_PLUS_es, one_PLUS_es) * Math.Pow(one_MINUS_es, one_MINUS_es)); sk = 0; sk_PLUS_1 = -1 + 2 * this.Polar_Scale_Factor; while (Math.Abs(sk_PLUS_1 - sk) > tolerance && count > 0) { sk = sk_PLUS_1; one_PLUS_es_sk = 1.0 + es * sk; one_MINUS_es_sk = 1.0 - es * sk; sk_PLUS_1 = ((2 * this.Polar_Scale_Factor * Math.Sqrt(Math.Pow(one_PLUS_es_sk, one_PLUS_es) * Math.Pow(one_MINUS_es_sk, one_MINUS_es))) / this.Polar_k90) - 1; count--; } if (count > 0) { //throw new ArgumentException(ErrorMessages.originLatitude); } double standardParallel = 0.0; if (sk_PLUS_1 >= -1.0 && sk_PLUS_1 <= 1.0) { standardParallel = Math.Asin(sk_PLUS_1); } else { throw new ArgumentException(ErrorMessages.originLatitude); } if (hemisphere == 'S') { standardParallel *= -1.0; } if (centralMeridian > Math.PI) { centralMeridian -= TWO_PI; } if (standardParallel < 0) { Southern_Hemisphere = 1; Polar_Standard_Parallel = -standardParallel; Polar_Central_Meridian = -centralMeridian; } else { Southern_Hemisphere = 0; Polar_Standard_Parallel = standardParallel; Polar_Central_Meridian = centralMeridian; } sinolat = Math.Sin(Polar_Standard_Parallel); if (Math.Abs(Math.Abs(Polar_Standard_Parallel) - PI_OVER_2) > 1.0e-10) { essin = es * sinolat; pow_es = polarPow(essin); cosolat = Math.Cos(Polar_Standard_Parallel); mc = cosolat / Math.Sqrt(1.0 - essin * essin); Polar_a_mc = semiMajorAxis * mc; Polar_tc = Math.Tan(PI_OVER_4 - Polar_Standard_Parallel / 2.0) / pow_es; } /* Calculate Radius */ MapProjectionCoordinates tempCoordinates = convertFromGeodetic(new GeodeticCoordinates(CoordinateType.Enum.geodetic, centralMeridian, 0)); Polar_Delta_Northing = tempCoordinates.getNorthing(); if (this.Polar_False_Northing > 0) { this.Polar_Delta_Northing -= this.Polar_False_Northing; } if (this.Polar_Delta_Northing < 0) { this.Polar_Delta_Northing = -this.Polar_Delta_Northing; } this.Polar_Delta_Northing *= 1.01; this.Polar_Delta_Easting = this.Polar_Delta_Northing; }
/// <summary> /// The function convertToGeodetic converts Transverse /// Mercator projection (easting and northing) coordinates to geodetic /// (latitude and longitude) coordinates, according to the current ellipsoid /// and Transverse Mercator projection parameters. If any errors occur, /// an exception is thrown with a description of the error. /// </summary> /// <param name="mapProjectionCoordinates"></param> /// <returns></returns> public GeodeticCoordinates convertToGeodetic(MapProjectionCoordinates mapProjectionCoordinates) { /* * easting : Easting/X in meters (input) * northing : Northing/Y in meters (input) * longitude : Longitude in radians (output) * latitude : Latitude in radians (output) */ double c; /* Cosine of latitude */ double de; /* Delta easting - Difference in Easting (easting-Fe) */ double dlam; /* Delta longitude - Difference in Longitude */ double eta1; /* constant - TranMerc_ebs *c *c */ double eta2; double eta3; double eta4; double ftphi; /* Footpoint latitude */ int i; /* Loop iterator */ double s; /* Sine of latitude */ double sn; /* Radius of curvature in the prime vertical */ double sr; /* Radius of curvature in the meridian */ double tan1; /* Tangent of latitude */ double tan2; double tan4; double t10; /* Term in coordinate conversion formula - GP to Y */ double t11; /* Term in coordinate conversion formula - GP to Y */ double t12; /* Term in coordinate conversion formula - GP to Y */ double t13; /* Term in coordinate conversion formula - GP to Y */ double t14; /* Term in coordinate conversion formula - GP to Y */ double t15; /* Term in coordinate conversion formula - GP to Y */ double t16; /* Term in coordinate conversion formula - GP to Y */ double t17; /* Term in coordinate conversion formula - GP to Y */ double tmd; /* True Meridianal distance */ double tmdo; /* True Meridianal distance for latitude of origin */ string errorStatus = ""; double latitude; double longitude; double easting = mapProjectionCoordinates.getEasting(); double northing = mapProjectionCoordinates.getNorthing(); if ((easting < (TranMerc_False_Easting - TranMerc_Delta_Easting)) || (easting > (TranMerc_False_Easting + TranMerc_Delta_Easting))) { /* easting out of range */ errorStatus += ErrorMessages.easting; } if ((northing < (TranMerc_False_Northing - TranMerc_Delta_Northing)) || (northing > (TranMerc_False_Northing + TranMerc_Delta_Northing))) { /* northing out of range */ errorStatus += ErrorMessages.northing; } if (errorStatus.Length > 0) { throw new ArgumentException(errorStatus); } /* True Meridianal Distances for latitude of origin */ tmdo = sphtmd(TranMerc_Origin_Lat); /* Origin */ tmd = tmdo + (northing - TranMerc_False_Northing) / TranMerc_Scale_Factor; /* First Estimate */ sr = sphsr(0.0); ftphi = tmd / sr; for (i = 0; i < 5; i++) { t10 = sphtmd(ftphi); sr = sphsr(ftphi); ftphi += (tmd - t10) / sr; } /* Radius of Curvature in the meridian */ sr = sphsr(ftphi); /* Radius of Curvature in the meridian */ sn = sphsn(ftphi); /* Sine CoMath.Sine terms */ s = Math.Sin(ftphi); c = Math.Cos(ftphi); /* Tangent Value */ tan1 = Math.Tan(ftphi); tan2 = tan1 * tan1; tan4 = tan2 * tan2; eta1 = TranMerc_ebs * Math.Pow(c, 2.0); eta2 = eta1 * eta1; eta3 = eta2 * eta1; eta4 = eta3 * eta1; de = easting - TranMerc_False_Easting; if (Math.Abs(de) < 0.0001) { de = 0.0; } /* Latitude */ t10 = tan1 / (2.0 * sr * sn * Math.Pow(TranMerc_Scale_Factor, 2.0)); t11 = tan1 * (5.0 + 3.0 * tan2 + eta1 - 4.0 * Math.Pow(eta1, 2.0) - 9.0 * tan2 * eta1) / (24.0 * sr * Math.Pow(sn, 3.0) * Math.Pow(this.TranMerc_Scale_Factor, 4.0)); t12 = tan1 * (61.0 + 90.0 * tan2 + 46.0 * eta1 + 45.0 * tan4 - 252.0 * tan2 * eta1 - 3.0 * eta2 + 100.0 * eta3 - 66.0 * tan2 * eta2 - 90.0 * tan4 * eta1 + 88.0 * eta4 + 225.0 * tan4 * eta2 + 84.0 * tan2 * eta3 - 192.0 * tan2 * eta4) / (720.0 * sr * Math.Pow(sn, 5.0) * Math.Pow(this.TranMerc_Scale_Factor, 6.0)); t13 = tan1 * (1385.0 + 3633.0 * tan2 + 4095.0 * tan4 + 1575.0 * Math.Pow(tan1, 6.0)) / (40320.0 * sr * Math.Pow(sn, 7.0) * Math.Pow(TranMerc_Scale_Factor, 8.0)); latitude = ftphi - Math.Pow(de, 2.0) * t10 + Math.Pow(de, 4.0) * t11 - Math.Pow(de, 6.0) * t12 + Math.Pow(de, 8.0) * t13; t14 = 1.0 / (sn * c * this.TranMerc_Scale_Factor); t15 = (1.0 + 2.0 * tan2 + eta1) / (6.0 * Math.Pow(sn, 3.0) * c * Math.Pow(this.TranMerc_Scale_Factor, 3.0)); t16 = (5.0 + 6.0 * eta1 + 28.0 * tan2 - 3.0 * eta2 + 8.0 * tan2 * eta1 + 24.0 * tan4 - 4.0 * eta3 + 4.0 * tan2 * eta2 + 24.0 * tan2 * eta3) / (120.0 * Math.Pow(sn, 5.0) * c * Math.Pow(this.TranMerc_Scale_Factor, 5.0)); t17 = (61.0 + 662.0 * tan2 + 1320.0 * tan4 + 720.0 * Math.Pow(tan1, 6.0)) / (5040.0 * Math.Pow(sn, 7.0) * c * Math.Pow(this.TranMerc_Scale_Factor, 7.0)); /* Difference in Longitude */ dlam = de * t14 - Math.Pow(de, 3.0) * t15 + Math.Pow(de, 5.0) * t16 - Math.Pow(de, 7.0) * t17; /* Longitude */ longitude = this.TranMerc_Origin_Long + dlam; if (Math.Abs(latitude) > PI_OVER_2) { throw new ArgumentException(ErrorMessages.northing); } if (longitude > Math.PI) { longitude -= (2 * Math.PI); if (Math.Abs(longitude) > Math.PI) { throw new ArgumentException(ErrorMessages.easting); } } else if (longitude < -Math.PI) { longitude += (2 * Math.PI); if (Math.Abs(longitude) > Math.PI) { throw new ArgumentException(ErrorMessages.easting); } } if (Math.Abs(dlam) > Math.PI / 20 * Math.Cos(latitude)) { /* Distortion will result if longitude is more than 9 degrees from the Central Meridian at the equator */ /* and decreases to 0 degrees at the poles */ /* As you move towards the poles, distortion will become more significant */ errorStatus += WarningMessages.longitude; } return(new GeodeticCoordinates(CoordinateType.Enum.geodetic, longitude, latitude)); }