/Plus/CtpGglMap/Util/GeoUtil.cs
C# | 293 lines | 173 code | 26 blank | 94 comment | 20 complexity | ddda90223dd2bdef088cdf40b6b38ada MD5 | raw file
- /*
- *Author: Jeff Liu
- *
- *Under MIT License
- *jebberwocky@gmail.com
- */
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using CtpGglMap.Core;
- using CtpGglMap.Impl;
-
- namespace CtpGglMap.Util
- {
- /// <summary>
- /// reference:
- /// http://www.appelsiini.net/2008/11/introduction-to-marker-clustering-with-google-maps
- /// </summary>
- public class GeoUtil
- {
- /// <summary>
- /// 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 *
- /// 536870912 pixels. Center of the map in pixel coordinates is 268435456,268435456 which in latitude and longitude would be 0,0.
- /// </summary>
- public const double OFFSET = 268435456;
-
- /// <summary>
- /// OFFSET / Math.PI
- /// </summary>
- public static double RADIUS
- {
- get
- {
- return OFFSET / Math.PI;
- }
- }
-
- /// <summary>
- /// Convert latitude to pixel Y
- /// refer: Mercator projection
- /// http://en.wikipedia.org/wiki/Mercator_projection
- /// &
- /// http://svn.appelsiini.net/svn/javascript/trunk/google_maps_nojs/Google/Maps.php
- /// </summary>
- /// <param name="latitude"></param>
- /// <returns></returns>
- public static int LatToY(double latitude)
- {
- //round($offset - $radius * log((1 + sin($lat * pi() / 180)) / (1 - sin($lat * pi() / 180))) / 2);
- return (int)Math.Round(
- OFFSET - RADIUS *
- Math.Log((1+Math.Sin(latitude*Math.PI/180))/(1-Math.Sin(latitude*Math.PI/180)))/2);
- }
-
- /// <summary>
- /// Convert pixel Y to latitude
- /// </summary>
- /// <param name="Y"></param>
- /// <returns></returns>
- public static double YToLat(int Y)
- {
- double dy = Y * 1.0;
- //(pi() / 2 - 2 * atan(exp((round($y) - self::$offset) / self::$radius))) * 180 / pi();
- return (Math.PI / 2 - 2 * Math.Atan(Math.Exp((Math.Round(dy) - OFFSET) / RADIUS))) * 180 / Math.PI;
- }
-
- /// <summary>
- /// Convert longitude to pixel X
- /// refer:
- /// http://svn.appelsiini.net/svn/javascript/trunk/google_maps_nojs/Google/Maps.php
- /// </summary>
- /// <param name="longtitude"></param>
- /// <returns></returns>
- public static int LongToX(double longtitude)
- {
- //round($offset + $radius * $lon * pi() / 180);
- return (int)Math.Round(OFFSET + RADIUS * longtitude * Math.PI / 180);
- }
-
- /// <summary>
- /// Convert pixel X to longitude
- /// </summary>
- /// <param name="X"></param>
- /// <returns></returns>
- public static double XToLong(int X)
- {
- //((round($x) - self::$offset) / self::$radius) * 180/ pi();
- double dx = X * 1.0;
- return ((Math.Round(dx) - OFFSET) / RADIUS) * 180 / Math.PI;
- }
-
- /// <summary>
- /// Convert GeoPoint to PixelXY
- /// </summary>
- /// <param name="point">GeoPoint object</param>
- /// <returns>converted PixelXY</returns>
- public static PixelXY GeoPointToXY(GeoPoint point)
- {
- if (point != null)
- throw new ArgumentNullException("point can not be null");
- else
- {
- return new PixelXY(GeoUtil.LongToX(point.Lng), GeoUtil.LatToY(point.Lat));
- }
- }
-
- public static GeoPoint XYToGeoPoint(PixelXY xy)
- {
- if (xy != null)
- throw new ArgumentNullException("point could not be null");
- else
- {
- return new GeoPointImpl(GeoUtil.YToLat(xy.Y), GeoUtil.XToLong(xy.X));
- }
- }
-
- public static double adjustLngByPixel(double lng, int delta, int zoom)
- {
- //return self::XToLon(self::LonToX($lon) + ($delta << (21 - $zoom)));
- return XToLong(LongToX(lng) + (delta << (21 - zoom)));
- }
-
- public static double adjustLatByPixel(double lat, int delta, int zoom)
- {
- //return self::YToLat(self::LatToY($lat) + ($delta << (21 - $zoom)));
- return YToLat(LatToY(lat) + (delta << (21 - zoom)));
- }
-
- /// <summary>
- /// calculate the center from list of IMapItem
- /// @since: 1.0.0
- /// </summary>
- /// <param name="items"></param>
- /// <returns></returns>
- public static GeoPoint CalculateCenterFromMapItem(List<IMapItem> items)
- {
- int count = items.Count;
- double total_lat = 0.0;
- double total_lng = 0.0;
- foreach (IMapItem item in items)
- {
- if (item != null)
- {
- if (item.GetType() == typeof(GMarker) || item.GetType().IsSubclassOf(typeof(GMarker)))
- {
- GMarker marker = item as GMarker;
- total_lat += marker.Point.Lat;
- total_lng += marker.Point.Lng;
- }
- }
- }
- GeoPoint point = new GeoPointImpl(total_lat / count, total_lng / count);
- return point;
- }
-
- /// <summary>
- /// calculate the bound for list of IMapItem
- /// @since 1.0.0
- /// </summary>
- /// <param name="map"></param>
- /// <param name="zoom"></param>
- /// <returns></returns>
- public static GBounds CalculateMapBounds(StaticGMap map, int zoom)
- {
- int delta_x = map.Width / 2;
- int delta_y = map.Height / 2;
- double lat = map.Center.Lat;
- double lng = map.Center.Lng;
- double north = GeoUtil.adjustLatByPixel(lat, delta_y * -1, zoom);
- double south = GeoUtil.adjustLatByPixel(lat, delta_y, zoom);
- double west = GeoUtil.adjustLngByPixel(lng, delta_x * -1, zoom);
- double east = GeoUtil.adjustLngByPixel(lng, delta_x, zoom);
-
- GeoPoint nw = new GeoPointImpl(north, west);
- GeoPoint se = new GeoPointImpl(south, east);
-
- return new GBounds(
- new List<GeoPoint>()
- {
- nw, se
- }
- );
- }
-
- /// <summary>
- /// Calculate the geo point from pixel
- /// </summary>
- /// <param name="map"></param>
- /// <param name="zoom"></param>
- /// <param name="xy"></param>
- /// <returns></returns>
- public static GeoPoint CalculateGeoPointFromXY(StaticGMap map, int zoom, PixelXY xy)
- {
- int delta_x = map.Width / 2;
- int delta_y = map.Height / 2;
- int x = xy.X - delta_x;
- int y = xy.Y - delta_y;
-
- return new GeoPointImpl(
- GeoUtil.adjustLatByPixel(map.Center.Lat, y, zoom),
- GeoUtil.adjustLngByPixel(map.Center.Lng, x, zoom)
- );
- }
-
- /// <summary>
- /// get the zoom from list of items
- /// @since 1.0.0
- /// </summary>
- /// <param name="map"></param>
- /// <param name="items"></param>
- /// <returns></returns>
- public static int ZoomToFit(StaticGMap map, List<IMapItem> items)
- {
- int zoom = 21;
- bool found = false;
- GBounds mark_bounds = new GBounds(items);
- while (!found)
- {
- GBounds map_bounds = CalculateMapBounds(map, zoom);
- found = map_bounds.Contains(mark_bounds);
- zoom--;
- }
- return zoom;
- }
-
- public static int ZoomToFit(StaticGMap map, List<IMapItem> items, int delta)
- {
- return ZoomToFit(map, items) + delta;
- }
-
- /// <summary>
- /// calculate the pixel point based on GeoPoint point with center of map
- /// </summary>
- /// <param name="point"></param>
- /// <param name="map"></param>
- /// <returns></returns>
- public static PixelXY CalculateRelativePixelXY(GeoPoint point, IMap map)
- {
- if (map!=null && map.GetType() == typeof(StaticGMap) || map.GetType().IsSubclassOf(typeof(StaticGMap)))
- {
- StaticGMap themap = (StaticGMap)map;
- int center_offset_x = (int)Math.Round((double)themap.Width / 2);
- int center_offset_y = (int)Math.Round((double)themap.Height / 2);
-
- int center_y = GeoUtil.LatToY(themap.Center.Lat);
- int center_x = GeoUtil.LongToX(themap.Center.Lng);
-
- int target_y = GeoUtil.LatToY(point.Lat);
- int target_x = GeoUtil.LongToX(point.Lng);
-
- Console.WriteLine("zoom:" + map.Zoom);
-
- int delta_x = (target_x - center_x) >> (21 - map.Zoom);
- int delta_y = (target_y - center_y) >> (21 - map.Zoom);
-
- int marker_x = center_offset_x + delta_x;
- int marker_y = center_offset_y + delta_y;
-
- return new PixelXY(marker_x, marker_y);
- }
- else
- {
- throw new ArgumentException();
- }
- }
-
- /// <summary>
- /// calculate the distance from point a to point b on the map
- /// </summary>
- /// <param name="a">from</param>
- /// <param name="b">to</param>
- /// <param name="map">map</param>
- /// <returns></returns>
- public static int CalculateDistance(GeoPoint a, GeoPoint b, IMap map)
- {
- if (a != null && b != null && map != null)
- {
- PixelXY _a = CalculateRelativePixelXY(a, map);
- PixelXY _b = CalculateRelativePixelXY(b, map);
- double _xp = Math.Pow((_a.X - _b.X), 2);
- double _yp = Math.Pow((_a.X - _b.Y), 2);
- double _ds = Math.Sqrt(_xp + _yp);
- int intd = Convert.ToInt32(_ds);
- Console.WriteLine("_a:"+_a+", _b:"+_b+", distance: " + intd);
- int d = intd;//(intd >> (21 - map.Zoom));
- return d;
- }
- else
- throw new ArgumentNullException();
- }
- }
- }