// // Instance Methods // public double DistanceFrom(Location remoteLocation) { Verify(this); Verify(remoteLocation); return Haversine.CalculateDistance(this, remoteLocation); }
/// <summary> /// Creates a box that encloses the specified location, where the sides of the square /// are inRadius miles away from the location at the perpendicular. Note that we do /// not actually generate lat/lon pairs; we only generate the coordinate that /// represents the side of the box. /// </summary> /// <remarks> /// <para>Formula obtained from Dr. Math at http://www.mathforum.org/library/drmath/view/51816.html.</para> /// </remarks> /// <param name="inLocation"></param> /// <param name="inRadius"></param> /// <returns></returns> public static RadiusBox Create(Location inLocation, double inRadius) { /* A point {lat,lon} is a distance d out on the tc radial from point 1 if: lat = asin (sin (lat1) * cos (d) + cos (lat1) * sin (d) * cos (tc)) dlon = atan2 (sin (tc) * sin (d) * cos (lat1), cos (d) - sin (lat1) * sin (lat)) lon = mod (lon1 + dlon + pi, 2 * pi) - pi Where: * d is the distance in radians (an arc), so the desired radius divided by the radius of the Earth. * tc = 0 is N, tc = pi is S, tc = pi/2 is E, tc = 3*pi/2 is W. */ double lat; double dlon; double dLatInRads = inLocation.Latitude * (Math.PI / 180.0); double dLongInRads = inLocation.Longitude * (Math.PI / 180.0); double dDistInRad = inRadius / Globals.EarthRadiusMiles; RadiusBox box = new RadiusBox(); box.Radius = inRadius; // N (tc == 0): // lat = asin (sin(lat1)*cos(d) + cos(lat1)*sin(d)) // = asin (sin(lat1 + d)) // = lat1 + d // Unused: // lon = lon1, because north-south lines follow lines of longitude. box.TopLine = dLatInRads + dDistInRad; box.TopLine *= (180.0 / Math.PI); // S (tc == pi): // lat = asin (sin(lat1)*cos(d) - cos(lat1)*sin(d)) // = asin (sin(lat1 - d)) // = lat1 - d // Unused: // lon = lon1, because north-south lines follow lines of longitude. box.BottomLine = dLatInRads - dDistInRad; box.BottomLine *= (180.0 / Math.PI); // E (tc == pi/2): // lat = asin (sin(lat1)*cos(d)) // dlon = atan2 (sin(tc)*sin(d)*cos(lat1), cos(d) - sin(lat1)*sin(lat)) // lon = mod (lon1 + dlon + pi, 2*pi) - pi lat = Math.Asin(Math.Sin(dLatInRads) * Math.Cos(dDistInRad)); dlon = Math.Atan2(Math.Sin(Math.PI / 2.0) * Math.Sin(dDistInRad) * Math.Cos(dLatInRads), Math.Cos(dDistInRad) - Math.Sin(dLatInRads) * Math.Sin(lat)); box.RightLine = ((dLongInRads + dlon + Math.PI) % (2.0 * Math.PI)) - Math.PI; box.RightLine *= (180.0 / Math.PI); // W (tc == 3*pi/2): // lat = asin (sin(lat1)*cos(d)) // dlon = atan2 (sin(tc)*sin(d)*cos(lat1), cos(d) - sin(lat1)*sin(lat)) // lon = mod (lon1 + dlon + pi, 2*pi) - pi dlon = Math.Atan2(Math.Sin(3.0 * Math.PI / 2.0) * Math.Sin(dDistInRad) * Math.Cos(dLatInRads), Math.Cos(dDistInRad) - Math.Sin(dLatInRads) * Math.Sin(lat)); box.LeftLine = ((dLongInRads + dlon + Math.PI) % (2.0 * Math.PI)) - Math.PI; box.LeftLine *= (180.0 / Math.PI); return box; }
/// <summary> /// Calculates the great-circle distance between two points on a sphere from their /// longitudes and latitudes. /// </summary> /// <remarks>See: http://en.wikipedia.org/wiki/Haversine_formula</remarks> /// <param name="loc1"></param> /// <param name="loc2"></param> /// <returns></returns> public static double CalculateDistance(Location loc1, Location loc2) { /* The Haversine formula according to Dr. Math. http://mathforum.org/library/drmath/view/51879.html dlon = lon2 - lon1 dlat = lat2 - lat1 a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2 c = 2 * atan2(sqrt(a), sqrt(1-a)) d = R * c Where * dlon is the change in longitude * dlat is the change in latitude * c is the great circle distance in Radians. * R is the radius of a spherical Earth. * The locations of the two points in spherical coordinates (longitude and latitude) are lon1,lat1 and lon2, lat2. */ double dDistance = double.MinValue; double dLat1InRad = loc1.Latitude * (Math.PI / 180.0); double dLong1InRad = loc1.Longitude * (Math.PI / 180.0); double dLat2InRad = loc2.Latitude * (Math.PI / 180.0); double dLong2InRad = loc2.Longitude * (Math.PI / 180.0); double dLongitude = dLong2InRad - dLong1InRad; double dLatitude = dLat2InRad - dLat1InRad; // Intermediate result a. double a = Math.Pow(Math.Sin(dLatitude / 2.0), 2.0) + Math.Cos(dLat1InRad) * Math.Cos(dLat2InRad) * Math.Pow(Math.Sin(dLongitude / 2.0), 2.0); // Intermediate result c (great circle distance in Radians). double c = 2.0 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1.0 - a)); // Distance. dDistance = Globals.EarthRadiusMiles * c; return dDistance; }
static void DisplayLocation(Location location) { Console.WriteLine(location); Console.WriteLine(); }
internal static void Verify(Location location) { if (location == null) { throw new ArgumentNullException("location"); } if (location.Latitude == double.MinValue) { throw new ArgumentException("inLoc1.Latitude", string.Format("The database does not contain latitude information for {0}, {1}.", location.City, location.State)); } if (location.Longitude == double.MinValue) { throw new ArgumentException("inLoc1.Longitude", string.Format("The database does not contain longitude information for {0}, {1}.", location.City, location.State)); } }