This commit is contained in:
Ricky Brundritt 2017-12-14 12:23:08 -08:00
Родитель b1c4eb059e
Коммит 4e1937ed36
69 изменённых файлов: 4749 добавлений и 721 удалений

2
.gitignore поставляемый
Просмотреть файл

@ -276,4 +276,4 @@ __pycache__/
# Ignore updates to the App.config file in the sample app. This file will contain sensitive data (credentials). By uploading an empty version of it earlier and now ignoring it, this will prevent credentials from being published to GitHub.
App.config
# App.config

Просмотреть файл

@ -37,6 +37,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{5F797BB6-1
Docs\Readme.md = Docs\Readme.md
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TravellingSalesmenRouteSample", "Samples\WPF\TravellingSalesmenRouteSample\TravellingSalesmenRouteSample.csproj", "{5173922A-0160-4EE1-9AD8-F629B23CFE71}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -63,6 +65,10 @@ Global
{1BCB3853-DAFE-4B33-9888-23666A1040B9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1BCB3853-DAFE-4B33-9888-23666A1040B9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1BCB3853-DAFE-4B33-9888-23666A1040B9}.Release|Any CPU.Build.0 = Release|Any CPU
{5173922A-0160-4EE1-9AD8-F629B23CFE71}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5173922A-0160-4EE1-9AD8-F629B23CFE71}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5173922A-0160-4EE1-9AD8-F629B23CFE71}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5173922A-0160-4EE1-9AD8-F629B23CFE71}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -76,5 +82,6 @@ Global
{F30DC2E6-FE4F-4F0B-BD52-CDA1940CAC4F} = {A155C82A-42DC-4206-8DA8-C9C8CC3BFFE2}
{1BCB3853-DAFE-4B33-9888-23666A1040B9} = {80170A9E-5ACF-483A-8A8E-18CA7B0C9A34}
{5F797BB6-13E8-4A02-BC01-613FC791EB41} = {833D0345-46F0-486E-9BEF-5269405683F8}
{5173922A-0160-4EE1-9AD8-F629B23CFE71} = {26E65B0F-9554-408A-95D4-BDEC52945FC3}
EndGlobalSection
EndGlobal

Просмотреть файл

@ -2,7 +2,7 @@
<package xmlns="http://schemas.microsoft.com/packaging/2013/01/nuspec.xsd">
<metadata>
<id>BingMapsRESTToolkit</id>
<version>1.0.8</version>
<version>1.0.9</version>
<title>Bing Maps REST Services Toolkit</title>
<authors>Microsoft</authors>
<owners>microsoft bingmaps</owners>

Просмотреть файл

@ -1,13 +1,23 @@
## Version 1.0.8
## Version 1.0.9 - 12/14/2017
* Add support for Truck Routing API.
* Add support for Isochrones API.
* Add support for Snap to Road API.
* Add Travelling Salesmen extension which includes 2 different TSP algorithms; greedy brute forcem and genetic approximation.
* Extended the RouteRequest class to support waypoint optimization as part of the request.
* Added a WPF sample for the travelling salesmen which demostrates the ease of calculating a route with optimized waypoints.
* Extended DistanceMatrix class with method to get edge/path (array of waypoint indicies to pass through) time/distance for easier analysis.
## Version 1.0.8 - 10/23/2017
* Fix stack overflow issue when calculating short routes.
## Version 1.0.7
## Version 1.0.7 - 10/19/2017
* Extended the RouteRequest class so that it can support more than 25 waypoints. It will simply break the request up into multiple sub-requests, process them, then merge the responses together.
* Extended the RouteRequest class so that it can support more than 25 waypoints for driving, walking and transit routes. It will simply break the request up into multiple sub-requests, process them, then merge the responses together.
* Bug fix for Distance Matrix waypoint geocoding.
## Version 1.0.6
## Version 1.0.6 - 10/2/2017
* Created a .NET Standard v1.4 assembly.
* Add Custom Map Styles support for static images.

Просмотреть файл

