AlbersProjection.cs
上传用户:sex100000
上传日期:2013-11-09
资源大小:1377k
文件大小:13k
源码类别:

GIS编程

开发平台:

C#

  1. // Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
  2. //
  3. // This file is part of SharpMap.
  4. // SharpMap is free software; you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation; either version 2 of the License, or
  7. // (at your option) any later version.
  8. // 
  9. // SharpMap is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. // GNU Lesser General Public License for more details.
  13. // You should have received a copy of the GNU Lesser General Public License
  14. // along with SharpMap; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  16. // SOURCECODE IS MODIFIED FROM ANOTHER WORK AND IS ORIGINALLY BASED ON GeoTools.NET:
  17. /*
  18.  *  Copyright (C) 2002 Urban Science Applications, Inc. 
  19.  *
  20.  *  This library is free software; you can redistribute it and/or
  21.  *  modify it under the terms of the GNU Lesser General Public
  22.  *  License as published by the Free Software Foundation; either
  23.  *  version 2.1 of the License, or (at your option) any later version.
  24.  *
  25.  *  This library is distributed in the hope that it will be useful,
  26.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  27.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  28.  *  Lesser General Public License for more details.
  29.  *
  30.  *  You should have received a copy of the GNU Lesser General Public
  31.  *  License along with this library; if not, write to the Free Software
  32.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  33.  *
  34.  */
  35. using System;
  36. using System.Collections.Generic;
  37. using System.Collections.ObjectModel;
  38. using SharpMap.Geometries;
  39. using SharpMap.CoordinateSystems;
  40. using SharpMap.CoordinateSystems.Transformations;
  41. namespace SharpMap.CoordinateSystems.Projections
  42. {
  43. /// <summary>
  44. /// Implements the Albers projection.
  45. /// </summary>
  46. /// <remarks>
  47. ///  <para>Implements the Albers projection. The Albers projection is most commonly
  48. ///  used to project the United States of America. It gives the northern
  49. ///  border with Canada a curved appearance.</para>
  50. /// 
  51. /// <para>The <a href="http://www.geog.mcgill.ca/courses/geo201/mapproj/naaeana.gif">Albers Equal Area</a>
  52. /// projection has the property that the area bounded
  53. /// by any pair of parallels and meridians is exactly reproduced between the 
  54. /// image of those parallels and meridians in the projected domain, that is,
  55. /// the projection preserves the correct area of the earth though distorts
  56. /// direction, distance and shape somewhat.</para>
  57. /// </remarks>
  58. internal class AlbersProjection : MapProjection
  59. {
  60. double _falseEasting;
  61. double _falseNorthing;
  62. double C; //constant c 
  63. double e; //eccentricity
  64. double e_sq = 0;
  65. double ro0;
  66. double n;
  67. double lon_center; //center longitude   
  68. #region Constructors
  69. /// <summary>
  70. /// Creates an instance of an Albers projection object.
  71. /// </summary>
  72. /// <param name="parameters">List of parameters to initialize the projection.</param>
  73. /// <remarks>
  74. /// <para>The parameters this projection expects are listed below.</para>
  75. /// <list type="table">
  76. /// <listheader><term>Items</term><description>Descriptions</description></listheader>
  77. /// <item><term>latitude_of_false_origin</term><description>The latitude of the point which is not the natural origin and at which grid coordinate values false easting and false northing are defined.</description></item>
  78. /// <item><term>longitude_of_false_origin</term><description>The longitude of the point which is not the natural origin and at which grid coordinate values false easting and false northing are defined.</description></item>
  79. /// <item><term>latitude_of_1st_standard_parallel</term><description>For a conic projection with two standard parallels, this is the latitude of intersection of the cone with the ellipsoid that is nearest the pole.  Scale is true along this parallel.</description></item>
  80. /// <item><term>latitude_of_2nd_standard_parallel</term><description>For a conic projection with two standard parallels, this is the latitude of intersection of the cone with the ellipsoid that is furthest from the pole.  Scale is true along this parallel.</description></item>
  81. /// <item><term>easting_at_false_origin</term><description>The easting value assigned to the false origin.</description></item>
  82. /// <item><term>northing_at_false_origin</term><description>The northing value assigned to the false origin.</description></item>
  83. /// </list>
  84. /// </remarks>
  85. public AlbersProjection(Collection<ProjectionParameter> parameters)
  86. : this(parameters, false)
  87. {
  88. }
  89. /// <summary>
  90. /// Creates an instance of an Albers projection object.
  91. /// </summary>
  92. /// <remarks>
  93. /// <para>The parameters this projection expects are listed below.</para>
  94. /// <list type="table">
  95. /// <listheader><term>Items</term><description>Descriptions</description></listheader>
  96. /// <item><term>latitude_of_center</term><description>The latitude of the point which is not the natural origin and at which grid coordinate values false easting and false northing are defined.</description></item>
  97. /// <item><term>longitude_of_center</term><description>The longitude of the point which is not the natural origin and at which grid coordinate values false easting and false northing are defined.</description></item>
  98. /// <item><term>standard_parallel_1</term><description>For a conic projection with two standard parallels, this is the latitude of intersection of the cone with the ellipsoid that is nearest the pole.  Scale is true along this parallel.</description></item>
  99. /// <item><term>standard_parallel_2</term><description>For a conic projection with two standard parallels, this is the latitude of intersection of the cone with the ellipsoid that is furthest from the pole.  Scale is true along this parallel.</description></item>
  100. /// <item><term>false_easting</term><description>The easting value assigned to the false origin.</description></item>
  101. /// <item><term>false_northing</term><description>The northing value assigned to the false origin.</description></item>
  102. /// </list>
  103. /// </remarks>
  104. /// <param name="parameters">List of parameters to initialize the projection.</param>
  105. /// <param name="isInverse">Indicates whether the projection forward (meters to degrees or degrees to meters).</param>
  106. public AlbersProjection(Collection<ProjectionParameter> parameters, bool isInverse)
  107. : base(parameters, isInverse)
  108. {
  109. this.Name = "Albers_Conic_Equal_Area";
  110. //Retrieve parameters
  111. ProjectionParameter central_meridian = GetParameter("central_meridian");
  112. ProjectionParameter latitude_of_origin = GetParameter("latitude_of_origin");
  113. ProjectionParameter standard_parallel_1 = GetParameter("standard_parallel_1");
  114. ProjectionParameter standard_parallel_2 = GetParameter("standard_parallel_2");
  115. ProjectionParameter false_easting = GetParameter("false_easting");
  116. ProjectionParameter false_northing = GetParameter("false_northing");
  117. //Check for missing parameters
  118. if (central_meridian == null)
  119. throw new ArgumentException("Missing projection parameter 'central_meridian'");
  120. if (latitude_of_origin == null)
  121. throw new ArgumentException("Missing projection parameter 'latitude_of_origin'");
  122. if (standard_parallel_1 == null)
  123. throw new ArgumentException("Missing projection parameter 'standard_parallel_1'");
  124. if (standard_parallel_2 == null)
  125. throw new ArgumentException("Missing projection parameter 'standard_parallel_2'");
  126. if (false_easting == null)
  127. throw new ArgumentException("Missing projection parameter 'false_easting'");
  128. if (false_northing == null)
  129. throw new ArgumentException("Missing projection parameter 'false_northing'");
  130. lon_center = Degrees2Radians(central_meridian.Value);
  131. double lat0 = Degrees2Radians(latitude_of_origin.Value);
  132. double lat1 = Degrees2Radians(standard_parallel_1.Value);
  133. double lat2 = Degrees2Radians(standard_parallel_2.Value);
  134. this._falseEasting = Degrees2Radians(false_easting.Value);
  135. this._falseNorthing = Degrees2Radians(false_northing.Value);
  136. if (Math.Abs(lat1 + lat2) < double.Epsilon)
  137. throw new ApplicationException("Equal latitudes for standard parallels on opposite sides of Equator.");
  138. e_sq = 1.0 - Math.Pow(this._semiMinor / this._semiMajor, 2);
  139. e = Math.Sqrt(e_sq); //Eccentricity
  140. double alpha1 = alpha(lat1);
  141. double alpha2 = alpha(lat2);
  142. double m1 = Math.Cos(lat1) / Math.Sqrt(1 - e_sq * Math.Pow(Math.Sin(lat1), 2));
  143. double m2 = Math.Cos(lat2) / Math.Sqrt(1 - e_sq * Math.Pow(Math.Sin(lat2), 2));
  144. n = (Math.Pow(m1, 2) - Math.Pow(m2, 2)) / (alpha2 - alpha1);
  145. C = Math.Pow(m1, 2) + (n * alpha1);
  146. ro0 = Ro(alpha(lat0));
  147. /*
  148. double sin_p0 = Math.Sin(lat0);
  149. double cos_p0 = Math.Cos(lat0);
  150. double q0 = qsfnz(e, sin_p0, cos_p0);
  151. double sin_p1 = Math.Sin(lat1);
  152. double cos_p1 = Math.Cos(lat1);
  153. double m1 = msfnz(e,sin_p1,cos_p1);
  154. double q1 = qsfnz(e,sin_p1,cos_p1);
  155. double sin_p2 = Math.Sin(lat2);
  156. double cos_p2 = Math.Cos(lat2);
  157. double m2 = msfnz(e,sin_p2,cos_p2);
  158. double q2 = qsfnz(e,sin_p2,cos_p2);
  159. if (Math.Abs(lat1 - lat2) > EPSLN)
  160. ns0 = (m1 * m1 - m2 * m2)/ (q2 - q1);
  161. else
  162. ns0 = sin_p1;
  163. C = m1 * m1 + ns0 * q1;
  164. rh = this._semiMajor * Math.Sqrt(C - ns0 * q0)/ns0;
  165. */
  166. }
  167. #endregion
  168. #region Public methods
  169. /// <summary>
  170. /// Converts coordinates in decimal degrees to projected meters.
  171. /// </summary>
  172. /// <param name="lonlat">The point in decimal degrees.</param>
  173. /// <returns>Point in projected meters</returns>
  174. public override SharpMap.Geometries.Point DegreesToMeters(SharpMap.Geometries.Point lonlat)
  175. {
  176. double dLongitude = Degrees2Radians(lonlat.X);
  177. double dLatitude = Degrees2Radians(lonlat.Y);
  178. double a = alpha(dLatitude);
  179. double ro = Ro(a);
  180. double theta = n * (dLongitude - lon_center);
  181. return new Point(
  182. _falseEasting + ro * Math.Sin(theta),
  183. _falseNorthing + ro0 - (ro * Math.Cos(theta)));
  184. /*
  185. double sin_phi,cos_phi; // sine and cos values
  186. double qs; // small q
  187. double theta; // angle
  188. double rh1; // height above ellipsoid
  189. sincos(dLatitude,out sin_phi,out cos_phi);
  190. qs = qsfnz(e,sin_phi,cos_phi);
  191. rh1 = this._semiMajor * Math.Sqrt(C - ns0 * qs)/ns0;
  192. theta = ns0 * adjust_lon(dLongitude - lon_center);
  193. return new SharpMap.Geometries.Point(
  194. rh1 * Math.Sin(theta) + this._falseEasting,
  195. rh - rh1 * Math.Cos(theta) + this._falseNorthing);
  196. */
  197. }
  198. /// <summary>
  199. /// Converts coordinates in projected meters to decimal degrees.
  200. /// </summary>
  201. /// <param name="p">Point in meters</param>
  202. /// <returns>Transformed point in decimal degrees</returns>
  203. public override SharpMap.Geometries.Point MetersToDegrees(SharpMap.Geometries.Point p) 
  204. {
  205. double theta = Math.Atan((p.X - _falseEasting) / (ro0 - (p.Y - _falseNorthing)));
  206. double ro = Math.Sqrt(Math.Pow(p.X - _falseEasting, 2) + Math.Pow(ro0 - (p.Y - _falseNorthing), 2));
  207. double q = (C - Math.Pow(ro, 2) * Math.Pow(n, 2) / Math.Pow(this._semiMajor, 2)) / n;
  208. double b = Math.Sin(q / (1 - ((1 - e_sq) / (2 * e)) * Math.Log((1 - e) / (1 + e))));
  209. double lat = Math.Asin(q * 0.5);
  210. double preLat = double.MaxValue;
  211. int iterationCounter = 0;
  212. while (Math.Abs(lat - preLat) > 0.000001)
  213. {
  214. preLat = lat;
  215. double sin = Math.Sin(lat);
  216. double e2sin2 = e_sq * Math.Pow(sin, 2);
  217. lat += (Math.Pow(1 - e2sin2, 2) / (2 * Math.Cos(lat))) * ((q / (1 - e_sq)) - sin / (1 - e2sin2) + 1 / (2 * e) * Math.Log((1 - e * sin) / (1 + e * sin)));
  218. iterationCounter++;
  219. if (iterationCounter > 25)
  220. throw new ApplicationException("Transformation failed to converge in Albers backwards transformation");
  221. }
  222. double lon = lon_center + (theta / n);
  223. return new SharpMap.Geometries.Point(Radians2Degrees(lon), Radians2Degrees(lat));
  224. }
  225. /// <summary>
  226. /// Returns the inverse of this projection.
  227. /// </summary>
  228. /// <returns>IMathTransform that is the reverse of the current projection.</returns>
  229. public override IMathTransform Inverse()
  230. {
  231. if (_inverse == null)
  232. {
  233. _inverse = new AlbersProjection(this._Parameters, !_isInverse);
  234. }
  235. return _inverse;
  236. }
  237. #endregion
  238. #region Math helper functions
  239. //private double ToAuthalic(double lat)
  240. //{
  241. //    return Math.Atan(Q(lat) / Q(Math.PI * 0.5));
  242. //}
  243. //private double Q(double angle)
  244. //{
  245. //    double sin = Math.Sin(angle);
  246. //    double esin = e * sin;
  247. //    return Math.Abs(sin / (1 - Math.Pow(esin, 2)) - 0.5 * e) * Math.Log((1 - esin) / (1 + esin)));
  248. //}
  249. private double alpha(double lat)
  250. {
  251. double sin = Math.Sin(lat);
  252. double sinsq = Math.Pow(sin,2);
  253. return (1 - e_sq) * (((sin / (1 - e_sq * sinsq)) - 1/(2 * e) * Math.Log((1 - e * sin) / (1 + e * sin))));
  254. }
  255. private double Ro(double a)
  256. {
  257. return this._semiMajor * Math.Sqrt((C - n * a)) / n;
  258. }
  259. #endregion
  260. }
  261. }