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

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.CoordinateSystems.Projections;
  21. namespace SharpMap.CoordinateSystems.Transformations
  22. {
  23. /// <summary>
  24. /// Creates coordinate transformations.
  25. /// </summary>
  26. public class CoordinateTransformationFactory : ICoordinateTransformationFactory
  27. {
  28. #region ICoordinateTransformationFactory Members
  29. /// <summary>
  30. /// Creates a transformation between two coordinate systems.
  31. /// </summary>
  32. /// <remarks>
  33. /// This method will examine the coordinate systems in order to construct
  34. /// a transformation between them. This method may fail if no path between 
  35. /// the coordinate systems is found, using the normal failing behavior of 
  36. /// the DCP (e.g. throwing an exception).</remarks>
  37. /// <param name="sourceCS">Source coordinate system</param>
  38. /// <param name="targetCS">Target coordinate system</param>
  39. /// <returns></returns>
  40. public ICoordinateTransformation CreateFromCoordinateSystems(ICoordinateSystem sourceCS, ICoordinateSystem targetCS)
  41. {
  42. if (sourceCS is IProjectedCoordinateSystem && targetCS is IGeographicCoordinateSystem) //Projected -> Geographic
  43. return Proj2Geog((IProjectedCoordinateSystem)sourceCS, (IGeographicCoordinateSystem)targetCS);
  44. else if (sourceCS is IGeographicCoordinateSystem && targetCS is IProjectedCoordinateSystem) //Geographic -> Projected
  45. return Geog2Proj((IGeographicCoordinateSystem)sourceCS, (IProjectedCoordinateSystem)targetCS);
  46. else if (sourceCS is IGeographicCoordinateSystem && targetCS is IGeocentricCoordinateSystem) //Geocentric -> Geographic
  47. return Geog2Geoc((IGeographicCoordinateSystem)sourceCS, (IGeocentricCoordinateSystem)targetCS);
  48. else if (sourceCS is IGeocentricCoordinateSystem && targetCS is IGeographicCoordinateSystem) //Geocentric -> Geographic
  49. return Geoc2Geog((IGeocentricCoordinateSystem)sourceCS, (IGeographicCoordinateSystem)targetCS);
  50. else if (sourceCS is IProjectedCoordinateSystem && targetCS is IProjectedCoordinateSystem) //Projected -> Projected
  51. return Proj2Proj((sourceCS as IProjectedCoordinateSystem),(targetCS as IProjectedCoordinateSystem));
  52. else if (sourceCS is IGeocentricCoordinateSystem && targetCS is IGeocentricCoordinateSystem) //Geocentric -> Geocentric
  53. return CreateGeoc2Geoc((IGeocentricCoordinateSystem)sourceCS, (IGeocentricCoordinateSystem)targetCS);
  54. else if (sourceCS is IGeographicCoordinateSystem && targetCS is IGeographicCoordinateSystem) //Geographic -> Geographic
  55. return CreateGeog2Geog(sourceCS as IGeographicCoordinateSystem, targetCS as IGeographicCoordinateSystem);
  56. throw new NotSupportedException("No support for transforming between the two specified coordinate systems");
  57. }
  58. #endregion
  59. #region Methods for converting between specific systems
  60. private static ICoordinateTransformation Geog2Geoc(IGeographicCoordinateSystem source, IGeocentricCoordinateSystem target)
  61. {
  62. IMathTransform geocMathTransform = CreateCoordinateOperation(target);
  63. return new CoordinateTransformation(source, target, TransformType.Conversion, geocMathTransform, String.Empty, String.Empty, -1, String.Empty, String.Empty);
  64. }
  65. private static ICoordinateTransformation Geoc2Geog(IGeocentricCoordinateSystem source, IGeographicCoordinateSystem target)
  66. {
  67. IMathTransform geocMathTransform = CreateCoordinateOperation(source).Inverse();
  68. return new CoordinateTransformation(source, target, TransformType.Conversion, geocMathTransform, String.Empty, String.Empty, -1, String.Empty, String.Empty);
  69. }
  70. private static ICoordinateTransformation Proj2Proj(IProjectedCoordinateSystem source, IProjectedCoordinateSystem target)
  71. {
  72. ConcatenatedTransform ct = new ConcatenatedTransform();
  73. CoordinateTransformationFactory ctFac = new CoordinateTransformationFactory();
  74. //First transform from projection to geographic
  75. ct.CoordinateTransformationList.Add(ctFac.CreateFromCoordinateSystems(source, source.GeographicCoordinateSystem));
  76. //Transform geographic to geographic:
  77. ct.CoordinateTransformationList.Add(ctFac.CreateFromCoordinateSystems(source.GeographicCoordinateSystem, target.GeographicCoordinateSystem));
  78. //Transform to new projection
  79. ct.CoordinateTransformationList.Add(ctFac.CreateFromCoordinateSystems(target.GeographicCoordinateSystem, target));
  80. return new CoordinateTransformation(source,
  81. target, TransformType.Transformation, ct,
  82. String.Empty, String.Empty, -1, String.Empty, String.Empty);
  83. }
  84. private static ICoordinateTransformation Geog2Proj(IGeographicCoordinateSystem source, IProjectedCoordinateSystem target)
  85. {
  86. IMathTransform mathTransform = CreateCoordinateOperation(target.Projection, target.GeographicCoordinateSystem.HorizontalDatum.Ellipsoid);
  87. return new CoordinateTransformation(source,target, TransformType.Transformation, mathTransform,
  88. String.Empty, String.Empty, -1, String.Empty, String.Empty);
  89. }
  90. private static ICoordinateTransformation Proj2Geog(IProjectedCoordinateSystem source, IGeographicCoordinateSystem target)
  91. {
  92. IMathTransform mathTransform = CreateCoordinateOperation(source.Projection, source.GeographicCoordinateSystem.HorizontalDatum.Ellipsoid).Inverse();
  93. return new CoordinateTransformation(source, target, TransformType.Transformation, mathTransform,
  94. String.Empty, String.Empty, -1, String.Empty, String.Empty);
  95. }
  96. /// <summary>
  97. /// Geographic to geographic transformation
  98. /// </summary>
  99. /// <remarks>Adds a datum shift if nessesary</remarks>
  100. /// <param name="source"></param>
  101. /// <param name="target"></param>
  102. /// <returns></returns>
  103. private ICoordinateTransformation CreateGeog2Geog(IGeographicCoordinateSystem source, IGeographicCoordinateSystem target)
  104. {
  105. if (source.HorizontalDatum.EqualParams(target.HorizontalDatum))
  106. {
  107. //No datum shift needed
  108. return new CoordinateTransformation(source,
  109. target, TransformType.Conversion, new GeographicTransform(source, target),
  110. String.Empty, String.Empty, -1, String.Empty, String.Empty);
  111. }
  112. else
  113. {
  114. //Create datum shift
  115. //Convert to geocentric, perform shift and return to geographic
  116. CoordinateTransformationFactory ctFac = new CoordinateTransformationFactory();
  117. CoordinateSystemFactory cFac = new CoordinateSystemFactory();
  118. IGeocentricCoordinateSystem sourceCentric = cFac.CreateGeocentricCoordinateSystem(source.HorizontalDatum.Name + " Geocentric",
  119. source.HorizontalDatum, LinearUnit.Metre, source.PrimeMeridian);
  120. IGeocentricCoordinateSystem targetCentric = cFac.CreateGeocentricCoordinateSystem(target.HorizontalDatum.Name + " Geocentric", 
  121. target.HorizontalDatum, LinearUnit.Metre, source.PrimeMeridian);
  122. ConcatenatedTransform ct = new ConcatenatedTransform();
  123. ct.CoordinateTransformationList.Add(ctFac.CreateFromCoordinateSystems(source, sourceCentric));
  124. ct.CoordinateTransformationList.Add(ctFac.CreateFromCoordinateSystems(sourceCentric, targetCentric));
  125. ct.CoordinateTransformationList.Add(ctFac.CreateFromCoordinateSystems(targetCentric, target));
  126. return new CoordinateTransformation(source,
  127. target, TransformType.Transformation, ct,
  128. String.Empty, String.Empty, -1, String.Empty, String.Empty);
  129. }
  130. }
  131. /// <summary>
  132. /// Geocentric to Geocentric transformation
  133. /// </summary>
  134. /// <param name="source"></param>
  135. /// <param name="target"></param>
  136. /// <returns></returns>
  137. private static ICoordinateTransformation CreateGeoc2Geoc(IGeocentricCoordinateSystem source, IGeocentricCoordinateSystem target)
  138. {
  139. ConcatenatedTransform ct = new ConcatenatedTransform();
  140. //Does source has a datum different from WGS84 and is there a shift specified?
  141. if (source.HorizontalDatum.Wgs84Parameters != null && !source.HorizontalDatum.Wgs84Parameters.HasZeroValuesOnly)
  142. ct.CoordinateTransformationList.Add(
  143. new CoordinateTransformation(
  144. ((target.HorizontalDatum.Wgs84Parameters == null || target.HorizontalDatum.Wgs84Parameters.HasZeroValuesOnly) ? target : GeocentricCoordinateSystem.WGS84),
  145. source, TransformType.Transformation,
  146. new DatumTransform(source.HorizontalDatum.Wgs84Parameters)
  147. , "", "", -1, "", ""));
  148. //Does target has a datum different from WGS84 and is there a shift specified?
  149. if (target.HorizontalDatum.Wgs84Parameters != null && !target.HorizontalDatum.Wgs84Parameters.HasZeroValuesOnly)
  150. ct.CoordinateTransformationList.Add(
  151. new CoordinateTransformation(
  152. ((source.HorizontalDatum.Wgs84Parameters == null || source.HorizontalDatum.Wgs84Parameters.HasZeroValuesOnly) ? source : GeocentricCoordinateSystem.WGS84),
  153. target,
  154. TransformType.Transformation,
  155. new DatumTransform(target.HorizontalDatum.Wgs84Parameters).Inverse()
  156. , "", "", -1, "", ""));
  157. if (ct.CoordinateTransformationList.Count == 1) //Since we only have one shift, lets just return the datumshift from/to wgs84
  158. return new CoordinateTransformation(source, target, TransformType.ConversionAndTransformation, ct.CoordinateTransformationList[0].MathTransform, "", "", -1, "", "");
  159. else
  160. return new CoordinateTransformation(source, target, TransformType.ConversionAndTransformation, ct, "", "", -1, "", "");
  161. }
  162. #endregion
  163. private static IMathTransform CreateCoordinateOperation(IGeocentricCoordinateSystem geo)
  164. {
  165. List<ProjectionParameter> parameterList = new List<ProjectionParameter>(2);
  166. parameterList.Add(new ProjectionParameter("semi_major", geo.HorizontalDatum.Ellipsoid.SemiMajorAxis));
  167. parameterList.Add(new ProjectionParameter("semi_minor", geo.HorizontalDatum.Ellipsoid.SemiMinorAxis));
  168. return new GeocentricTransform(parameterList);
  169. }
  170. private static IMathTransform CreateCoordinateOperation(IProjection projection, IEllipsoid ellipsoid)
  171. {
  172.             //Collection<ProjectionParameter> parameterList = new Collection<ProjectionParameter>(projection.NumParameters);
  173.             Collection<ProjectionParameter> parameterList = new Collection<ProjectionParameter>();
  174. for (int i = 0; i < projection.NumParameters; i++)
  175. parameterList.Add(projection.GetParameter(i));
  176. parameterList.Add(new ProjectionParameter("semi_major", ellipsoid.SemiMajorAxis));
  177. parameterList.Add(new ProjectionParameter("semi_minor", ellipsoid.SemiMinorAxis));
  178. IMathTransform transform = null;
  179. switch (projection.ClassName.ToLower())
  180. {
  181. case "mercator_1sp":
  182. case "mercator_2sp":
  183. //1SP
  184. transform = new Mercator(parameterList);
  185. break;
  186. case "transverse_mercator":
  187. transform = new TransverseMercator(parameterList);
  188. break;
  189. case "albers":
  190. transform = new AlbersProjection(parameterList);
  191. break;
  192. case "lambert_conformal_conic":
  193. case "lambert_conformal_conic_2sp":
  194. transform = new LambertConformalConic2SP(parameterList);
  195. break;
  196. default:
  197. throw new NotSupportedException(String.Format("Projection {0} is not supported.", projection.ClassName));
  198. }
  199. return transform;
  200. }
  201. }
  202. }