/// <summary> /// Gets the distance between 2 points calculated with the curvature of the earth. /// </summary> /// <param name="locationA"> /// The first point. /// </param> /// <param name="locationB"> /// The second point. /// </param> /// <returns> /// The straight line distance in kilometers. /// </returns> public static double GetStraightLineDistance(Location locationA, Location locationB) { /* * Sourced from http://www.movable-type.co.uk/scripts/latlong.html * Javascript code: var R = 6371; // km var dLat = (lat2-lat1).toRad(); var dLon = (lon2-lon1).toRad(); var lat1 = lat1.toRad(); var lat2 = lat2.toRad(); var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); var d = R * c; * * */ const double R = 6371; // Mean radius of the earth in KM double dlat = ToRads(locationB.Latitude - locationA.Latitude); double dlon = ToRads(locationB.Longitude - locationA.Longitude); double lat1 = ToRads(locationA.Latitude); double lat2 = ToRads(locationB.Latitude); double a = (Math.Sin(dlat / 2.0) * Math.Sin(dlat / 2.0)) + (Math.Sin(dlon / 2.0) * Math.Sin(dlon / 2.0) * Math.Cos(lat1) * Math.Cos(lat2)); double c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); return R * c; }
/// <summary> /// Returns the distance between 2 points using the specified transport mode. /// </summary> /// <param name="pointA"> /// The first point /// </param> /// <param name="pointB"> /// The second point /// </param> /// <param name="transportMode"> /// Specified the mode of transport used between points. /// </param> /// <returns> /// The distance between pointA and pointB /// </returns> public Arc GetDistance(Location pointA, Location pointB, TransportMode transportMode) { // Set parameters this.Parameters["mode"] = transportMode.ToString().ToLower(); this.Parameters["origins"] = pointA.ToString(); this.Parameters["destinations"] = pointB.ToString(); // Make XML request XmlDocument doc = this.Request(); if (doc["DistanceMatrixResponse"] == null) { throw new Exception("XML response is invalid."); } XmlNode response = doc["DistanceMatrixResponse"]; // Check for null references if (response == null || response["status"] == null) { throw new Exception("XML response is invalid."); } // Check request status if (response["status"].InnerText != "OK") { throw new GoogleApiException(response["status"].InnerText); } // Check for null references if (response["row"] == null || response["row"]["element"] == null) { throw new Exception("XML response is invalid."); } // Extract element XmlNode element = response["row"]["element"]; // Check for null references if (element["duration"]["value"] == null || element["distance"]["value"] == null) { throw new Exception("XML response is invalid."); } // Get results var duration = new TimeSpan(0, 0, Convert.ToInt32(element["duration"]["value"].InnerText)); double distance = Convert.ToDouble(element["distance"]["value"].InnerText); // Return new object return new Arc( pointA, pointB, new TransportTimeSpan { TravelTime = duration, WaitingTime = default(TimeSpan) }, distance, default(DateTime), transportMode.ToString()); }
/// <summary> /// Estimates the distance between 2 points. This method must always underestimate the time and distance. /// </summary> /// <param name="locationA"> /// The first point. /// </param> /// <param name="locationB"> /// The second point. /// </param> /// <returns> /// The <see cref="Arc"/> representing the distance between the 2 points. /// </returns> public Arc EstimateDistance(Location locationA, Location locationB) { double distance = GeometryHelper.GetStraightLineDistance(locationA, locationB); var time = TimeSpan.FromHours(distance / this.WalkSpeed); return new Arc( locationA, locationB, new TransportTimeSpan { TravelTime = time, WaitingTime = default(TimeSpan) }, distance, default(DateTime), "Walking"); }
/// <summary> /// Initializes a new instance of the <see cref="Arc"/> class. Initializes a new arc defining information between 2 points. /// </summary> /// <param name="source"> /// The source location of the arc. /// </param> /// <param name="destination"> /// The destination location of the arc. /// </param> /// <param name="time"> /// The total time of the arc. /// </param> /// <param name="distance"> /// The total distance in Km of the arc. /// </param> /// <param name="departureTime"> /// The departure time of this arc. Set to default(DateTime) if departure time is not relevant. /// </param> /// <param name="transportMode"> /// Sets the transport id used in the arc. /// </param> public Arc( Location source, Location destination, TransportTimeSpan time, double distance, DateTime departureTime, string transportMode) { this.source = source; this.destination = destination; this.time = time; this.distance = distance; this.transportMode = transportMode; this.departureTime = departureTime; }
/// <summary> /// Gets the path walked from locationA to locationB /// </summary> /// <param name="locationA"> /// The first point. /// </param> /// <param name="locationB"> /// The second point. /// </param> /// <returns> /// A list of <see cref="Location"/> objects that designate a path. /// </returns> public List<Location> GetPath(Location locationA, Location locationB) { //// TODO: Impliment Google walking path finding. throw new NotImplementedException(); }
/// <summary> /// Gets the distance walking from locationA to locationB /// </summary> /// <param name="locationA"> /// The first point. /// </param> /// <param name="locationB"> /// The second point. /// </param> /// <returns> /// The <see cref="Arc"/> representing the distance between the 2 points. /// </returns> public Arc GetDistance(Location locationA, Location locationB) { return this.distanceApi.GetDistance(locationA, locationB, TransportMode.Walking); }
/// <summary> /// Calculates the new position if you were to move along the bearing for a specified distance. /// </summary> /// <param name="initial"> /// The initial location /// </param> /// <param name="bearing"> /// The bearing in degrees from north in degrees. /// </param> /// <param name="distance"> /// The distance travelled in kilometers /// </param> /// <returns> /// The new position. /// </returns> public static Location Travel(Location initial, double bearing, double distance) { /* var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) + Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng) ); var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1), Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2)); * */ const double R = 6371; // Mean radius of the earth in KM bearing = ToRads(bearing); double lat1 = ToRads(initial.Latitude); double lon1 = ToRads(initial.Longitude); double lat2 = Math.Asin( (Math.Sin(lat1) * Math.Cos(distance / R)) + (Math.Cos(lat1) * Math.Sin(distance / R) * Math.Cos(bearing))); double lon2 = lon1 + Math.Atan2( Math.Sin(bearing) * Math.Sin(distance / R) * Math.Cos(lat1), Math.Cos(distance / R) - (Math.Sin(lat1) * Math.Sin(lat2))); lon2 = ((lon2 + (3.0 * Math.PI)) % (2 * Math.PI)) - Math.PI; return new Location(ToDegs(lat2), ToDegs(lon2)); }
/// <summary> /// Returns the distance between 2 points using the default transport mode (driving). /// </summary> /// <param name="pointA"> /// The first point /// </param> /// <param name="pointB"> /// The second point /// </param> /// <returns> /// The distance between pointA and pointB /// </returns> public Arc GetDistance(Location pointA, Location pointB) { return this.GetDistance(pointA, pointB, TransportMode.Driving); }
/// <summary> /// Gets a human readable address that is closest to the provided location. /// </summary> /// <param name="location"> /// A location for which you want to find the nearest address /// </param> /// <returns> /// A string representing a human readable address corresponding to that location. /// </returns> public string GetLocationString(Location location) { this.Parameters.Remove("address"); // Set new request data this.Parameters["latlng"] = location.ToString(); // Perform XML request XmlDocument doc = this.Request(); if (doc["GeocodeResponse"] == null || doc["GeocodeResponse"]["status"] == null) { throw new Exception("XML response is invalid."); } // Check request status if (doc["GeocodeResponse"]["status"].InnerText != "OK") { throw new Exception("Error processing XML request"); } // Get the useful node XmlNode locationNode = doc["GeocodeResponse"]["result"]["formatted_address"]; // Return the new location string return locationNode.InnerText; }