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

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. using System.Text;
  42. namespace SharpMap.CoordinateSystems.Projections
  43. {
  44. /// <summary>
  45. /// Projections inherit from this abstract class to get access to useful mathematical functions.
  46. /// </summary>
  47. internal abstract class MapProjection : MathTransform, IProjection
  48. {
  49. protected bool _isInverse = false;
  50. protected bool _isSpherical = false;
  51. protected double _e;
  52. protected double _es;
  53. protected double _semiMajor;
  54. protected double _semiMinor;
  55. protected Collection<ProjectionParameter> _Parameters;
  56. protected MathTransform _inverse;
  57. protected MapProjection(Collection<ProjectionParameter> parameters, bool isInverse)
  58. : this(parameters)
  59. {
  60. _isInverse = isInverse;
  61. }
  62. protected MapProjection(Collection<ProjectionParameter> parameters)
  63. {
  64. _Parameters = parameters;
  65. //todo. Should really convert to the correct linear units??
  66. ProjectionParameter semimajor = GetParameter("semi_major");
  67. ProjectionParameter semiminor = GetParameter("semi_minor");
  68. if(semimajor == null)
  69. throw new ArgumentException("Missing projection parameter 'semi_major'");
  70. if (semiminor == null)
  71. throw new ArgumentException("Missing projection parameter 'semi_minor'");
  72. this._semiMajor = semimajor.Value;
  73. this._semiMinor = semiminor.Value;
  74. this._isSpherical = (_semiMajor == _semiMinor);
  75. this._es = 1.0 - (_semiMinor * _semiMinor ) / ( _semiMajor * _semiMajor);
  76. this._e  = Math.Sqrt(_es);
  77. }
  78. #region Implementation of IProjection
  79. public ProjectionParameter GetParameter(int Index)
  80. {
  81. return this._Parameters[Index];
  82. }
  83. /// <summary>
  84. /// Gets an named parameter of the projection.
  85. /// </summary>
  86. /// <remarks>The parameter name is case insensitive</remarks>
  87. /// <param name="name">Name of parameter</param>
  88. /// <returns>parameter or null if not found</returns>
  89. public ProjectionParameter GetParameter(string name)
  90. {
  91.             //return _Parameters.Find(delegate(ProjectionParameter par)
  92.             //        { return par.Name.Equals(name, StringComparison.OrdinalIgnoreCase); });
  93.             for (int i = 0; i < _Parameters.Count; i++)
  94.                 if (String.Equals(_Parameters[i].Name, name, StringComparison.OrdinalIgnoreCase))
  95.                     return _Parameters[i];
  96.             return null;
  97. }
  98.         public int NumParameters
  99. {
  100. get { return this._Parameters.Count; }
  101. }
  102. public string ClassName
  103. {
  104. get { return this.ClassName; }
  105. }
  106. private string _Abbreviation;
  107. /// <summary>
  108. /// Gets or sets the abbreviation of the object.
  109. /// </summary>
  110. public string Abbreviation
  111. {
  112. get { return _Abbreviation; }
  113. set { _Abbreviation = value; }
  114. }
  115. private string _Alias;
  116. /// <summary>
  117. /// Gets or sets the alias of the object.
  118. /// </summary>
  119. public string Alias
  120. {
  121. get { return _Alias; }
  122. set { _Alias = value; }
  123. }
  124. private string _Authority;
  125. /// <summary>
  126. /// Gets or sets the authority name for this object, e.g., "EPSG",
  127. /// is this is a standard object with an authority specific
  128. /// identity code. Returns "CUSTOM" if this is a custom object.
  129. /// </summary>
  130. public string Authority
  131. {
  132. get { return _Authority; }
  133. set { _Authority = value; }
  134. }
  135. private long _Code;
  136. /// <summary>
  137. /// Gets or sets the authority specific identification code of the object
  138. /// </summary>
  139. public long AuthorityCode
  140. {
  141. get { return _Code; }
  142. set { _Code = value; }
  143. }
  144. private string _Name;
  145. /// <summary>
  146. /// Gets or sets the name of the object.
  147. /// </summary>
  148. public string Name
  149. {
  150. get { return _Name; }
  151. set { _Name = value; }
  152. }
  153. private string _Remarks;
  154. /// <summary>
  155. /// Gets or sets the provider-supplied remarks for the object.
  156. /// </summary>
  157. public string Remarks
  158. {
  159. get { return _Remarks; }
  160. set { _Remarks = value; }
  161. }
  162. /// <summary>
  163. /// Returns the Well-known text for this object
  164. /// as defined in the simple features specification.
  165. /// </summary>
  166. public override string WKT
  167. {
  168. get
  169. {
  170. StringBuilder sb = new StringBuilder();
  171. if (_isInverse)
  172. sb.Append("INVERSE_MT[");
  173. sb.AppendFormat("PARAM_MT["{0}"", this.Name);
  174. for (int i = 0; i < this.NumParameters; i++)
  175. sb.AppendFormat(", {0}", this.GetParameter(i).WKT);
  176. //if (!String.IsNullOrEmpty(Authority) && AuthorityCode > 0)
  177. // sb.AppendFormat(", AUTHORITY["{0}", "{1}"]", Authority, AuthorityCode);
  178. sb.Append("]");
  179. if (_isInverse)
  180. sb.Append("]");
  181. return sb.ToString();
  182. }
  183. }
  184. /// <summary>
  185. /// Gets an XML representation of this object
  186. /// </summary>
  187. public override string XML
  188. {
  189. get
  190. {
  191. StringBuilder sb = new StringBuilder();
  192. sb.Append("<CT_MathTransform>");
  193. if (_isInverse)
  194. sb.AppendFormat("<CT_InverseTransform Name="{0}">", ClassName);
  195. else
  196. sb.AppendFormat("<CT_ParameterizedMathTransform Name="{0}">", ClassName);
  197. for (int i = 0; i < this.NumParameters; i++)
  198. sb.AppendFormat(this.GetParameter(i).XML);
  199. if (_isInverse)
  200. sb.Append("</CT_InverseTransform>");
  201. else
  202. sb.Append("</CT_ParameterizedMathTransform>");
  203. sb.Append("</CT_MathTransform>");
  204. return sb.ToString();
  205. }
  206. }
  207. #endregion
  208. #region IMathTransform
  209. public abstract SharpMap.Geometries.Point MetersToDegrees(SharpMap.Geometries.Point p);
  210. public abstract SharpMap.Geometries.Point DegreesToMeters(SharpMap.Geometries.Point lonlat);
  211. /// <summary>
  212. /// Reverses the transformation
  213. /// </summary>
  214. public override void Invert()
  215. {
  216. _isInverse = !_isInverse;
  217. }
  218. /// <summary>
  219. /// Returns true if this projection is inverted.
  220. /// Most map projections define forward projection as "from geographic to projection", and backwards
  221. /// as "from projection to geographic". If this projection is inverted, this will be the other way around.
  222. /// </summary>
  223. internal bool IsInverse
  224. {
  225. get { return _isInverse; }
  226. }
  227. public override SharpMap.Geometries.Point Transform(SharpMap.Geometries.Point cp)
  228. {
  229. Point projectedPoint = new Point();
  230. if (!_isInverse)
  231. return this.DegreesToMeters(cp);
  232. else
  233. return this.MetersToDegrees(cp);
  234. }
  235. public override Collection<SharpMap.Geometries.Point> TransformList(Collection<SharpMap.Geometries.Point> ord)
  236. {
  237.             //Collection<SharpMap.Geometries.Point> result = new Collection<SharpMap.Geometries.Point>(ord.Count);
  238.             Collection<SharpMap.Geometries.Point> result = new Collection<SharpMap.Geometries.Point>();
  239. for(int i=0; i<ord.Count; i++)
  240. {
  241. SharpMap.Geometries.Point point = ord[i];
  242. result.Add(Transform(point));
  243. }
  244. return result;
  245. }
  246. /// <summary>
  247. /// Checks whether the values of this instance is equal to the values of another instance.
  248. /// Only parameters used for coordinate system are used for comparison.
  249. /// Name, abbreviation, authority, alias and remarks are ignored in the comparison.
  250. /// </summary>
  251. /// <param name="obj"></param>
  252. /// <returns>True if equal</returns>
  253. public bool EqualParams(object obj)
  254. {
  255. if (!(obj is MapProjection))
  256. return false;
  257. MapProjection proj = obj as MapProjection;
  258. if (proj.NumParameters != this.NumParameters)
  259. return false;
  260. for (int i = 0; i < _Parameters.Count; i++)
  261. {
  262.                 //ProjectionParameter param = _Parameters.Find(delegate(ProjectionParameter par) { return par.Name.Equals(proj.GetParameter(i).Name, StringComparison.OrdinalIgnoreCase); });
  263.                 
  264.                 ProjectionParameter param = null;
  265.                 for (int j = 0; j < proj.NumParameters; j++)
  266.                     if (String.Equals(proj.GetParameter(j).Name, _Parameters[i].Name, StringComparison.OrdinalIgnoreCase))
  267.                         param = proj.GetParameter(j);
  268. if (param == null)
  269. return false;
  270. if (param.Value != proj.GetParameter(i).Value)
  271. return false;
  272. }
  273. if (this.IsInverse != proj.IsInverse)
  274. return false;
  275. return true;
  276. }
  277. #endregion
  278. #region Helper mathmatical functions
  279. // defines some usefull constants that are used in the projection routines
  280. /// <summary>
  281. /// PI
  282. /// </summary>
  283. protected const double PI = Math.PI;
  284. /// <summary>
  285. /// Half of PI
  286. /// </summary>
  287. protected const double HALF_PI = (PI*0.5);
  288. /// <summary>
  289. /// PI * 2
  290. /// </summary>
  291. protected const double TWO_PI = (PI*2.0);
  292. /// <summary>
  293. /// EPSLN
  294. /// </summary>
  295. protected const double EPSLN = 1.0e-10;
  296. /// <summary>
  297. /// S2R
  298. /// </summary>
  299. protected const double S2R = 4.848136811095359e-6;
  300. /// <summary>
  301. /// MAX_VAL
  302. /// </summary>
  303. protected const double MAX_VAL = 4;
  304. /// <summary>
  305. /// prjMAXLONG
  306. /// </summary>
  307. protected const double prjMAXLONG = 2147483647;
  308. /// <summary>
  309. /// DBLLONG
  310. /// </summary>
  311. protected const double DBLLONG = 4.61168601e18;
  312. /// <summary>
  313. /// Returns the cube of a number.
  314. /// </summary>
  315. /// <param name="x"> </param>
  316. protected static double CUBE(double x)
  317. {
  318. return Math.Pow(x,3);   /* x^3 */
  319. }
  320. /// <summary>
  321. /// Returns the quad of a number.
  322. /// </summary>
  323. /// <param name="x"> </param>
  324. protected static double QUAD(double x)
  325. {
  326. return Math.Pow(x,4);  /* x^4 */
  327. }
  328. /// <summary>
  329. /// 
  330. /// </summary>
  331. /// <param name="A"></param>
  332. /// <param name="B"></param>
  333. /// <returns></returns>
  334. protected static double GMAX(ref double A,ref double B)
  335. {
  336. return Math.Max(A, B); /* assign maximum of a and b */
  337. }
  338. /// <summary>
  339. /// 
  340. /// </summary>
  341. /// <param name="A"></param>
  342. /// <param name="B"></param>
  343. /// <returns></returns>
  344. protected static double GMIN(ref double A,ref double B)
  345. {
  346. return ((A) < (B) ? (A) : (B)); /* assign minimum of a and b */
  347. }
  348. /// <summary>
  349. /// IMOD
  350. /// </summary>
  351. /// <param name="A"></param>
  352. /// <param name="B"></param>
  353. /// <returns></returns>
  354. protected static double IMOD(double A, double B)
  355. {
  356. return (A) - (((A) / (B)) * (B)); /* Integer mod function */
  357. }
  358. ///<summary>
  359. ///Function to return the sign of an argument
  360. ///</summary>
  361. protected static double sign(double x)
  362. if (x < 0.0) 
  363. return(-1); 
  364. else 
  365. return(1);
  366. }
  367. /// <summary>
  368. /// 
  369. /// </summary>
  370. /// <param name="x"></param>
  371. /// <returns></returns>
  372. protected static double adjust_lon(double x) 
  373. {
  374. long count = 0;
  375. for(;;)
  376. {
  377. if (Math.Abs(x)<=PI)
  378. break;
  379. else
  380. if (((long) Math.Abs(x / Math.PI)) < 2)
  381. x = x-(sign(x) *TWO_PI);
  382. else
  383. if (((long) Math.Abs(x / TWO_PI)) < prjMAXLONG)
  384. {
  385. x = x-(((long)(x / TWO_PI))*TWO_PI);
  386. }
  387. else
  388. if (((long) Math.Abs(x / (prjMAXLONG * TWO_PI))) < prjMAXLONG)
  389. {
  390. x = x-(((long)(x / (prjMAXLONG * TWO_PI))) * (TWO_PI * prjMAXLONG));
  391. }
  392. else
  393. if (((long) Math.Abs(x / (DBLLONG * TWO_PI))) < prjMAXLONG)
  394. {
  395. x = x-(((long)(x / (DBLLONG * TWO_PI))) * (TWO_PI * DBLLONG));
  396. }
  397. else
  398. x = x-(sign(x) *TWO_PI);
  399. count++;
  400. if (count > MAX_VAL)
  401. break;
  402. }
  403. return(x);
  404. }
  405. /// <summary>
  406. /// Function to compute the constant small m which is the radius of
  407. /// a parallel of latitude, phi, divided by the semimajor axis.
  408. /// </summary>
  409. protected static double msfnz (double eccent, double sinphi, double cosphi)
  410. {
  411. double con;
  412. con = eccent * sinphi;
  413. return((cosphi / (Math.Sqrt(1.0 - con * con))));
  414. }
  415. /// <summary>
  416. /// Function to compute constant small q which is the radius of a 
  417. /// parallel of latitude, phi, divided by the semimajor axis. 
  418. /// </summary>
  419. protected static double qsfnz (double eccent, double sinphi, double cosphi)
  420. {
  421. double con;
  422. if (eccent > 1.0e-7)
  423. {
  424. con = eccent * sinphi;
  425. return (( 1.0- eccent * eccent) * (sinphi /(1.0 - con * con) - (.5/eccent)*
  426. Math.Log((1.0 - con)/(1.0 + con))));
  427. }
  428. else
  429. return(2.0 * sinphi);
  430. }
  431. /// <summary>
  432. /// Function to calculate the sine and cosine in one call.  Some computer
  433. /// systems have implemented this function, resulting in a faster implementation
  434. /// than calling each function separately.  It is provided here for those
  435. /// computer systems which don`t implement this function
  436. /// </summary>
  437. protected static void sincos(double val, out double sin_val, out double cos_val) 
  438. sin_val = Math.Sin(val); 
  439. cos_val = Math.Cos(val);
  440. }
  441. /// <summary>
  442. /// Function to compute the constant small t for use in the forward
  443. /// computations in the Lambert Conformal Conic and the Polar
  444. /// Stereographic projections.
  445. /// </summary>
  446. protected static double tsfnz( double eccent,
  447. double phi,
  448. double sinphi
  449. )
  450. {
  451. double con;
  452. double com;
  453. con = eccent * sinphi;
  454. com = .5 * eccent; 
  455. con = Math.Pow(((1.0 - con) / (1.0 + con)),com);
  456. return (Math.Tan(.5 * (HALF_PI - phi))/con);
  457. }
  458. /// <summary>
  459. /// 
  460. /// 
  461. /// </summary>
  462. /// <param name="eccent"></param>
  463. /// <param name="qs"></param>
  464. /// <param name="flag"></param>
  465. /// <returns></returns>
  466. protected static double phi1z(double eccent,double qs,out long flag)
  467. {
  468. double eccnts;
  469. double dphi;
  470. double con;
  471. double com;
  472. double sinpi;
  473. double cospi;
  474. double phi;
  475. flag=0;
  476. //double asinz();
  477. long i;
  478. phi = asinz(.5 * qs);
  479. if (eccent < EPSLN) 
  480. return(phi);
  481. eccnts = eccent * eccent; 
  482. for (i = 1; i <= 25; i++)
  483. {
  484. sincos(phi,out sinpi,out cospi);
  485. con = eccent * sinpi; 
  486. com = 1.0 - con * con;
  487. dphi = .5 * com * com / cospi * (qs / (1.0 - eccnts) - sinpi / com + 
  488. .5 / eccent * Math.Log((1.0 - con) / (1.0 + con)));
  489. phi = phi + dphi;
  490. if (Math.Abs(dphi) <= 1e-7)
  491. return(phi);
  492. }
  493. //p_error ("Convergence error","phi1z-conv");
  494. //ASSERT(FALSE);
  495. throw new ApplicationException("Convergence error.");
  496. }
  497. ///<summary>
  498. ///Function to eliminate roundoff errors in asin
  499. ///</summary>
  500. protected static double asinz (double con)
  501. {
  502. if (Math.Abs(con) > 1.0)
  503. {
  504. if (con > 1.0)
  505. con = 1.0;
  506. else
  507. con = -1.0;
  508. }
  509. return(Math.Asin(con));
  510. }
  511.  
  512. /// <summary>Function to compute the latitude angle, phi2, for the inverse of the
  513. ///   Lambert Conformal Conic and Polar Stereographic projections.
  514. ///   </summary>
  515. protected static double phi2z(double eccent,double ts,out long flag)
  516. /* Spheroid eccentricity */
  517. /* Constant value t */
  518. /* Error flag number */
  519. {
  520. double con;
  521. double dphi;
  522. double sinpi;
  523. long i;
  524. flag = 0;
  525. double eccnth = .5 * eccent;
  526. double chi = HALF_PI - 2 * Math.Atan(ts);
  527. for (i = 0; i <= 15; i++)
  528. {
  529. sinpi = Math.Sin(chi);
  530. con = eccent * sinpi;
  531. dphi = HALF_PI - 2 * Math.Atan(ts *(Math.Pow(((1.0 - con)/(1.0 + con)),eccnth))) -  chi;
  532. chi += dphi; 
  533. if (Math.Abs(dphi) <= .0000000001)
  534. return(chi);
  535. }
  536. throw new ApplicationException("Convergence error - phi2z-conv");
  537. }
  538. ///<summary>
  539. ///Functions to compute the constants e0, e1, e2, and e3 which are used
  540. ///in a series for calculating the distance along a meridian.  The
  541. ///input x represents the eccentricity squared.
  542. ///</summary>
  543. protected static double e0fn(double x)
  544. {
  545. return(1.0-0.25*x*(1.0+x/16.0*(3.0+1.25*x)));
  546. }
  547. /// <summary>
  548. /// 
  549. /// </summary>
  550. /// <param name="x"></param>
  551. /// <returns></returns>
  552. protected static double e1fn(double x)
  553. {
  554. return(0.375*x*(1.0+0.25*x*(1.0+0.46875*x)));
  555. }
  556. /// <summary>
  557. /// 
  558. /// </summary>
  559. /// <param name="x"></param>
  560. /// <returns></returns>
  561. protected static double e2fn(double x)
  562. {
  563. return(0.05859375*x*x*(1.0+0.75*x));
  564. }
  565. /// <summary>
  566. /// 
  567. /// </summary>
  568. /// <param name="x"></param>
  569. /// <returns></returns>
  570. protected static double e3fn(double x)
  571. {
  572. return(x*x*x*(35.0/3072.0));
  573. }
  574. /// <summary>
  575. /// Function to compute the constant e4 from the input of the eccentricity
  576. /// of the spheroid, x.  This constant is used in the Polar Stereographic
  577. /// projection.
  578. /// </summary>
  579. protected static double e4fn(double x)
  580. {
  581. double con;
  582. double com;
  583. con = 1.0 + x;
  584. com = 1.0 - x;
  585. return (Math.Sqrt((Math.Pow(con,con))*(Math.Pow(com,com))));
  586. }
  587. /// <summary>
  588. /// Function computes the value of M which is the distance along a meridian
  589. /// from the Equator to latitude phi.
  590. /// </summary>
  591. protected static double mlfn(double e0,double e1,double e2,double e3,double phi) 
  592. {
  593. return(e0*phi-e1*Math.Sin(2.0*phi)+e2*Math.Sin(4.0*phi)-e3*Math.Sin(6.0*phi));
  594. }
  595. /// <summary>
  596. /// Function to calculate UTM zone number--NOTE Longitude entered in DEGREES!!!
  597. /// </summary>
  598. protected static long calc_utm_zone(double lon)
  599. return((long)(((lon + 180.0) / 6.0) + 1.0)); 
  600. }
  601. #endregion
  602. #region Static Methods;
  603. /// <summary>
  604. /// Converts a longitude value in degrees to radians.
  605. /// </summary>
  606. /// <param name="x">The value in degrees to convert to radians.</param>
  607. /// <param name="edge">If true, -180 and +180 are valid, otherwise they are considered out of range.</param>
  608. /// <returns></returns>
  609. static protected double LongitudeToRadians( double x, bool edge) 
  610. {
  611. if (edge ? (x>=-180 && x<=180) : (x>-180 && x<180))
  612. {
  613. return  Degrees2Radians(x);
  614. }
  615. throw new ArgumentOutOfRangeException("x",x," not a valid longitude in degrees.");
  616. }
  617.   
  618. /// <summary>
  619. /// Converts a latitude value in degrees to radians.
  620. /// </summary>
  621. /// <param name="y">The value in degrees to to radians.</param>
  622. /// <param name="edge">If true, -90 and +90 are valid, otherwise they are considered out of range.</param>
  623. /// <returns></returns>
  624. static protected double LatitudeToRadians(double y, bool edge)
  625. {
  626. if (edge ? (y>=-90 && y<=90) : (y>-90 && y<90))
  627. {
  628. return  Degrees2Radians(y);
  629. }
  630. throw new ArgumentOutOfRangeException("x",y," not a valid latitude in degrees.");
  631. }
  632. #endregion
  633. }
  634. }