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

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. using System;
  17. using System.Collections.Generic;
  18. using System.Collections.ObjectModel;
  19. using System.Text;
  20. using SharpMap.Geometries;
  21. using SharpMap.CoordinateSystems;
  22. using SharpMap.CoordinateSystems.Transformations;
  23. namespace SharpMap.CoordinateSystems.Transformations
  24. {
  25. /// <summary>
  26. /// 
  27. /// </summary>
  28. /// <remarks>
  29. /// <para>Latitude, Longitude and ellipsoidal height in terms of a 3-dimensional geographic system
  30. /// may by expressed in terms of a geocentric (earth centered) Cartesian coordinate reference system
  31. /// X, Y, Z with the Z axis corresponding to the earth's rotation axis positive northwards, the X
  32. /// axis through the intersection of the prime meridian and equator, and the Y axis through
  33. /// the intersection of the equator with longitude 90 degrees east. The geographic and geocentric
  34. /// systems are based on the same geodetic datum.</para>
  35. /// <para>Geocentric coordinate reference systems are conventionally taken to be defined with the X
  36. /// axis through the intersection of the Greenwich meridian and equator. This requires that the equivalent
  37. /// geographic coordinate reference systems based on a non-Greenwich prime meridian should first be
  38. /// transformed to their Greenwich equivalent. Geocentric coordinates X, Y and Z take their units from
  39. /// the units of the ellipsoid axes (a and b). As it is conventional for X, Y and Z to be in metres,
  40. /// if the ellipsoid axis dimensions are given in another linear unit they should first be converted
  41. /// to metres.</para>
  42. /// </remarks>
  43. internal class GeocentricTransform : MathTransform
  44. {
  45. private const double COS_67P5 = 0.38268343236508977;  /* cosine of 67.5 degrees */
  46. private const double AD_C = 1.0026000;            /* Toms region 1 constant */
  47.  
  48. protected bool _isInverse = false;
  49. /// <summary>
  50. /// Eccentricity squared : (a^2 - b^2)/a^2
  51. /// </summary>
  52. private double es;
  53. private double semiMajor; // major axis
  54. private double semiMinor; // minor axis
  55. private double ab; // Semi_major / semi_minor
  56. private double ba; // Semi_minor / semi_major
  57. /// <summary>
  58. /// Second eccentricity squared : (a^2 - b^2)/b^2    
  59. /// </summary>
  60. private double ses;
  61. protected List<ProjectionParameter> _Parameters;
  62. protected MathTransform _inverse;
  63. /// <summary>
  64. /// Initializes a geocentric projection object
  65. /// </summary>
  66. /// <param name="parameters">List of parameters to initialize the projection.</param>
  67. /// <param name="isInverse">Indicates whether the projection forward (meters to degrees or degrees to meters).</param>
  68. public GeocentricTransform(List<ProjectionParameter> parameters, bool isInverse)
  69. : this(parameters)
  70. {
  71. _isInverse = isInverse;
  72. }
  73. /// <summary>
  74. /// Initializes a geocentric projection object
  75. /// </summary>
  76. /// <param name="parameters">List of parameters to initialize the projection.</param>
  77. internal GeocentricTransform(List<ProjectionParameter> parameters)
  78. {
  79. _Parameters = parameters;
  80. semiMajor = _Parameters.Find(delegate(ProjectionParameter par)
  81. { return par.Name.Equals("semi_major", StringComparison.OrdinalIgnoreCase); }).Value;
  82. semiMinor = _Parameters.Find(delegate(ProjectionParameter par)
  83. { return par.Name.Equals("semi_minor", StringComparison.OrdinalIgnoreCase); }).Value;
  84. es = 1.0 - (semiMinor * semiMinor) / (semiMajor * semiMajor); //e^2
  85. ses = (Math.Pow(semiMajor, 2) - Math.Pow(semiMinor, 2)) / Math.Pow(semiMinor, 2);
  86. ba = semiMinor / semiMajor;
  87. ab = semiMajor / semiMinor;
  88. }
  89. /// <summary>
  90. /// Returns the inverse of this conversion.
  91. /// </summary>
  92. /// <returns>IMathTransform that is the reverse of the current conversion.</returns>
  93. public override IMathTransform Inverse()
  94. {
  95. if (_inverse == null)
  96. _inverse = new GeocentricTransform(this._Parameters, !_isInverse);
  97. return _inverse;
  98. }
  99. /// <summary>
  100. /// Converts coordinates in decimal degrees to projected meters.
  101. /// </summary>
  102. /// <param name="lonlat">The point in decimal degrees.</param>
  103. /// <returns>Point in projected meters</returns>
  104. private SharpMap.Geometries.Point DegreesToMeters(SharpMap.Geometries.Point lonlat)
  105. {
  106. double lon = Degrees2Radians(lonlat.X);
  107. double lat = Degrees2Radians(lonlat.Y);
  108. double h = 0;
  109. if (lonlat is Point3D) h = (lonlat as Point3D).Z;
  110. double v = semiMajor / Math.Sqrt(1 - es * Math.Pow(Math.Sin(lat), 2));
  111. double x = (v + h) * Math.Cos(lat) * Math.Cos(lon);
  112. double y = (v + h) * Math.Cos(lat) * Math.Sin(lon);
  113. double z = ((1 - es) * v + h) * Math.Sin(lat);
  114. return new SharpMap.Geometries.Point3D(x, y, z);
  115. }
  116. /// <summary>
  117. /// Converts coordinates in projected meters to decimal degrees.
  118. /// </summary>
  119. /// <param name="pnt">Point in meters</param>
  120. /// <returns>Transformed point in decimal degrees</returns>
  121. private SharpMap.Geometries.Point MetersToDegrees(SharpMap.Geometries.Point pnt)
  122. {
  123. if (!(pnt is Point3D))
  124. throw new ArgumentException("Need 3D point to convert from geocentric coordinates");
  125. //The following method is based on Proj.4
  126. bool At_Pole = false; // indicates whether location is in polar region */
  127. double Z = (pnt as Point3D).Z;
  128. double lon = 0;
  129. double lat = 0;
  130. double Height = 0;
  131. if (pnt.X != 0.0)
  132. lon = Math.Atan2(pnt.Y, pnt.X);
  133. else
  134. {
  135. if (pnt.Y > 0)
  136. lon = Math.PI/2;
  137. else if (pnt.Y < 0)
  138. lon = -Math.PI * 0.5;
  139. else
  140. {
  141. At_Pole = true;
  142. lon = 0.0;
  143. if (Z > 0.0)
  144. {  /* north pole */
  145. lat = Math.PI * 0.5;
  146. }
  147. else if (Z < 0.0)
  148. {  /* south pole */
  149. lat = -Math.PI * 0.5;
  150. }
  151. else
  152. {  /* center of earth */
  153. return new Point3D(Radians2Degrees(lon), Radians2Degrees(Math.PI * 0.5), -semiMinor);
  154. }
  155. }
  156. }
  157. double W2 = pnt.X * pnt.X + pnt.Y * pnt.Y; // Square of distance from Z axis
  158. double W = Math.Sqrt(W2); // distance from Z axis
  159. double T0 = Z * AD_C; // initial estimate of vertical component
  160. double S0 = Math.Sqrt(T0 * T0 + W2); //initial estimate of horizontal component
  161. double Sin_B0 = T0 / S0; //sin(B0), B0 is estimate of Bowring aux variable
  162. double Cos_B0 = W / S0; //cos(B0)
  163. double Sin3_B0 = Math.Pow(Sin_B0, 3);
  164. double T1 = Z + semiMinor * ses * Sin3_B0; //corrected estimate of vertical component
  165. double Sum = W - semiMajor * es * Cos_B0 * Cos_B0 * Cos_B0; //numerator of cos(phi1)
  166. double S1 = Math.Sqrt(T1 * T1 + Sum * Sum); //corrected estimate of horizontal component
  167. double Sin_p1 = T1 / S1; //sin(phi1), phi1 is estimated latitude
  168. double Cos_p1 = Sum / S1; //cos(phi1)
  169. double Rn = semiMajor / Math.Sqrt(1.0 - es * Sin_p1 * Sin_p1); //Earth radius at location
  170. if (Cos_p1 >= COS_67P5)
  171. Height = W / Cos_p1 - Rn;
  172. else if (Cos_p1 <= -COS_67P5)
  173. Height = W / -Cos_p1 - Rn;
  174. else
  175. Height = Z / Sin_p1 + Rn * (es - 1.0);
  176. if(!At_Pole)
  177. lat = Math.Atan(Sin_p1 / Cos_p1);
  178. return new Point3D(Radians2Degrees(lon), Radians2Degrees(lat), Height);
  179. }
  180. public override SharpMap.Geometries.Point Transform(SharpMap.Geometries.Point point)
  181. {
  182. if (!_isInverse)
  183. return this.DegreesToMeters(point);
  184. else
  185. return this.MetersToDegrees(point);
  186. }
  187. public override Collection<SharpMap.Geometries.Point> TransformList(Collection<SharpMap.Geometries.Point> points)
  188. {
  189.             //Collection<SharpMap.Geometries.Point> result = new Collection<SharpMap.Geometries.Point>(points.Count);
  190.             Collection<SharpMap.Geometries.Point> result = new Collection<SharpMap.Geometries.Point>();
  191. for (int i = 0; i < points.Count; i++)
  192. {
  193. SharpMap.Geometries.Point point = points[i];
  194. result.Add(Transform(point));
  195. }
  196. return result;
  197. }
  198. /// <summary>
  199. /// Reverses the transformation
  200. /// </summary>
  201. public override void Invert()
  202. {
  203. _isInverse = !_isInverse;
  204. }
  205. public override string WKT
  206. {
  207. get { throw new NotImplementedException("The method or operation is not implemented."); }
  208. }
  209. public override string XML
  210. {
  211. get { throw new NotImplementedException("The method or operation is not implemented."); }
  212. }
  213. }
  214. }