@ -1,8 +1,5 @@
Table of contents
=================
# Table of contents
* [ServiceManager Class](#ServiceManager)
* [CustomMapStyleManager Class](#CustomMapStyleManager)
* [Request Classes](#RequestClasses)
- [BaseRestRequest Class](#BaseRestRequest)
- [BaseImageryRestRequest Class](#BaseImageryRestRequest)
@ -11,69 +8,56 @@ Table of contents
- [GeocodeRequest Class](#GeocodeRequest)
- [ImageryMetadataRequest Class](#ImageryMetadataRequest)
- [ImageryRequest Class](#ImageryRequest)
- [IsochroneRequest Class](#IsochroneRequest)
- [ReverseGeocodeRequest Class](#ReverseGeocodeRequest)
- [RouteMajorRoadsRequest Class](#RouteMajorRoadsRequest)
- [RouteRequest Class](#RouteRequest)
- [SnapToRoadRequest Class](#SnapToRoadRequest)
- [TrafficRequest Class](#TrafficRequest)
* [Common Classes](#CommonClasses)
- [BoundingBox Class](#BoundingBox)
- [Coordinate Class](#Coordinate)
- [CustomMapStyleManager Class](#CustomMapStyleManager)
- [ImageryPushpin Class](#ImageryPushpin)
- [PointCompression Class](#PointCompression)
- [RouteOptions Class](#RouteOptions)
- [SimpleAddress Class](#SimpleAddress)
- [ServiceManager Class](#ServiceManager)
- [SimpleAddress Class](#SimpleAddress)
- [SimpleWaypoint Class](#SimpleWaypoint)
- [VehicleSpec Class](#VehicleSpec)
* [Enumerations](#Enumerations)
- [AvoidType Enumeration](#AvoidType)
- [ConfidenceLevel Enumeration](#ConfidenceLevel)
- [ConfidenceLevelType Enumeration](#ConfidenceLevelType)
- [DimensionUnitType Enumeration](#DimensionUnitType)
- [DistanceUnitType Enumeration](#DistanceUnitType)
- [ElevationType Enumeration](#ElevationType)
- [EntityType Enumeration](#EntityType)
- [HazardousMaterialPermitType Enumeration](#HazardousMaterialPermitType)
- [HazardousMaterialType Enumeration](#HazardousMaterialType)
- [ImageFormatType Enumeration](#ImageFormatType)
- [ImageryType Enumeration](#ImageryType)
- [RouteAttributeType Enumeration](#RouteAttributeType)
- [RouteOptimizationType Enumeration](#RouteOptimizationType)
- [RouteTimeType Enumeration](#RouteTimeType)
- [SeverityType Enumeration](#SeverityType)
- [SpeedUnitType Enumeration](#SpeedUnitType)
- [TimeUnitType Enumeration](#TimeUnitType)
- [TrafficType Enumeration](#TrafficType)
- [TravelModeType Enumeration](#TravelModeType)
- [WeightUnitType Enumeration](#WeightUnitType)
* [Enhanced Response Classes](#EnhancedResponseClasses)
- [DistanceMatrix Class](#DistanceMatrix)
* [Extension Classes](#ExtensionClasses)
- [TravellingSalesmen Classes](#TravellingSalesmen)
- [TspOptimizationType Enumeration](#TspOptimizationType)
- [TspSolution Class](#TspSolution)
This documentation does not include the class definitions for the REST Response. These are documented in the Bing Maps MSDN documentation [here](https://msdn.microsoft.com/en-us/library/ff701707.aspx).
<a name="ServiceManager"></a> ServiceManager Class
==================================================
# <a name="RequestClasses"></a> Request Classes
This is a static class that is used for processing all requests to the Bing Maps REST Services asynchronously.
Static Methods
--------------
| Name | Return Type | Description |
|------------------------------------------------------|----------------------|----------------------|
| GetResponseAsync([BaseRestRequest](#BaseRestRequest) request) | Task&lt;Response&gt; | Processes a REST requests that returns data. |
| GetResponseAsync([BaseRestRequest](#BaseRestRequest) request, Action<int> remainingTimeCallback) | Task&lt;Response&gt; | Processes a REST requests that returns data. |
| GetImageAsync([BaseImageryRestRequest](#BaseImageryRestRequest) imageryRequest) | Task&lt;Stream&gt; | Processes a REST requests that returns an image stream. |
<a name="CustomMapStyleManager"></a> CustomMapStyleManager Class
==================================================
A static class to assit with working with Bing Maps Customer Map Styles.
Static Methods
--------------
| Name | Return Type | Description |
|------------------------------------------------------|----------------------|----------------------|
| GetRestStyle(string style) | string | Converts a custom JSON map style, into a style using the REST parameter format. If the style is already in the REST parameter formatter, it will be unaltered. |
<a name="RequestClasses"></a> Request Classes
===============
<a name="BaseRestRequest"></a> BaseRestRequest Class
---------------------
## <a name="BaseRestRequest"></a> BaseRestRequest Class
An abstract class in which all REST service requests derive from.
@ -81,8 +65,8 @@ An abstract class in which all REST service requests derive from.
| Name | Return Type | Description |
|-----------------|-------------|-----------------------------------------------------------------|
| Execute() | Task<Response> | Executes the request. |
| Execute(Action<int> remainingTimeCallback) | Task<Response> | Executes the request. |
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetRequestUrl() | string | Abstract method which generates the Bing Maps REST request URL. |
### Properties
@ -96,13 +80,11 @@ An abstract class in which all REST service requests derive from.
| UserLocation | [Coordinate](#Coordinate) | The users current position. |
| UserMapView | [BoundingBox](#BoundingBox) | The geographic region that corresponds to the current viewport. |
<a name="BaseImageryRestRequest"></a> BaseImageryRestRequest Class
----------------------------
## <a name="BaseImageryRestRequest"></a> BaseImageryRestRequest Class
Abstract class that all Imagery rest requests will derive from. Inherits from the BaseRestRequest class and currently exposes all the same properties and methods.
<a name="DistanceMatrixRequest"></a> Distance Matrix Request
----------------------
## <a name="DistanceMatrixRequest"></a> Distance Matrix Request
A request that calculates a distance matrix between origins and destinations. Inherits from the BaseRestRequest class.
@ -110,10 +92,10 @@ Abstract class that all Imagery rest requests will derive from. Inherits from th
| Name | Return Type | Description |
|---------------------------|------------------------|----------------|
| Execute() | Task<Response> | Executes the request. |
| Execute(Action<int> remainingTimeCallback) | Task<Response> | Executes the request. |
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GeocodeWaypoints() | Task | Geocodes the origins and destinations. |
| GetEuclideanDistanceMatrix() | Task&lt;[DistanceMatrix](#DistanceMatrix)&gt; | Calculates a Distance Matrix for the origins and destinations based on the euclidean distance (straight line/as the crow flies). This calculation only uses; Origins, Destinations, and Distance Units properties from the request and only calculates travel distance. |
| GetEuclideanDistanceMatrix() | Task\<[DistanceMatrix](#DistanceMatrix)\> | Calculates a Distance Matrix for the origins and destinations based on the euclidean distance (straight line/as the crow flies). This calculation only uses; Origins, Destinations, and Distance Units properties from the request and only calculates travel distance. |
| GetNumberOfCoordinatePairs() | int | Returns the number of coordinate pairs that would be in the resulting matrix based on the number of origins and destinations in the request. |
| GetPostRequestBody() | string | Returns a JSON string object representing the request. |
| GetRequestUrl() | string | Gets the request URL to perform a query for a distance matrix when using POST. |
@ -122,8 +104,8 @@ Abstract class that all Imagery rest requests will derive from. Inherits from th
| Name | Type | Description |
|------------|-------------|
| origins | List&lt;[SimpleWaypoint](#SimpleWaypoint)&gt; |**Required**. List of origins. |
| destinations | List&lt;[SimpleWaypoint](#SimpleWaypoint)&gt; | **Required**. List of destinations. |
| origins | List\<[SimpleWaypoint](#SimpleWaypoint)\> |**Required**. List of origins. |
| destinations | List\<[SimpleWaypoint](#SimpleWaypoint)\> | **Required**. List of destinations. |
| TravelMode | [TravelModeType](#TravelModeType) | **Required**. Specifies the mode of transportation to use when calculating the distance matrix. |
| StartTime | DateTime | **Optional for Driving**. Specifies the start or departure time of the matrix to calculate and uses predictive traffic data. |
| endTime | DateTime | **Optional for Driving**. If specified, a matrix based on traffic data with contain a histogram of travel times and distances for the specified resolution intervals (default is 15 minutes) between the start and end times. A start time must be specified for the request to be valid and the total time between start and end cannot be greater than 24 hours. |
@ -131,8 +113,7 @@ Abstract class that all Imagery rest requests will derive from. Inherits from th
| distanceUnit | [DistanceUnitType](#DistanceUnitType) | **Optional.** The units to use for distances in the response. |
| timeUnit | [TimeUnitType](#TimeUnitType) | **Optional.** The units to use for time durations in the response. |
<a name="ElevationRequest"></a> ElevationRequest Class
----------------------
## <a name="ElevationRequest"></a> ElevationRequest Class
A request for elevation data. Inherits from the BaseRestRequest class.
@ -140,9 +121,9 @@ A request for elevation data. Inherits from the BaseRestRequest class.
| Name | Return Type | Description |
|---------------------------|------------------------|----------------|
| Execute() | Task<Response> | Executes the request. |
| Execute(Action<int> remainingTimeCallback) | Task<Response> | Executes the request. |
| GetElevationCoordinates() | List&lt;[Coordinate](#Coordinate)&gt; | Gets a list of coordinates that are related to the returned index of the elevation data. |
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetElevationCoordinates() | List\<[Coordinate](#Coordinate)\> | Gets a list of coordinates that are related to the returned index of the elevation data. |
| GetPointsAsString() | string | Returns the Point information as a formatted string. Only the first 1024 points will be used. Example: `points=38.8895,77.0501,38.8877,-77.0472,38.8904,-77.0474,38.8896,77.0351` |
| GetPostRequestUrl() | string | Gets a URL for requesting elevation data for a POST request. |
| GetRequestUrl() | string | Gets a URL for requesting elevation data for a GET request. |
@ -155,13 +136,12 @@ A request for elevation data. Inherits from the BaseRestRequest class.
| Col | int | Specifies the number of columns to use to divide the bounding box area into a grid. The rows and columns that define the bounding box each count as two (2) of the rows and columns. Elevation values are returned for all vertices of the grid. |
| GetGeoidOffset | bool | A boolean indicating if the offset from the geoid should be returned. Requires a list of points to be specified. |
| Height | [ElevationType](#ElevationType) | Specifies which sea level model to use to calculate elevation. |
| Points | List&lt;[Coordinate](#Coordinate)&gt; | A set of coordinates on the Earth to use in elevation calculations. The exact use of these points depends on the type of elevation request. Overrides the Bounds value if both are specified. The maximum number of points is 1024. |
| Points | List\<[Coordinate](#Coordinate)\> | A set of coordinates on the Earth to use in elevation calculations. The exact use of these points depends on the type of elevation request. Overrides the Bounds value if both are specified. The maximum number of points is 1024. |
| Row | int | Specifies the number of rows to use to divide the bounding box area into a grid. The rows and columns that define the bounding box each count as two (2) of the rows and columns. Elevation values are returned for all vertices of the grid. |
| Samples | int | Specifies the number of equally-spaced elevation values to provide along a polyline path. Used when Points value is set. Make = 1024 |
| Bounds | [BoundingBox](#BoundingBox) | Specifies the rectangular area over which to provide elevation values. |
<a name="GeocodeRequest"></a> GeocodeRequest Class
--------------------
## <a name="GeocodeRequest"></a> GeocodeRequest Class
Geocodes a query to its coordinates. Inherits from the BaseRestRequest class.
@ -169,8 +149,8 @@ Geocodes a query to its coordinates. Inherits from the BaseRestRequest class.
| Name | Return Type | Description |
|-----------------|-------------|-------------------|
| Execute() | Task<Response> | Executes the request. |
| Execute(Action<int> remainingTimeCallback) | Task<Response> | Executes the request. |
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetRequestUrl() | string | Gets the request URL. If both a Query and Address are specified, the Query value will be used. Throws an exception if a Query or Address value is not specified. |
### Properties
@ -183,8 +163,7 @@ Geocodes a query to its coordinates. Inherits from the BaseRestRequest class.
| MaxResults | int | Specifies the maximum number of locations to return in the response. |
| Query | string | A free form string address or Landmark. Overrides the Address values if both are specified. |
<a name="ImageryMetadataRequest"></a> ImageryMetadataRequest Class
----------------------------
## <a name="ImageryMetadataRequest"></a> ImageryMetadataRequest Class
Requests imagery metadata information from Bing Maps. Inherits from the BaseRestRequest class.
@ -192,8 +171,8 @@ Requests imagery metadata information from Bing Maps. Inherits from the BaseRest
| Name | Return Type | Description |
|-----------------|-------------|--------------------------------------------|
| Execute() | Task<Response> | Executes the request. |
| Execute(Action<int> remainingTimeCallback) | Task<Response> | Executes the request. |
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetRequestUrl() | string | Gets the request URL. Throws an exception if a zoom level is not specified when a centerPoint is specified when ImagerySet is Road, Aerial and AerialWithLabels. |
### Properties
@ -208,8 +187,7 @@ Requests imagery metadata information from Bing Maps. Inherits from the BaseRest
| UseHTTPS | bool | When set to true tile URL's will use HTTPS. |
| ZoomLevel | int | Required if a centerPoint is specified and imagerySet is set to Road, Aerial or AerialWithLabels The level of zoom to use for the imagery metadata. |
<a name="ImageryRequest"></a> ImageryRequest Class
====================
## <a name="ImageryRequest"></a> ImageryRequest Class
Requests an image from the REST imagery service. Inherits from the BaseImageryRestRequest class.
@ -217,8 +195,8 @@ Requests an image from the REST imagery service. Inherits from the BaseImageryRe
| Name | Return Type | Description |
|-----------------------|-------------|----------------------------|
| Execute() | Task<Response> | Executes the request. |
| Execute(Action<int> remainingTimeCallback) | Task<Response> | Executes the request. |
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetPostRequestUrl() | string | Gets a URL for requesting imagery data for a POST request. |
| GetPushpinsAsString() | string | Returns the Pushpin information as a formatted string. |
| GetRequestUrl() | string | Gets the request URL. If both a Query and Address are specified, the Query value will be used. Throws an exception if a Query or Address value is not specified. |
@ -237,16 +215,40 @@ Requests an image from the REST imagery service. Inherits from the BaseImageryRe
| MapArea | [BoundingBox](#BoundingBox) | Required when a center point or set of route points are not specified. The geographic area to display on the map. |
| MapHeight | int | The height of the map. Default is **350px**. |
| MapWidth | int | The width of the map. Default is **350px**. |
| Pushpins | List&lt;[ImageryPushpin](#ImageryPushpin)&gt; | List of pushpins to display on the map. |
| Pushpins | List\<[ImageryPushpin](#ImageryPushpin)\>| List of pushpins to display on the map. |
| Query | string | A query string that is used to determine the map location to display. |
| RouteOptions | [RouteOptions](#RouteOptions) | Options for calculating route. |
| ShowTraffic | bool | Specifies if the traffic flow layer should be displayed on the map or not. Default is **false**. |
| Style | string | The custom map style to apply to the image. |
| Waypoints | List&lt;[SimpleWaypoint](#SimpleWaypoint)&gt; | Specifies two or more locations that define the route and that are in sequential order. A route is defined by a set of waypoints and viaWaypoints (intermediate locations that the route must pass through). You can have a maximum of 25 waypoints, and a maximum of 10 viaWaypoints between each set of waypoints. The start and end points of the route cannot be viaWaypoints. |
| Waypoints | List\<[SimpleWaypoint](#SimpleWaypoint)\> | Specifies two or more locations that define the route and that are in sequential order. A route is defined by a set of waypoints and viaWaypoints (intermediate locations that the route must pass through). You can have a maximum of 25 waypoints, and a maximum of 10 viaWaypoints between each set of waypoints. The start and end points of the route cannot be viaWaypoints. |
| ZoomLevel | int | The level of zoom to display. |
<a name="ReverseGeocodeRequest"></a> ReverseGeocodeRequest Class
---------------------------
## <a name="IsochroneRequest"></a> IsochroneRequest Class
Requests a that requests an isochrone (drive time polygon). Inherits from the BaseRestRequest class.
### Methods
| Name | Return Type | Description |
|-----------------|-------------|----------------------------------------------------------|
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetRequestUrl() | string | Gets the request URL for an asynchronous isochrone request. |
### Properties
| Name | Type | Description |
|---------------------|------------------------|----------------|
| DateTime | DateTime | The dateTime parameter identifies the desired time to be used when calculating an isochrone route. This is supported for driving. When calculating, driving routes the route optimization type should be TimeWithTraffic. The route time will be used as the departure time. |
| DistanceUnits | [DistanceUnitType](#DistanceUnitType) | The units in which the maxTime value is specified. |
| MaxDistance | double | The maximum travel distance in the specified distance units in which the isochrone polygon is generated. Cannot be set when maxTime is set. |
| MaxTime | double | The maximum travel time in the specified time units in which the isochrone polygon is generated. Cannot be set when maxDistance is set. Maximum value is 120 minutes. |
| TimeUnit | [TimeUnitType](#TimeUnitType) | The units in which the maxTime value is specified. Default: **Seconds** |
| TravelMode | [TravelModeType](#TravelModeType) | The mode of travel for the route. Default: Driving. |
| Waypoint | [SimplyWaypoint](#SimplyWaypoint) | The point around which the isochrone will be calculated. |
## <a name="ReverseGeocodeRequest"></a> ReverseGeocodeRequest Class
Requests a that converts a coordinate into a location such as an address. Inherits from the BaseRestRequest class.
@ -254,21 +256,20 @@ Requests a that converts a coordinate into a location such as an address. Inheri
| Name | Return Type | Description |
|-----------------|-------------|----------------------------------------------------------|
| Execute() | Task<Response> | Executes the request. |
| Execute(Action<int> remainingTimeCallback) | Task<Response> | Executes the request. |
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetRequestUrl() | string | Gets the request URL to perform a reverse geocode query. |
### Properties
| Name | Type | Description |
|---------------------|------------------------|----------------|
| IncludeEntityTypes | List&lt;[EntityType](#EntityType)&gt; | Specifies the entity types that you want to return in the response. Only the types you specify will be returned. If the point cannot be mapped to the entity types you specify, no location information is returned in the response. |
| IncludeEntityTypes | List\<[EntityType](#EntityType)\> | Specifies the entity types that you want to return in the response. Only the types you specify will be returned. If the point cannot be mapped to the entity types you specify, no location information is returned in the response. |
| IncludeIso2 | bool | When you specified the two-letter ISO country code is included for addresses in the response. |
| IncludeNeighborhood | bool | Specifies to include the neighborhood in the response when it is available. |
| Point | [Coordinate](#Coordinate) | A central coordinate to perform the nearby search. |
<a name="RouteMajorRoadsRequest"></a> RouteMajorRoadsRequest Class
----------------------------
## <a name="RouteMajorRoadsRequest"></a> RouteMajorRoadsRequest Class
Requests routes from a location to major nearby roads. Inherits from the BaseRestRequest class.
@ -276,8 +277,8 @@ Requests routes from a location to major nearby roads. Inherits from the BaseRes
| Name | Return Type | Description |
|-----------------|-------------|------------------------------------------------|
| Execute() | Task<Response> | Executes the request. |
| Execute(Action<int> remainingTimeCallback) | Task<Response> | Executes the request. |
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetRequestUrl() | string | Gets the request URL to perform a query for routes using major roads. |
### Properties
@ -287,10 +288,9 @@ Requests routes from a location to major nearby roads. Inherits from the BaseRes
| Destination | [SimpleWaypoint](#SimpleWaypoint) | Specifies the final location for all the routes. A destination can be specified as a Point, a landmark, or an address. |
| DistanceUnits | [DistanceUnitType](#DistanceUnitType) | The units to use for distance. |
| ExcludeInstructions | bool | Specifies to return only starting points for each major route in the response. When this option is not specified, detailed directions for each route are returned. |
| RouteAttributes | List&lt;[RouteAttributeType](#RouteAttributeType)&gt; | Specifies to include or exclude parts of the routes response. |
| RouteAttributes | List\<[RouteAttributeType](#RouteAttributeType)\> | Specifies to include or exclude parts of the routes response. |
<a name="RouteRequest"></a> RouteRequest Class
------------------
## <a name="RouteRequest"></a> RouteRequest Class
A request that calculates routes between waypoints. Inherits from the BaseRestRequest class.
@ -298,19 +298,50 @@ A request that calculates routes between waypoints. Inherits from the BaseRestRe
| Name | Return Type | Description |
|-----------------|-------------|---------------------------------------------------------------|
| Execute() | Task<Response> | Executes the request. |
| Execute(Action<int> remainingTimeCallback) | Task<Response> | Executes the request. |
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetRequestUrl() | string | Gets the request URL to perform a query for route directions. |
### Properties
| Name | Type | Description |
|--------------|----------------------------|-------------------|
| RouteOptions | [RouteOptions](#RouteOptions) | Options to use when calculate route. |
| Waypoints | List&lt;[SimpleWaypoint](#SimpleWaypoint)&gt; | Specifies two or more locations that define the route and that are in sequential order. A route is defined by a set of waypoints and viaWaypoints (intermediate locations that the route must pass through). You can have a maximum of 25 waypoints, and a maximum of 10 viaWaypoints between each set of waypoints. The start and end points of the route cannot be viaWaypoints. |
| RouteOptions | [RouteOptions](#RouteOptions) | Options to use when calculate route. |
| Waypoints | List\<[SimpleWaypoint](#SimpleWaypoint)\> | Specifies two or more locations that define the route and that are in sequential order. A route is defined by a set of waypoints and viaWaypoints (intermediate locations that the route must pass through). You can have a maximum of 25 waypoints, and a maximum of 10 viaWaypoints between each set of waypoints. The start and end points of the route cannot be viaWaypoints. |
<a name="TrafficRequest"></a> TrafficRequest Class
--------------------
### Extended Properties
Some additional options have been added to the route request to increase its functionality.
| Name | Type | Description |
|--------------|----------------------------|-------------------|
| BatchSize | int | The maximium number of waypoints that can be in a single request. If the batchSize is smaller than the number of waypoints, when the request is executed, it will break the request up into multiple requests, thus allowing routes with more than 25 waypoints to be . Must by between 2 and 25. Default: 25. |
| WaypointOptimization | [TspOptimizationType](#TspOptimizationType) | Specifies if the waypoint order should be optimized using a travelling salesmen algorithm which metric to optimize on. If less than 10 waypoints, brute force is used, for more than 10 waypoints, a genetic algorithm is used. Ignores IsViaPoint on waypoints and makes them waypoints. Default: **false**<br/><br/>**Warning**: If travel time or travel distance is used, a standard Bing Maps key will need to be required, not a session key, as the distance matrix API will be used to process the waypoints. This can generate a lot of billable transactions. |
## <a name="SnapToRoadRequest"></a> SnapToRoadRequest Class
Snaps a set of coordinates to roads. Inherits from the BaseRestRequest class.
### Methods
| Name | Return Type | Description |
|-----------------|-------------|---------------------------------------------------------------|
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetRequestUrl() | string | Gets the request URL to perform a snap to road query. |
### Properties
| Name | Type | Description |
|--------------|----------------------------|-------------------|
| Points | List\<Coordinate\> | A set of points to snap to roads. Up to 100  points may be passed in. |
| Interpolate | bool | Indicates if the space between the snapped points should be filled with additional points along the road, thus returning the full route path. Default: false |
| IncludeSpeedLimit | bool | Indicates if speed limitation data should be returned for the snapped points. Default: false |
| IncludeTruckSpeedLimit  | bool | Indicates if speed limitation data should be returned for the snapped points. Default: false |
| SpeedUnit  | [SpeedUnitType](#SpeedUnitType) | Indicates the units in which the returned speed limit data is in. |
| TravelMode | [TravelModeType](#TravelModeType) | Indicates which routing profile to snap the points to. Default: Driving |
## <a name="TrafficRequest"></a> TrafficRequest Class
Requests traffic information. Inherits from the BaseRestRequest class.
@ -318,8 +349,8 @@ Requests traffic information. Inherits from the BaseRestRequest class.
| Name | Return Type | Description |
|-----------------|-------------|-----------------------------------------------------------|
| Execute() | Task<Response> | Executes the request. |
| Execute(Action<int> remainingTimeCallback) | Task<Response> | Executes the request. |
| Execute() | Task\<Response\> | Executes the request. |
| Execute(Action\<int\> remainingTimeCallback) | Task\<Response\> | Executes the request. |
| GetRequestUrl() | string | Gets a URL for requesting traffic data for a GET request. |
### Properties
@ -328,14 +359,12 @@ Requests traffic information. Inherits from the BaseRestRequest class.
|----------------------|--------------------------|----------------|
| IncludeLocationCodes | bool | Specifies whether to include traffic location codes in the response. Traffic location codes provide traffic incident information for pre-defined road segments. A subscription is typically required to be able to interpret these codes for a geographical area or country. Default is **false**. |
| MapArea | [BoundingBox](#BoundingBox) | Specifies the area to search for traffic incident information. A rectangular area specified as a bounding box. The size of the area can be a maximum of 500 km x 500 km. |
| Severity | List&lt;SeverityType&gt; | Specifies severity level of traffic incidents to return. The default is to return traffic incidents for all severity levels. |
| TrafficType | List&lt;TrafficType&gt; | Specifies the type of traffic incidents to return. |
| Severity | List\<SeverityType\> | Specifies severity level of traffic incidents to return. The default is to return traffic incidents for all severity levels. |
| TrafficType | List\<TrafficType\>; | Specifies the type of traffic incidents to return. |
<a name="CommonClasses"></a> Common Classes
==============
# <a name="CommonClasses"></a> Common Classes
<a name="BoundingBox"></a> BoundingBox Class
-----------------
## <a name="BoundingBox"></a> BoundingBox Class
### Methods
@ -352,8 +381,7 @@ Requests traffic information. Inherits from the BaseRestRequest class.
| SouthLatitude | double | The southern most latitude value. |
| WestLongitude | double | The western most longitude value. |
<a name="Coordinate"></a> Coordinate Class
----------------
## <a name="Coordinate"></a> Coordinate Class
A class that defines location coordinate value.
@ -370,15 +398,25 @@ A class that defines location coordinate value.
| Latitude | double | Latitude coordinate. |
| Longitude | double | Longitude coordinate. |
<a name="ImageryPushpin"></a> ImageryPushpin Class
--------------------
## <a name="CustomMapStyleManager"></a> CustomMapStyleManager Class
A static class to assit with working with Bing Maps Customer Map Styles.
### Static Methods
| Name | Return Type | Description |
|------------------------------------------------------|----------------------|----------------------|
| GetRestStyle(string style) | string | Converts a custom JSON map style, into a style using the REST parameter format. If the style is already in the REST parameter formatter, it will be unaltered. |
## <a name="ImageryPushpin"></a> ImageryPushpin Class
Pushpin defination for Bing Maps REST imagery service as documented [here](https://msdn.microsoft.com/en-us/library/ff701719.aspx)
### Methods
| Name | Return Type | Description |
|------------|-------------|------------------------------------------------------------------------------------------------------|
| Name | Return Type | Description |
|------------|-------------|----------------|
| ToString() | string | Returns a string version of the pushpin in the format `pushpin=latitude,longitude;iconStyle;label` |
### Properties
@ -387,10 +425,9 @@ Pushpin defination for Bing Maps REST imagery service as documented [here](https
|-----------|------------|----------------------------------------|
| IconStyle | int | The icon style to use for the pushpin. |
| Label | string | Label to display on top of pushpin. |
| Location | [Coordinate](#Coordinate) | Coordinate to display pushpin. |
| Location | [Coordinate](#Coordinate) | Coordinate to display pushpin. |
<a name="PointCompression"></a> PointCompression Class
----------------------
## <a name="PointCompression"></a> PointCompression Class
This is a static class that exposes a compression algorithm to encodes/decodes a collections of coordinates into a string. This algorithm is used for generating a compressed collection of coordinates for use with the Bing Maps REST Elevation Service and also used for decoding the compressed coordinates returned by the GeoData API.
@ -402,49 +439,59 @@ These algorithms come from the following documentation:
### Static Methods
| Name | Return Type | Description |
|-----------------------------------------------------------------|-------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Encode(List&lt;[Coordinate](#Coordinate)&gt; points) | string | Compresses a list of coordinates into a string. Based on: [http://msdn.microsoft.com/en-us/library/jj158958.aspx](http://msdn.microsoft.com/en-us/library/jj158958.aspx) |
| TryDecode(string value, out List&lt;[Coordinate](#Coordinate)&gt; parsedValue) | bool | Decodes a collection of coordinates from a compressed string. Returns a boolean indicating if the algorithm was able to decode the compressed coordinates or not. Based on: [http://msdn.microsoft.com/en-us/library/dn306801.aspx](http://msdn.microsoft.com/en-us/library/dn306801.aspx) |
| Name | Return Type | Description |
|-----------------------------------------------------------------|-------------|-------------|
| Encode(List\<[Coordinate](#Coordinate\> points) | string | Compresses a list of coordinates into a string. Based on: [http://msdn.microsoft.com/en-us/library/jj158958.aspx](http://msdn.microsoft.com/en-us/library/jj158958.aspx) |
| TryDecode(string value, out List\<[Coordinate](#Coordinate)\> parsedValue) | bool | Decodes a collection of coordinates from a compressed string. Returns a boolean indicating if the algorithm was able to decode the compressed coordinates or not. Based on: [http://msdn.microsoft.com/en-us/library/dn306801.aspx](http://msdn.microsoft.com/en-us/library/dn306801.aspx) |
<a name="RouteOptions"></a> RouteOptions Class
------------------
## <a name="RouteOptions"></a> RouteOptions Class
A class that defines the options that can to use when calculating a route.
### Properties
| Name | Type | Description |
|-------------------------|--------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| Avoid | List&lt;[AvoidType](#AvoidType)&gt; | Specifies the road types to minimize or avoid when a route is created for the driving travel mode. |
| DateTime | DateTime | The dateTime parameter identifies the desired time to be used when calculating a route. This is supported by driving and transit routes. When calculating, driving routes the route optimization type should be TimeWithTraffic. The route time will be used as the departure time. When calculating transit routes timeType can be specified. |
| DistanceBeforeFirstTurn | int | Specifies the distance before the first turn is allowed in the route. This option only applies to the driving travel mode. An integer distance specified in meters. Use this parameter to make sure that the moving vehicle has enough distance to make the first turn. |
| DistanceUnits | [DistanceUnitType](#DistanceUnitType) | The units to use for distance. |
| Heading | int | Specifies the initial heading for the route. An integer value between 0 and 359 that represents degrees from north where north is 0 degrees and the heading is specified clockwise from north. |
| Name | Type | Description |
|-------------------------|--------------------------------|---------------|
| Avoid | List\<[AvoidType](#AvoidType)\> | Specifies the road types to minimize or avoid when a route is created for the driving travel mode. |
| DateTime | DateTime | The dateTime parameter identifies the desired time to be used when calculating a route. This is supported by driving and transit routes. When calculating, driving routes the route optimization type should be TimeWithTraffic. The route time will be used as the departure time. When calculating transit routes timeType can be specified. |
| DistanceBeforeFirstTurn | int | Specifies the distance before the first turn is allowed in the route. This option only applies to the driving travel mode. An integer distance specified in meters. Use this parameter to make sure that the moving vehicle has enough distance to make the first turn. |
| DistanceUnits | [DistanceUnitType](#DistanceUnitType) | The units to use for distance. |
| Heading | int | Specifies the initial heading for the route. An integer value between 0 and 359 that represents degrees from north where north is 0 degrees and the heading is specified clockwise from north. |
| MaxSolutions | int | Specifies the maximum number of transit or driving routes to return. An interger between 1 and 3. This parameter is available for the Driving and Transit travel modes for routes between two waypoints. This parameter does not support routes with more than two waypoints. For driving routes, you must not set the avoid and distanceBeforeFirstTurn parameters. The maxSolutions parameter is supported for routes in the United States, Canada, Mexico, United Kingdom, Australia, and India. |
| Optimize | [RouteOptimizationType](#RouteOptimizationType) | Specifies what parameters to use to optimize the route. |
| RouteAttributes | List&lt;[RouteAttributeType](#RouteAttributeType)&gt; | Specifies to include or exclude parts of the routes response. |
| TimeType | [RouteTimeType](#RouteTimeType) | Specifies how to interpret the date and transit time value that is specified by the dateTime parameter. |
| Tolerances | List&lt;double&gt; | Specifies a series of tolerance values. Each value produces a subset of points that approximates the route that is described by the full set of points. This parameter is only valid when the routePathOutput parameter is set to Points. You can specify a maximum of seven (7) tolerance values. |
| TravelMode | [TravelModeType](#TravelModeType) | The mode of travel for the route. Default: Driving. |
| Optimize | [RouteOptimizationType](#RouteOptimizationType) | Specifies what parameters to use to optimize the route. |
| RouteAttributes | List\<[RouteAttributeType](#RouteAttributeType)\> | Specifies to include or exclude parts of the routes response. |
| TimeType | [RouteTimeType](#RouteTimeType) | Specifies how to interpret the date and transit time value that is specified by the dateTime parameter. |
| Tolerances | List\<double\> | Specifies a series of tolerance values. Each value produces a subset of points that approximates the route that is described by the full set of points. This parameter is only valid when the routePathOutput parameter is set to Points. You can specify a maximum of seven (7) tolerance values. |
| TravelMode | [TravelModeType](#TravelModeType) | The mode of travel for the route. Default: Driving. |
| VehicleSpec | [VehicleSpec](#VehicleSpec) | Truck routing specific vehicle attribute. |
<a name="SimpleAddress"></a> SimpleAddress Class
-------------------
## <a name="ServiceManager"></a> ServiceManager Class
This is a static class that is used for processing all requests to the Bing Maps REST Services asynchronously. Note that all requests classes now have an Execute function which will retrun a Response object which can be used as an alternative.
### Static Methods
| Name | Return Type | Description |
|------------------------------------------------------|----------------------|----------------------|
| GetResponseAsync([BaseRestRequest](#BaseRestRequest) request) | Task\<Response\>| Processes a REST requests that returns data. |
| GetResponseAsync([BaseRestRequest](#BaseRestRequest) request, Action\<int\> remainingTimeCallback) | Task\<Response\> | Processes a REST requests that returns data. |
| GetImageAsync([BaseImageryRestRequest](#BaseImageryRestRequest) imageryRequest) | Task\<Stream\> | Processes a REST requests that returns an image stream. |
## <a name="SimpleAddress"></a> SimpleAddress Class
A simple address class that can be passed in to queries.
### Properties
| Name | Type | Description |
|---------------|--------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| AddressLine | string | The official street line of an address relative to the area, as specified by the Locality, or PostalCode, properties. Typical use of this element would be to provide a street address or any official address. |
| Name | Type | Description |
|---------------|--------|---------------|
| AddressLine | string | The official street line of an address relative to the area, as specified by the Locality, or PostalCode, properties. Typical use of this element would be to provide a street address or any official address. |
| AdminDistrict | string | The subdivision name in the country or region for an address. This element is typically treated as the first order administrative subdivision, but in some cases, it is the second, third, or fourth order subdivision in a country, dependency, or region. |
| CountryRegion | string | The ISO country code for the country. |
| Locality | string | The locality, such as the city or neighborhood, that corresponds to an address. |
| PostalCode | string | The post code, postal code, or ZIP Code of an address. |
| CountryRegion | string | The ISO country code for the country. |
| Locality | string | The locality, such as the city or neighborhood, that corresponds to an address. |
| PostalCode | string | The post code, postal code, or ZIP Code of an address. |
<a name="SimpleWaypoint"></a> SimpleWaypoint Class
--------------------
## <a name="SimpleWaypoint"></a> SimpleWaypoint Class
A simple waypoint class that can be used to calculate a route.
@ -462,17 +509,39 @@ A simple waypoint class that can be used to calculate a route.
### Properties
| Name | Type | Description |
|------------|------------|------------------------------------------------------------------------------------------------------------|
| Address | string | The address query for the waypoint. |
| Name | Type | Description |
|------------|------------|---------------|
| Address | string | The address query for the waypoint. |
| Coordinate | [Coordinate](#Coordinate) | The coordinate of the waypoint. When specified this will be used instead of the Address value in requests. |
| IsViaPoint | bool | A bool indicating whether the waypoint is a via point. |
| IsViaPoint | bool | A bool indicating whether the waypoint is a via point. |
<a name="Enumerations"></a> Enumerations
============
## <a name="VehicleSpec"></a> VehicleSpec Class
<a name="AvoidType"></a> AvoidType Enumeration
---------------------
A class that defines the options that can to use when calculating a truck route. Extends the [RouteOptions class](#RouteOptions).
### Properties
| Name | Type | Description |
|-------------------------|--------------------------------|--------------------|
| DimensionUnit | [DimensionUnitType](#DimensionUnitType) | The unit of measurement of width, height, length. |
| WeightUnit | [WeightUnitType](#WeightUnitType) | The unit of measurement of weight. |
| VehicleHeight | double | The height of the vehicle in the specified dimension units. |
| VehicleWidth | double | The width of the vehicle in the specified dimension units. |
| VehicleLength | double | The length of the vehicle in the specified dimension units. |
| VehicleWeight | double | The weight of the vehicle in the specified weight units. |
| VehicleAxles | int | The number of axles. |
| VehicleSemi | bool | Indicates if the truck is pulling a semi-trailer. Semi-trailer restrictions are mostly used in North America. |
| VehicleTrailers | int | Specifies number of trailers pulled by a vehicle. The provided value must be between 0 and 4. |
| VehicleMaxGradient | double | The max gradient the vehicle can drive measured in degrees. |
| VehicleMinTurnRadius | double | The mini-mum required radius for the vehicle to turn in the specified dimension units. |
| VehicleAvoidCrossWind | bool | Indicates if the vehicle shall avoid crosswinds. |
| VehicleAvoidGroundingRisk | bool | Indicates if the route shall avoid the risk of grounding. |
| VehicleHazardousMaterials | List\<[HazardousMaterialType](#HazardousMaterialType)\> | A list of one or more hazardous materials for which the vehicle is transporting. |
| VehicleHazardousPermits | List\<[HazardousMaterialPermitType](#HazardousMaterialPermitType)\> | A list of one or more hazardous materials for which the vehicle has permits. |
# <a name="Enumerations"></a> Enumerations
## <a name="AvoidType"></a> AvoidType Enumeration
Specifies the road types to minimize or avoid when the route is created for the driving travel mode.
@ -483,8 +552,7 @@ Specifies the road types to minimize or avoid when the route is created for the
| MinimizeTolls | Minimizes (tries to avoid) the use of toll roads in the route. |
| Tolls | Avoids the use of toll roads in the route. |
<a name="ConfidenceLevel"></a> ConfidenceLevel Enumeration
---------------------------
## <a name="ConfidenceLevelType"></a> ConfidenceLevelType Enumeration
The level of confidence that the geocoded location result is a match.
@ -495,8 +563,17 @@ The level of confidence that the geocoded location result is a match.
| Medium | Medium confidence match. |
| None | No confidence level set. |
<a name="DistanceUnitType"></a> DistanceUnitType Enumeration
----------------------------
## <a name="DimensionUnitType"></a> DimensionUnitType Enumeration
Measurement units of vehicle dimensions.
| Name | Description |
|---------|--------------------------|
| Meter | Dimensions in meters. |
| Foot | Dimensions in feet. |
## <a name="DistanceUnitType"></a> DistanceUnitType Enumeration
Units of measurements for distances.
@ -505,8 +582,7 @@ Units of measurements for distances.
| Kilometers | Distances in Kilometers. |
| Miles | Distances in Miles. |
<a name="ElevationType"></a> ElevationType Enumeration
-------------------------
## <a name="ElevationType"></a> ElevationType Enumeration
Relative elevation type.
@ -515,8 +591,7 @@ Relative elevation type.
| Ellipsoid | Ellipsoid Earth model (WGS84). |
| Sealevel | Geoid Earth model (EGM2008 2.5). |
<a name="EntityType"></a> EntityType Enumeration
----------------------
## <a name="EntityType"></a> EntityType Enumeration
Types of location based entities.
@ -530,8 +605,43 @@ Types of location based entities.
| PopulatedPlace | A concentrated area of human settlement, such as a city, town or village. |
| Postcode1 | The smallest post code category, such as a zip code. |
<a name="ImageFormatType"></a> ImageFormatType Enumeration
---------------------------
## <a name="HazardousMaterialPermitType"></a> HazardousMaterialPermitType Enumeration
Types of hazardous material permits for truck routing.
| Name | Description |
|-------|----------------------------------------------------------------------------------------------|
| AllAppropriateForLoad | Permit for goods which are all appropriate for load. |
| Combustible | Permit for combustible material. |
| Corrosive | Permit for corrosive material. |
| Explosive | Permit for explosive material. |
| Flammable | Permit for flammable material. |
| FlammableSolid | Permit for flammable solid material. |
| Gas | Permit for gases. |
| Organic | Permit for organic material. |
| Poison | Permit for poisonous material. |
| PoisonousInhalation | Permit for poisonous inhalation material. |
| Radioactive | Permit for radioactive material. |
## <a name="HazardousMaterialType"></a> HazardousMaterialType Enumeration
Hazardous materials in which a truck may transport.
| Name | Description |
|-------|----------------------------------------------------------------------------------------------|
| Combustable | Combustable materials. |
| Corrosive | Corrosive materials. |
| Explosive | Explosive materials. |
| Flammable | Flammable materials. |
| FlammableSolid | Flammable Solid materials. |
| Gas | Gases. |
| GoodsHarmfulToWater | Goods Harmful To Water. |
| Organic | Organic materials. |
| Poison | Poisonous materials. |
| PoisonousInhalation | Poisonous Inhalation materials. |
| Radioactive | Radioactive materials. |
## <a name="ImageFormatType"></a> ImageFormatType Enumeration
Imagery format types.
@ -541,8 +651,7 @@ Imagery format types.
| JPEG | JPEG image format. JPEG format is the default for Road, Aerial and AerialWithLabels imagery. |
| PNG | PNG image format. PNG is the default format for CollinsBart and OrdnanceSurvey imagery. |
<a name="ImageryType"></a> ImageryType Enumeration
-----------------------
## <a name="ImageryType"></a> ImageryType Enumeration
Types of map imagery.
@ -562,8 +671,7 @@ Types of map imagery.
| Road | Roads without additional imagery. |
| RoadOnDemand | Roads without additional imagery. Uses dynamic tile service. |
<a name="RouteAttributeType"></a> RouteAttributeType Enumeration
------------------------------
## <a name="RouteAttributeType"></a> RouteAttributeType Enumeration
The type of route attributes to include in a route response.
@ -575,8 +683,7 @@ The type of route attributes to include in a route response.
| RouteSummariesOnly | Include only travel time and distance for the route, and does not provide other information. |
| TransitStops | Include information about transit stops for transit routes. |
<a name="RouteOptimizationType"></a> RouteOptimizationType Enumeration
---------------------------------
## <a name="RouteOptimizationType"></a> RouteOptimizationType Enumeration
Specifies what parameters to use to optimize the route on the map.
@ -587,8 +694,7 @@ Specifies what parameters to use to optimize the route on the map.
| TimeAvoidClosure | The route is calculated to minimize the time and avoid road closures. Traffic information is not used in the calculation. |
| TimeWithTraffic | Optimizes route for shortest travel time with respect to current traffic conditions. |
<a name="RouteTimeType"></a> RouteTimeType Enumeration
-------------------------
## <a name="RouteTimeType"></a> RouteTimeType Enumeration
Specifies how to interpret the date and transit time value that is specified by the dateTime parameter.
@ -598,8 +704,7 @@ Specifies how to interpret the date and transit time value that is specified by
| Departure | The dateTime parameter contains the desired departure time for a transit request. |
| LastAvailable | The dateTime parameter contains the latest departure time available for a transit request. |
<a name="SeverityType"></a> SeverityType Enumeration
------------------------
## <a name="SeverityType"></a> SeverityType Enumeration
Specifies the severity level of a traffic incident.
@ -610,18 +715,25 @@ Specifies the severity level of a traffic incident.
| Moderate | Moderate severity. |
| Serious | Serious severity. |
<a name="TimeUnitType"></a> TimeUnitType Enumeration
-----------------------
## <a name="SpeedUnitType"></a> SpeedUnitType Enumeration
Unit of speed.
| Name | Description |
|------------|----------------------|
| KPH | Kilometers per hour. |
| MPH | Miles per hour. |
## <a name="TimeUnitType"></a> TimeUnitType Enumeration
Represents the units in which time is measured.
| Name | Description |
|------------------|---------------------------------|
| Minutes | Time is in minutes. |
| Seconds | Time is in seconds. |
<a name="TrafficType"></a> TrafficType Enumeration
-----------------------
| Name | Description |
|-----------------|---------------------------------|
| Minute | Time is in minutes. |
| Second | Time is in seconds. |
## <a name="TrafficType"></a> TrafficType Enumeration
Specifies the type of a traffic incident.
@ -639,8 +751,7 @@ Specifies the type of a traffic incident.
| Alert | Alert incident type. |
| Weather | Weather incident type. |
<a name="TravelModeType"></a> TravelModeType Enumeration
--------------------------
## <a name="TravelModeType"></a> TravelModeType Enumeration
The mode of travel for the route.
@ -649,14 +760,28 @@ The mode of travel for the route.
| Driving | Driving mode. |
| Walking | Walking mode. |
| Transit | Transit mode. |
| Truck | Truck driving mode. |
<a name="EnhancedResponseClasses"></a> Enhanced Response Classes
================================================================
## <a name="WeightUnitType"></a> WeightUnitType Enumeration
Unit of measurement for vehicle weights.
| Name | Description |
|---------|--------------------------|
| Kilograms | Weight in kilograms. |
| Pounds | Weight in pounds. |
# <a name="EnhancedResponseClasses"></a> Enhanced Response Classes
These are response classes that have been extended extensively to make them easier to use.
<a name="DistanceMatrix"><a/> DistanceMatrix Class
--------------------------------------------------
## <a name="DistanceMatrix"><a/> DistanceMatrix Class
### Static Methods
| Name | Return Type | Description |
|-----------------|-------------|----------------------------------------------------------|
| CreateStraightLineNxNMatrix(List\<SimpleWaypoint\> waypoints, DistanceUnitType distanceUnits, string bingMapsKey) | Distance Matrix | Creates a NxN distance matrix with straight line distances. |
### Methods
@ -672,13 +797,15 @@ An indexing system has been added to the DistanceMatrix class to make it easy to
| GetDistance(int originIdx, int destinationIdx, DateTime timeInterval) | double | Retrives the travel distance for a specified origin-destination pair and time interval. Returns -1 if a cell can not be found in the results or had an error in calculation. |
| GetDistance(int originIdx, int destinationIdx, int timeIntervalIdx) | double | Retrives the travel distance for a specified origin-destination pair and time interval. Returns -1 if a cell can not be found in the results or had an error in calculation. |
| GetDistances(int originIdx, int destinationIdx) | double[] | Gets all travel distances for the specified origin and destination index, ordered by time (ascending). |
| GetEdgeDistance(int[] waypointIndicies) | double | Retrieves the total travel distance between all waypoints indicies which represent an edge (graph/path). |
| GetEdgeDistance(int[] waypointIndicies, bool isRoundTrip) | double | Retrieves the total travel distance between all waypoints indicies which represent an edge (graph/path). |
| GetEdgeTime(int[] waypointIndicies) | double | Retrieves the total travel time between all waypoints indicies which represent an edge (graph/path). |
| GetEdgeTime(int[] waypointIndicies, bool isRoundTrip) | double | Retrieves the total travel time between all waypoints indicies which represent an edge (graph/path). |
| GetTime(int originIdx, int destinationIdx) | double | Retrives the travel time for a specified origin-destination pair. Returns -1 if a cell can not be found in the results or had an error in calculation. |
| GetTime(int originIdx, int destinationIdx, DateTime timeInterval) | double | Retrieves the travel time for a specified origin-destination pair and time interval. Returns -1 if a cell can not be found in the results or had an error in calculation. |
| GetTime(int originIdx, int destinationIdx, int timeIntervalIdx) | double | Retrieves the travel time for a specified origin-destination pair and time interval. Returns -1 if a cell can not be found in the results or had an error in calculation. |
| GetTimes(int originIdx, int destinationIdx) | double[] | Gets all travel times for the specified origin and destination index, ordered by time (ascending). |
### Properties
| Name | Type | Description |
@ -687,4 +814,44 @@ An indexing system has been added to the DistanceMatrix class to make it easy to
| ErrorMessage| string | Details of an error that may have occurred when processing the request. |
| Origins | [SimpleWaypoint](#SimpleWaypoint)\[\] | The array of destinations that were used to calculate the distance matrix. |
| Result | DistanceMatrixCell\[\] | Array of distance matrix cell results containing information for each coordinate pair and time interval. |
| TimeIntervals | List&lt;DateTime&gt; | A list of time intervals in which the distance matrix calculated for. |
| TimeIntervals | List\<DateTime\> | A list of time intervals in which the distance matrix calculated for. |
# <a name="ExtensionClasses"></a> Extension Classes
## <a name="TravellingSalesmen"></a> TravellingSalesmen Class
This is a static class that solves the [travelling salesmen problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem). Uses a greedy algrithm when 10 or less waypoints are specified, and a genetic algorithm for larger waypoint sets.
### Methods
| Name | Return Type | Description |
|-----------------|-------------|-----------------------------------------------------------------|
| Solve(List\<[SimpleWaypoint](#SimpleWaypoint)\> waypoints, [TravelModeType](#TravelModeType)? travelMode, [TspOptimizationType](#TspOptimizationType)? tspOptimization, DateTime? departureTime, string bingMapsKey) | Task\<[TspSolution](#TspSolution)\> | Solves the travelling salesmen problem. |
| Solve([DistanceMatrix](#DistanceMatrix) matrix, [TspOptimizationType](#TspOptimizationType) tspOptimization)| Task\<[TspSolution](#TspSolution)\> | Solves the travelling salesmen problem. |
## <a name="TspOptimizationType"></a> TspOptimizationType Enumeration
Metrics in which the travelling salesmen problem is solved for.
| Name | Description |
|-------|--------------------------|
| StraightLineDistance | Optimizes based on straight line distances (as the crow flies). |
| TravelDistance | Optimizes based on travel distances (roads). Uses the Distance Matrix API. |
| TravelTime | Optimizes based on travel times (roads). Uses the Distance Matrix API. |
## <a name="TspSolution"></a> TspSolution Class
The result from a Travelling Salesmen calculation.
### Properties
| Name | Type | Description |
|--------------|-------------|-----------------------------------------------------------------|
| DistanceMatrix | [DistanceMatrix](#DistanceMatrix) | The distance matrix used in the calculation. |
| IsRoundTrip | bool | Indicates if the path is for a round trip and returns to the origin or not. |
| OptimizedWaypoints | List\<[SimpleWaypoint](#SimpleWaypoint)\> | A list of the waypoints in an optimized ordered. |
| OptimizedWeight | double | The optimized weight (time or distance) between all waypoints based on the TspOptimizationType. |
| TravelMode | [TravelModeType](#TravelModeType) | The travel mode used to calculate the distance matrix. |
| TspOptimization | [TspOptimizationType](#TspOptimizationType) | The metric used to solve the travelling salesmen problem for. |

Просмотреть файл

@ -2,11 +2,11 @@
* [Running the Samples](#RunningTheSamples)
* [Adding the Bing Maps REST Toolkit to your project](#AddingToolkitToProject)
* [How to make a Request to the REST services](#HowToMakeARequest)
* [Travelling Salesmen Problem](#TravellingSalesmen)
The Bing Maps REST services allow you to query the raw data that powers Bing Maps. The Bing Maps REST Services Toolkit provides an easy to use .NET wrapper around these services. To keep things easy the request and response classes in this library are aligned with the structure of the [documented Bing Maps REST Services API](https://msdn.microsoft.com/en-us/library/ff701713.aspx).
<a name="CreatingABingMapsKey"></a> Creating a Bing Maps key
------------------------
## <a name="CreatingABingMapsKey"></a> Creating a Bing Maps key
To use Bing Maps in your own application you will need a Bing Maps key. All Bing Maps map controls and services use a Bing Maps key for authentication. You can get a Bing Maps key in two ways:
@ -38,13 +38,11 @@ If you are an Azure user, you can create a Bing Maps key through the [Azure mark
To find out about licensing options and learn about Bing Maps controls, please visit [www.microsoft.com/maps](http://www.microsoft.com/maps).
<a name="RunningTheSamples"></a> Running the Samples
-------------------
## <a name="RunningTheSamples"></a> Running the Samples
Download the complete project including the samples and the source code for the Ring Maps REST toolkit. All of the samples require a Bing Maps key to work. To add your Bing Maps key to the sample, open the **App.config** file of the sample and add it to the **BingMapsKey** property. This property likely has a placeholder value of **YOUR\_BING\_MAPS\_KEY**. Once this is done, simply run the sample in debug or release mode.
<a name="AddingToolkitToProject"></a> Adding the Bing Maps REST Toolkit to your project
-------------------------------------------------
## <a name="AddingToolkitToProject"></a> Adding the Bing Maps REST Toolkit to your project
There are two options for adding the Bing Maps REST toolkit to your project.
@ -60,8 +58,7 @@ Alternatively, if you are using the nuget command line:
Download the source code and add the BingMapsRESTToolkit project to your solution. Once this is done you can a reference to it from your main project.
<a name="HowToMakeARequest"></a> How to make a Request to the REST services
------------------------------------------
## <a name="HowToMakeARequest"></a> How to make a Request to the REST services
| Update |
|--------|
@ -192,4 +189,46 @@ using (var imageStream = await ServiceManager.GetImageAsync(request))
bitmapImage.EndInit();
MyImage.Source = bitmapImage;
}
```
```
## <a name="TravellingSalesmen"></a> Travelling Salesmen Problem
This toolkit provides some classes which wrap the routing and distance matrix API's and provides solutions for the [travelling salesmen problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem) (waypoint order optimization). You can optimize based on travel time, travel distance or straight line distance. When travel time/distance is specified, the distance matrix API which will generate Bing Maps transactions. For straight line distances, the haversine formula will be used to generate a matrix based on as-the-crow-flies distance between the waypoints.
The travelling salesmen functionality is exposed in two ways;
- A TravellingSalesmen class which takes in a set of waypoints or a distance matrix and optimizes the waypoints. This uses a greedy algrithm when 10 or less waypoints are specified, and a genetic algorithm for larger waypoint sets. Here is an example of how to implement this:
```C#
var tspResult = await TravellingSalesmen.Solve(new List<SimpleWaypoint>(){
new SimpleWaypoint("Seattle, WA"),
new SimpleWaypoint("Bellevue, WA"),
new SimpleWaypoint("Redmond, WA"),
new SimpleWaypoint("Kirkland, WA")
}, TspOptimizationType.TravelTime);
//Do something with the results.
```
- A WaypointOptimization option has been added to the RouteRequest class which, when set, will optimize the waypoints before calculating the requested route. Here is an example of how to implement this:
```C#
var routeRequest = new RouteRequest()
{
Waypoints = new List<SimpleWaypoint>(){
new SimpleWaypoint("Seattle, WA"),
new SimpleWaypoint("Bellevue, WA"),
new SimpleWaypoint("Redmond, WA"),
new SimpleWaypoint("Kirkland, WA")
},
WaypointOptimization = TspOptimizationType.TravelTime,
RouteOptions = new RouteOptions()
{
TravelMode = TravelModeType.Driving
},
BingMapsKey = BingMapsKey
};
var response = await routeRequest.Execute();
//Do something with the route response which will be based on an optimized ordered set of waypoints.
```

Просмотреть файл

@ -1,20 +1,30 @@
![Bing Maps Logo](https://github.com/Microsoft/Bing-Maps-V8-TypeScript-Definitions/blob/master/images/BingMapsLogoTeal.png)
[![NuGet](https://img.shields.io/badge/NuGet-1.0.8-blue.svg)](https://www.nuget.org/packages/BingMapsRESTToolkit)
[![NuGet](https://img.shields.io/badge/NuGet-1.0.9-blue.svg)](https://www.nuget.org/packages/BingMapsRESTToolkit)
[![license](https://img.shields.io/badge/license-MIT-yellow.svg)](https://github.com/Microsoft/BingMapsRESTToolkit/blob/master/LICENSE.md)
# Bing Maps REST Toolkit for .NET #
This is a portable .NET class library which provides a set of tools that make it easy to access the Bing Maps REST services in .NET based apps. Take a look at the [Getting Started documentation](https://github.com/Microsoft/BingMapsRESTToolkit/blob/master/Docs/Getting%20Started.md).
This is a portable .NET class library which provides a set of tools that make it easy to access the Bing Maps REST services in .NET based apps. Take a look at the [Getting Started documentation](https://github.com/Microsoft/BingMapsRESTToolkit/blob/master/Docs/Getting%20Started.md). The Bing Maps REST Services provides the following functionality:
## Features ##
* **Forward and reverse geocoding**
* Route calculations for driving, walking, transit and truck
* **Distance matricies** - time and distance based matrices between a set of origins and destinations. Optionally retrieve this data over a period of time using predictive traffic data
* **Isochrones** (drive time polygons)
* **Snap to Road API** - snap GPS points to their closest logical point on a road. Also provides speed limit data
* **Traffic incident data**
* **Elevation data**
* **Static map imagery and metadata**
## Toolkit Features ##
* Uses HTTPS by default.
* Implements the documented [best practices for Bing Maps](https://msdn.microsoft.com/en-us/library/dn894107.aspx). For example, it automatically encodes query parameters. A commonly overlooked stepped which greatly reduces the chances of invalid queries being sent to the service.
* Handles errors and rate limiting by catching exception and returning response with error message.
* Automatically determines when a POST request should be made instead of a GET request.
* Fast indexed lookups of Distance Matrix results.
* Supports calculating routes of any size.
* Supports calculating driving, walking and transit routes that have more than 25 waypoints.
* Travelling Salesmen algorithms that tie into the distance matrix API [documentation](https://github.com/Microsoft/BingMapsRESTToolkit/blob/master/Docs/Getting%20Started.md#TravellingSalesmen).
## NuGet Package ##

Просмотреть файл

@ -29,6 +29,7 @@
<Button Content="Route" Click="RouteBtn_Clicked" Height="30"/>
<Button Content="Long Route" Click="LongRouteBtn_Clicked" Height="30"/>
<Button Content="Transit Route" Click="TransitRouteBtn_Clicked" Height="30"/>
<Button Content="Truck Route" Click="TruckRouteBtn_Clicked" Height="30"/>
<Button Content="Traffic" Click="TrafficBtn_Clicked" Height="30"/>
<Button Content="Imagery Metadata" Click="ImageMetadataBtn_Clicked" Height="30"/>
<Button Content="Static Image" Click="StaticImageBtn_Clicked" Height="30"/>
@ -36,6 +37,8 @@
<Button Content="Geospatial Endpoint" Click="GeospatialEndpointBtn_Clicked" Height="30"/>
<Button Content="Distance Matrix" Click="DistanceMatrixBtn_Clicked" Height="30"/>
<Button Content="Distance Matrix Histogram" Click="DistanceMatrixHistogramBtn_Clicked" Height="30"/>
<Button Content="Isochrone" Click="IsochroneBtn_Clicked" Height="30"/>
<Button Content="Snap To Road" Click="SnapToRoadBtn_Clicked" Height="30"/>
</StackPanel>
</ScrollViewer>

Просмотреть файл

@ -28,7 +28,6 @@ using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
@ -246,7 +245,7 @@ namespace RESTToolkitTestApp
RouteAttributeType.TransitStops
},
Optimize = RouteOptimizationType.TimeAvoidClosure,
DateTime = new DateTime(2016, 6, 30, 8, 0, 0, DateTimeKind.Utc),
DateTime = DateTime.Now,
TimeType = RouteTimeType.Departure
},
Waypoints = new List<SimpleWaypoint>()
@ -264,6 +263,60 @@ namespace RESTToolkitTestApp
ProcessRequest(r);
}
/// <summary>
/// Demostrates how to make a Truck Routing Request.
/// </summary>
private void TruckRouteBtn_Clicked(object sender, RoutedEventArgs e)
{
var r = new RouteRequest()
{
RouteOptions = new RouteOptions()
{
Avoid = new List<AvoidType>()
{
AvoidType.MinimizeTolls
},
TravelMode = TravelModeType.Truck,
DistanceUnits = DistanceUnitType.Miles,
Heading = 45,
RouteAttributes = new List<RouteAttributeType>()
{
RouteAttributeType.RoutePath
},
Optimize = RouteOptimizationType.Time,
VehicleSpec = new VehicleSpec()
{
VehicleWidth = 3,
VehicleHeight = 5,
DimensionUnit = DimensionUnitType.Meter,
VehicleWeight = 15000,
WeightUnit = WeightUnitType.Pound,
VehicleHazardousMaterials = new List<HazardousMaterialType>()
{
HazardousMaterialType.Combustable,
HazardousMaterialType.Flammable
}
}
},
Waypoints = new List<SimpleWaypoint>()
{
new SimpleWaypoint(){
Address = "Seattle, WA"
},
new SimpleWaypoint(){
Address = "Bellevue, WA",
IsViaPoint = true
},
new SimpleWaypoint(){
Address = "Redmond, WA"
}
},
BingMapsKey = BingMapsKey
};
ProcessRequest(r);
}
/// <summary>
/// Demostrates how to make a Traffic Request.
/// </summary>
@ -470,9 +523,9 @@ namespace RESTToolkitTestApp
new SimpleWaypoint(47.4747, -122.2057)
},
BingMapsKey = BingMapsKey,
TimeUnits = TimeUnitType.Minutes,
TimeUnits = TimeUnitType.Minute,
DistanceUnits = DistanceUnitType.Miles,
TravelMode = TravelModeType.Transit
TravelMode = TravelModeType.Driving
};
ProcessRequest(r);
@ -505,6 +558,49 @@ namespace RESTToolkitTestApp
ProcessRequest(r);
}
/// <summary>
/// Demostrates how to make an Isochrone Request.
/// </summary>
private void IsochroneBtn_Clicked(object sender, RoutedEventArgs e)
{
var r = new IsochroneRequest()
{
Waypoint = new SimpleWaypoint("Bellevue, WA"),
MaxTime = 30,
TimeUnit = TimeUnitType.Minute,
DateTime = DateTime.Now.AddMinutes(15),
TravelMode = TravelModeType.Transit,
BingMapsKey = BingMapsKey
};
ProcessRequest(r);
}
/// <summary>
/// Demostrates how to make an Snap to Road Request.
/// </summary>
private void SnapToRoadBtn_Clicked(object sender, RoutedEventArgs e)
{
var r = new SnapToRoadRequest()
{
Points = new List<Coordinate>()
{
new Coordinate(47.590868, -122.336729),
new Coordinate(47.601604, -122.336042),
new Coordinate(47.60849, -122.34241),
new Coordinate(47.610568, -122.345064)
},
IncludeSpeedLimit = true,
IncludeTruckSpeedLimit = true,
Interpolate = true,
SpeedUnit = SpeedUnitType.MPH,
TravelMode = TravelModeType.Driving,
BingMapsKey = BingMapsKey
};
ProcessRequest(r);
}
#endregion
#region Private Methods
@ -545,10 +641,9 @@ namespace RESTToolkitTestApp
ProcessingTimeTbx.Text = string.Format(CultureInfo.InvariantCulture, "{0:0} ms", processingTime.TotalMilliseconds);
var nodes = new List<ObjectNode>()
{
new ObjectNode("result", response)
};
var nodes = new List<ObjectNode>();
var tree = await ObjectNode.ParseAsync("result", response);
nodes.Add(tree);
ResultTreeView.ItemsSource = nodes;
ResponseTab.IsSelected = true;

Просмотреть файл

@ -26,6 +26,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Threading.Tasks;
namespace RESTToolkitTestApp
{
@ -86,6 +87,19 @@ namespace RESTToolkitTestApp
#endregion
/// <summary>
/// Takes any Object and generates an Object Tree.
/// </summary>
/// <param name="name">The name of the root node.</param>
/// <param name="value">The object to parse into an Object Tree.</param>
public static async Task<ObjectNode> ParseAsync(string name, object value)
{
return await Task.Run<ObjectNode>(() =>
{
return new ObjectNode(name, value);
});
}
#region Public Properties
/// <summary>

Просмотреть файл

@ -0,0 +1,9 @@
<Application x:Class="TravellingSalesmenRouteSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TravellingSalesmenRouteSample"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

Просмотреть файл

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace TravellingSalesmenRouteSample
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

Просмотреть файл

@ -0,0 +1,51 @@
<Window x:Class="TravellingSalesmenRouteSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TravellingSalesmenRouteSample"
xmlns:m="clr-namespace:Microsoft.Maps.MapControl.WPF;assembly=Microsoft.Maps.MapControl.WPF"
mc:Ignorable="d"
Title="Travelling Salesmen Route Sample" Height="600" Width="1000">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="350"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Margin="10,0">
<TextBlock Text="Input" FontWeight="Bold"/>
<TextBlock Text="Enter one location per line and then press solve."/>
<TextBox Name="InputTbx" Height="280" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" AcceptsReturn="True"/>
<StackPanel Orientation="Horizontal" Margin="0,10" HorizontalAlignment="Center">
<TextBlock Text="Waypoint Optimization: "/>
<ComboBox Name="TspOptimizationTypeCbx">
<ComboBoxItem Content="Travel Time" Tag="TravelTime"/>
<ComboBoxItem Content="Travel Distance" Tag="TravelDistance"/>
<ComboBoxItem Content="Straight Line Distance" IsSelected="True" Tag="StraightLineDistance"/>
</ComboBox>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,10" HorizontalAlignment="Center">
<TextBlock Text="Travel Mode: "/>
<ComboBox Name="TravelModeTypeCbx">
<ComboBoxItem Content="Driving" IsSelected="True"/>
<ComboBoxItem Content="Walking"/>
<ComboBoxItem Content="Transit"/>
<ComboBoxItem Content="Truck"/>
</ComboBox>
</StackPanel>
<Button Content="Calculate Route" Width="100" Height="25" Click="CalculateRouteBtn_Clicked" />
<TextBlock Text="Output" FontWeight="Bold" Margin="0,10"/>
<TextBox Name="OutputTbx" Height="85" Grid.Column="1" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap"/>
</StackPanel>
<m:Map Name="MyMap" Grid.Column="1"/>
<ProgressBar Grid.Column="1" Name="LoadingBar" IsIndeterminate="True" Height="25" Width="250" VerticalAlignment="Center" HorizontalAlignment="Center" Visibility="Collapsed"/>
</Grid>
</Window>

Просмотреть файл

@ -0,0 +1,204 @@
using BingMapsRESTToolkit;
using BingMapsRESTToolkit.Extensions;
using Microsoft.Maps.MapControl.WPF;
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace TravellingSalesmenRouteSample
{
public partial class MainWindow : Window
{
#region Private Properties
private string BingMapsKey = System.Configuration.ConfigurationManager.AppSettings.Get("BingMapsKey");
private string SessionKey;
private Regex CoordinateRx = new Regex(@"^[\s\r\n\t]*(-?[0-9]{0,2}(\.[0-9]*)?)[\s\t]*,[\s\t]*(-?[0-9]{0,3}(\.[0-9]*)?)[\s\r\n\t]*$");
#endregion
public MainWindow()
{
InitializeComponent();
MyMap.CredentialsProvider = new ApplicationIdCredentialsProvider(BingMapsKey);
MyMap.CredentialsProvider.GetCredentials((c) =>
{
SessionKey = c.ApplicationId;
});
//Add some sample locations to the input panel.
InputTbx.Text = "Seattle, WA\r\nRedmond, WA\r\nBellevue, WA\r\n47.532122, -122.042934\r\nEverett, WA\r\nTacoma, WA\r\nKirkland, WA\r\nSammamish, WA\r\nLynnwood, WA\r\nRenton, WA\r\nDuvall, WA\r\nMonroe, WA\r\nSummer, WA";
}
private async void CalculateRouteBtn_Clicked(object sender, RoutedEventArgs e)
{
MyMap.Children.Clear();
OutputTbx.Text = string.Empty;
LoadingBar.Visibility = Visibility.Visible;
var waypoints = GetWaypoints();
if (waypoints.Count < 2)
{
MessageBox.Show("Need a minimum of 2 waypoints to calculate a route.");
return;
}
var travelMode = (TravelModeType)Enum.Parse(typeof(TravelModeType), (string)(TravelModeTypeCbx.SelectedItem as ComboBoxItem).Content);
var tspOptimization = (TspOptimizationType)Enum.Parse(typeof(TspOptimizationType), (string)(TspOptimizationTypeCbx.SelectedItem as ComboBoxItem).Tag);
try
{
//Calculate a route between the waypoints so we can draw the path on the map.
var routeRequest = new RouteRequest()
{
Waypoints = waypoints,
//Specify that we want the route to be optimized.
WaypointOptimization = tspOptimization,
RouteOptions = new RouteOptions()
{
TravelMode = travelMode,
RouteAttributes = new List<RouteAttributeType>()
{
RouteAttributeType.RoutePath,
RouteAttributeType.ExcludeItinerary
}
},
//When straight line distances are used, the distance matrix API is not used, so a session key can be used.
BingMapsKey = (tspOptimization == TspOptimizationType.StraightLineDistance)? SessionKey : BingMapsKey
};
//Only use traffic based routing when travel mode is driving.
if(routeRequest.RouteOptions.TravelMode != TravelModeType.Driving)
{
routeRequest.RouteOptions.Optimize = RouteOptimizationType.Time;
}
else
{
routeRequest.RouteOptions.Optimize = RouteOptimizationType.TimeWithTraffic;
}
var r = await routeRequest.Execute();
RenderRouteResponse(routeRequest, r);
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
LoadingBar.Visibility = Visibility.Collapsed;
}
#region Private Methods
/// <summary>
/// Renders a route response on the map.
/// </summary>
private void RenderRouteResponse(RouteRequest routeRequest, Response response)
{
//Render the route on the map.
if (response != null && response.ResourceSets != null && response.ResourceSets.Length > 0 &&
response.ResourceSets[0].Resources != null && response.ResourceSets[0].Resources.Length > 0
&& response.ResourceSets[0].Resources[0] is Route)
{
var route = response.ResourceSets[0].Resources[0] as Route;
var timeSpan = new TimeSpan(0, 0, (int)Math.Round(route.TravelDurationTraffic));
if (timeSpan.Days > 0)
{
OutputTbx.Text = string.Format("Travel Time: {3} days {0} hr {1} min {2} sec\r\n", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds, timeSpan.Days);
}
else
{
OutputTbx.Text = string.Format("Travel Time: {0} hr {1} min {2} sec\r\n", timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds);
}
var routeLine = route.RoutePath.Line.Coordinates;
var routePath = new LocationCollection();
for (int i = 0; i < routeLine.Length; i++)
{
routePath.Add(new Microsoft.Maps.MapControl.WPF.Location(routeLine[i][0], routeLine[i][1]));
}
var routePolyline = new MapPolyline()
{
Locations = routePath,
Stroke = new SolidColorBrush(Colors.Red),
StrokeThickness = 3
};
MyMap.Children.Add(routePolyline);
var locs = new List<Microsoft.Maps.MapControl.WPF.Location>();
//Create pushpins for the optimized waypoints.
//The waypoints in the request were optimized for us.
for (var i = 0; i < routeRequest.Waypoints.Count; i++)
{
var loc = new Microsoft.Maps.MapControl.WPF.Location(routeRequest.Waypoints[i].Coordinate.Latitude, routeRequest.Waypoints[i].Coordinate.Longitude);
//Only render the last waypoint when it is not a round trip.
if (i < routeRequest.Waypoints.Count - 1)
{
MyMap.Children.Add(new Pushpin()
{
Location = loc,
Content = i
});
}
locs.Add(loc);
}
MyMap.SetView(locs, new Thickness(50), 0);
}
else if (response != null && response.ErrorDetails != null && response.ErrorDetails.Length > 0)
{
throw new Exception(String.Join("", response.ErrorDetails));
}
}
/// <summary>
/// Gets the inputted waypoints.
/// </summary>
private List<SimpleWaypoint> GetWaypoints()
{
var places = InputTbx.Text.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
var waypoints = new List<SimpleWaypoint>();
foreach (var p in places)
{
if (!string.IsNullOrWhiteSpace(p))
{
var m = CoordinateRx.Match(p);
if (m.Success)
{
waypoints.Add(new SimpleWaypoint(double.Parse(m.Groups[1].Value), double.Parse(m.Groups[3].Value)));
}
else
{
waypoints.Add(new SimpleWaypoint(p));
}
}
}
return waypoints;
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,55 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("TravellingSalesmenRouteSample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("TravellingSalesmenRouteSample")]
[assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

Просмотреть файл

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TravellingSalesmenRouteSample.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TravellingSalesmenRouteSample.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

Просмотреть файл

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

Просмотреть файл

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace TravellingSalesmenRouteSample.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

Просмотреть файл

@ -0,0 +1,108 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{5173922A-0160-4EE1-9AD8-F629B23CFE71}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>TravellingSalesmenRouteSample</RootNamespace>
<AssemblyName>TravellingSalesmenRouteSample</AssemblyName>
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Maps.MapControl.WPF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\..\packages\Microsoft.Maps.MapControl.WPF.1.0.0.3\lib\net40-Client\Microsoft.Maps.MapControl.WPF.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Source\BingMapsRESTToolkit.csproj">
<Project>{AC15CCAC-63B7-43EB-A1CB-25925F04398B}</Project>
<Name>BingMapsRESTToolkit</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.Maps.MapControl.WPF" version="1.0.0.3" targetFramework="net452" />
</packages>

Просмотреть файл

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard1.4</TargetFramework>
<Version>1.0.7</Version>
<Version>1.0.9</Version>
<Authors>Microsoft</Authors>
<Company>Microsoft</Company>
<Description>A toolkit that makes it easy to access the Bing Maps REST services from .NET</Description>
@ -13,17 +13,20 @@
<PackageTags>Microsoft "Bing Maps" Maps GIS Map Geospatial VB C# .NET REST</PackageTags>
<PackageReleaseNotes>See the changelog here: https://github.com/Microsoft/BingMapsRESTToolkit/blob/master/CHANGELOG.md</PackageReleaseNotes>
<PackageId>BingMapsRESTToolkit</PackageId>
<AssemblyVersion>1.0.8.0</AssemblyVersion>
<FileVersion>1.0.8.0</FileVersion>
<AssemblyVersion>1.0.9.0</AssemblyVersion>
<FileVersion>1.0.9.0</FileVersion>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\CustomMapStyleManager.cs" Link="CustomMapStyleManager.cs" />
<Compile Include="..\Enums\AvoidType.cs" Link="Enums\AvoidType.cs" />
<Compile Include="..\Enums\ConfidenceLevel.cs" Link="Enums\ConfidenceLevel.cs" />
<Compile Include="..\Enums\ConfidenceLevelType.cs" Link="Enums\ConfidenceLevelType.cs" />
<Compile Include="..\Enums\DimensionUnitType.cs" Link="Enums\DimensionUnitType.cs" />
<Compile Include="..\Enums\DistanceUnitType.cs" Link="Enums\DistanceUnitType.cs" />
<Compile Include="..\Enums\ElevationType.cs" Link="Enums\ElevationType.cs" />
<Compile Include="..\Enums\EntityType.cs" Link="Enums\EntityType.cs" />
<Compile Include="..\Enums\HazardousMaterialPermitType.cs" Link="Enums\HazardousMaterialPermitType.cs" />
<Compile Include="..\Enums\HazardousMaterialType.cs" Link="Enums\HazardousMaterialType.cs" />
<Compile Include="..\Enums\ImageFormatType.cs" Link="Enums\ImageFormatType.cs" />
<Compile Include="..\Enums\ImageResolutionType.cs" Link="Enums\ImageResolutionType.cs" />
<Compile Include="..\Enums\ImageryType.cs" Link="Enums\ImageryType.cs" />
@ -32,12 +35,21 @@
<Compile Include="..\Enums\RouteOptimizationType.cs" Link="Enums\RouteOptimizationType.cs" />
<Compile Include="..\Enums\RouteTimeType.cs" Link="Enums\RouteTimeType.cs" />
<Compile Include="..\Enums\SeverityType.cs" Link="Enums\SeverityType.cs" />
<Compile Include="..\Enums\SpeedUnitType.cs" Link="Enums\SpeedUnitType.cs" />
<Compile Include="..\Enums\TimeUnitType.cs" Link="Enums\TimeUnitType.cs" />
<Compile Include="..\Enums\TrafficType.cs" Link="Enums\TrafficType.cs" />
<Compile Include="..\Enums\TravelModeType.cs" Link="Enums\TravelModeType.cs" />
<Compile Include="..\Enums\WarningType.cs" Link="Enums\WarningType.cs" />
<Compile Include="..\Enums\WeightUnitType.cs" Link="Enums\WeightUnitType.cs" />
<Compile Include="..\Extensions\TravellingSalesmen.cs" Link="Extensions\TravellingSalesmen.cs" />
<Compile Include="..\Extensions\TSP Resources\BaseTspAlgorithm.cs" Link="Extensions\TSP Resources\BaseTspAlgorithm.cs" />
<Compile Include="..\Extensions\TSP Resources\GeneticTspAlgorithm.cs" Link="Extensions\TSP Resources\GeneticTspAlgorithm.cs" />
<Compile Include="..\Extensions\TSP Resources\GreedyTspAlgorithm.cs" Link="Extensions\TSP Resources\GreedyTspAlgorithm.cs" />
<Compile Include="..\Extensions\TspOptimizationType.cs" Link="Extensions\TspOptimizationType.cs" />
<Compile Include="..\Extensions\TspResult.cs" Link="Extensions\TspResult.cs" />
<Compile Include="..\Internal\DateTimeHelper.cs" Link="Internal\DateTimeHelper.cs" />
<Compile Include="..\Internal\EnumHelper.cs" Link="Internal\EnumHelper.cs" />
<Compile Include="..\Internal\InternalSettings.cs" Link="Internal\InternalSettings.cs" />
<Compile Include="..\Internal\ServiceHelper.cs" Link="Internal\ServiceHelper.cs" />
<Compile Include="..\Internal\SpatialTools.cs" Link="Internal\SpatialTools.cs" />
<Compile Include="..\Models\BoundingBox.cs" Link="Models\BoundingBox.cs" />
@ -50,6 +62,7 @@
<Compile Include="..\Models\ImageryPushpin.cs" Link="Models\ImageryPushpin.cs" />
<Compile Include="..\Models\PointCompression.cs" Link="Models\PointCompression.cs" />
<Compile Include="..\Models\ResponseModels\Address.cs" Link="Models\ResponseModels\Address.cs" />
<Compile Include="..\Models\ResponseModels\AsyncStatus.cs" Link="Models\ResponseModels\AsyncStatus.cs" />
<Compile Include="..\Models\ResponseModels\BirdseyeMetadata.cs" Link="Models\ResponseModels\BirdseyeMetadata.cs" />
<Compile Include="..\Models\ResponseModels\CompressedPointList.cs" Link="Models\ResponseModels\CompressedPointList.cs" />
<Compile Include="..\Models\ResponseModels\CoverageArea.cs" Link="Models\ResponseModels\CoverageArea.cs" />
@ -65,11 +78,14 @@
<Compile Include="..\Models\ResponseModels\ImageryMetadata.cs" Link="Models\ResponseModels\ImageryMetadata.cs" />
<Compile Include="..\Models\ResponseModels\ImageryProvider.cs" Link="Models\ResponseModels\ImageryProvider.cs" />
<Compile Include="..\Models\ResponseModels\Instruction.cs" Link="Models\ResponseModels\Instruction.cs" />
<Compile Include="..\Models\ResponseModels\IsochroneAsyncStatus.cs" Link="Models\ResponseModels\IsochroneAsyncStatus.cs" />
<Compile Include="..\Models\ResponseModels\IsochroneResponse.cs" Link="Models\ResponseModels\IsochroneResponse.cs" />
<Compile Include="..\Models\ResponseModels\ItineraryItem.cs" Link="Models\ResponseModels\ItineraryItem.cs" />
<Compile Include="..\Models\ResponseModels\Line.cs" Link="Models\ResponseModels\Line.cs" />
<Compile Include="..\Models\ResponseModels\Location.cs" Link="Models\ResponseModels\Location.cs" />
<Compile Include="..\Models\ResponseModels\Pixel.cs" Link="Models\ResponseModels\Pixel.cs" />
<Compile Include="..\Models\ResponseModels\Point.cs" Link="Models\ResponseModels\Point.cs" />
<Compile Include="..\Models\ResponseModels\Polygon.cs" Link="Models\ResponseModels\Polygon.cs" />
<Compile Include="..\Models\ResponseModels\PushpinMetdata.cs" Link="Models\ResponseModels\PushpinMetdata.cs" />
<Compile Include="..\Models\ResponseModels\QueryParseValue.cs" Link="Models\ResponseModels\QueryParseValue.cs" />
<Compile Include="..\Models\ResponseModels\Resource.cs" Link="Models\ResponseModels\Resource.cs" />
@ -83,14 +99,18 @@
<Compile Include="..\Models\ResponseModels\SeaLevelData.cs" Link="Models\ResponseModels\SeaLevelData.cs" />
<Compile Include="..\Models\ResponseModels\Shape.cs" Link="Models\ResponseModels\Shape.cs" />
<Compile Include="..\Models\ResponseModels\Shield.cs" Link="Models\ResponseModels\Shield.cs" />
<Compile Include="..\Models\ResponseModels\SnappedPoint.cs" Link="Models\ResponseModels\SnappedPoint.cs" />
<Compile Include="..\Models\ResponseModels\SnapToRoadResponse.cs" Link="Models\ResponseModels\SnapToRoadResponse.cs" />
<Compile Include="..\Models\ResponseModels\StaticMapMetadata.cs" Link="Models\ResponseModels\StaticMapMetadata.cs" />
<Compile Include="..\Models\ResponseModels\TrafficIncident.cs" Link="Models\ResponseModels\TrafficIncident.cs" />
<Compile Include="..\Models\ResponseModels\TransitLine.cs" Link="Models\ResponseModels\TransitLine.cs" />
<Compile Include="..\Models\ResponseModels\TruckAsyncStatus.cs" Link="Models\ResponseModels\TruckAsyncStatus.cs" />
<Compile Include="..\Models\ResponseModels\Warning.cs" Link="Models\ResponseModels\Warning.cs" />
<Compile Include="..\Models\ResponseModels\Waypoint.cs" Link="Models\ResponseModels\Waypoint.cs" />
<Compile Include="..\Models\RouteOptions.cs" Link="Models\RouteOptions.cs" />
<Compile Include="..\Models\SimpleAddress.cs" Link="Models\SimpleAddress.cs" />
<Compile Include="..\Models\SimpleWaypoint.cs" Link="Models\SimpleWaypoint.cs" />
<Compile Include="..\Models\VehicleSpec.cs" Link="Models\VehicleSpec.cs" />
<Compile Include="..\Requests\BaseImageryRestRequest.cs" Link="Requests\BaseImageryRestRequest.cs" />
<Compile Include="..\Requests\BaseRestRequest.cs" Link="Requests\BaseRestRequest.cs" />
<Compile Include="..\Requests\DistanceMatrixRequest.cs" Link="Requests\DistanceMatrixRequest.cs" />
@ -99,15 +119,18 @@
<Compile Include="..\Requests\GeospatialEndpointRequest.cs" Link="Requests\GeospatialEndpointRequest.cs" />
<Compile Include="..\Requests\ImageryMetadataRequest.cs" Link="Requests\ImageryMetadataRequest.cs" />
<Compile Include="..\Requests\ImageryRequest.cs" Link="Requests\ImageryRequest.cs" />
<Compile Include="..\Requests\IsochroneRequest.cs" Link="Requests\IsochroneRequest.cs" />
<Compile Include="..\Requests\ReverseGeocodeRequest.cs" Link="Requests\ReverseGeocodeRequest.cs" />
<Compile Include="..\Requests\RouteMajorRoadsRequest.cs" Link="Requests\RouteMajorRoadsRequest.cs" />
<Compile Include="..\Requests\RouteRequest.cs" Link="Requests\RouteRequest.cs" />
<Compile Include="..\Requests\SnapToRoadRequest.cs" Link="Requests\SnapToRoadRequest.cs" />
<Compile Include="..\Requests\TrafficRequest.cs" Link="Requests\TrafficRequest.cs" />
<Compile Include="..\ServiceManager.cs" Link="ServiceManager.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Enums\" />
<Folder Include="Extensions\TSP Resources\" />
<Folder Include="Models\CustomMapStyles\" />
<Folder Include="Models\ResponseModels\" />
<Folder Include="Internal\" />

Просмотреть файл

@ -40,7 +40,10 @@
</PropertyGroup>
<ItemGroup>
<Compile Include="Enums\AvoidType.cs" />
<Compile Include="Enums\ConfidenceLevel.cs" />
<Compile Include="Enums\ConfidenceLevelType.cs" />
<Compile Include="Enums\DimensionUnitType.cs" />
<Compile Include="Enums\HazardousMaterialPermitType.cs" />
<Compile Include="Enums\HazardousMaterialType.cs" />
<Compile Include="Enums\ImageResolutionType.cs" />
<Compile Include="Enums\ImageFormatType.cs" />
<Compile Include="Enums\ImageryType.cs" />
@ -48,13 +51,23 @@
<Compile Include="Enums\RouteAttributeType.cs" />
<Compile Include="Enums\RouteOptimizationType.cs" />
<Compile Include="Enums\RouteTimeType.cs" />
<Compile Include="Enums\SpeedUnitType.cs" />
<Compile Include="Enums\TimeUnitType.cs" />
<Compile Include="Enums\TravelModeType.cs" />
<Compile Include="Enums\SeverityType.cs" />
<Compile Include="Enums\TrafficType.cs" />
<Compile Include="Enums\WarningType.cs" />
<Compile Include="Enums\WeightUnitType.cs" />
<Compile Include="Extensions\TSP Resources\BaseTspAlgorithm.cs" />
<Compile Include="Extensions\TSP Resources\GreedyTspAlgorithm.cs" />
<Compile Include="Extensions\TSP Resources\GeneticTspAlgorithm.cs" />
<Compile Include="Extensions\TravellingSalesmen.cs" />
<Compile Include="Extensions\TspOptimizationType.cs" />
<Compile Include="Extensions\TspResult.cs" />
<Compile Include="Internal\DateTimeHelper.cs" />
<Compile Include="Internal\EnumHelper.cs" />
<Compile Include="Internal\InternalSettings.cs" />
<Compile Include="Models\ResponseModels\AsyncStatus.cs" />
<Compile Include="Models\BoundingBox.cs" />
<Compile Include="CustomMapStyleManager.cs" />
<Compile Include="Models\CustomMapStyles\CustomMapStyle.cs" />
@ -79,11 +92,14 @@
<Compile Include="Models\ResponseModels\ImageryMetadata.cs" />
<Compile Include="Models\ResponseModels\ImageryProvider.cs" />
<Compile Include="Models\ResponseModels\Instruction.cs" />
<Compile Include="Models\ResponseModels\IsochroneAsyncStatus.cs" />
<Compile Include="Models\ResponseModels\IsochroneResponse.cs" />
<Compile Include="Models\ResponseModels\ItineraryItem.cs" />
<Compile Include="Models\ResponseModels\Line.cs" />
<Compile Include="Models\ResponseModels\Location.cs" />
<Compile Include="Models\ResponseModels\Pixel.cs" />
<Compile Include="Models\ResponseModels\Point.cs" />
<Compile Include="Models\ResponseModels\Polygon.cs" />
<Compile Include="Models\ResponseModels\PushpinMetdata.cs" />
<Compile Include="Models\ResponseModels\QueryParseValue.cs" />
<Compile Include="Models\ResponseModels\Resource.cs" />
@ -97,12 +113,16 @@
<Compile Include="Models\ResponseModels\SeaLevelData.cs" />
<Compile Include="Models\ResponseModels\Shape.cs" />
<Compile Include="Models\ResponseModels\Shield.cs" />
<Compile Include="Models\ResponseModels\SnappedPoint.cs" />
<Compile Include="Models\ResponseModels\SnapToRoadResponse.cs" />
<Compile Include="Models\ResponseModels\StaticMapMetadata.cs" />
<Compile Include="Models\ResponseModels\TrafficIncident.cs" />
<Compile Include="Models\ResponseModels\TransitLine.cs" />
<Compile Include="Models\ResponseModels\TruckAsyncStatus.cs" />
<Compile Include="Models\ResponseModels\Warning.cs" />
<Compile Include="Models\ResponseModels\Waypoint.cs" />
<Compile Include="Models\RouteOptions.cs" />
<Compile Include="Models\VehicleSpec.cs" />
<Compile Include="Requests\DistanceMatrixRequest.cs" />
<Compile Include="Requests\GeospatialEndpointRequest.cs" />
<Compile Include="Requests\ImageryMetadataRequest.cs" />
@ -115,6 +135,8 @@
<Compile Include="Enums\ElevationType.cs" />
<Compile Include="Enums\EntityType.cs" />
<Compile Include="Internal\ServiceHelper.cs" />
<Compile Include="Requests\IsochroneRequest.cs" />
<Compile Include="Requests\SnapToRoadRequest.cs" />
<Compile Include="Internal\SpatialTools.cs" />
<Compile Include="Models\SimpleAddress.cs" />
<Compile Include="Requests\BaseRestRequest.cs" />

Просмотреть файл

@ -27,7 +27,7 @@ namespace BingMapsRESTToolkit
/// <summary>
/// The level of confidence that the geocoded location result is a match.
/// </summary>
public enum ConfidenceLevel
public enum ConfidenceLevelType
{
/// <summary>
/// No confidence level set.

Просмотреть файл

@ -0,0 +1,18 @@
namespace BingMapsRESTToolkit
{
/// <summary>
/// Measurement units of vehicle dimensions.
/// </summary>
public enum DimensionUnitType
{
/// <summary>
/// Dimensions in meters.
/// </summary>
Meter,
/// <summary>
/// Dimensions in feet.
/// </summary>
Feet
}
}

Просмотреть файл

@ -0,0 +1,68 @@
namespace BingMapsRESTToolkit
{
/// <summary>
/// Types of hazardous material permits for truck routing.
/// </summary>
public enum HazardousMaterialPermitType
{
/// <summary>
/// Permit for goods which are all appropriate for load.
/// </summary>
AllAppropriateForLoad,
/// <summary>
/// Permit for combustible material.
/// </summary>
Combustible,
/// <summary>
/// Permit for corrosive material.
/// </summary>
Corrosive,
/// <summary>
/// Permit for explosive material.
/// </summary>
Explosive,
/// <summary>
/// Permit for flammable material.
/// </summary>
Flammable,
/// <summary>
/// Permit for flammable solid material.
/// </summary>
FlammableSolid,
/// <summary>
/// Permit for gases.
/// </summary>
Gas,
/// <summary>
/// No hazardous material permits.
/// </summary>
None,
/// <summary>
/// Permit for organic material.
/// </summary>
Organic,
/// <summary>
/// Permit for poisonous material.
/// </summary>
Poison,
/// <summary>
/// Permit for poisonous inhalation material.
/// </summary>
PoisonousInhalation,
/// <summary>
/// Permit for radioactive material.
/// </summary>
Radioactive
}
}

Просмотреть файл

@ -0,0 +1,73 @@
namespace BingMapsRESTToolkit
{
/// <summary>
/// Hazardous materials in which a truck may transport.
/// </summary>
public enum HazardousMaterialType
{
/// <summary>
/// Combustable materials.
/// </summary>
Combustable,
/// <summary>
/// Corrosive materials.
/// </summary>
Corrosive,
/// <summary>
/// Explosive materials.
/// </summary>
Explosive,
/// <summary>
/// Flammable materials.
/// </summary>
Flammable,
/// <summary>
/// Flammable Solid materials.
/// </summary>
FlammableSolid,
/// <summary>
/// Gases.
/// </summary>
Gas,
/// <summary>
/// Goods Harmful To Water.
/// </summary>
GoodsHarmfulToWater,
/// <summary>
/// No hazardous materials.
/// </summary>
None,
/// <summary>
/// Organic materials.
/// </summary>
Organic,
/// <summary>
/// Some other hazardous materials.
/// </summary>
Other,
/// <summary>
/// Poisonous materials.
/// </summary>
Poison,
/// <summary>
/// Poisonous Inhalation materials.
/// </summary>
PoisonousInhalation,
/// <summary>
/// Radioactive materials.
/// </summary>
Radioactive
}
}

Просмотреть файл

@ -0,0 +1,42 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace BingMapsRESTToolkit
{
/// <summary>
/// Unit of speed.
/// </summary>
public enum SpeedUnitType
{
/// <summary>
/// Kilometers per hour.
/// </summary>
KPH,
/// <summary>
/// Miles per hour.
/// </summary>
MPH
}
}

Просмотреть файл

@ -32,11 +32,11 @@ namespace BingMapsRESTToolkit
/// <summary>
/// Time is in seconds.
/// </summary>
Seconds,
Second,
/// <summary>
/// Time is in minutes.
/// </summary>
Minutes
Minute
}
}

Просмотреть файл

@ -42,6 +42,11 @@ namespace BingMapsRESTToolkit
/// <summary>
/// Transit mode.
/// </summary>
Transit
Transit,
/// <summary>
/// Truck driving mode.
/// </summary>
Truck
}
}

Просмотреть файл

@ -0,0 +1,18 @@
namespace BingMapsRESTToolkit
{
/// <summary>
/// Unit of measurement for vehicle weights.
/// </summary>
public enum WeightUnitType
{
/// <summary>
/// Weight in kilograms.
/// </summary>
Kilogram,
/// <summary>
/// Weight in pounds.
/// </summary>
Pound
}
}

Просмотреть файл

@ -0,0 +1,186 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
namespace BingMapsRESTToolkit.Extensions
{
/// <summary>
/// An algorithm for solving the travelling salesmen problem.
/// </summary>
internal class BaseTspAlgorithm
{
#region Protected Properties
/// <summary>
/// Random number generator.
/// </summary>
protected Random random;
#endregion
#region Constructor
/// <summary>
/// An algorithm for solving the travelling salesmen problem.
/// </summary>
public BaseTspAlgorithm()
{
random = new Random();
}
#endregion
#region Public Methods
/// <summary>
/// Calculates an efficient path between all waypoints based on time or distance.
/// </summary>
/// <param name="waypoints">The waypoints to calculate a path through.</param>
/// <param name="travelMode">The mode of transportation.</param>
/// <param name="tspOptimization">The metric in which to base the TSP algorithm.</param>
/// <param name="departureTime">The departure time in which to consider predictive traffic for. Only used when travel mode is driving and tsp optimiation is based on travel time or travel distance. Ignored if there is more than 10 waypoints as that would exceed limits of a distance matrix call.</param>
/// <param name="isRoundTrip">Indicates if the path should be round trip and return to the origin or not.</param>
/// <param name="bingMapsKey">A bing maps key.</param>
/// <returns>An efficient path between all waypoints based on time or distance.</returns>
public async Task<TspResult> Solve(List<SimpleWaypoint> waypoints, TravelModeType? travelMode, TspOptimizationType? tspOptimization, DateTime? departureTime, string bingMapsKey)
{
if(waypoints == null && waypoints.Count > 0)
{
//Ensure that unique waypoints are in the list. This will reduce the number of cells generated in the distance matrix, thus lower cost.
waypoints = waypoints.Distinct().ToList();
}
if (tspOptimization == null || !tspOptimization.HasValue)
{
tspOptimization = TspOptimizationType.TravelTime;
}
DistanceMatrix dm = null;
if (tspOptimization.Value == TspOptimizationType.StraightLineDistance)
{
//Calculate a distance matrix based on straight line distances (haversine).
dm = await DistanceMatrix.CreateStraightLineNxNMatrix(waypoints, DistanceUnitType.Kilometers, bingMapsKey);
}
else
{
if (travelMode == null || !travelMode.HasValue)
{
//Default to driving if not specified.
travelMode = TravelModeType.Driving;
}
else if (travelMode == TravelModeType.Truck)
{
//Truck routes not supported for distance matrix, fall back to driving.
travelMode = TravelModeType.Driving;
}
var distanceMatrixRequest = new DistanceMatrixRequest()
{
TravelMode = travelMode.Value,
BingMapsKey = bingMapsKey
};
if (departureTime.HasValue && distanceMatrixRequest.TravelMode == TravelModeType.Driving && waypoints.Count <= 10)
{
distanceMatrixRequest.StartTime = departureTime.Value;
}
distanceMatrixRequest.Origins = waypoints;
var r = await distanceMatrixRequest.Execute();
if (r != null)
{
if (r.ErrorDetails != null && r.ErrorDetails.Length > 0)
{
throw new Exception(String.Join("", r.ErrorDetails));
}
if (r.ResourceSets != null && r.ResourceSets.Length > 0 && r.ResourceSets[0] != null &&
r.ResourceSets[0].Resources != null && r.ResourceSets.Length > 0 && r.ResourceSets[0].Resources[0] != null &&
r.ResourceSets[0].Resources[0] is DistanceMatrix)
{
dm = r.ResourceSets[0].Resources[0] as DistanceMatrix;
}
}
}
if(dm != null)
{
var solution = await Solve(dm, tspOptimization.Value);
solution.TspOptimization = tspOptimization.Value;
solution.TravelMode = travelMode.Value;
return solution;
}
throw new Exception("Unable to calculate distance matrix.");
}
/// <summary>
/// Calculates an efficient path between all waypoints based on time or distance.
/// </summary>
/// <param name="matrix">A precalculated distance matrix (n x n).</param>
/// <param name="tspOptimization">The metric in which to base the TSP algorithm.</param>
/// <returns>An efficient path between all waypoints based on time or distance.</returns>
#pragma warning disable 1998
public virtual async Task<TspResult> Solve(DistanceMatrix matrix, TspOptimizationType tspOptimization)
{
throw new NotImplementedException();
}
#pragma warning restore 1998
/// <summary>
/// Generates the optimized list of waypoints based on an optimized array of waypoint indicies.
/// </summary>
/// <param name="waypoints">Waypoints to optimize.</param>
/// <param name="minTour">An optimized array of waypoint indicies</param>
/// <param name="isRoundTrip">A boolean indicating if it is a round trip tour.</param>
/// <returns>An optimized lis tof waypoints.</returns>
protected List<SimpleWaypoint> GetOptimizedWaypoints(List<SimpleWaypoint> waypoints, int[] minTour)
{
var optimizedOrder = new List<SimpleWaypoint>();
for (var i = 0; i < minTour.Length; i++)
{
optimizedOrder.Add(waypoints[minTour[i]]);
}
//Close the loop
if (minTour[minTour.Length - 1] != 0)
{
optimizedOrder.Add(waypoints[0]);
}
return optimizedOrder;
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,478 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BingMapsRESTToolkit.Extensions
{
/// <summary>
/// A genetic algorithim for solving the Travelling Salesmen problem using the Bing Maps Distance Matrix service, based on travel time.
/// </summary>
internal class GeneticTspAlgorithm: BaseTspAlgorithm
{
#region Public Properties
/// <summary>
/// The initial number of random tours that are created when the algorithm starts.
/// A large number of generations takes longer to find a result.
/// A smaller number of generations increases the chance that every tour will eventually look the same. This increases the chance that the best solution will not be found.
/// </summary>
public int Generations = 10000;
/// <summary>
/// The percentage that each crossover will undergo a mutution. When a mutation occurs, one of the waypoints is randomly within the order.
/// </summary>
public double MutationRate = 0.2;
#endregion
#region Public Methods
/// <summary>
/// Calculates an efficient path between all waypoints based on time or distance.
/// </summary>
/// <param name="matrix">A precalculated distance matrix (n x n).</param>
/// <param name="tspOptimization">The metric in which to base the TSP algorithm.</param>
/// <returns>An efficient path between all waypoints based on time or distance.</returns>
public override async Task<TspResult> Solve(DistanceMatrix matrix, TspOptimizationType tspOptimization)
{
return await Task<TspResult>.Run<TspResult>(() =>
{
int population = matrix.Origins.Count;
double[] weight = new double[population];
var minTour = new int[population];
int[,] chromosome = new int[population, population];
double minWeight = double.MaxValue;
for (int p = 0; p < population; p++)
{
bool[] used = new bool[population];
int[] currentOrder = new int[population];
for (int n = 0; n < population; n++)
{
used[n] = false;
}
for (int n = 0; n < population; n++)
{
int i;
do
{
i = random.Next(population);
}
while (used[i]);
used[i] = true;
currentOrder[n] = i;
}
for (int n = 0; n < population; n++)
{
chromosome[p, n] = currentOrder[n];
}
if (tspOptimization == TspOptimizationType.TravelTime)
{
weight[p] = matrix.GetEdgeTime(currentOrder, true);
}
else
{
weight[p] = matrix.GetEdgeDistance(currentOrder, true);
}
if (weight[p] < minWeight)
{
minWeight = weight[p];
for (int n = 0; n < population; n++)
{
minTour[n] = chromosome[p, n];
}
}
}
for (int g = 0; g < Generations; g++)
{
if (random.NextDouble() < MutationRate)
{
int i, j, parent1, parent2;
int[] p1 = new int[population];
int[] p2 = new int[population];
int[] o1 = new int[population];
int[] o2 = new int[population];
i = random.Next(population);
j = random.Next(population);
if (weight[i] < weight[j])
{
parent1 = i;
}
else
{
parent1 = j;
}
i = random.Next(population);
j = random.Next(population);
if (weight[i] < weight[j])
{
parent2 = i;
}
else
{
parent2 = j;
}
for (i = 0; i < population; i++)
{
p1[i] = chromosome[parent1, i];
p2[i] = chromosome[parent2, i];
}
int cp1 = -1, cp2 = -1;
do
{
cp1 = random.Next(population);
cp2 = random.Next(population);
} while (cp1 == cp2 || cp1 > cp2);
Crossover(cp1, cp2, p1, p2, o1, o2, population, random);
double o1Fitness;
if (tspOptimization == TspOptimizationType.TravelTime)
{
o1Fitness = matrix.GetEdgeTime(o1, true);
}
else
{
o1Fitness = matrix.GetEdgeDistance(o1, true);
}
if (o1Fitness < weight[parent1])
{
for (i = 0; i < population; i++)
{
chromosome[parent1, i] = o1[i];
}
}
double o2Fitness;
if (tspOptimization == TspOptimizationType.TravelTime)
{
o2Fitness = matrix.GetEdgeTime(o2, true);
}
else
{
o2Fitness = matrix.GetEdgeDistance(o2, true);
}
if (o2Fitness < weight[parent2])
{
for (i = 0; i < population; i++)
{
chromosome[parent2, i] = o2[i];
}
}
for (int p = 0; p < population; p++)
{
if (weight[p] < minWeight)
{
minWeight = weight[p];
for (int n = 0; n < population; n++)
{
minTour[n] = chromosome[p, n];
}
}
}
}
else
{
int i, j, p;
int[] child = new int[population];
i = random.Next(population);
j = random.Next(population);
if (weight[i] < weight[j])
{
p = i;
}
else
{
p = j;
}
double childWeight;
for (int n = 0; n < population; n++)
{
child[n] = chromosome[p, n];
}
do
{
i = random.Next(population);
j = random.Next(population);
}
while (i == j);
int t = child[i];
child[i] = child[j];
child[j] = t;
if (tspOptimization == TspOptimizationType.TravelTime)
{
childWeight = matrix.GetEdgeTime(child, true);
}
else
{
childWeight = matrix.GetEdgeDistance(child, true);
}
int maxIndex = int.MaxValue;
double maxD = double.MinValue;
for (int q = 0; q < population; q++)
{
if (weight[q] >= maxD)
{
maxIndex = q;
maxD = weight[q];
}
}
int[] index = new int[population];
int count = 0;
for (int q = 0; q < population; q++)
{
if (weight[q] == maxD)
{
index[count++] = q;
}
}
maxIndex = index[random.Next(count)];
if (childWeight < weight[maxIndex])
{
weight[maxIndex] = childWeight;
for (int n = 0; n < population; n++)
{
chromosome[maxIndex, n] = child[n];
}
if (childWeight < minWeight)
{
minWeight = childWeight;
for (int n = 0; n < population; n++)
{
minTour[n] = child[n];
}
}
}
}
}
//Ensure first point is the starting point. Indicies form a cycle, so just need to shift.
if (minTour[0] != 0)
{
var minTourList = minTour.ToList();
var startIdx = minTourList.IndexOf(0);
var order = new List<int>();
order.AddRange(minTourList.GetRange(startIdx, minTourList.Count - startIdx));
order.AddRange(minTourList.GetRange(0, startIdx));
minTour = order.ToArray();
}
return new TspResult()
{
DistanceMatrix = matrix,
OptimizedWeight = minWeight,
OptimizedWaypoints = GetOptimizedWaypoints(matrix.Origins, minTour)
};
});
}
#endregion
#region Private Methods
/// <summary>
/// Partially Mapped Crossover.
/// </summary>
private static void Crossover(int cp1, int cp2, int[] p1, int[] p2, int[] o1, int[] o2, int number, Random random)
{
for (int i = 0; i < number; i++)
{
o1[i] = o2[i] = -1;
}
for (int i = cp1; i <= cp2; i++)
{
o1[i] = p2[i];
o2[i] = p1[i];
}
for (int i = 0; i < cp1; i++)
{
bool found = false;
int t = p1[i];
for (int j = i + 1; !found && j < number; j++)
{
found = t == o1[j];
}
if (!found)
{
o1[i] = t;
}
}
for (int i = cp2 + 1; i < number; i++)
{
bool found = false;
int t = p1[i];
for (int j = 0; !found && j < number; j++)
{
found = t == o1[j];
}
if (!found)
{
o1[i] = t;
}
}
List<int> used = new List<int>();
for (int i = 0; i < number; i++)
{
if (o1[i] != -1)
{
used.Add(o1[i]);
}
}
for (int i = 0; i < number; i++)
{
if (o1[i] == -1)
{
int x;
do
{
x = random.Next(number);
} while (used.Contains(x));
o1[i] = x;
used.Add(x);
}
}
for (int i = 0; i < cp1; i++)
{
bool found = false;
int t = p2[i];
for (int j = i + 1; !found && j < number; j++)
{
found = t == o2[j];
}
if (!found)
{
o2[i] = t;
}
}
for (int i = cp2 + 1; i < number; i++)
{
bool found = false;
int t = p2[i];
for (int j = 0; !found && j < number; j++)
{
found = t == o2[j];
}
if (!found)
{
o2[i] = t;
}
}
used = new List<int>();
for (int i = 0; i < number; i++)
{
if (o2[i] != -1)
{
used.Add(o2[i]);
}
}
for (int i = 0; i < number; i++)
{
if (o2[i] == -1)
{
int x;
do
{
x = random.Next(number);
} while (used.Contains(x));
o2[i] = x;
used.Add(x);
}
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,143 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Threading.Tasks;
namespace BingMapsRESTToolkit.Extensions
{
/// <summary>
/// A genetic algorithim for solving the Travelling Salesmen problem using the Bing Maps Distance Matrix service, based on travel time.
/// This uses brute force and recommended for 10 or less waypoints.
/// </summary>
internal class GreedyAlgorithm : BaseTspAlgorithm
{
#region Public Methods
/// <summary>
/// Calculates an efficient path between all waypoints based on time or distance.
/// </summary>
/// <param name="matrix">A precalculated distance matrix (n x n).</param>
/// <param name="tspOptimization">The metric in which to base the TSP algorithm.</param>
/// <returns>An efficient path between all waypoints based on time or distance.</returns>
public override async Task<TspResult> Solve(DistanceMatrix matrix, TspOptimizationType tspOptimization)
{
return await Task<TspResult>.Run<TspResult>(() =>
{
var tour = new int[matrix.Origins.Count];
for (var i = 0; i < matrix.Origins.Count; i++)
{
tour[i] = i;
}
double minWeight = double.MaxValue;
double weight;
int[] minTour = tour;
while (NextPermutation(tour))
{
//Break out if the first location isn't in the first position.
if (tour[0] != 0)
{
break;
}
if (tspOptimization == TspOptimizationType.TravelTime)
{
weight = matrix.GetEdgeTime(tour, true);
}
else
{
weight = matrix.GetEdgeDistance(tour, true);
}
if (weight < minWeight)
{
minWeight = weight;
minTour = (int[])tour.Clone();
}
}
return new TspResult()
{
DistanceMatrix = matrix,
OptimizedWeight = minWeight,
OptimizedWaypoints = GetOptimizedWaypoints(matrix.Origins, minTour)
};
});
}
#endregion
#region Private Properties
/// <summary>
/// Computes the next lexicographical permutation of the given array of integers in place, returning whether a next permutation existed.
/// Returns false when the argument is already the last possible permutation.
/// </summary>
/// <param name="array">The array of integers to permutate through.</param>
/// <returns>A boolean indicating if more permutations exist.</returns>
public static bool NextPermutation(int[] array)
{
// Find non-increasing suffix
int i = array.Length - 1;
while (i > 0 && array[i - 1] >= array[i])
{
i--;
}
if (i <= 0)
{
return false;
}
// Find successor to pivot
int j = array.Length - 1;
while (array[j] <= array[i - 1])
{
j--;
}
int temp = array[i - 1];
array[i - 1] = array[j];
array[j] = temp;
// Reverse suffix
j = array.Length - 1;
while (i < j)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
return true;
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,91 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BingMapsRESTToolkit.Extensions
{
/// <summary>
/// This is a static class that solves the [travelling salesmen problem](https://en.wikipedia.org/wiki/Travelling_salesman_problem).
/// Uses a greedy algrithm when 10 or less waypoints are specified, and a genetic algorithm for largre waypoint sets.
/// </summary>
public static class TravellingSalesmen
{
/// <summary>
/// Solves the travelling salesmen problem.
/// </summary>
/// <param name="waypoints">The waypoints to calculate a path through.</param>
/// <param name="travelMode">The mode of transportation.</param>
/// <param name="tspOptimization">The metric in which to base the TSP algorithm.</param>
/// <param name="departureTime">The departure time in which to consider predictive traffic for. Only used when travel mode is driving and tsp optimiation is based on travel time or travel distance. Ignored if there is more than 10 waypoints as that would exceed limits of a distance matrix call.</param>
/// <param name="bingMapsKey">A bing maps key.</param>
/// <returns>An efficient path between all waypoints based on time or distance.</returns>
public static async Task<TspResult> Solve(List<SimpleWaypoint> waypoints, TravelModeType? travelMode, TspOptimizationType? tspOptimization, DateTime? departureTime, string bingMapsKey)
{
return await GetTspAlgorithm(waypoints).Solve(waypoints, travelMode, tspOptimization, departureTime, bingMapsKey);
}
///<summary>
/// Solves the travelling salesmen problem.
/// </summary>
/// <param name="matrix">A precalculated distance matrix (n x n).</param>
/// <param name="tspOptimization">The metric in which to base the TSP algorithm.</param>
/// <returns>An efficient path between all waypoints based on time or distance.</returns>
public static async Task<TspResult> Solve(DistanceMatrix matrix, TspOptimizationType tspOptimization)
{
return await GetTspAlgorithm(matrix.Origins).Solve(matrix, tspOptimization);
}
/// <summary>
/// Gets the appropriate TSP algorithm based on the waypoints provided.
/// </summary>
/// <param name="waypoints">Waypoints to be optimized.</param>
/// <returns>The appropriate TSP algorithm based on the waypoints provided.</returns>
private static BaseTspAlgorithm GetTspAlgorithm(List<SimpleWaypoint> waypoints)
{
if (waypoints != null && waypoints.Count > 0)
{
//Ensure that unique waypoints are in the list. This will reduce the number of cells generated in the distance matrix, thus lowering cost.
var wps = waypoints.Distinct().ToList();
if (wps.Count >= 2)
{
if (wps.Count > 10)
{
return new GeneticTspAlgorithm();
}
else
{
return new GreedyAlgorithm();
}
}
}
throw new Exception("Insufficient number of waypoints specified.");
}
}
}

Просмотреть файл

@ -0,0 +1,47 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace BingMapsRESTToolkit.Extensions
{
/// <summary>
/// Metrics in which the travelling salesmen problem is solved for.
/// </summary>
public enum TspOptimizationType
{
/// <summary>
/// Optimizes based on travel times (roads). Uses the Distance Matrix API.
/// </summary>
TravelTime,
/// <summary>
/// Optimizes based on travel distances (roads). Uses the Distance Matrix API.
/// </summary>
TravelDistance,
/// <summary>
/// Optimizes based on straight line distances (as the crow flies).
/// </summary>
StraightLineDistance
}
}

Просмотреть файл

@ -0,0 +1,64 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Collections.Generic;
namespace BingMapsRESTToolkit.Extensions
{
/// <summary>
/// The result from a Travelling Salesmen calculation.
/// </summary>
public class TspResult
{
/// <summary>
/// A list of the waypoints in an optimized ordered.
/// </summary>
public List<SimpleWaypoint> OptimizedWaypoints { get; set; }
/// <summary>
/// The optimized weight (time or distance) between all waypoints based on the TspOptimizationType.
/// </summary>
public double OptimizedWeight { get; set; }
/// <summary>
/// Indicates if the path is for a round trip and returns to the origin or not.
/// </summary>
public bool IsRoundTrip { get; set; }
/// <summary>
/// The metric used to solve the travelling salesmen problem for.
/// </summary>
public TspOptimizationType TspOptimization { get; set; }
/// <summary>
/// The travel mode used to calculate the distance matrix.
/// </summary>
public TravelModeType TravelMode { get; set; }
/// <summary>
/// The distance matrix used in the calculation.
/// </summary>
public DistanceMatrix DistanceMatrix { get; set; }
}
}

Просмотреть файл

@ -37,11 +37,11 @@ namespace BingMapsRESTToolkit
/// </summary>
/// <param name="dateTime">The DateTime to convert.</param>
/// <returns>An OData version of the DateTime.</returns>
public static string ToOdataJson(DateTime dateTime)
internal static string ToOdataJson(DateTime dateTime)
{
DateTime d1 = new DateTime(1970, 1, 1);
DateTime d2 = dateTime.ToUniversalTime();
TimeSpan ts = new TimeSpan(d2.Ticks - d1.Ticks);
var d1 = new DateTime(1970, 1, 1);
var d2 = dateTime.ToUniversalTime();
var ts = new TimeSpan(d2.Ticks - d1.Ticks);
return "\\/Date(" + ts.TotalMilliseconds.ToString("#") + ")\\/";
}
@ -50,7 +50,7 @@ namespace BingMapsRESTToolkit
/// </summary>
/// <param name="jsonDate">OData Date to convert.</param>
/// <returns>The converted DateTime object.</returns>
public static DateTime FromOdataJson(string jsonDate)
internal static DateTime FromOdataJson(string jsonDate)
{
// /Date(1235764800000)/
// /Date(1467298867000-0700)/

Просмотреть файл

@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
namespace BingMapsRESTToolkit
{
/// <summary>
@ -34,14 +35,14 @@ namespace BingMapsRESTToolkit
/// </summary>
/// <param name="dut">Distance unit to convert.</param>
/// <returns>A string version of the distance unit.</returns>
public static string DistanceUnitTypeToString(DistanceUnitType dut)
internal static string DistanceUnitTypeToString(DistanceUnitType dut)
{
if(dut == DistanceUnitType.Miles)
{
return "miles";
return "mile";
}
return "kilometers";
return "kilometer";
}
/// <summary>
@ -49,7 +50,7 @@ namespace BingMapsRESTToolkit
/// </summary>
/// <param name="dut">A string to convert.</param>
/// <returns>A distance unit type.</returns>
public static DistanceUnitType DistanceUnitStringToEnum(string dut)
internal static DistanceUnitType DistanceUnitStringToEnum(string dut)
{
switch (dut.ToLowerInvariant())
{
@ -69,42 +70,127 @@ namespace BingMapsRESTToolkit
}
}
/// <summary>
/// Converts time unit type to a string.
/// </summary>
/// <param name="tut">Time unit to convert.</param>
/// <returns>A string version of the time unit.</returns>
public static string TimeUnitTypeToString(TimeUnitType tut)
{
if (tut == TimeUnitType.Minutes)
{
return "minutes";
}
return "seconds";
}
/// <summary>
/// Converts a string into a TimeUnitType.
/// </summary>
/// <param name="tut">A string to convert.</param>
/// <returns>A time unit type.</returns>
public static TimeUnitType TimeUnitStringToEnum(string tut)
internal static TimeUnitType TimeUnitStringToEnum(string tut)
{
switch (tut.ToLowerInvariant())
{
{
case "minutes":
case "minute":
case "min":
case "mins":
case "m":
return TimeUnitType.Minutes;
return TimeUnitType.Minute;
case "seconds":
case "second":
case "secs":
case "sec":
case "s":
default:
return TimeUnitType.Seconds;
return TimeUnitType.Second;
}
}
/// <summary>
/// Converts a string into a ConfidenceLevelType.
/// </summary>
/// <param name="confidence">A string to convert.</param>
/// <returns>A confidence level type.</returns>
internal static ConfidenceLevelType ConfidenceLevelTypeStringToEnum(string confidence)
{
if (!string.IsNullOrWhiteSpace(confidence))
{
switch (confidence.ToLowerInvariant())
{
case "high":
return ConfidenceLevelType.High;
case "medium":
return ConfidenceLevelType.Medium;
case "low":
return ConfidenceLevelType.Low;
}
}
return ConfidenceLevelType.None;
}
/// <summary>
/// Converts a HazardousMaterialPermitType enumeration into its short form string format.
/// </summary>
/// <param name="hmpt">HazardousMaterialPermitType enumeration to convert.</param>
/// <returns>A HazardousMaterialPermitType enumeration convrted into its short form string format.</returns>
internal static string HazardousMaterialPermitTypeToString(HazardousMaterialPermitType hmpt)
{
switch (hmpt)
{
case HazardousMaterialPermitType.AllAppropriateForLoad:
return "AllAppropriateForLoad";
case HazardousMaterialPermitType.Combustible:
return "C";
case HazardousMaterialPermitType.Corrosive:
return "Cr";
case HazardousMaterialPermitType.Explosive:
return "E";
case HazardousMaterialPermitType.Flammable:
return "F";
case HazardousMaterialPermitType.FlammableSolid:
return "FS";
case HazardousMaterialPermitType.Gas:
return "G";
case HazardousMaterialPermitType.Organic:
return "O";
case HazardousMaterialPermitType.Poison:
return "P";
case HazardousMaterialPermitType.PoisonousInhalation:
return "PI";
case HazardousMaterialPermitType.Radioactive:
return "R";
case HazardousMaterialPermitType.None:
default:
return "None";
}
}
/// <summary>
/// Converts a HazardousMaterialType enumeration into its short form string format.
/// </summary>
/// <param name="hmt">HazardousMaterialType enumeration to convert.</param>
/// <returns>A HazardousMaterialType enumeration convrted into its short form string format.</returns>
internal static string HazardousMaterialTypeToString(HazardousMaterialType hmt)
{
switch (hmt)
{
case HazardousMaterialType.Combustable:
return "C";
case HazardousMaterialType.Corrosive:
return "Cr";
case HazardousMaterialType.Explosive:
return "E";
case HazardousMaterialType.Flammable:
return "F";
case HazardousMaterialType.FlammableSolid:
return "FS";
case HazardousMaterialType.Gas:
return "G";
case HazardousMaterialType.GoodsHarmfulToWater:
return "WH";
case HazardousMaterialType.Organic:
return "O";
case HazardousMaterialType.Other:
return "Other";
case HazardousMaterialType.Poison:
return "P";
case HazardousMaterialType.PoisonousInhalation:
return "PI";
case HazardousMaterialType.Radioactive:
return "R";
case HazardousMaterialType.None:
default:
return "None";
}
}
}

Просмотреть файл

@ -0,0 +1,37 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
namespace BingMapsRESTToolkit
{
/// <summary>
/// Internal settings.
/// </summary>
public static class InternalSettings
{
/// <summary>
/// API identifier. Used to help trace and debug issues with the toolkit.
/// </summary>
public static string ClientApi = "CSToolkit";
}
}

Просмотреть файл

@ -23,7 +23,9 @@
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Threading.Tasks;
@ -35,6 +37,20 @@ namespace BingMapsRESTToolkit
/// </summary>
internal class ServiceHelper
{
#region Private Properties
/// <summary>
/// The maximium number of times the retry the status check if it fails. This will allow for possible connection issues.
/// </summary>
private const int MaxStatusCheckRetries = 3;
/// <summary>
/// Number of seconds to delay a retry of a status check.
/// </summary>
private const int StatusCheckRetryDelay = 10;
#endregion
#region Public Methods
/// <summary>
@ -42,7 +58,7 @@ namespace BingMapsRESTToolkit
/// </summary>
/// <param name="url">URL that points to data to download.</param>
/// <returns>A string with the data.</returns>
public static Task<string> GetStringAsync(Uri url)
internal static Task<string> GetStringAsync(Uri url)
{
var tcs = new TaskCompletionSource<string>();
@ -88,7 +104,7 @@ namespace BingMapsRESTToolkit
/// </summary>
/// <param name="url">URL that points to data to download.</param>
/// <returns>A stream with the data.</returns>
public static Task<Stream> GetStreamAsync(Uri url)
internal static Task<Stream> GetStreamAsync(Uri url)
{
var tcs = new TaskCompletionSource<Stream>();
@ -130,7 +146,7 @@ namespace BingMapsRESTToolkit
/// <param name="data">String representation of data to be posted to service.</param>
/// <param name="contentType">The content type of the data.</param>
/// <returns>Response stream.</returns>
public static Task<Stream> PostStringAsync(Uri url, string data, string contentType)
internal static Task<Stream> PostStringAsync(Uri url, string data, string contentType)
{
var tcs = new TaskCompletionSource<Stream>();
@ -213,7 +229,7 @@ namespace BingMapsRESTToolkit
/// </summary>
/// <param name="responseStream">The response stream to deserialize.</param>
/// <returns>A Response object.</returns>
public static T DeserializeStream<T>(Stream responseStream) where T : class
internal static T DeserializeStream<T>(Stream responseStream) where T : class
{
if (responseStream != null)
{
@ -225,6 +241,61 @@ namespace BingMapsRESTToolkit
return null;
}
/// <summary>
/// Makes an Async request and monitors it till completion.
/// </summary>
/// <typeparam name="T">The type of resource to expect to be returned.</typeparam>
/// <param name="requestUrl">REST URL request.</param>
/// <param name="remainingTimeCallback">A callback function in which the estimated remaining time is sent.</param>
/// <returns>A completed response for a request.</returns>
internal static async Task<Response> MakeAsyncGetRequest<T>(string requestUrl, Action<int> remainingTimeCallback) where T : Resource
{
Response response = null;
using (var responseStream = await ServiceHelper.GetStreamAsync(new Uri(requestUrl)))
{
response = ServiceHelper.DeserializeStream<Response>(responseStream);
return await ProcessAsyncResponse<T>(response, remainingTimeCallback);
}
}
/// <summary>
/// Makes an Async request and monitors it till completion.
/// </summary>
/// <typeparam name="T">The type of resource to expect to be returned.</typeparam>
/// <param name="requestUrl">REST URL request.</param>
/// <param name="requestBody">The post request body.</param>
/// <param name="remainingTimeCallback">A callback function in which the estimated remaining time is sent.</param>
/// <returns>A completed response for a request.</returns>
internal static async Task<Response> MakeAsyncPostRequest<T>(string requestUrl, string requestBody, Action<int> remainingTimeCallback) where T: Resource
{
Response response = null;
using (var responseStream = await ServiceHelper.PostStringAsync(new Uri(requestUrl), requestBody, "application/json"))
{
response = ServiceHelper.DeserializeStream<Response>(responseStream);
return await ProcessAsyncResponse<T>(response, remainingTimeCallback);
}
}
/// <summary>
/// Generates a unqiue hash for a list of items.
/// </summary>
/// <typeparam name="T">The type of a list. </typeparam>
/// <param name="sequence">The list to create a hash for.</param>
/// <returns>A unqiue hash for a list of items.</returns>
internal static int GetSequenceHashCode<T>(IList<T> sequence)
{
const int seed = 487;
const int modifier = 31;
unchecked
{
return sequence.Aggregate(seed, (current, item) =>
(current * modifier) + item.GetHashCode());
}
}
#endregion
#region Private Methods
@ -237,6 +308,159 @@ namespace BingMapsRESTToolkit
return ms;
}
private static async Task<Response> ProcessAsyncResponse<T>(Response response, Action<int> remainingTimeCallback) where T: Resource
{
if (response != null)
{
if (response.ErrorDetails != null && response.ErrorDetails.Length > 0)
{
throw new Exception(String.Join("", response.ErrorDetails));
}
if (response.ResourceSets != null && response.ResourceSets.Length > 0 && response.ResourceSets[0].Resources != null && response.ResourceSets[0].Resources.Length > 0)
{
if (response.ResourceSets[0].Resources[0] is AsyncStatus && !string.IsNullOrEmpty((response.ResourceSets[0].Resources[0] as AsyncStatus).RequestId))
{
var status = response.ResourceSets[0].Resources[0] as AsyncStatus;
status = await ServiceHelper.ProcessAsyncStatus(status, remainingTimeCallback);
if (status != null && status.IsCompleted && !string.IsNullOrEmpty(status.ResultUrl))
{
try
{
using (var resultStream = await ServiceHelper.GetStreamAsync(new Uri(status.ResultUrl)))
{
var resource = ServiceHelper.DeserializeStream<T>(resultStream);
response.ResourceSets[0].Resources[0] = resource;
}
}
catch (Exception ex)
{
throw new Exception("There was an issue downloading and serializing the results. Results Download URL: " + status.ResultUrl + "\r\n" + ex.Message);
}
}
return response;
}
else if (response.ResourceSets[0].Resources[0] is AsyncStatus && !string.IsNullOrEmpty((response.ResourceSets[0].Resources[0] as AsyncStatus).ErrorMessage))
{
throw new Exception((response.ResourceSets[0].Resources[0] as AsyncStatus).ErrorMessage);
}
else if (response.ResourceSets[0].Resources[0] is Resource && !(response.ResourceSets[0].Resources[0] is AsyncStatus))
{
return response;
}
}
}
throw new Exception("No response returned by service.");
}
/// <summary>
/// Processes an Async Status until it is completed or runs into an error.
/// </summary>
/// <param name="status">The async status to process.</param>
/// <param name="remainingTimeCallback">A callback function in which the estimated remaining time is sent.</param>
/// <returns></returns>
private static async Task<AsyncStatus> ProcessAsyncStatus(AsyncStatus status, Action<int> remainingTimeCallback)
{
var statusUrl = new Uri(status.CallbackUrl);
if (status.CallbackInSeconds > 0 || !status.IsCompleted || string.IsNullOrEmpty(status.ResultUrl))
{
remainingTimeCallback?.Invoke(status.CallbackInSeconds);
//Wait remaining seconds.
await Task.Delay(TimeSpan.FromSeconds(status.CallbackInSeconds));
status = await ServiceHelper.MonitorAsyncStatus(statusUrl, 0, remainingTimeCallback);
}
else
{
return status;
}
if (status != null)
{
if (status.IsCompleted && !string.IsNullOrEmpty(status.ResultUrl))
{
return status;
}
else if (!status.IsAccepted)
{
throw new Exception("The request was not accepted.");
}
else if (!string.IsNullOrEmpty(status.ErrorMessage))
{
throw new Exception(status.ErrorMessage);
}
}
return null;
}
/// <summary>
/// Monitors the status of an async request.
/// </summary>
/// <param name="statusUrl">The status URL for the async request.</param>
/// <param name="failedTries">The number of times the status check has failed consecutively.</param>
/// <param name="remainingTimeCallback">A callback function in which the estimated remaining time is sent.</param>
/// <returns>The final async status when the request completed, had an error, or was not accepted.</returns>
private static async Task<AsyncStatus> MonitorAsyncStatus(Uri statusUrl, int failedTries, Action<int> remainingTimeCallback)
{
AsyncStatus status = null;
try
{
using (var rs = await ServiceHelper.GetStreamAsync(statusUrl))
{
var r = ServiceHelper.DeserializeStream<Response>(rs);
if (r != null)
{
if (r.ErrorDetails != null && r.ErrorDetails.Length > 0)
{
throw new Exception(r.ErrorDetails[0]);
}
else if (r.ResourceSets != null && r.ResourceSets.Length > 0 && r.ResourceSets[0].Resources != null && r.ResourceSets[0].Resources.Length > 0 && r.ResourceSets[0].Resources[0] is DistanceMatrixAsyncStatus)
{
status = r.ResourceSets[0].Resources[0] as AsyncStatus;
if (status.CallbackInSeconds > 0)
{
remainingTimeCallback?.Invoke(status.CallbackInSeconds);
//Wait remaining seconds.
await Task.Delay(TimeSpan.FromSeconds(status.CallbackInSeconds));
return await MonitorAsyncStatus(statusUrl, 0, remainingTimeCallback);
}
}
}
}
}
catch (Exception ex)
{
//Check to see how many times the status check has failed consecutively.
if (failedTries < MaxStatusCheckRetries)
{
//Wait some time and try again.
await Task.Delay(TimeSpan.FromSeconds(StatusCheckRetryDelay));
return await MonitorAsyncStatus(statusUrl, failedTries + 1, remainingTimeCallback);
}
else
{
status.ErrorMessage = "Failed to get status, and exceeded the maximium of " + MaxStatusCheckRetries + " retries. Error message: " + ex.Message;
status.CallbackInSeconds = -1;
status.IsCompleted = false;
}
}
//Should only get here is the request has completed, was not accepted or there was an error.
return status;
}
#endregion
}
}

Просмотреть файл

@ -23,7 +23,6 @@
*/
using System;
using System.Collections.Generic;
namespace BingMapsRESTToolkit
{
@ -32,58 +31,9 @@ namespace BingMapsRESTToolkit
/// </summary>
internal static class SpatialTools
{
#region Earth Related Constants
#region Public Methods
/// <summary>
/// The approximate spherical radius of the Earth
/// </summary>
public static class EarthRadius
{
/// <summary>
/// Earth Radius in Kilometers
/// </summary>
public const double KM = 6378.135;
/// <summary>
/// Earth Radius in Meters
/// </summary>
public const double Meters = 6378135;
/// <summary>
/// Earth Radius in Miles
/// </summary>
public const double Miles = 3963.189;
/// <summary>
/// Earth Radius in Feet
/// </summary>
public const double Feet = 20925640;
}
#endregion
#region Earth Radius
/// <summary>
/// Retrieves the radius of the earth in a specific distance unit for WGS84.
/// </summary>
/// <param name="units">Unit of distance measurement.</param>
/// <returns>The radius of the earth in a specified distance units.</returns>
public static double GetEarthRadius(DistanceUnitType units)
{
switch (units)
{
case DistanceUnitType.Miles:
return EarthRadius.Miles;
case DistanceUnitType.Kilometers:
default:
return EarthRadius.KM;
}
}
#endregion
#region Distance Conversion
#region Unit Conversion
/// <summary>
/// Converts distances from miles to km or km to miles.
@ -107,38 +57,70 @@ namespace BingMapsRESTToolkit
if (toUnits == DistanceUnitType.Miles)
{
distance /= 1.609344;
distance *= 0.62137119;
}
return distance;
}
#endregion
#region Degree and Radian Conversions
/// <summary>
/// Converts an angle that is in degrees to radians. Angle * (PI / 180)
/// Converts dimensions from meters to feet or feet to meters.
/// </summary>
/// <param name="angle">An angle in degrees</param>
/// <returns>An angle in radians</returns>
public static double ToRadians(double angle)
/// <param name="dimension">Dimension to convert.</param>
/// <param name="fromUnits">The units that the dimension is in.</param>
/// <param name="toUnits">The units to convert the dimension to.</param>
/// <returns>A dimension in the specified unit of measurement.</returns>
public static double CovertDimension(double dimension, DimensionUnitType fromUnits, DimensionUnitType toUnits)
{
return angle * (Math.PI / 180);
if (fromUnits == toUnits || double.IsNaN(dimension))
{
return dimension;
}
//Convert the distance to meters
if (fromUnits == DimensionUnitType.Feet)
{
dimension *= 0.3048;
}
if (toUnits == DimensionUnitType.Feet)
{
dimension *= 3.2808399;
}
return dimension;
}
/// <summary>
/// Converts an angle that is in radians to degress. Angle * (180 / PI)
/// Converts weights from kg to lbs or lbs to kg.
/// </summary>
/// <param name="angle">An angle in radians</param>
/// <returns>An angle in degrees</returns>
public static double ToDegrees(double angle)
/// <param name="weight">Weight to convert.</param>
/// <param name="fromUnits">The units that the weights is in.</param>
/// <param name="toUnits">The units to convert the weights to.</param>
/// <returns>A weights in the specified unit of measurement.</returns>
public static double CovertWeight(double weight, WeightUnitType fromUnits, WeightUnitType toUnits)
{
return angle * (180 / Math.PI);
if (fromUnits == toUnits || double.IsNaN(weight))
{
return weight;
}
//Convert the distance to kilograms
if (fromUnits == WeightUnitType.Pound)
{
weight *= 0.45359237;
}
if (toUnits == WeightUnitType.Pound)
{
weight *= 2.20462262;
}
return weight;
}
#endregion
#region Haversine Distance Calculation method
/// <summary>
@ -214,5 +196,86 @@ namespace BingMapsRESTToolkit
Longitude = ToDegrees(lon2)
};
}
#endregion
#region Internal Methods
#region Degree and Radian Conversions
/// <summary>
/// Converts an angle that is in degrees to radians. Angle * (PI / 180)
/// </summary>
/// <param name="angle">An angle in degrees</param>
/// <returns>An angle in radians</returns>
internal static double ToRadians(double angle)
{
return angle * (Math.PI / 180);
}
/// <summary>
/// Converts an angle that is in radians to degress. Angle * (180 / PI)
/// </summary>
/// <param name="angle">An angle in radians</param>
/// <returns>An angle in degrees</returns>
internal static double ToDegrees(double angle)
{
return angle * (180 / Math.PI);
}
#endregion
#region Earth Related Constants
/// <summary>
/// The approximate spherical radius of the Earth
/// </summary>
internal static class EarthRadius
{
/// <summary>
/// Earth Radius in Kilometers
/// </summary>
public const double KM = 6378.135;
/// <summary>
/// Earth Radius in Meters
/// </summary>
public const double Meters = 6378135;
/// <summary>
/// Earth Radius in Miles
/// </summary>
public const double Miles = 3963.189;
/// <summary>
/// Earth Radius in Feet
/// </summary>
public const double Feet = 20925640;
}
#endregion
#region Earth Radius
/// <summary>
/// Retrieves the radius of the earth in a specific distance unit for WGS84.
/// </summary>
/// <param name="units">Unit of distance measurement.</param>
/// <returns>The radius of the earth in a specified distance units.</returns>
internal static double GetEarthRadius(DistanceUnitType units)
{
switch (units)
{
case DistanceUnitType.Miles:
return EarthRadius.Miles;
case DistanceUnitType.Kilometers:
default:
return EarthRadius.KM;
}
}
#endregion
#endregion
}
}

Просмотреть файл

@ -104,6 +104,10 @@ namespace BingMapsRESTToolkit
}
}
#endregion
#region Public Methods
/// <summary>
/// Returns a formatted string of the coordinate in the format "latitude,longitude", with the values rounded off to 5 decimal places.
/// </summary>
@ -113,6 +117,43 @@ namespace BingMapsRESTToolkit
return string.Format(CultureInfo.InvariantCulture, "{0:0.#####},{1:0.#####}", Latitude, Longitude);
}
/// <summary>
/// Compares two coordinates. Only compares the first 6 decimal places to avoid floating point errors.
/// </summary>
/// <param name="obj">Coordinate to compare to.</param>
/// <returns>A boolean indicating if the two coordinates are equal.</returns>
public override bool Equals(object obj)
{
if(obj != null && obj is Coordinate)
{
var c = obj as Coordinate;
return Math.Round(Latitude, 6) == Math.Round(c.Latitude, 6) && Math.Round(Longitude, 6) == Math.Round(c.Longitude, 6);
}
return false;
}
/// <summary>
/// Compares two coordinates.
/// </summary>
/// <param name="c">Coordinate to compare to.</param>
/// <param name="decimals">The number of decimal places to compare to.</param>
/// <returns>A boolean indicating if the two coordinates are equal.</returns>
public bool Equals(Coordinate c, int decimals)
{
return Math.Round(Latitude, decimals) == Math.Round(c.Latitude, decimals) && Math.Round(Longitude, decimals) == Math.Round(c.Longitude, decimals);
}
/// <summary>
/// Get hash for coordinate.
/// </summary>
/// <returns>Hash for coordinate.</returns>
public override int GetHashCode()
{
return string.Format("{0:0.######}|{1:0.######}", Latitude, Longitude).GetHashCode();
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,85 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Runtime.Serialization;
namespace BingMapsRESTToolkit
{
/// <summary>
/// The status of an asynchronous request.
/// </summary>
[DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
[KnownType(typeof(DistanceMatrixAsyncStatus))]
[KnownType(typeof(IsochroneAsyncStatus))]
[KnownType(typeof(TruckAsyncStatus))]
public class AsyncStatus: Resource
{
#region Public Properties
/// <summary>
/// Specifies if the request is accepted.
/// </summary>
[DataMember(Name = "isAccepted", EmitDefaultValue = false)]
public bool IsAccepted { get; set; }
/// <summary>
/// Specifies if the request has completed.
/// </summary>
[DataMember(Name = "isCompleted", EmitDefaultValue = false)]
public bool IsCompleted { get; set; }
/// <summary>
/// A unique identifier for an asynchronous request. This can be used to retrieve the results of an asynchronous request when it has completed.
/// </summary>
[DataMember(Name = "requestId", EmitDefaultValue = false)]
public string RequestId { get; set; }
/// <summary>
/// Details of an error that may have occurred when processing the request.
/// </summary>
[DataMember(Name = "errorMessage", EmitDefaultValue = false)]
public string ErrorMessage { get; set; }
/// <summary>
/// An estimated number of seconds to wait before calling back for results when making an asynchronous request.
/// </summary>
[DataMember(Name = "callbackInSeconds", EmitDefaultValue = false)]
public int CallbackInSeconds { get; set; }
/// <summary>
/// The callback URL to use to check the status of the request.
/// </summary>
[DataMember(Name = "callbackUrl", EmitDefaultValue = false)]
public string CallbackUrl { get; set; }
/// <summary>
/// The URL where the results can be downloaded from.
/// </summary>
[DataMember(Name = "resultUrl", EmitDefaultValue = false)]
public string ResultUrl { get; set; }
#endregion
}
}

Просмотреть файл

@ -53,7 +53,7 @@ namespace BingMapsRESTToolkit
{
get
{
if (string.IsNullOrWhiteSpace(ManeuverType))
if (!string.IsNullOrWhiteSpace(ManeuverType))
{
try
{

Просмотреть файл

@ -71,13 +71,13 @@ namespace BingMapsRESTToolkit
/// The array of destinations that were used to calculate the distance matrix.
/// </summary>
[DataMember(Name = "destinations", EmitDefaultValue = false)]
public SimpleWaypoint[] Destinations { get; set; }
public List<SimpleWaypoint> Destinations { get; set; }
/// <summary>
/// The array of origins that were used to calculate the distance matrix.
/// </summary>
[DataMember(Name = "origins", EmitDefaultValue = false)]
public SimpleWaypoint[] Origins { get; set; }
public List<SimpleWaypoint> Origins { get; set; }
/// <summary>
/// Details of an error that may have occurred when processing the request.
@ -114,6 +114,104 @@ namespace BingMapsRESTToolkit
#region Public Methods
/// <summary>
/// Retrieves the total travel distance between all waypoints indicies which represent an edge (graph/path).
/// </summary>
/// <param name="waypointIndicies">Waypoint indicies that represent the edge/path.</param>
/// <returns>The total travel distance between all waypoints indicies.</returns>
public double GetEdgeDistance(int[] waypointIndicies)
{
if(waypointIndicies.Length >= 2)
{
double distance = 0;
for(var i = 0; i < waypointIndicies.Length - 1; i++)
{
var d = GetDistance(waypointIndicies[i], waypointIndicies[i + 1]);
if (d > 0)
{
distance += d;
}
}
return distance;
}
return 0;
}
/// <summary>
/// Retrieves the total travel distance between all waypoints indicies which represent an edge (graph/path).
/// </summary>
/// <param name="waypointIndicies">Waypoint indicies that represent the edge/path.</param>
/// <param name="isRoundTrip">Indicates if the edge should be round trip and return to the first waypoint in the indicies array.</param>
/// <returns>The total travel distance between all waypoints indicies.</returns>
public double GetEdgeDistance(int[] waypointIndicies, bool isRoundTrip)
{
var distance = GetEdgeDistance(waypointIndicies);
if (isRoundTrip && waypointIndicies.Length >= 2)
{
var d = GetDistance(waypointIndicies[waypointIndicies.Length - 1], waypointIndicies[0]);
if (d > 0)
{
distance += d;
}
}
return distance;
}
/// <summary>
/// Retrieves the total travel time between all waypoints indicies which represent an edge (graph/path).
/// </summary>
/// <param name="waypointIndicies">Waypoint indicies that represent the edge/path.</param>
/// <returns>The total travel time between all waypoints indicies.</returns>
public double GetEdgeTime(int[] waypointIndicies)
{
if (waypointIndicies.Length >= 2)
{
double time = 0;
for (var i = 0; i < waypointIndicies.Length - 1; i++)
{
var t = GetTime(waypointIndicies[i], waypointIndicies[i + 1]);
if (t > 0)
{
time += t;
}
}
return time;
}
return 0;
}
/// <summary>
/// Retrieves the total travel time between all waypoints indicies which represent an edge (graph/path).
/// </summary>
/// <param name="waypointIndicies">Waypoint indicies that represent the edge/path.</param>
/// <param name="isRoundTrip">Indicates if the edge should be round trip and return to the first waypoint in the indicies array.</param>
/// <returns>The total travel time between all waypoints indicies.</returns>
public double GetEdgeTime(int[] waypointIndicies, bool isRoundTrip)
{
var time = GetEdgeTime(waypointIndicies);
if (isRoundTrip && waypointIndicies.Length >= 2)
{
var t = GetTime(waypointIndicies[waypointIndicies.Length - 1], waypointIndicies[0]);
if (t > 0)
{
time += t;
}
}
return time;
}
/// <summary>
/// Retrives the distance matrix cell for a specified origin-destination pair.
/// Returns -1 if a cell can not be found in the results or had an error in calculation.
@ -358,6 +456,58 @@ namespace BingMapsRESTToolkit
return null;
}
/// <summary>
/// Creates a NxN distance matrix with straight line distances.
/// </summary>
/// <param name="waypoints">The waypoints to generate a matrix for.</param>
/// <param name="distanceUnits">The distance units to calculate the distances in.</param>
/// <param name="bingMapsKey">A bing maps key that can be used to geocode waypoints, if needed.</param>
/// <returns>A NxN distance matrix with straight line distances.</returns>
public static async Task<DistanceMatrix> CreateStraightLineNxNMatrix(List<SimpleWaypoint> waypoints, DistanceUnitType distanceUnits, string bingMapsKey)
{
//Ensure all the waypoints are geocoded.
if (waypoints == null || waypoints.Count <= 2)
{
throw new Exception("Not enough waypoints provided.");
}
if (!string.IsNullOrEmpty(bingMapsKey))
{
await SimpleWaypoint.TryGeocodeWaypoints(waypoints, bingMapsKey);
}
var numWaypoints = waypoints.Count;
var cells = new DistanceMatrixCell[numWaypoints * numWaypoints];
await Task.Run(() => Parallel.For(0, numWaypoints, i =>
{
for (var j = 0; j < numWaypoints; j++)
{
double distance = -1;
if (i != j && waypoints[i].Coordinate != null && waypoints[j].Coordinate != null)
{
distance = SpatialTools.HaversineDistance(waypoints[i].Coordinate, waypoints[j].Coordinate, distanceUnits);
}
cells[i * numWaypoints + j] = new DistanceMatrixCell()
{
OriginIndex = i,
DestinationIndex = j,
TravelDistance = distance
};
}
}));
return new DistanceMatrix()
{
Origins = waypoints,
Destinations = waypoints,
Results = cells
};
}
#endregion
#region Private Methods

Просмотреть файл

@ -30,53 +30,7 @@ namespace BingMapsRESTToolkit
/// The status of an asynchronous distance matrix request.
/// </summary>
[DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
public class DistanceMatrixAsyncStatus : Resource
public class DistanceMatrixAsyncStatus : AsyncStatus
{
#region Public Properties
/// <summary>
/// Specifies if the request is accepted. A request will not be accepted if it is not valid, is not within the
/// coordinate pair limits, or if a coordinate in origins or destinations has no coverage.
/// </summary>
[DataMember(Name = "isAccepted", EmitDefaultValue = false)]
public bool IsAccepted { get; set; }
/// <summary>
/// Specifies if the request has completed.
/// </summary>
[DataMember(Name = "isCompleted", EmitDefaultValue = false)]
public bool IsCompleted { get; set; }
/// <summary>
/// A unique identifier for an asynchronous request. This can be used to retrieve the results of an asynchronous request when it has completed.
/// </summary>
[DataMember(Name = "requestId", EmitDefaultValue = false)]
public string RequestId { get; set; }
/// <summary>
/// Details of an error that may have occurred when processing the request.
/// </summary>
[DataMember(Name = "errorMessage", EmitDefaultValue = false)]
public string ErrorMessage { get; set; }
/// <summary>
/// An estimated number of seconds to wait before calling back for results when making an asynchronous request.
/// </summary>
[DataMember(Name = "callbackInSeconds", EmitDefaultValue = false)]
public int CallbackInSeconds { get; set; }
/// <summary>
/// The callback URL to use to check the status of the request.
/// </summary>
[DataMember(Name = "callbackUrl", EmitDefaultValue = false)]
public string CallbackUrl { get; set; }
/// <summary>
/// The URL where the results can be downloaded from. The result is a DistanceMatrix object in JSON form.
/// </summary>
[DataMember(Name = "resultUrl", EmitDefaultValue = false)]
public string ResultUrl { get; set; }
#endregion
}
}

Просмотреть файл

@ -59,6 +59,12 @@ namespace BingMapsRESTToolkit
[DataMember(Name = "travelDuration", EmitDefaultValue = false)]
public double TravelDuration { get; set; }
/// <summary>
/// The portion of the total route duration which requires walking. This may occur when the travel mode is set to transit.
/// </summary>
[DataMember(Name = "totalWalkDuration", EmitDefaultValue = false)]
public double TotalWalkDuration { get; set; }
/// <summary>
/// The departure time in which this cell was calculated for. Only returned when a startTime is specified.
/// When an endTime is specified in the request several cells will be returned for the same origin and destination pairs,
@ -76,21 +82,17 @@ namespace BingMapsRESTToolkit
{
get
{
if (string.IsNullOrEmpty(DepartureTime))
{
return null;
}
else
if (!string.IsNullOrEmpty(DepartureTime))
{
DateTime dt;
if(DateTime.TryParse(DepartureTime, out dt))
if (DateTime.TryParse(DepartureTime, out dt))
{
return dt;
}
return null;
}
return null;
}
set
{

Просмотреть файл

@ -0,0 +1,36 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Runtime.Serialization;
namespace BingMapsRESTToolkit
{
/// <summary>
/// The status of an asynchronous distance matrix request.
/// </summary>
[DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
public class IsochroneAsyncStatus : AsyncStatus
{
}
}

Просмотреть файл

@ -0,0 +1,41 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Runtime.Serialization;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Represents the response from an IsochroneRequest.
/// </summary>
[DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
public class IsochroneResponse : Resource
{
/// <summary>
/// The polygons that represent the isochrone area.
/// </summary>
[DataMember(Name = "polygons", EmitDefaultValue = false)]
public Polygon[] Polygons { get; set; }
}
}

Просмотреть файл

@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
using System;
using System.Runtime.Serialization;
namespace BingMapsRESTToolkit
@ -60,7 +61,22 @@ namespace BingMapsRESTToolkit
/// The level of confidence that the geocoded location result is a match. Can be High, Medium, Low.
/// </summary>
[DataMember(Name = "confidence", EmitDefaultValue = false)]
public string Confidence { get; set; }
public string Confidence
{
get
{
return Enum.GetName(typeof(ConfidenceLevelType), ConfidenceLevelType);
}
set
{
ConfidenceLevelType = EnumHelper.ConfidenceLevelTypeStringToEnum(value);
}
}
/// <summary>
/// The level of confidence that the geocoded location result is a match as an Enum.
/// </summary>
public ConfidenceLevelType ConfidenceLevelType { get; set; }
/// <summary>
/// One or more match code values that represent the geocoding level for each location in the response. Can be Good, Ambiguous, UpHierarchy.

Просмотреть файл

@ -0,0 +1,41 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Runtime.Serialization;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Represents a polygon object.
/// </summary>
[DataContract]
public class Polygon
{
/// <summary>
/// The coordinate rings that make up the polygon. Where double[] represents a single coordinate [latitude, longitude], and double[][] represents a single ring within a polygon.
/// </summary>
[DataMember(Name = "coordinates", EmitDefaultValue = false)]
public double[][][] Coordinates { get; set; }
}
}

Просмотреть файл

@ -40,6 +40,8 @@ namespace BingMapsRESTToolkit
[KnownType(typeof(GeospatialEndpointResponse))]
[KnownType(typeof(DistanceMatrix))]
[KnownType(typeof(DistanceMatrixAsyncStatus))]
[KnownType(typeof(IsochroneResponse))]
[KnownType(typeof(SnapToRoadResponse))]
public class Resource
{
/// <summary>

Просмотреть файл

@ -55,7 +55,6 @@ namespace BingMapsRESTToolkit
}
}
/// <summary>
/// The unit used for distance as an Enum.
/// </summary>
@ -69,7 +68,7 @@ namespace BingMapsRESTToolkit
{
get
{
return EnumHelper.TimeUnitTypeToString(TimeUnitType);
return Enum.GetName(typeof(TimeUnitType), TimeUnitType);
}
set
{
@ -77,13 +76,11 @@ namespace BingMapsRESTToolkit
}
}
/// <summary>
/// The unit used for time as an Enum.
/// </summary>
public TimeUnitType TimeUnitType { get; set; }
/// <summary>
/// The physical distance covered by the entire route. This value is not supported for the Transit travel mode.
/// </summary>

Просмотреть файл

@ -0,0 +1,41 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Runtime.Serialization;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Represents a list of snapped or interpolated points returned by the Snap To Road API.
/// </summary>
[DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
public class SnapToRoadResponse : Resource
{
/// <summary>
/// The array of points that have been snapped as well as any points added through interpolation.
/// </summary>
[DataMember(Name = "snappedPoints", EmitDefaultValue = false)]
public SnappedPoint[] SnappedPoints { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,67 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Runtime.Serialization;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Represents a snapped or interpolated point.
/// </summary>
[DataContract]
public class SnappedPoint
{
/// <summary>
/// The coordinate in which a point was snapped to or an interpolated point.
/// </summary>
[DataMember(Name = "coordinate", EmitDefaultValue = false)]
public Coordinate Coordinate { get; set; }
/// <summary>
/// The index in the original list of points passed into the query that this snapped point corresponds to.
/// Can be 0 to the number of elements in the input array - 1. It can also be the value -1, which means this is an interpolated point.
/// </summary>
[DataMember(Name = "index", EmitDefaultValue = false)]
public int Index { get; set; }
/// <summary>
/// The name of the street this snapped point lies on, if available.
/// </summary>
[DataMember(Name = "name", EmitDefaultValue = false)]
public string Name { get; set; }
/// <summary>
/// The posted speed limit. If unavailable, will be set to 0. If not requested, will be set to null.
/// </summary>
[DataMember(Name = "speedLimit", EmitDefaultValue = false)]
public double? SpeedLimit { get; set; }
/// <summary>
/// The posted truck speed limit. If unavailable, will be set to 0. If not requested, will be set to null.
/// </summary>
[DataMember(Name = "truckSpeedLimit", EmitDefaultValue = false)]
public double? TruckSpeedLimit { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,36 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Runtime.Serialization;
namespace BingMapsRESTToolkit
{
/// <summary>
/// The status of an asynchronous truck routing request.
/// </summary>
[DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
public class TruckAsyncStatus: AsyncStatus
{
}
}

Просмотреть файл

@ -46,11 +46,7 @@ namespace BingMapsRESTToolkit
{
get
{
if (string.IsNullOrEmpty(Origin))
{
return null;
}
else
if (!string.IsNullOrEmpty(Origin))
{
var latLng = Origin.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
double lat;
@ -60,9 +56,9 @@ namespace BingMapsRESTToolkit
{
return new Coordinate(lat, lon);
}
}
return null;
}
}
set
{
@ -102,11 +98,7 @@ namespace BingMapsRESTToolkit
{
get
{
if (string.IsNullOrEmpty(To))
{
return null;
}
else
if (!string.IsNullOrEmpty(To))
{
var latLng = To.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
double lat;
@ -116,9 +108,9 @@ namespace BingMapsRESTToolkit
{
return new Coordinate(lat, lon);
}
return null;
}
return null;
}
set
{
@ -146,7 +138,7 @@ namespace BingMapsRESTToolkit
{
get
{
if (string.IsNullOrWhiteSpace(WarningType))
if (!string.IsNullOrWhiteSpace(WarningType))
{
try
{

Просмотреть файл

@ -36,7 +36,8 @@ namespace BingMapsRESTToolkit
{
#region Private Properties
private int distanceBeforeFirstTurn = 0, heading = 0, maxSolutions = 1;
private int distanceBeforeFirstTurn = 0, maxSolutions = 1;
private int? heading = null;
#endregion
@ -50,7 +51,6 @@ namespace BingMapsRESTToolkit
Optimize = RouteOptimizationType.Time;
TravelMode = TravelModeType.Driving;
TimeType = RouteTimeType.Departure;
DateTime = DateTime.Now.AddMinutes(15);
}
#endregion
@ -84,7 +84,7 @@ namespace BingMapsRESTToolkit
/// Specifies the initial heading for the route. An integer value between 0 and 359 that represents degrees from
/// north where north is 0 degrees and the heading is specified clockwise from north.
/// </summary>
public int Heading
public int? Heading
{
get { return heading; }
set
@ -119,7 +119,7 @@ namespace BingMapsRESTToolkit
/// When calculating driving routes the route optimization type should be TimeWithTraffic. The route time will be used as the departure time.
/// When calculating transit routes timeType can be specified.
/// </summary>
public DateTime DateTime { get; set; }
public DateTime? DateTime { get; set; }
/// <summary>
/// Specifies how to interpret the date and transit time value that is specified by the dateTime parameter.
@ -170,6 +170,11 @@ namespace BingMapsRESTToolkit
}
}
/// <summary>
/// Truck routing specific vehicle attribute.
/// </summary>
public VehicleSpec VehicleSpec { get; set; }
#endregion
#region Internal Methods
@ -205,15 +210,19 @@ namespace BingMapsRESTToolkit
sb.AppendFormat("&dbft={0}", distanceBeforeFirstTurn);
}
if (heading > 0)
if (heading.HasValue)
{
sb.AppendFormat("&hd={0}", heading);
sb.AppendFormat("&hd={0}", heading.Value);
}
}
if (DistanceUnits != DistanceUnitType.Kilometers)
if (DistanceUnits == DistanceUnitType.Kilometers)
{
sb.AppendFormat("&du=mi");
sb.Append("&du=kilometer");
}
else
{
sb.Append("&du=mile");
}
if (Tolerances != null && Tolerances.Count > 0)
@ -248,20 +257,20 @@ namespace BingMapsRESTToolkit
}
}
if (DateTime != null)
if (DateTime != null && DateTime.HasValue)
{
if (TravelMode == TravelModeType.Transit)
{
sb.AppendFormat(DateTimeFormatInfo.InvariantInfo, "&dt={0:G}", DateTime);
sb.AppendFormat(DateTimeFormatInfo.InvariantInfo, "&dt={0:G}", DateTime.Value);
sb.AppendFormat("&tt={0}", Enum.GetName(typeof(RouteTimeType), TimeType));
}
else if (TravelMode == TravelModeType.Driving)
{
sb.AppendFormat(DateTimeFormatInfo.InvariantInfo, "&dt={0:G}", DateTime);
sb.AppendFormat(DateTimeFormatInfo.InvariantInfo, "&dt={0:G}", DateTime.Value);
}
}
if (TravelMode != TravelModeType.Walking)
if (TravelMode != TravelModeType.Walking && maxSolutions > 1 && maxSolutions <= 3)
{
sb.AppendFormat("&maxSolns={0}", maxSolutions);
}

Просмотреть файл

@ -172,6 +172,49 @@ namespace BingMapsRESTToolkit
#endregion
#region Public Methods
/// <summary>
/// Compares two simple waypoints. Intially only concern with coordinates, but if no coordinates specified, falls back on comparing address. Ignored IsViaPoint.
/// </summary>
/// <param name="obj">Simple waypoint to compare to.</param>
/// <returns>A boolean indicating if the two simple waypoints are equal.</returns>
public override bool Equals(object obj)
{
if (obj != null && obj is SimpleWaypoint)
{
var wp = obj as SimpleWaypoint;
if((Coordinate == null && wp.Coordinate != null) || (Coordinate != null && wp.Coordinate == null))
{
return false;
}
else if (Coordinate != null && wp.Coordinate != null)
{
//Limit comparison to coordinates.
return Coordinate.Equals(wp.Coordinate);
}
else if (string.Compare(Address, wp.Address, System.StringComparison.OrdinalIgnoreCase) == 0)
{
//Compare address strings.
return true;
}
}
return false;
}
/// <summary>
/// Get hash for simple waypoint.
/// </summary>
/// <returns>Hash for simple waypoint.</returns>
public override int GetHashCode()
{
return string.Format("{0}|{1:0.######}|{2:0.######}", Address, Latitude, Longitude).GetHashCode();
}
#endregion
#region Static Methods
/// <summary>
@ -224,7 +267,7 @@ namespace BingMapsRESTToolkit
/// <param name="waypoints">A list of simple waypoints to geocode.</param>
/// <param name="baseRequest">A base request that has the information need to perform a geocode, primarily a Bing Maps key.</param>
/// <returns>A Task in which a list of simple waypoints will be geocoded.</returns>
internal static async Task GeocodeWaypoints(List<SimpleWaypoint> waypoints, BaseRestRequest baseRequest)
internal static async Task TryGeocodeWaypoints(List<SimpleWaypoint> waypoints, BaseRestRequest baseRequest)
{
var geocodeTasks = new List<Task>();
@ -242,6 +285,68 @@ namespace BingMapsRESTToolkit
}
}
/// <summary>
/// Tries to geocode a simple waypoint.
/// </summary>
/// <param name="waypoint">The simple waypoint to geocode.</param>
/// <param name="bingMapsKey">The Bing Maps key to use when geocoding.</param>
/// <returns>A Task in which the simple waypoint will be geocoded.</returns>
internal static async Task TryGeocode(SimpleWaypoint waypoint, string bingMapsKey)
{
if (waypoint != null && waypoint.Coordinate == null && !string.IsNullOrEmpty(waypoint.Address))
{
var request = new GeocodeRequest()
{
Query = waypoint.Address,
MaxResults = 1,
BingMapsKey = bingMapsKey,
};
try
{
var r = await ServiceManager.GetResponseAsync(request);
if (r != null && r.ResourceSets != null &&
r.ResourceSets.Length > 0 &&
r.ResourceSets[0].Resources != null &&
r.ResourceSets[0].Resources.Length > 0)
{
var l = r.ResourceSets[0].Resources[0] as Location;
waypoint.Coordinate = new Coordinate(l.Point.Coordinates[0], l.Point.Coordinates[1]);
}
}
catch
{
//Do nothing.
}
}
}
/// <summary>
/// Attempts to geocode a list of simple waypoints.
/// </summary>
/// <param name="waypoints">A list of simple waypoints to geocode.</param>
/// <param name="bingMapsKey">The Bing Maps key to use when geocoding.</param>
/// <returns>A Task in which a list of simple waypoints will be geocoded.</returns>
internal static async Task TryGeocodeWaypoints(List<SimpleWaypoint> waypoints, string bingMapsKey)
{
var geocodeTasks = new List<Task>();
foreach (var wp in waypoints)
{
if (wp != null && wp.Coordinate == null && !string.IsNullOrEmpty(wp.Address))
{
geocodeTasks.Add(TryGeocode(wp, bingMapsKey));
}
}
if (geocodeTasks.Count > 0)
{
await Task.WhenAll(geocodeTasks);
}
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,109 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System.Collections.Generic;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Truck routing specific vehicle attribute.
/// </summary>
public class VehicleSpec
{
/// <summary>
/// The unit of measurement of width, height, length.
/// </summary>
public DimensionUnitType DimensionUnit { get; set; }
/// <summary>
/// The unit of measurement of weight.
/// </summary>
public WeightUnitType WeightUnit { get; set; }
/// <summary>
/// The height of the vehicle in the specified dimension units.
/// </summary>
public double VehicleHeight { get; set; }
/// <summary>
/// The width of the vehicle in the specified dimension units.
/// </summary>
public double VehicleWidth { get; set; }
/// <summary>
/// The length of the vehicle in the specified dimension units.
/// </summary>
public double VehicleLength { get; set; }
/// <summary>
/// The weight of the vehicle in the specified weight units.
/// </summary>
public double VehicleWeight { get; set; }
/// <summary>
/// The number of axles.
/// </summary>
public int VehicleAxles { get; set; }
/// <summary>
/// Indicates if the truck is pulling a semi-trailer. Semi-trailer restrictions are mostly used in North America.
/// </summary>
public bool VehicleSemi { get; set; }
/// <summary>
/// Specifies number of trailers pulled by a vehicle. The provided value must be between 0 and 4.
/// </summary>
public int VehicleTrailers { get; set; }
/// <summary>
/// The max gradient the vehicle can drive measured in degrees.
/// </summary>
public double VehicleMaxGradient { get; set; }
/// <summary>
/// The mini-mum required radius for the vehicle to turn in the specified dimension units.
/// </summary>
public double VehicleMinTurnRadius { get; set; }
/// <summary>
/// Indicates if the vehicle shall avoid crosswinds.
/// </summary>
public bool VehicleAvoidCrossWind { get; set; }
/// <summary>
/// Indicates if the route shall avoid the risk of grounding.
/// </summary>
public bool VehicleAvoidGroundingRisk { get; set; }
/// <summary>
/// A list of one or more hazardous materials for which the vehicle is transporting.
/// </summary>
public List<HazardousMaterialType> VehicleHazardousMaterials { get; set; }
/// <summary>
/// A list of one or more hazardous materials for which the vehicle has permits.
/// </summary>
public List<HazardousMaterialPermitType> VehicleHazardousPermits { get; set; }
}
}

Просмотреть файл

@ -26,5 +26,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.8.0")]
[assembly: AssemblyFileVersion("1.0.8.0")]
[assembly: AssemblyVersion("1.0.9.0")]
[assembly: AssemblyFileVersion("1.0.9.0")]

Просмотреть файл

@ -31,7 +31,6 @@ namespace BingMapsRESTToolkit
/// <summary>
/// An abstract class in which all REST service requests derive from.
/// </summary>
[DataContract]
public abstract class BaseRestRequest
{
#region Private Properties
@ -150,7 +149,7 @@ namespace BingMapsRESTToolkit
url += "&uip=" + UserIp;
}
return url + "&key=" + BingMapsKey + "&clientApi=CSToolkit";
return url + "&key=" + BingMapsKey + "&clientApi=" + InternalSettings.ClientApi;
}
#endregion

Просмотреть файл

@ -25,7 +25,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
@ -34,7 +33,6 @@ namespace BingMapsRESTToolkit
/// <summary>
/// A request that calculates a distance matrix between origins and destinations.
/// </summary>
[DataContract]
public class DistanceMatrixRequest : BaseRestRequest
{
#region Private Properties
@ -54,16 +52,6 @@ namespace BingMapsRESTToolkit
/// </summary>
private const double MaxTimeSpanHours = 24;
/// <summary>
/// The maximium number of times the retry the status check if it fails. This will allow for possible connection issues.
/// </summary>
private const int MaxStatusCheckRetries = 3;
/// <summary>
/// Number of seconds to delay a retry of a status check.
/// </summary>
private const int StatusCheckRetryDelay = 10;
#endregion
#region Constructure
@ -75,7 +63,7 @@ namespace BingMapsRESTToolkit
{
TravelMode = TravelModeType.Driving;
DistanceUnits = DistanceUnitType.Kilometers;
TimeUnits = TimeUnitType.Seconds;
TimeUnits = TimeUnitType.Minute;
Resolution = 1;
}
@ -124,7 +112,7 @@ namespace BingMapsRESTToolkit
public DistanceUnitType DistanceUnits { get; set; }
/// <summary>
/// The units to use for time. Default: Seconds.
/// The units to use for time. Default: Minute.
/// </summary>
public TimeUnitType TimeUnits { get; set; }
@ -153,106 +141,25 @@ namespace BingMapsRESTToolkit
var requestUrl = GetRequestUrl();
var requestBody = GetPostRequestBody();
Response response = null;
var response = await ServiceHelper.MakeAsyncPostRequest<DistanceMatrix>(requestUrl, requestBody, remainingTimeCallback);
using (var responseStream = await ServiceHelper.PostStringAsync(new Uri(requestUrl), requestBody, "application/json"))
var dm = response.ResourceSets[0].Resources[0] as DistanceMatrix;
//TODO: Overwrite origins/destinations for now as we have added support for geocoding in this library, but this is not yet supported by the Distance Matirx API.
dm.Origins = this.Origins;
if (this.Destinations != null)
{
response = ServiceHelper.DeserializeStream<Response>(responseStream);
dm.Destinations = this.Destinations;
}
if(response != null && response.ErrorDetails != null && response.ErrorDetails.Length > 0)
if (dm.Results != null)
{
throw new Exception("Error: " + response.ErrorDetails[0]);
return response;
}
if (response != null && response.ResourceSets != null && response.ResourceSets.Length > 0 && response.ResourceSets[0].Resources != null && response.ResourceSets[0].Resources.Length > 0)
else if (!string.IsNullOrEmpty(dm.ErrorMessage))
{
if (response.ResourceSets[0].Resources[0] is DistanceMatrixAsyncStatus && !string.IsNullOrEmpty((response.ResourceSets[0].Resources[0] as DistanceMatrixAsyncStatus).RequestId))
{
var status = response.ResourceSets[0].Resources[0] as DistanceMatrixAsyncStatus;
var statusUrl = new Uri(status.CallbackUrl);
//var statusUrl = new Uri(this.Domain + "Routes/DistanceMatrixAsyncCallback?requestId=" + status.RequestId + "&key=" + this.BingMapsKey);
if (status.CallbackInSeconds > 0 || !status.IsCompleted || string.IsNullOrEmpty(status.ResultUrl))
{
remainingTimeCallback?.Invoke(status.CallbackInSeconds);
//Wait remaining seconds.
await Task.Delay(TimeSpan.FromSeconds(status.CallbackInSeconds));
status = await MonitorAsyncStatus(statusUrl, 0, remainingTimeCallback);
}
if (status != null)
{
if (status.IsCompleted && !string.IsNullOrEmpty(status.ResultUrl))
{
try
{
using (var resultStream = await ServiceHelper.GetStreamAsync(new Uri(status.ResultUrl)))
{
DistanceMatrix dm = ServiceHelper.DeserializeStream<DistanceMatrix>(resultStream);
response.ResourceSets[0].Resources[0] = dm;
//TODO: Overwrite origins/destinations for now as we have added support for geocoding in this library, but this is not yet supported by the Distance Matirx API.
dm.Origins = this.Origins.ToArray();
dm.Destinations = this.Destinations.ToArray();
}
}
catch(Exception ex)
{
response.ResourceSets[0].Resources[0] = new DistanceMatrix()
{
ErrorMessage = "There was an issue downloading and serializing the results. Results Download URL: " + status.ResultUrl
};
}
}
else if (!status.IsAccepted)
{
response.ResourceSets[0].Resources[0] = new DistanceMatrix()
{
ErrorMessage = "The request was not accepted."
};
}
else if (!string.IsNullOrEmpty(status.ErrorMessage))
{
response.ResourceSets[0].Resources[0] = new DistanceMatrix()
{
ErrorMessage = status.ErrorMessage
};
}
}
return response;
}
else if (response.ResourceSets[0].Resources[0] is DistanceMatrix && (response.ResourceSets[0].Resources[0] as DistanceMatrix).Results != null)
{
DistanceMatrix dm = response.ResourceSets[0].Resources[0] as DistanceMatrix;
//TODO: Overwrite origins/destinations for now as we have added support for geocoding in this library, but this is not yet supported by the Distance Matirx API.
dm.Origins = this.Origins.ToArray();
dm.Destinations = this.Destinations.ToArray();
if (dm.Results != null) {
return response;
}
else if(!string.IsNullOrEmpty(dm.ErrorMessage))
{
var msg = "Error: " + (response.ResourceSets[0].Resources[0] as DistanceMatrix).ErrorMessage;
throw new Exception(msg);
}
}
else if (response.ResourceSets[0].Resources[0] is DistanceMatrixAsyncStatus && !string.IsNullOrEmpty((response.ResourceSets[0].Resources[0] as DistanceMatrixAsyncStatus).ErrorMessage))
{
var msg = "Error: " + (response.ResourceSets[0].Resources[0] as DistanceMatrixAsyncStatus).ErrorMessage;
throw new Exception(msg);
}
else if (response.ResourceSets[0].Resources[0] is DistanceMatrix && !string.IsNullOrEmpty((response.ResourceSets[0].Resources[0] as DistanceMatrix).ErrorMessage))
{
var msg = "Error: " + (response.ResourceSets[0].Resources[0] as DistanceMatrix).ErrorMessage;
throw new Exception(msg);
}
throw new Exception(dm.ErrorMessage);
}
return null;
@ -267,13 +174,13 @@ namespace BingMapsRESTToolkit
//Ensure all the origins are geocoded.
if (Origins != null)
{
await SimpleWaypoint.GeocodeWaypoints(Origins, this);
await SimpleWaypoint.TryGeocodeWaypoints(Origins, this);
}
//Ensure all the destinations are geocoded.
if (Destinations != null)
{
await SimpleWaypoint.GeocodeWaypoints(Destinations, this);
await SimpleWaypoint.TryGeocodeWaypoints(Destinations, this);
}
}
@ -289,14 +196,14 @@ namespace BingMapsRESTToolkit
var dm = new DistanceMatrix()
{
Origins = this.Origins.ToArray()
Origins = this.Origins
};
int cnt = 0;
if (this.Destinations == null || this.Destinations.Count == 0)
{
dm.Destinations = this.Origins.ToArray();
dm.Destinations = this.Origins;
dm.Results = new DistanceMatrixCell[this.Origins.Count * this.Origins.Count];
for (var i = 0; i < Origins.Count; i++)
@ -316,7 +223,7 @@ namespace BingMapsRESTToolkit
}
else
{
dm.Destinations = this.Destinations.ToArray();
dm.Destinations = this.Destinations;
dm.Results = new DistanceMatrixCell[this.Origins.Count * this.Destinations.Count];
for (var i = 0; i < Origins.Count; i++)
@ -436,7 +343,7 @@ namespace BingMapsRESTToolkit
foreach (var o in Origins)
{
sb.AppendFormat("{{\"latitude\":{0:0.#####},\"longitude\":{1:0.#####}}},", o.Latitude, o.Longitude);
sb.AppendFormat(CultureInfo.InvariantCulture, "{{\"latitude\":{0:0.#####},\"longitude\":{1:0.#####}}},", o.Latitude, o.Longitude);
}
//Remove trailing comma.
@ -450,7 +357,7 @@ namespace BingMapsRESTToolkit
foreach (var d in Destinations)
{
sb.AppendFormat("{{\"latitude\":{0:0.#####},\"longitude\":{1:0.#####}}},", d.Latitude, d.Longitude);
sb.AppendFormat(CultureInfo.InvariantCulture, "{{\"latitude\":{0:0.#####},\"longitude\":{1:0.#####}}},", d.Latitude, d.Longitude);
}
//Remove trailing comma.
@ -461,6 +368,7 @@ namespace BingMapsRESTToolkit
string mode;
//TODO: Add truck when support added in distance matirx API.
switch (TravelMode)
{
case TravelModeType.Transit:
@ -492,12 +400,12 @@ namespace BingMapsRESTToolkit
switch (TimeUnits)
{
case TimeUnitType.Minutes:
tu = "minutes";
case TimeUnitType.Minute:
tu = "minute";
break;
case TimeUnitType.Seconds:
case TimeUnitType.Second:
default:
tu = "seconds";
tu = "second";
break;
}
@ -561,66 +469,6 @@ namespace BingMapsRESTToolkit
}
}
/// <summary>
/// Monitors the status of an async distance matrix request.
/// </summary>
/// <param name="statusUrl">The status URL for the async request.</param>
/// <param name="failedTries">The number of times the status check has failed consecutively.</param>
/// <param name="remainingTimeCallback">A callback function in whichthe estimated remaining time is sent.</param>
/// <returns>The final async status when the request completed, had an error, or was not accepted.</returns>
private async Task<DistanceMatrixAsyncStatus> MonitorAsyncStatus(Uri statusUrl, int failedTries, Action<int> remainingTimeCallback)
{
DistanceMatrixAsyncStatus status = null;
try
{
using (var rs = await ServiceHelper.GetStreamAsync(statusUrl))
{
var r = ServiceHelper.DeserializeStream<Response>(rs);
if (r != null)
{
if(r.ErrorDetails != null && r.ErrorDetails.Length > 0)
{
throw new Exception(r.ErrorDetails[0]);
}
else if (r.ResourceSets != null && r.ResourceSets.Length > 0 && r.ResourceSets[0].Resources != null && r.ResourceSets[0].Resources.Length > 0 && r.ResourceSets[0].Resources[0] is DistanceMatrixAsyncStatus)
{
status = r.ResourceSets[0].Resources[0] as DistanceMatrixAsyncStatus;
if (status.CallbackInSeconds > 0)
{
remainingTimeCallback?.Invoke(status.CallbackInSeconds);
//Wait remaining seconds.
await Task.Delay(TimeSpan.FromSeconds(status.CallbackInSeconds));
return await MonitorAsyncStatus(statusUrl, 0, remainingTimeCallback);
}
}
}
}
}
catch (Exception ex)
{
//Check to see how many times the status check has failed consecutively.
if (failedTries < MaxStatusCheckRetries)
{
//Wait some time and try again.
await Task.Delay(TimeSpan.FromSeconds(StatusCheckRetryDelay));
return await MonitorAsyncStatus(statusUrl, failedTries + 1, remainingTimeCallback);
}
else
{
status.ErrorMessage = "Failed to get status, and exceeded the maximium of " + MaxStatusCheckRetries + " retries. Error message: " + ex.Message;
status.CallbackInSeconds = -1;
status.IsCompleted = false;
}
}
//Should only get here is the request has completed, was not accepted or there was an error.
return status;
}
#endregion
}
}

Просмотреть файл

@ -23,6 +23,7 @@
*/
using System;
using System.Text;
namespace BingMapsRESTToolkit
{
@ -83,11 +84,12 @@ namespace BingMapsRESTToolkit
/// <returns>Geocode request URL for GET request.</returns>
public override string GetRequestUrl()
{
string url = this.Domain + "Locations";
var sb = new StringBuilder(this.Domain);
sb.Append("Locations");
if (!string.IsNullOrWhiteSpace(Query))
{
url += string.Format("?q={0}", Uri.EscapeDataString(Query));
sb.AppendFormat("?q={0}", Uri.EscapeDataString(Query));
}
else if (Address != null)
{
@ -95,31 +97,31 @@ namespace BingMapsRESTToolkit
if (!string.IsNullOrWhiteSpace(Address.AddressLine))
{
url += string.Format("{0}addressLine={1}", seperator, Uri.EscapeDataString(Address.AddressLine));
sb.AppendFormat("{0}addressLine={1}", seperator, Uri.EscapeDataString(Address.AddressLine));
seperator = "&";
}
if (!string.IsNullOrWhiteSpace(Address.Locality))
{
url += string.Format("{0}locality={1}", seperator, Uri.EscapeDataString(Address.Locality));
sb.AppendFormat("{0}locality={1}", seperator, Uri.EscapeDataString(Address.Locality));
seperator = "&";
}
if (!string.IsNullOrWhiteSpace(Address.AdminDistrict))
{
url += string.Format("{0}adminDistrict={1}", seperator, Uri.EscapeDataString(Address.AdminDistrict));
sb.AppendFormat("{0}adminDistrict={1}", seperator, Uri.EscapeDataString(Address.AdminDistrict));
seperator = "&";
}
if (!string.IsNullOrWhiteSpace(Address.PostalCode))
{
url += string.Format("{0}postalCode={1}", seperator, Uri.EscapeDataString(Address.PostalCode));
sb.AppendFormat("{0}postalCode={1}", seperator, Uri.EscapeDataString(Address.PostalCode));
seperator = "&";
}
if (!string.IsNullOrWhiteSpace(Address.CountryRegion))
{
url += string.Format("{0}countryRegion={1}", seperator, Uri.EscapeDataString(Address.CountryRegion));
sb.AppendFormat("{0}countryRegion={1}", seperator, Uri.EscapeDataString(Address.CountryRegion));
}
}
else
@ -129,20 +131,22 @@ namespace BingMapsRESTToolkit
if (IncludeIso2)
{
url += "&incl=ciso2";
sb.Append("&incl=ciso2");
}
if (IncludeNeighborhood)
{
url += "&inclnb=1";
sb.Append("&inclnb=1");
}
if (maxResults != 5)
{
url += "&maxResults=" + maxResults;
sb.AppendFormat("&maxResults={0}", maxResults);
}
return url + GetBaseRequestUrl();
sb.Append(GetBaseRequestUrl());
return sb.ToString();
}
#endregion

Просмотреть файл

@ -0,0 +1,226 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Threading.Tasks;
namespace BingMapsRESTToolkit
{
/// <summary>
/// A request that calculates an isochrone.
/// </summary>
public class IsochroneRequest : BaseRestRequest
{
#region Constructor
/// <summary>
/// A request that calculates an isochrone.
/// </summary>
public IsochroneRequest(): base()
{
TimeUnit = TimeUnitType.Second;
DistanceUnit = DistanceUnitType.Kilometers;
TravelMode = TravelModeType.Driving;
}
#endregion
#region Public Properties
/// <summary>
/// The point around which the isochrone will be calculated.
/// </summary>
public SimpleWaypoint Waypoint { get; set; }
/// <summary>
/// The maximum travel time in the specified time units in which the isochrone polygon is generated. Cannot be set when maxDistance is set. Maximum value is 120 minutes.
/// </summary>
public double MaxTime { get; set; }
/// <summary>
/// The maximum travel distance in the specified distance units in which the isochrone polygon is generated. Cannot be set when maxTime is set.
/// </summary>
public double MaxDistance { get; set; }
/// <summary>
/// The units in which the maxTime value is specified. Default: Seconds
/// </summary>
public TimeUnitType TimeUnit { get; set; }
/// <summary>
/// The units in which the maxDistance value is specified. Default: Kilometers
/// </summary>
public DistanceUnitType DistanceUnit { get; set; }
//TODO: uncomment when/if avoid is supported.
/// <summary>
/// Specifies the road types to minimize or avoid when a route is created for the driving travel mode.
/// </summary>
//public List<AvoidType> Avoid { get; set; }
/// <summary>
/// The mode of travel for the isochrone. Default: Driving
/// </summary>
public TravelModeType TravelMode { get; set; }
/// <summary>
/// When travel mode is set to driving, and optimize is set to timeWithTraffic, predictive traffic data is used to calculate the best isochrone route for the specified date time.
/// </summary>
public DateTime? DateTime { get; set; }
#endregion
#region Public Methods
/// <summary>
/// Executes the request.
/// </summary>
/// <returns>A response containing the requested data.</returns>
public override async Task<Response> Execute()
{
return await this.Execute(null);
}
/// <summary>
/// Executes the request.
/// </summary>
/// <param name="remainingTimeCallback">A callback function in which the estimated remaining time is sent.</param>
/// <returns>A response containing the requested data.</returns>
public override async Task<Response> Execute(Action<int> remainingTimeCallback)
{
var requestUrl = GetRequestUrl();
//TODO: change to async when supported
using (var responseStream = await ServiceHelper.GetStreamAsync(new Uri(GetRequestUrl())))
{
return ServiceHelper.DeserializeStream<Response>(responseStream);
}
//return await ServiceHelper.MakeAsyncGetRequest<IsochroneResponse>(requestUrl, remainingTimeCallback);
}
/// <summary>
/// Gets the request URL to perform a query for an isochrone.
/// </summary>
/// <returns>A request URL to perform a query for an isochron.</returns>
public override string GetRequestUrl()
{
var sb = new StringBuilder(this.Domain);
//TODO: change to async when supported
sb.Append("Routes/Isochrones");
//sb.Append("Routes/IsochronesAsync");
//Truck mode is not supported, so fall back to driving.
if (TravelMode == TravelModeType.Truck)
{
TravelMode = TravelModeType.Driving;
}
sb.AppendFormat("?travelMode={0}", Enum.GetName(typeof(TravelModeType), TravelMode));
if(Waypoint == null)
{
throw new Exception("A waypoint must be specified.");
}
if (Waypoint.Coordinate != null)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "&waypoint={0:0.#####},{1:0.#####}", Waypoint.Coordinate.Latitude, Waypoint.Coordinate.Longitude);
}
else if (!String.IsNullOrWhiteSpace(Waypoint.Address))
{
sb.AppendFormat("&waypoint={0}", Waypoint.Address);
}
else
{
throw new Exception("Invalid waypoint: A coordinate or address must be specified.");
}
if(MaxTime > 0)
{
//TODO: Verify limits
//if(TimeUnit == TimeUnitType.Second && MaxTime > 7200)
//{
// throw new Exception("MaxTime value must be <= 7200 seconds.");
//}
//else if(TimeUnit == TimeUnitType.Minute && MaxTime > 120)
//{
// throw new Exception("MaxTime value must be <= 120 minutes.");
//}
sb.AppendFormat("&maxTime={0}&timeUnit={1}", MaxTime, Enum.GetName(typeof(TimeUnitType), TimeUnit));
if (TravelMode != TravelModeType.Walking && DateTime != null && DateTime.HasValue)
{
sb.AppendFormat(DateTimeFormatInfo.InvariantInfo, "&dt={0:G}", DateTime.Value);
}
//TODO: in the future expose the optimize option and add support for timeWithTraffic.
sb.AppendFormat("&optimize={0}", Enum.GetName(typeof(RouteOptimizationType), RouteOptimizationType.Time));
}
else if (MaxDistance > 0)
{
if(TravelMode == TravelModeType.Transit)
{
throw new Exception("Distance based isochrones are not supported for transit travel mode. Use maxTime.");
}
sb.AppendFormat("&maxDistance={0}&distanceUnit={1}", MaxDistance, EnumHelper.DistanceUnitTypeToString(DistanceUnit));
sb.AppendFormat("&optimize={0}", Enum.GetName(typeof(RouteOptimizationType), RouteOptimizationType.Distance));
}
else
{
throw new Exception("A max time or distance must be specified.");
}
//TODO: uncomment when/if avoid is supported.
//if (TravelMode == TravelModeType.Driving)
//{
// if (Avoid != null && Avoid.Count > 0)
// {
// sb.Append("&avoid=");
// for (var i = 0; i < Avoid.Count; i++)
// {
// sb.Append(Enum.GetName(typeof(AvoidType), Avoid[i]));
// if (i < Avoid.Count - 1)
// {
// sb.Append(",");
// }
// }
// }
//}
sb.Append(GetBaseRequestUrl());
return sb.ToString();
}
#endregion
}
}

Просмотреть файл

@ -65,10 +65,10 @@ namespace BingMapsRESTToolkit
/// <returns>A request URL to perform a reverse geocode query.</returns>
public override string GetRequestUrl()
{
string url = string.Format(CultureInfo.InvariantCulture, "{2}Locations/{0:0.#####},{1:0.#####}?",
string url = string.Format(CultureInfo.InvariantCulture, "{0}Locations/{1:0.#####},{2:0.#####}?",
this.Domain,
Point.Latitude,
Point.Longitude,
this.Domain);
Point.Longitude);
if (IncludeEntityTypes != null && IncludeEntityTypes.Count > 0)
{

Просмотреть файл

@ -28,6 +28,7 @@ using System.Globalization;
using System.Text;
using System.Threading.Tasks;
using System.Linq;
using BingMapsRESTToolkit.Extensions;
namespace BingMapsRESTToolkit
{
@ -36,6 +37,18 @@ namespace BingMapsRESTToolkit
/// </summary>
public class RouteRequest : BaseRestRequest
{
#region Private Properties
private int batchSize = 25;
/// <summary>
/// Hash values used to quickly check if any thing needed for waypoint optimization has changed since the last travelling salesmen calculation.
/// </summary>
private int waypointsHash;
private string optimizationOptionHash;
#endregion
#region Public Properties
/// <summary>
@ -51,10 +64,9 @@ namespace BingMapsRESTToolkit
/// </summary>
public RouteOptions RouteOptions { get; set; }
private int batchSize = 25;
/// <summary>
/// The maximium number of waypoints that can be in a single request. If the batchSize is smaller than the number of waypoints, when the request is executed, it will break the request up into multiple requests. Must by between 2 and 25. Default: 25.
/// The maximium number of waypoints that can be in a single request. If the batchSize is smaller than the number of waypoints,
/// when the request is executed, it will break the request up into multiple requests. Must by between 2 and 25. Default: 25.
/// </summary>
public int BatchSize
{
@ -64,13 +76,23 @@ namespace BingMapsRESTToolkit
}
set
{
if(value >=2 && value <= 25)
if (value >= 2 && value <= 25)
{
batchSize = value;
}
}
}
/// <summary>
/// Specifies if the waypoint order should be optimized using a travelling salesmen algorithm which metric to optimize on.
/// If less than 10 waypoints, brute force is used, for more than 10 waypoints, a genetic algorithm is used.
/// Ignores IsViaPoint on waypoints and makes them waypoints.
/// Default: false
/// Warning: If travel time or travel distance is used, a standard Bing Maps key will need to be required, not a session key, as the distance matrix API will be used to process the waypoints.
/// This can generate a lot of billable transactions.
/// </summary>
public TspOptimizationType? WaypointOptimization { get; set; }
#endregion
#region Public Methods
@ -91,101 +113,152 @@ namespace BingMapsRESTToolkit
/// <returns>A response containing the requested data.</returns>
public override async Task<Response> Execute(Action<int> remainingTimeCallback)
{
if (Waypoints.Count <= batchSize)
{
using (var responseStream = await ServiceHelper.GetStreamAsync(new Uri(GetRequestUrl())))
{
return ServiceHelper.DeserializeStream<Response>(responseStream);
}
}
//There is more waypoints than the batchSize value (default 25), break it up into multiple requests. Only allow a single route in the response and no tolerances.
if (RouteOptions != null)
{
if (RouteOptions.MaxSolutions > 1)
{
RouteOptions.MaxSolutions = 1;
}
RouteOptions.Tolerances = null;
}
if (Waypoints == null)
{
throw new Exception("Waypoints not specified.");
}
else if (Waypoints.Count < 2)
{
throw new Exception("Not enough Waypoints specified.");
}
else if (Waypoints[0].IsViaPoint || Waypoints[Waypoints.Count - 1].IsViaPoint)
{
throw new Exception("Start and end waypoints must not be ViaWaypoints.");
}
int startIdx = 0;
int endIdx = 0;
var requestUrls = new List<string>();
while (endIdx < Waypoints.Count - 1)
{
requestUrls.Add(GetRequestUrl(startIdx, out endIdx));
startIdx = endIdx - 1;
}
var routes = new Route[requestUrls.Count];
Response response = null;
Response errorResponse = null;
Parallel.For(0, requestUrls.Count, (i) =>
if (WaypointOptimization != null && WaypointOptimization.HasValue && Waypoints.Count >= 2)
{
try
var wpHash = ServiceHelper.GetSequenceHashCode<SimpleWaypoint>(Waypoints);
var optionHash = Enum.GetName(typeof(TspOptimizationType), WaypointOptimization);
var mode = TravelModeType.Driving;
DateTime? depart = null;
if (RouteOptions != null)
{
//Make the call synchronously as we are in a parrallel for loop and need this to block, otherwise the for loop will exist before the async code has completed.
using (var responseStream = ServiceHelper.GetStreamAsync(new Uri(requestUrls[i])).GetAwaiter().GetResult())
optionHash += "|" + Enum.GetName(typeof(RouteTimeType), RouteOptions.TimeType);
if (RouteOptions.TimeType == RouteTimeType.Departure && RouteOptions.DateTime != null && RouteOptions.DateTime.HasValue)
{
var r = ServiceHelper.DeserializeStream<Response>(responseStream);
depart = RouteOptions.DateTime;
optionHash += "|" + RouteOptions.DateTime.ToString();
}
if (r != null)
{
if (r.ErrorDetails != null && r.ErrorDetails.Length > 0)
{
errorResponse = r;
}
else if (r.ResourceSets != null && r.ResourceSets.Length > 0 &&
r.ResourceSets[0].Resources != null && r.ResourceSets[0].Resources.Length > 0)
{
routes[i] = r.ResourceSets[0].Resources[0] as Route;
}
}
mode = RouteOptions.TravelMode;
if (i == 0)
{
response = r;
}
optionHash += "|" + Enum.GetName(typeof(TravelModeType), mode);
}
else
{
optionHash += "|" + Enum.GetName(typeof(RouteTimeType), RouteTimeType.Departure);
}
//Check to see if the waypoints have changed since they were last optimized.
if (waypointsHash != wpHash || string.Compare(optimizationOptionHash, optionHash) != 0)
{
var tspResult = await TravellingSalesmen.Solve(Waypoints, mode, WaypointOptimization, depart, BingMapsKey);
Waypoints = tspResult.OptimizedWaypoints;
//Update the stored hashes to prevent unneeded optimizations in the future if not needed.
waypointsHash = ServiceHelper.GetSequenceHashCode<SimpleWaypoint>(Waypoints);
optimizationOptionHash = optionHash;
}
}
var requestUrl = GetRequestUrl();
if (RouteOptions != null && RouteOptions.TravelMode == TravelModeType.Truck)
{
var requestBody = GetTruckPostRequestBody();
response = await ServiceHelper.MakeAsyncPostRequest<Route>(requestUrl, requestBody, remainingTimeCallback);
}
else
{
if (Waypoints.Count <= batchSize)
{
using (var responseStream = await ServiceHelper.GetStreamAsync(new Uri(requestUrl)))
{
return ServiceHelper.DeserializeStream<Response>(responseStream);
}
}
catch (Exception ex)
//There is more waypoints than the batchSize value (default 25), break it up into multiple requests. Only allow a single route in the response and no tolerances.
if (RouteOptions != null)
{
errorResponse = new Response()
if (RouteOptions.MaxSolutions > 1)
{
ErrorDetails = new string[]
{
ex.Message
}
};
RouteOptions.MaxSolutions = 1;
}
RouteOptions.Tolerances = null;
}
});
//If any of the responses failed to process, do not merge results, return the error info.
if(errorResponse != null)
{
return errorResponse;
if (Waypoints == null)
{
throw new Exception("Waypoints not specified.");
}
else if (Waypoints.Count < 2)
{
throw new Exception("Not enough Waypoints specified.");
}
else if (Waypoints[0].IsViaPoint || Waypoints[Waypoints.Count - 1].IsViaPoint)
{
throw new Exception("Start and end waypoints must not be ViaWaypoints.");
}
int startIdx = 0;
int endIdx = 0;
var requestUrls = new List<string>();
while (endIdx < Waypoints.Count - 1)
{
requestUrls.Add(GetRequestUrl(startIdx, out endIdx));
startIdx = endIdx - 1;
}
var routes = new Route[requestUrls.Count];
Response errorResponse = null;
Parallel.For(0, requestUrls.Count, (i) =>
{
try
{
//Make the call synchronously as we are in a parrallel for loop and need this to block, otherwise the for loop will exist before the async code has completed.
using (var responseStream = ServiceHelper.GetStreamAsync(new Uri(requestUrls[i])).GetAwaiter().GetResult())
{
var r = ServiceHelper.DeserializeStream<Response>(responseStream);
if (r != null)
{
if (r.ErrorDetails != null && r.ErrorDetails.Length > 0)
{
errorResponse = r;
}
else if (r.ResourceSets != null && r.ResourceSets.Length > 0 &&
r.ResourceSets[0].Resources != null && r.ResourceSets[0].Resources.Length > 0)
{
routes[i] = r.ResourceSets[0].Resources[0] as Route;
}
}
if (i == 0)
{
response = r;
}
}
}
catch (Exception ex)
{
errorResponse = new Response()
{
ErrorDetails = new string[]
{
ex.Message
}
};
}
});
//If any of the responses failed to process, do not merge results, return the error info.
if (errorResponse != null)
{
return errorResponse;
}
response.ResourceSets[0].Resources[0] = await MergeRoutes(routes);
}
response.ResourceSets[0].Resources[0] = await MergeRoutes(routes);
return response;
}
@ -217,6 +290,8 @@ namespace BingMapsRESTToolkit
#endregion
#region Private Methods
/// <summary>
/// Generates a route REST request
/// </summary>
@ -233,53 +308,56 @@ namespace BingMapsRESTToolkit
sb.AppendFormat("Routes/{0}?", Enum.GetName(typeof(TravelModeType), TravelMode));
int wayCnt = 0, viaCnt = 0;
for (int i = startIdx; i < Waypoints.Count; i++)
if (TravelMode != TravelModeType.Truck)
{
if (Waypoints[i].IsViaPoint)
{
sb.AppendFormat("&vwp.{0}=", i - startIdx);
viaCnt++;
int wayCnt = 0, viaCnt = 0;
if (TravelMode == TravelModeType.Transit)
for (int i = startIdx; i < Waypoints.Count; i++)
{
if (Waypoints[i].IsViaPoint)
{
throw new Exception("ViaWaypoints not supported for Transit directions.");
sb.AppendFormat("&vwp.{0}=", i - startIdx);
viaCnt++;
if (TravelMode == TravelModeType.Transit)
{
throw new Exception("ViaWaypoints not supported for Transit directions.");
}
}
}
else
{
sb.AppendFormat("&wp.{0}=", i - startIdx);
if (viaCnt > 10)
else
{
throw new Exception("More than 10 viaWaypoints between waypoints.");
sb.AppendFormat("&wp.{0}=", i - startIdx);
if (viaCnt > 10)
{
throw new Exception("More than 10 viaWaypoints between waypoints.");
}
wayCnt++;
viaCnt = 0;
}
wayCnt++;
viaCnt = 0;
if (Waypoints[i].Coordinate != null)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{0:0.#####},{1:0.#####}", Waypoints[i].Coordinate.Latitude, Waypoints[i].Coordinate.Longitude);
}
else
{
sb.AppendFormat("{0}", Uri.EscapeDataString(Waypoints[i].Address));
}
//Only allow up to the batchSize waypoints in a request.
if (wayCnt == batchSize)
{
endIdx = i;
break;
}
}
if (Waypoints[i].Coordinate != null)
if (RouteOptions != null)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{0:0.#####},{1:0.#####}", Waypoints[i].Coordinate.Latitude, Waypoints[i].Coordinate.Longitude);
sb.Append(RouteOptions.GetUrlParam(startIdx));
}
else
{
sb.AppendFormat("{0}", Uri.EscapeDataString(Waypoints[i].Address));
}
//Only allow up to the batchSize waypoints in a request.
if (wayCnt == batchSize)
{
endIdx = i;
break;
}
}
if (RouteOptions != null)
{
sb.Append(RouteOptions.GetUrlParam(startIdx));
}
sb.Append(GetBaseRequestUrl());
@ -378,5 +456,251 @@ namespace BingMapsRESTToolkit
return null;
});
}
/// <summary>
/// Gets a POST body for a truck route request.
/// </summary>
/// <returns>A POST body for a truck route request.</returns>
private string GetTruckPostRequestBody()
{
var sb = new StringBuilder();
sb.Append("{");
if (Waypoints.Count > 25)
{
throw new Exception("More than 25 waypoints or viaWaypoints specified.");
}
sb.Append("\"waypoints\":[");
foreach (var wp in Waypoints)
{
if (wp.Coordinate != null)
{
sb.AppendFormat("{{\"latitude\":{0:0.#####},\"longitude\":{1:0.#####}", wp.Latitude, wp.Longitude);
}
else if (!string.IsNullOrWhiteSpace(wp.Address))
{
sb.AppendFormat("{{\"address\":\"{0}\"", wp.Address);
}
else
{
throw new Exception("Invalid waypoint, an Address or Coordinate must be specified.");
}
if (wp.IsViaPoint)
{
sb.Append(",\"isViaPoint\":true},");
}
else
{
sb.Append("},");
}
}
//Remove trailing comma.
sb.Length--;
sb.Append("]");
if (RouteOptions != null)
{
if (RouteOptions.Avoid != null && RouteOptions.Avoid.Count > 0)
{
sb.Append(",\"avoid\":\"");
for (var i = 0; i < RouteOptions.Avoid.Count; i++)
{
sb.Append(Enum.GetName(typeof(AvoidType), RouteOptions.Avoid[i]));
sb.Append(",");
}
//Remove trailing comma.
sb.Length--;
sb.Append("\"");
}
if (RouteOptions.DistanceBeforeFirstTurn > 0)
{
sb.AppendFormat(",\"distanceBeforeFirstTurn\":{0}", RouteOptions.DistanceBeforeFirstTurn);
}
if (RouteOptions.Heading.HasValue)
{
sb.AppendFormat(",\"heading\":{0}", RouteOptions.Heading.Value);
}
if (RouteOptions.MaxSolutions > 1 && RouteOptions.MaxSolutions <= 3)
{
sb.AppendFormat(",\"maxSolutions\":{0}", RouteOptions.MaxSolutions);
}
if (RouteOptions.Optimize == RouteOptimizationType.Time)
{
sb.Append(",\"optimize\":\"time\"");
}
else if (RouteOptions.Optimize == RouteOptimizationType.TimeWithTraffic)
{
sb.Append(",\"optimize\":\"timeWithTraffic\"");
}
else
{
throw new Exception("Truck routes must be optimized based on time or timeWithTraffic.");
}
if (RouteOptions.RouteAttributes != null && RouteOptions.RouteAttributes.Count > 0)
{
sb.Append(",\"routeAttributes\":\"");
//Route summaries only supported, but other route attributes try to do something similar, so have them short circuit to this option.
if(RouteOptions.RouteAttributes.Contains(RouteAttributeType.RouteSummariesOnly) || RouteOptions.RouteAttributes.Contains(RouteAttributeType.All) || RouteOptions.RouteAttributes.Contains(RouteAttributeType.ExcludeItinerary))
{
sb.Append("routeSummariesOnly,");
}
if (RouteOptions.RouteAttributes.Contains(RouteAttributeType.RoutePath) || RouteOptions.RouteAttributes.Contains(RouteAttributeType.All))
{
sb.Append("routePath,");
}
//Remove trailing comma.
sb.Length--;
sb.Append("\"");
}
if (RouteOptions.DistanceUnits == DistanceUnitType.Kilometers)
{
sb.Append(",\"distanceUnit\":\"kilometer\"");
}
else
{
sb.Append(",\"distanceUnit\":\"mile\"");
}
if (RouteOptions.DateTime != null)
{
sb.AppendFormat(DateTimeFormatInfo.InvariantInfo, ",\"dateTime\":\"{0:G}\"", RouteOptions.DateTime);
}
if (RouteOptions.Tolerances != null && RouteOptions.Tolerances.Count > 0)
{
sb.Append(",\"tolerances\":[");
int cnt = Math.Min(RouteOptions.Tolerances.Count, 7);
for (int i = 0; i < cnt; i++)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{0:0.######}", RouteOptions.Tolerances[i]);
sb.Append(",");
}
//Remove trailing comma.
sb.Length--;
sb.Append("]");
}
if (RouteOptions.VehicleSpec != null)
{
sb.Append(",\"vehicleSpec\":{");
sb.AppendFormat("\"dimensionUnit\":\"{0}\"", Enum.GetName(typeof(DimensionUnitType), RouteOptions.VehicleSpec.DimensionUnit).ToLowerInvariant());
sb.AppendFormat(",\"weightUnit\":\"{0}\"", Enum.GetName(typeof(WeightUnitType), RouteOptions.VehicleSpec.WeightUnit).ToLowerInvariant());
if (RouteOptions.VehicleSpec.VehicleAvoidCrossWind)
{
sb.Append(",\"vehicleAvoidCrossWind\":true");
}
if (RouteOptions.VehicleSpec.VehicleAvoidGroundingRisk)
{
sb.Append(",\"vehicleAvoidGroundingRisk\":true");
}
if (RouteOptions.VehicleSpec.VehicleSemi)
{
sb.Append(",\"VehicleSemi\":true");
}
if (RouteOptions.VehicleSpec.VehicleAxles > 1)
{
sb.AppendFormat(",\"vehicleAxles\":{0}", RouteOptions.VehicleSpec.VehicleAxles);
}
if (RouteOptions.VehicleSpec.VehicleHeight > 0)
{
sb.AppendFormat(",\"vehicleHeight\":{0}", RouteOptions.VehicleSpec.VehicleHeight);
}
if (RouteOptions.VehicleSpec.VehicleWidth > 0)
{
sb.AppendFormat(",\"vehicleWidth\":{0}", RouteOptions.VehicleSpec.VehicleWidth);
}
if (RouteOptions.VehicleSpec.VehicleLength > 0)
{
sb.AppendFormat(",\"vehicleLength\":{0}", RouteOptions.VehicleSpec.VehicleLength);
}
if (RouteOptions.VehicleSpec.VehicleWeight > 0)
{
sb.AppendFormat(",\"vehicleWeight\":{0}", RouteOptions.VehicleSpec.VehicleWeight);
}
if (RouteOptions.VehicleSpec.VehicleMaxGradient > 0)
{
sb.AppendFormat(",\"vehicleMaxGradient\":{0}", RouteOptions.VehicleSpec.VehicleMaxGradient);
}
if (RouteOptions.VehicleSpec.VehicleMinTurnRadius > 0)
{
sb.AppendFormat(",\"vehicleMinTurnRadius\":{0}", RouteOptions.VehicleSpec.VehicleMinTurnRadius);
}
if (RouteOptions.VehicleSpec.VehicleTrailers > 0)
{
sb.AppendFormat(",\"vehicleTrailers\":{0}", RouteOptions.VehicleSpec.VehicleTrailers);
}
if (RouteOptions.VehicleSpec.VehicleHazardousMaterials != null && RouteOptions.VehicleSpec.VehicleHazardousMaterials.Count > 0 &&
!(RouteOptions.VehicleSpec.VehicleHazardousMaterials.Count == 1 && RouteOptions.VehicleSpec.VehicleHazardousMaterials[0] == HazardousMaterialType.None))
{
sb.Append(",\"vehicleHazardousMaterials\":\"");
foreach (var vhm in RouteOptions.VehicleSpec.VehicleHazardousMaterials)
{
sb.Append(EnumHelper.HazardousMaterialTypeToString(vhm));
sb.Append(",");
}
//Remove trailing comma.
sb.Length--;
sb.Append("\"");
}
if (RouteOptions.VehicleSpec.VehicleHazardousPermits != null && RouteOptions.VehicleSpec.VehicleHazardousPermits.Count > 0 &&
!(RouteOptions.VehicleSpec.VehicleHazardousPermits.Count == 1 && RouteOptions.VehicleSpec.VehicleHazardousPermits[0] == HazardousMaterialPermitType.None))
{
sb.Append(",\"vehicleHazardousPermits\":\"");
foreach (var vhp in RouteOptions.VehicleSpec.VehicleHazardousPermits)
{
sb.Append(EnumHelper.HazardousMaterialPermitTypeToString(vhp));
sb.Append(",");
}
//Remove trailing comma.
sb.Length--;
sb.Append("\"");
}
sb.Append("}");
}
}
sb.Append("}");
return sb.ToString();
}
#endregion
}
}

Просмотреть файл

@ -0,0 +1,197 @@
/*
* Copyright(c) 2017 Microsoft Corporation. All rights reserved.
*
* This code is licensed under the MIT License (MIT).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is furnished to do
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Threading.Tasks;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Snaps a set of coordinates to roads.
/// </summary>
public class SnapToRoadRequest : BaseRestRequest
{
#region Constructor
/// <summary>
/// A request that calculates an isochrone.
/// </summary>
public SnapToRoadRequest(): base()
{
SpeedUnit = SpeedUnitType.KPH;
TravelMode = TravelModeType.Driving;
}
#endregion
#region Public Properties
/// <summary>
/// A set of coordinates to snap to roads.
/// </summary>
public List<Coordinate> Points { get; set; }
/// <summary>
/// Indicates if the space between the snapped points should be filled with additional points along the road, thus returning the full route path.
/// </summary>
public bool Interpolate { get; set; }
/// <summary>
/// Indicates if speed limitation data should be returned for the snapped points.
/// </summary>
public bool IncludeSpeedLimit { get; set; }
/// <summary>
/// Indicates if speed limitation data should be returned for the snapped points.
/// </summary>
public bool IncludeTruckSpeedLimit { get; set; }
/// <summary>
/// Indicates the units in which the returned speed limit data is in.
/// </summary>
public SpeedUnitType SpeedUnit { get; set; }
/// <summary>
/// Indicates which routing profile to snap the points to. Default: Driving
/// </summary>
public TravelModeType TravelMode { get; set; }
#endregion
#region Public Methods
/// <summary>
/// Executes the request.
/// </summary>
/// <returns>A response containing the requested data.</returns>
public override async Task<Response> Execute()
{
return await this.Execute(null);
}
/// <summary>
/// Executes the request.
/// </summary>
/// <param name="remainingTimeCallback">A callback function in which the estimated remaining time is sent.</param>
/// <returns>A response containing the requested data.</returns>
public override async Task<Response> Execute(Action<int> remainingTimeCallback)
{
var requestUrl = GetRequestUrl();
var requestBody = GetPostRequestBody();
return await ServiceHelper.MakeAsyncPostRequest<Route>(requestUrl, requestBody, remainingTimeCallback);
}
/// <summary>
/// Gets the request URL to perform a query to snap points to roads. This method will only generate an post URL.
/// </summary>
/// <returns>A request URL to perform a query to snap points to roads.</returns>
public override string GetRequestUrl()
{
if (Points == null)
{
throw new Exception("Points not specified.");
}
else if (Points.Count < 1)
{
throw new Exception("Not enough Points specified.");
}
else if (Points.Count > 100)
{
throw new Exception("More than 100 Points specified.");
}
if(TravelMode == TravelModeType.Transit)
{
throw new Exception("Transit is not supported by SnapToRoad API.");
}
//https://dev.virtualearth.net/REST/v1/Routes/SnapToRoad?key=BingMapsKey
return this.Domain + "Routes/SnapToRoad?key=" + this.BingMapsKey;
}
#endregion
#region Private Methods
/// <summary>
/// Gets a POST body for a snap to road request.
/// </summary>
/// <returns>A POST body for a snap to road request.</returns>
private string GetPostRequestBody()
{
var sb = new StringBuilder();
sb.Append("{");
sb.Append("\"points\":[");
foreach (var p in Points)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{{\"latitude\":{0:0.#####},\"longitude\":{1:0.#####}}},", p.Latitude, p.Longitude);
}
//Remove trailing comma.
sb.Length--;
sb.Append("]");
if (Interpolate)
{
sb.Append(",\"interpolate\":true");
}
if (IncludeSpeedLimit)
{
sb.Append(",\"includeSpeedLimit\":true");
}
if (IncludeTruckSpeedLimit)
{
sb.Append(",\"includeTruckSpeedLimit\":true");
}
sb.AppendFormat(",\"speedUnit\":\"{0}\"", Enum.GetName(typeof(SpeedUnitType), SpeedUnit));
//TODO: Truck mode is not supported, so fall back to driving. Remove this if truck routing support added.
//Note, difference between snapping car vs truck should be minor since the truck GPS points should only be on roads it is meant to be on.
if (TravelMode == TravelModeType.Truck)
{
TravelMode = TravelModeType.Driving;
}
sb.AppendFormat(",\"travelMode\":\"{0}\"", Enum.GetName(typeof(TravelModeType), TravelMode));
sb.Append("}");
return sb.ToString();
}
#endregion
}
}