PageRenderTime 85ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/Plus/CtpGglMap/Util/GeoUtil.cs

#
C# | 293 lines | 173 code | 26 blank | 94 comment | 20 complexity | ddda90223dd2bdef088cdf40b6b38ada MD5 | raw file
  1. /*
  2. *Author: Jeff Liu
  3. *
  4. *Under MIT License
  5. *jebberwocky@gmail.com
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Text;
  11. using CtpGglMap.Core;
  12. using CtpGglMap.Impl;
  13. namespace CtpGglMap.Util
  14. {
  15. /// <summary>
  16. /// reference:
  17. /// http://www.appelsiini.net/2008/11/introduction-to-marker-clustering-with-google-maps
  18. /// </summary>
  19. public class GeoUtil
  20. {
  21. /// <summary>
  22. /// It is half of the earth circumference in pixels at zoom level 21. You can visualize it by thinking of full map. Full map size is 536870912 *
  23. /// 536870912 pixels. Center of the map in pixel coordinates is 268435456,268435456 which in latitude and longitude would be 0,0.
  24. /// </summary>
  25. public const double OFFSET = 268435456;
  26. /// <summary>
  27. /// OFFSET / Math.PI
  28. /// </summary>
  29. public static double RADIUS
  30. {
  31. get
  32. {
  33. return OFFSET / Math.PI;
  34. }
  35. }
  36. /// <summary>
  37. /// Convert latitude to pixel Y
  38. /// refer: Mercator projection
  39. /// http://en.wikipedia.org/wiki/Mercator_projection
  40. /// &
  41. /// http://svn.appelsiini.net/svn/javascript/trunk/google_maps_nojs/Google/Maps.php
  42. /// </summary>
  43. /// <param name="latitude"></param>
  44. /// <returns></returns>
  45. public static int LatToY(double latitude)
  46. {
  47. //round($offset - $radius * log((1 + sin($lat * pi() / 180)) / (1 - sin($lat * pi() / 180))) / 2);
  48. return (int)Math.Round(
  49. OFFSET - RADIUS *
  50. Math.Log((1+Math.Sin(latitude*Math.PI/180))/(1-Math.Sin(latitude*Math.PI/180)))/2);
  51. }
  52. /// <summary>
  53. /// Convert pixel Y to latitude
  54. /// </summary>
  55. /// <param name="Y"></param>
  56. /// <returns></returns>
  57. public static double YToLat(int Y)
  58. {
  59. double dy = Y * 1.0;
  60. //(pi() / 2 - 2 * atan(exp((round($y) - self::$offset) / self::$radius))) * 180 / pi();
  61. return (Math.PI / 2 - 2 * Math.Atan(Math.Exp((Math.Round(dy) - OFFSET) / RADIUS))) * 180 / Math.PI;
  62. }
  63. /// <summary>
  64. /// Convert longitude to pixel X
  65. /// refer:
  66. /// http://svn.appelsiini.net/svn/javascript/trunk/google_maps_nojs/Google/Maps.php
  67. /// </summary>
  68. /// <param name="longtitude"></param>
  69. /// <returns></returns>
  70. public static int LongToX(double longtitude)
  71. {
  72. //round($offset + $radius * $lon * pi() / 180);
  73. return (int)Math.Round(OFFSET + RADIUS * longtitude * Math.PI / 180);
  74. }
  75. /// <summary>
  76. /// Convert pixel X to longitude
  77. /// </summary>
  78. /// <param name="X"></param>
  79. /// <returns></returns>
  80. public static double XToLong(int X)
  81. {
  82. //((round($x) - self::$offset) / self::$radius) * 180/ pi();
  83. double dx = X * 1.0;
  84. return ((Math.Round(dx) - OFFSET) / RADIUS) * 180 / Math.PI;
  85. }
  86. /// <summary>
  87. /// Convert GeoPoint to PixelXY
  88. /// </summary>
  89. /// <param name="point">GeoPoint object</param>
  90. /// <returns>converted PixelXY</returns>
  91. public static PixelXY GeoPointToXY(GeoPoint point)
  92. {
  93. if (point != null)
  94. throw new ArgumentNullException("point can not be null");
  95. else
  96. {
  97. return new PixelXY(GeoUtil.LongToX(point.Lng), GeoUtil.LatToY(point.Lat));
  98. }
  99. }
  100. public static GeoPoint XYToGeoPoint(PixelXY xy)
  101. {
  102. if (xy != null)
  103. throw new ArgumentNullException("point could not be null");
  104. else
  105. {
  106. return new GeoPointImpl(GeoUtil.YToLat(xy.Y), GeoUtil.XToLong(xy.X));
  107. }
  108. }
  109. public static double adjustLngByPixel(double lng, int delta, int zoom)
  110. {
  111. //return self::XToLon(self::LonToX($lon) + ($delta << (21 - $zoom)));
  112. return XToLong(LongToX(lng) + (delta << (21 - zoom)));
  113. }
  114. public static double adjustLatByPixel(double lat, int delta, int zoom)
  115. {
  116. //return self::YToLat(self::LatToY($lat) + ($delta << (21 - $zoom)));
  117. return YToLat(LatToY(lat) + (delta << (21 - zoom)));
  118. }
  119. /// <summary>
  120. /// calculate the center from list of IMapItem
  121. /// @since: 1.0.0
  122. /// </summary>
  123. /// <param name="items"></param>
  124. /// <returns></returns>
  125. public static GeoPoint CalculateCenterFromMapItem(List<IMapItem> items)
  126. {
  127. int count = items.Count;
  128. double total_lat = 0.0;
  129. double total_lng = 0.0;
  130. foreach (IMapItem item in items)
  131. {
  132. if (item != null)
  133. {
  134. if (item.GetType() == typeof(GMarker) || item.GetType().IsSubclassOf(typeof(GMarker)))
  135. {
  136. GMarker marker = item as GMarker;
  137. total_lat += marker.Point.Lat;
  138. total_lng += marker.Point.Lng;
  139. }
  140. }
  141. }
  142. GeoPoint point = new GeoPointImpl(total_lat / count, total_lng / count);
  143. return point;
  144. }
  145. /// <summary>
  146. /// calculate the bound for list of IMapItem
  147. /// @since 1.0.0
  148. /// </summary>
  149. /// <param name="map"></param>
  150. /// <param name="zoom"></param>
  151. /// <returns></returns>
  152. public static GBounds CalculateMapBounds(StaticGMap map, int zoom)
  153. {
  154. int delta_x = map.Width / 2;
  155. int delta_y = map.Height / 2;
  156. double lat = map.Center.Lat;
  157. double lng = map.Center.Lng;
  158. double north = GeoUtil.adjustLatByPixel(lat, delta_y * -1, zoom);
  159. double south = GeoUtil.adjustLatByPixel(lat, delta_y, zoom);
  160. double west = GeoUtil.adjustLngByPixel(lng, delta_x * -1, zoom);
  161. double east = GeoUtil.adjustLngByPixel(lng, delta_x, zoom);
  162. GeoPoint nw = new GeoPointImpl(north, west);
  163. GeoPoint se = new GeoPointImpl(south, east);
  164. return new GBounds(
  165. new List<GeoPoint>()
  166. {
  167. nw, se
  168. }
  169. );
  170. }
  171. /// <summary>
  172. /// Calculate the geo point from pixel
  173. /// </summary>
  174. /// <param name="map"></param>
  175. /// <param name="zoom"></param>
  176. /// <param name="xy"></param>
  177. /// <returns></returns>
  178. public static GeoPoint CalculateGeoPointFromXY(StaticGMap map, int zoom, PixelXY xy)
  179. {
  180. int delta_x = map.Width / 2;
  181. int delta_y = map.Height / 2;
  182. int x = xy.X - delta_x;
  183. int y = xy.Y - delta_y;
  184. return new GeoPointImpl(
  185. GeoUtil.adjustLatByPixel(map.Center.Lat, y, zoom),
  186. GeoUtil.adjustLngByPixel(map.Center.Lng, x, zoom)
  187. );
  188. }
  189. /// <summary>
  190. /// get the zoom from list of items
  191. /// @since 1.0.0
  192. /// </summary>
  193. /// <param name="map"></param>
  194. /// <param name="items"></param>
  195. /// <returns></returns>
  196. public static int ZoomToFit(StaticGMap map, List<IMapItem> items)
  197. {
  198. int zoom = 21;
  199. bool found = false;
  200. GBounds mark_bounds = new GBounds(items);
  201. while (!found)
  202. {
  203. GBounds map_bounds = CalculateMapBounds(map, zoom);
  204. found = map_bounds.Contains(mark_bounds);
  205. zoom--;
  206. }
  207. return zoom;
  208. }
  209. public static int ZoomToFit(StaticGMap map, List<IMapItem> items, int delta)
  210. {
  211. return ZoomToFit(map, items) + delta;
  212. }
  213. /// <summary>
  214. /// calculate the pixel point based on GeoPoint point with center of map
  215. /// </summary>
  216. /// <param name="point"></param>
  217. /// <param name="map"></param>
  218. /// <returns></returns>
  219. public static PixelXY CalculateRelativePixelXY(GeoPoint point, IMap map)
  220. {
  221. if (map!=null && map.GetType() == typeof(StaticGMap) || map.GetType().IsSubclassOf(typeof(StaticGMap)))
  222. {
  223. StaticGMap themap = (StaticGMap)map;
  224. int center_offset_x = (int)Math.Round((double)themap.Width / 2);
  225. int center_offset_y = (int)Math.Round((double)themap.Height / 2);
  226. int center_y = GeoUtil.LatToY(themap.Center.Lat);
  227. int center_x = GeoUtil.LongToX(themap.Center.Lng);
  228. int target_y = GeoUtil.LatToY(point.Lat);
  229. int target_x = GeoUtil.LongToX(point.Lng);
  230. Console.WriteLine("zoom:" + map.Zoom);
  231. int delta_x = (target_x - center_x) >> (21 - map.Zoom);
  232. int delta_y = (target_y - center_y) >> (21 - map.Zoom);
  233. int marker_x = center_offset_x + delta_x;
  234. int marker_y = center_offset_y + delta_y;
  235. return new PixelXY(marker_x, marker_y);
  236. }
  237. else
  238. {
  239. throw new ArgumentException();
  240. }
  241. }
  242. /// <summary>
  243. /// calculate the distance from point a to point b on the map
  244. /// </summary>
  245. /// <param name="a">from</param>
  246. /// <param name="b">to</param>
  247. /// <param name="map">map</param>
  248. /// <returns></returns>
  249. public static int CalculateDistance(GeoPoint a, GeoPoint b, IMap map)
  250. {
  251. if (a != null && b != null && map != null)
  252. {
  253. PixelXY _a = CalculateRelativePixelXY(a, map);
  254. PixelXY _b = CalculateRelativePixelXY(b, map);
  255. double _xp = Math.Pow((_a.X - _b.X), 2);
  256. double _yp = Math.Pow((_a.X - _b.Y), 2);
  257. double _ds = Math.Sqrt(_xp + _yp);
  258. int intd = Convert.ToInt32(_ds);
  259. Console.WriteLine("_a:"+_a+", _b:"+_b+", distance: " + intd);
  260. int d = intd;//(intd >> (21 - map.Zoom));
  261. return d;
  262. }
  263. else
  264. throw new ArgumentNullException();
  265. }
  266. }
  267. }