See changelog
This commit is contained in:
Ricky Brundritt 2022-03-17 16:18:59 -07:00
Родитель b20de9d11b
Коммит d9940c0e92
69 изменённых файлов: 4206 добавлений и 339 удалений

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

@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26430.16
# Visual Studio Version 16
VisualStudioVersion = 16.0.32228.343
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{EE7ACF1F-56D3-4A01-8262-A49A8B444639}"
EndProject
@ -9,7 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{A155C8
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{833D0345-46F0-486E-9BEF-5269405683F8}"
ProjectSection(SolutionItems) = preProject
..\..\..\..\Source\Repos\Bing-Maps-V8-TypeScript-Definitions\.gitignore = ..\..\..\..\Source\Repos\Bing-Maps-V8-TypeScript-Definitions\.gitignore
..\..\..\Source\Repos\Bing-Maps-V8-TypeScript-Definitions\.gitignore = ..\..\..\Source\Repos\Bing-Maps-V8-TypeScript-Definitions\.gitignore
CHANGELOG.md = CHANGELOG.md
CONTRIBUTING.md = CONTRIBUTING.md
LICENSE.md = LICENSE.md
@ -42,6 +42,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{5F797BB6-1
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TravellingSalesmenRouteSample", "Samples\WPF\TravellingSalesmenRouteSample\TravellingSalesmenRouteSample.csproj", "{5173922A-0160-4EE1-9AD8-F629B23CFE71}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultiRouteOptimizationSample", "Samples\WPF\MultiRouteOptimizationSample\MultiRouteOptimizationSample.csproj", "{9AEB32AD-D999-4E5F-8CB7-B6A0727DA12A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -72,6 +74,10 @@ Global
{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
{9AEB32AD-D999-4E5F-8CB7-B6A0727DA12A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9AEB32AD-D999-4E5F-8CB7-B6A0727DA12A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9AEB32AD-D999-4E5F-8CB7-B6A0727DA12A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9AEB32AD-D999-4E5F-8CB7-B6A0727DA12A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -86,6 +92,7 @@ Global
{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}
{9AEB32AD-D999-4E5F-8CB7-B6A0727DA12A} = {26E65B0F-9554-408A-95D4-BDEC52945FC3}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C3DB70BA-969B-47D7-8A77-65B190E2CC81}

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

@ -1,3 +1,14 @@
## Version 1.1.5 - 3/15/2022
* Added AutoSuggest, LocalSearch, LocalInsights, and OptimizeItineraryRequest APIs. Added samples for each.
* Added a visual sample for OptimizeItineraryRequest.
* Added support for regional travel summary in routes.
* Fixed backlog of issues and updates.
* Add helper methods to existing classes
- SimpleWaypoint and Coordinate classes - static Parse method.
- Resource class - static HasResource and GetFirstResouce methods.
- RoutePath class - method to retrieve route path as an array of coordinates.
## Version 1.1.4 - 3/9/2018
* Async support added to SnapToRoadRequest, thus allowing up to 1,000 points to be snapped in a single request.

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

@ -12,6 +12,9 @@
- [GeocodeRequest Class](#GeocodeRequest)
- [ReverseGeocodeRequest Class](#ReverseGeocodeRequest)
- [LocationRecogRequest Class](#LocationRecogRequest)
- [LocalSearchRequest Class](#LocalSearchRequest)
- [LocalInsightsRequest Class](#LocalInsightsRequest)
- [AutosuggestRequest Class](#AutosuggestRequest)
- [Routes API](#routes-api)
- [DistanceMatrixRequest Class](#DistanceMatrixRequest)
- [IsochroneRequest Class](#IsochroneRequest)
@ -19,6 +22,7 @@
- [RouteRequest Class](#RouteRequest)
- [SnapToRoadRequest Class](#SnapToRoadRequest)
- [TrafficRequest Class](#TrafficRequest)
- [OptimizeItineraryRequest class](#OptimizeItineraryRequest)
- [Elevation API](#elevation-api)
- [ElevationRequest Class](#ElevationRequest)
- [Imagery API](#imagery-api)
@ -62,6 +66,7 @@
- [TravellingSalesmen Classes](#TravellingSalesmen)
- [TspOptimizationType Enumeration](#TspOptimizationType)
- [TspSolution Class](#TspSolution)
* [Response class extensions](#response-class-extensions)
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).
@ -265,7 +270,7 @@ The [Location Recognition API](https://msdn.microsoft.com/en-us/library/mt847173
#### Constructor
> `public LocationRecogRequest();`
> `public LocationRecogRequest()`
#### Methods
@ -288,6 +293,75 @@ The [Location Recognition API](https://msdn.microsoft.com/en-us/library/mt847173
|`Radius`| `double`| Maximum search radius, from `0` to `2` kilometers. |
|`VerbosePlaceNames`| `bool`| Whether to include verbose entity names.|
### <a name="LocalSearchRequest"></a> `LocalSearchRequest` Class
The [Local Search API](https://docs.microsoft.com/en-us/bingmaps/rest-services/locations/local-search) returns a list of business entities centered around a location or a geographic region.
#### 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 reverse geocode query. |
#### Properties
| Name | Type | Description |
|---------------------|------------------------|----------------|
| `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. |
| `Types` | `List<string>` | The specified types used to filter the local entities returned by the Local Search API. A comma-separated list of string type identifiers. See the [list of available Type IDs](https://docs.microsoft.com/en-us/bingmaps/rest-services/common-parameters-and-types/type-identifiers/) |
### <a name="LocalInsightsRequest"></a> `LocalInsightsRequest` Class
The [Local Insights API](https://docs.microsoft.com/en-us/bingmaps/rest-services/routes/local-insights) returns a list of local entities within the specified maximum driving time or distance traveled from a specified point on Earth.
#### 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 reverse geocode query. |
#### 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. |
| `Optimize` | [`RouteOptimizationType`](#RouteOptimizationType) | Specifies what parameters to use to optimize the isochrone route. One of the following values:<br/><br/>- distance: The route is calculated to minimize the distance. Traffic information is not used. Use with maxDistance.<br/>- time [default]: The route is calculated to minimize the time. Traffic information is not used. Use with maxTime.<br/>- timeWithTraffic: The route is calculated to minimize the time and uses current or predictive traffic information depending on if a dateTime value is specified. Use with maxTime. |
| `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. |
| `Types` | `List<string>` | The specified types used to filter the local entities returned by the Local Search API. A comma-separated list of string type identifiers. See the [list of available Type IDs](https://docs.microsoft.com/en-us/bingmaps/rest-services/common-parameters-and-types/type-identifiers/) |
| `Waypoint` | [SimplyWaypoint](#SimplyWaypoint) | The point around which the isochrone will be calculated. |
## <a name="AutosuggestRequest"></a> AutosuggestRequest Class
The [Autosuggest API](https://docs.microsoft.com/en-us/bingmaps/rest-services/autosuggest) returns a list of suggested entities which the user is most likely searching for.
#### 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 reverse geocode query. |
#### Properties
| Name | Type | Description |
|---------------------|------------------------|----------------|
| `CountryFilter` | `string` | A list of returned entity types. |
| `IncludeEntityTypes` | `List<AutosuggestEntityType>` | Specifies the maximum number of locations to return in the response. |
| `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. |
## Routes API
### <a name="DistanceMatrixRequest"></a> Distance Matrix Request
@ -438,6 +512,29 @@ Requests traffic information. Inherits from the BaseRestRequest class.
| `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="OptimizeItineraryRequest"></a> OptimizeItineraryRequest class
Request for Bing Maps Multi-Itinerary Optimization API.
#### Methods
| Name | Return Type | Description |
|-----------------|-------------|-----------------------------------------------------------|
| `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
| Name | Type | Description |
|----------------------|--------------------------|----------------|
| `Agents` | `List<Agent>` | List of agent itinerary information: including the agent name, shift starting and ending locations for agent, and capacity of the agent's vehicle. |
| `ItineraryItems` | `List<OptimizeItineraryItem>` | List of itinerary items to be scheduled among the specified agents, including the location name, location (lat/lon), priority, dwell time, business closing and opening times for each item to be scheduled, quantity to be delivered to or picked up from each location, and pickup/drop off sequence dependency with other itineraryItems. |
| `Type` | `OptimizationType` | Specifies whether traffic data should used to optimize the order of waypoint items. Default: `SimpleRequest` Note: If the type parameter is set to TrafficRequest, it will automatically use true as the roadnetwork parameter value. |
| `RoadNetwork` | `bool`; | Optional. If true, uses actual road network information, and both travel distances and travel times between the itinerary locations to calculate optimizations. If false, a constant radius is used to measure distances and a constant travel speed is used to calculate travel times between locations. |
| `CostValue` | `CostValueType` | A parameter used to optimize itineraries in addition to maximizing the sum of item priorities. Default: TravelTime |
## Elevations API
### <a name="ElevationRequest"></a> ElevationRequest Class
@ -557,6 +654,13 @@ A class that defines location coordinate value.
> Coordinate(double latitude, double longitude)
### Static Methods
| Name | Return Type | Description |
|-----------------|-------------|---------------------------------------------------------------|
| Parse(string coordinateString) | Coordinate | Parses a coordinate value from a string with the format "latitude,longitude". |
### Properties
| Name | Type | Description |
@ -680,6 +784,8 @@ A simple waypoint class that can be used to calculate a route.
> SimpleWaypoint(double latitude, double longitude)
### Methods
| Name | Return Type | Description |
|-----------------|-------------|---------------------------------------------------------------|
| TryGeocode(SimpleWaypoint waypoint, string bingMapsKey) | Task | Tries to geocode a simple waypoint. |
@ -687,6 +793,12 @@ A simple waypoint class that can be used to calculate a route.
| TryGeocodeWaypoints(List\<SimpleWaypoint\> waypoints, string bingMapsKey) | Task | Attempts to geocode a list of simple waypoints. |
| TryGeocodeWaypoints(List\<SimpleWaypoint\> waypoints, BaseRestRequest baseRequest) | Task | Attempts to geocode a list of simple waypoints. |
### Static Methods
| Name | Return Type | Description |
|-----------------|-------------|---------------------------------------------------------------|
| Parse(string waypointString) | SimpleWaypoint | Parses a simple waypoint value from a string. If it has the format "latitude,longitude", it will be used as a coordinate, otherwise as an address. |
### Properties
| Name | Type | Description |
@ -860,7 +972,8 @@ The type of route attributes to include in a route response.
| All | Used to specify the following attributes as a group: excluteItinerary, routePath, and transitStops. |
| ExcludeItinerary | Do not include detailed directions in the response. Detailed directions are provided as itinerary items and contain details such as written instructions and traffic location codes. |
| RoutePath | Include a set of point (latitude and longitude) values that describe the route-s path in the response. |
| RouteSummariesOnly | Include only travel time and distance for the route, and does not provide other information. |
| RouteSummariesOnly | Include only travel time and distance for the route, and does not provide other information.
| RegionTravelSummary | Include travel summary of distance, time, and toll road distance by two entity types: country (e.g. US, Canada) and administrative division or subregion (e.g. “state” in US and “province” in Canada). |
| TransitStops | Include information about transit stops for transit routes. |
## <a name="RouteOptimizationType"></a> RouteOptimizationType Enumeration
@ -1035,3 +1148,27 @@ The result from a Travelling Salesmen calculation.
| 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. |
## Response class extensions
Extensions that have been added to response classes.
### Response class extension
Extensions to the `Response` class to assist with common tasks.
#### Static Methods
| Name | Return Type | Description |
|-----------------|-------------|----------------------------------------------------------|
| HasResource(Response response) | bool | Check that a response has one or more resources. This is a helper class to save on having to check all the parts of the response tree. |
| GetFirstResource(Response response) | Resource | Gets the first resource in a response. |
### RoutePath class extension
Extensions to the `RoutePath` class to assist with common tasks.
## Methods
| Name | Return Type | Description |
|-----------------|-------------|----------------------------------------------------------|
| GetCoordinates() | Coordinate[] | Gets an array of coordinate objects for the route path. |

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

@ -1,5 +1,6 @@
![Bing Maps Logo](https://github.com/Microsoft/Bing-Maps-V8-TypeScript-Definitions/blob/master/images/BingMapsLogoTeal.png)
![Local version](https://img.shields.io/badge/Local%20version-1.1.5-green.svg)
[![NuGet](https://img.shields.io/badge/NuGet-1.1.4-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)
@ -7,6 +8,7 @@
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:
* **Autosuggest**
* **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
@ -15,10 +17,8 @@ This is a portable .NET class library which provides a set of tools that make it
* **Traffic incident data**
* **Elevation data**
* **Static map imagery and metadata**
## What's New
* September 2018: Requests for [Location Recognition](https://msdn.microsoft.com/en-US/library/mt847173.aspx) and the [Time Zone API](https://msdn.microsoft.com/en-us/library/mt829726.aspx), including Data Contracts, are now available.
* **Local search**
* And much more!
## Toolkit Features
@ -31,6 +31,12 @@ This is a portable .NET class library which provides a set of tools that make it
* **Travelling Salesmen** algorithms that tie into the distance matrix API [documentation](https://github.com/Microsoft/BingMapsRESTToolkit/blob/master/Docs/Getting%20Started.md#TravellingSalesmen).
* **Truck routing based Distance Matricies** - The Bing Maps distance matric API does not support truck routing based matricies. This library adds support for this by wrapping the truck routing API.
## Reference locally
The NuGet package is not updated as frequently as the source code in this repo. You can use the latest version by
downloading the source code and copying the contents of the `Source` folder into your solution folder.
Then in your solution add an "Existing project" and select the "BingMapsRESTToolkit.csproj" file.
## NuGet Package
The Bing Maps REST Services Toolkit is available as a [NuGet package](https://www.nuget.org/packages/BingMapsRESTToolkit). If using Visual Studio, open the nuget package manager, select the Browse tab and search for "Bing Maps REST". This should reduce the list of results enough to find the "BingMapsRESTToolkit" package. The owner of the package is bingmaps and the author is Microsoft.

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

@ -4,6 +4,6 @@
<add key="BingMapsKey" value="YOUR_API_KEY_HERE"/>
</appSettings>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1"/>
</startup>
</configuration>

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

@ -51,17 +51,17 @@ namespace RESTToolkitTestConsoleApp
public void AutoSuggestTest()
{
Console.WriteLine("Running Autosuggest Test");
CoordWithRadius ul = new CoordWithRadius() { Latitude = 47.668697, Longitude = -122.376373, Radius = 5 };
var ul = new CircularView(47.668697, -122.376373, 5);
var request = new AutosuggestRequest()
{
BingMapsKey = _ApiKey,
Query = "El Bur",
UserLoc = ul
UserLocation = ul,
};
Console.WriteLine(request.GetRequestUrl());
var resources = GetResourcesFromRequest(request);
var entities = (resources[0] as AutosuggestResource);
var entities = (resources[0] as Autosuggest);
foreach (var entity in entities.Value)
Console.Write($"Entity of type {entity.Type} returned.");
@ -167,7 +167,7 @@ namespace RESTToolkitTestConsoleApp
if (r.BusinessAtLocation != null)
{
foreach (LocalBusiness business in r.BusinessAtLocation)
foreach (BusinessAtLocation business in r.BusinessAtLocation)
{
Console.WriteLine($"Business:\n{business.BusinessInfo.EntityName}");
}

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

@ -8,7 +8,7 @@
<OutputType>Exe</OutputType>
<RootNamespace>RESTToolkitTestConsoleApp.NetStandard</RootNamespace>
<AssemblyName>RESTToolkitTestConsoleApp.NetStandard</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<TargetFrameworkProfile />

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

@ -48,32 +48,6 @@ namespace RESTToolkitTestConsoleApp
return r.ResourceSets[0].Resources;
}
/*
*
* Pending review.
*
static public void AutoSuggestTest()
{
Console.WriteLine("Running Autosuggest Test");
CoordWithRadius ul = new CoordWithRadius() { Latitude = 47.668697, Longitude = -122.376373, Radius = 5 };
var request = new AutosuggestRequest()
{
BingMapsKey = _ApiKey,
Query = "El Bur",
UserLoc = ul
};
Console.WriteLine(request.GetRequestUrl());
var resources = GetResourcesFromRequest(request);
var entities = (resources[0] as AutosuggestResource);
foreach (var entity in entities.Value)
Console.Write($"Entity of type {entity.Type} returned.");
Console.ReadLine();
}
*/
/// <summary>
/// Convert Time Zone Test
/// https://msdn.microsoft.com/en-us/library/mt829733.aspx
@ -194,7 +168,7 @@ namespace RESTToolkitTestConsoleApp
if (r.BusinessAtLocation != null)
{
foreach (LocalBusiness business in r.BusinessAtLocation)
foreach (BusinessAtLocation business in r.BusinessAtLocation)
{
Console.WriteLine($"Business:\n{business.BusinessInfo.EntityName}");
}

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

@ -49,7 +49,6 @@
<DebugSymbols>true</DebugSymbols>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Source\BingMapsRESTToolkit.csproj" />
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core" />
@ -80,6 +79,12 @@
<Install>false</Install>
</BootstrapperPackage>
</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" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

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

@ -0,0 +1,9 @@
<Application x:Class="MultiRouteOptimizationSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MultiRouteOptimizationSample"
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 MultiRouteOptimizationSample
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

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

@ -0,0 +1,10 @@
using System.Windows;
[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)
)]

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

@ -0,0 +1,106 @@
<Window x:Class="MultiRouteOptimizationSample.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:MultiRouteOptimizationSample"
xmlns:m="clr-namespace:Microsoft.Maps.MapControl.WPF;assembly=Microsoft.Maps.MapControl.WPF"
mc:Ignorable="d"
Title="Multi-route itinerary optimization sample" Height="800" Width="1200">
<Window.Resources>
<Style x:Key="CustomInfoboxStyle" TargetType="ToolTip">
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="VerticalOffset" Value="15" />
<Setter Property="HorizontalOffset" Value="155" />
<Setter Property="Placement" Value="Top" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="BorderBrush" Value="Transparent" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<StackPanel>
<Grid Width="200" MinHeight="50" HorizontalAlignment="Left">
<Border Background="Black"/>
<StackPanel Margin="5">
<ContentPresenter Margin="5" Content="{TemplateBinding Content}"/>
</StackPanel>
</Grid>
<Polygon HorizontalAlignment="Left" Fill="Black">
<Polygon.Points>
<Point X="0" Y="0"/>
<Point X="20" Y="0"/>
<Point X="30" Y="30"/>
</Polygon.Points>
</Polygon>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Header="Main">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Margin="5">
<Button Content="Instructions" Click="InstructionsBtn_Clicked" />
<Button Content="Calculate itinerary" Click="CalculateBtn_Clicked" />
<Button Name="CalculateRoutePathBtn" Content="Calculate route path" Click="CalculateRoutePathBtn_Clicked" IsEnabled="False" />
<TextBlock Text="Output" FontWeight="Bold" Margin="0,10"/>
<TextBox Name="OutputTbx" Height="200" Grid.Column="1" VerticalScrollBarVisibility="Auto" TextWrapping="Wrap" Margin="0,0,0,10"/>
<Button Content="Export request" Click="ExportRequestBtn_Clicked" />
<Button Content="Import request" Click="ImportRequestBtn_Clicked" />
<Button Content="Export result" Click="ExportResultBtn_Clicked" />
<Button Content="Import result" Click="ImportResultBtn_Clicked" />
</StackPanel>
<m:Map Name="MyMap" Grid.Column="1"/>
<StackPanel Grid.Column="1" Background="White" Width="100" Height="100" Margin="10" VerticalAlignment="Bottom" HorizontalAlignment="Left">
<TextBlock Text="Legend" FontSize="16" FontWeight="Bold" Margin="5"/>
<StackPanel Orientation="Horizontal">
<Rectangle Width="10" Height="10" Margin="5" Fill="Blue"/>
<TextBlock Text="Agent 1"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Rectangle Width="10" Height="10" Margin="5" Fill="Orange"/>
<TextBlock Text="Agent 2"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Rectangle Width="10" Height="10" Margin="5" Fill="Red"/>
<TextBlock Text="Agent 3"/>
</StackPanel>
</StackPanel>
</Grid>
</TabItem>
<TabItem Header="Request details">
<StackPanel>
<TextBlock Text="Agents" Margin="0,10" FontSize="14" FontWeight="Bold"/>
<DataGrid Name="AgentTable" CanUserAddRows="False" CanUserResizeColumns="True" CanUserSortColumns="True" IsReadOnly="True" />
<TextBlock Text="Initerary stops" Margin="0,10" FontSize="14" FontWeight="Bold"/>
<DataGrid Name="IniteraryStopTable" CanUserAddRows="False" CanUserResizeColumns="True" CanUserSortColumns="True" IsReadOnly="True" />
</StackPanel>
</TabItem>
</TabControl>
<Grid Name="LoadingScreen" Background="#55000000" Visibility="Collapsed" Grid.ColumnSpan="2">
<TextBlock FontSize="20" VerticalAlignment="Center" HorizontalAlignment="Center" Text="Calculating..." Foreground="White"/>
</Grid>
</Grid>
</Window>

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

@ -0,0 +1,895 @@
using BingMapsRESTToolkit;
using Microsoft.Maps.MapControl.WPF;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Data;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace MultiRouteOptimizationSample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
#region Private Properties
private string BingMapsKey = System.Configuration.ConfigurationManager.AppSettings.Get("BingMapsKey");
OptimizeItineraryRequest request = new OptimizeItineraryRequest()
{
Agents = new List<Agent>()
{
new Agent()
{
Name = "Bob",
Shifts = new List<Shift>()
{
new Shift()
{
StartTimeUtc = new DateTime(2022, 1, 1, 8, 0, 0), //8 am
StartLocation = new SimpleWaypoint("1603 NW 89th St, Seattle, WA 98117, US"),
EndTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
EndLocation = new SimpleWaypoint(47.7070790545669, -122.355226696231),
Breaks = new Break[]
{
new Break()
{
StartTimeUtc = new DateTime(2022, 1, 1, 12, 0, 0), //12pm/noon
EndTimeUtc = new DateTime(2022, 1, 1, 14, 0, 0), //2pm
DurationTimeSpan = new TimeSpan(0, 30, 0) //30 minutes.
},
new Break()
{
StartTimeUtc = new DateTime(2022, 1, 1, 16, 0, 0), //4pm
EndTimeUtc = new DateTime(2022, 1, 1, 16, 30, 0) //4:30pm
}
}
}
},
Price = new Price()
{
FixedPrice = 100,
PricePerHour = 5,
PricePerKM = 1
},
Capacity = new int[] { 16 }
},
new Agent()
{
Name = "Charlie",
Shifts = new List<Shift>()
{
new Shift()
{
StartTimeUtc = new DateTime(2022, 1, 1, 8, 0, 0), //8 am
StartLocation = new SimpleWaypoint("1 Microsoft way, WA 98052, US"),
EndTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
EndLocation = new SimpleWaypoint(47.7070790545669, -122.355226696231),
Breaks = new Break[]
{
new Break()
{
StartTimeUtc = new DateTime(2022, 1, 1, 12, 0, 0), //12pm/noon
EndTimeUtc = new DateTime(2022, 1, 1, 14, 0, 0), //2pm
DurationTimeSpan = new TimeSpan(0, 30, 0) //30 minutes.
},
new Break()
{
StartTimeUtc = new DateTime(2022, 1, 1, 16, 0, 0), //4pm
EndTimeUtc = new DateTime(2022, 1, 1, 16, 30, 0) //4:30pm
}
}
}
},
Price = new Price()
{
FixedPrice = 100,
PricePerHour = 5,
PricePerKM = 1
},
Capacity = new int[] { 16 }
},
new Agent()
{
Name = "Terry",
Shifts = new List<Shift>()
{
new Shift()
{
StartTimeUtc = new DateTime(2022, 1, 1, 8, 0, 0), //8 am
StartLocation = new SimpleWaypoint(47.746135, -122.199314),
EndTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
EndLocation = new SimpleWaypoint(47.746135, -122.199314),
Breaks = new Break[]
{
new Break()
{
StartTimeUtc = new DateTime(2022, 1, 1, 12, 0, 0), //12pm/noon
EndTimeUtc = new DateTime(2022, 1, 1, 14, 0, 0), //2pm
DurationTimeSpan = new TimeSpan(0, 30, 0) //30 minutes.
},
new Break()
{
StartTimeUtc = new DateTime(2022, 1, 1, 16, 0, 0), //4pm
EndTimeUtc = new DateTime(2022, 1, 1, 16, 30, 0) //4:30pm
}
}
}
},
Price = new Price()
{
FixedPrice = 100,
PricePerHour = 5,
PricePerKM = 1
},
Capacity = new int[] { 16 }
}
},
ItineraryItems = new List<OptimizeItineraryItem>()
{
new OptimizeItineraryItem()
{
Name = "Customer 1",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 32, 0), //32 minutes
Priority = 5,
Quantity = new int[] { 4 },
//Waypoint = new SimpleWaypoint(47.692290770423,-122.385954752402),
Waypoint = new SimpleWaypoint("8712 Jones Pl NW, Seattle, WA 98117, US")
},
new OptimizeItineraryItem()
{
Name = "Customer 2",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(1, 34, 0), //1 hour 34 minutes
Priority = 16,
Quantity = new int[] { -3 },
Waypoint = new SimpleWaypoint(47.6962193175262,-122.342180147243),
DropOffFrom = new string[] { "Customer 3" }
},
new OptimizeItineraryItem()
{
Name = "Customer 3",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(1, 0, 0), //1 hour
Priority = 88,
Quantity = new int[] { 3 },
Waypoint = new SimpleWaypoint(47.6798098928389,-122.383036445391)
},
new OptimizeItineraryItem()
{
Name = "Customer 4",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 25, 0), //25 minutes
Priority = 3,
Quantity = new int[] { -3 },
Waypoint = new SimpleWaypoint(47.6867440824094,-122.354711700877),
DropOffFrom = new string[] { "Customer 1" }
},
new OptimizeItineraryItem()
{
Name = "Customer 5",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { -1 },
Waypoint = new SimpleWaypoint(47.6846639223203,-122.364839942855),
DropOffFrom = new string[] { "Customer 1" }
},
new OptimizeItineraryItem()
{
Name = "Customer 6",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { 5 },
Waypoint = new SimpleWaypoint(47.668492, -122.193820)
},
new OptimizeItineraryItem()
{
Name = "Customer 7",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { 5 },
Waypoint = new SimpleWaypoint(47.745673, -122.246702)
},
new OptimizeItineraryItem()
{
Name = "Customer 8",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { 5 },
Waypoint = new SimpleWaypoint(47.609720, -122.143685)
},
new OptimizeItineraryItem()
{
Name = "Customer 9",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { 5 },
Waypoint = new SimpleWaypoint(47.536975, -122.167035)
},
new OptimizeItineraryItem()
{
Name = "Customer 10",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { 5 },
Waypoint = new SimpleWaypoint(47.594438, -122.311946)
},
new OptimizeItineraryItem()
{
Name = "Customer 11",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { 5 },
Waypoint = new SimpleWaypoint(47.583784, -122.180084)
},
new OptimizeItineraryItem()
{
Name = "Customer 12",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { 5 },
Waypoint = new SimpleWaypoint(47.658778, -122.047535)
},
new OptimizeItineraryItem()
{
Name = "Customer 13",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { 5 },
Waypoint = new SimpleWaypoint(47.727659, -122.101104)
},
new OptimizeItineraryItem()
{
Name = "Customer 14",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { 5 },
Waypoint = new SimpleWaypoint(47.701782, -122.298898)
},
new OptimizeItineraryItem()
{
Name = "Customer 15",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 40, 0), //18 minutes
Priority = 1,
Quantity = new int[] { 15 },
Waypoint = new SimpleWaypoint(47.791548, -122.204411)
}
}
};
OptimizeItinerary result = null;
//Only used for import/export feature in sample.
DataContractJsonSerializer requestSerializer = new DataContractJsonSerializer(typeof(OptimizeItineraryRequest));
DataContractJsonSerializer resultSerializer = new DataContractJsonSerializer(typeof(OptimizeItinerary));
Color[] AgentColors = new Color[] {
Colors.Blue, Colors.Orange, Colors.Red
};
MapLayer pinLayer = new MapLayer();
MapLayer lineLayer = new MapLayer();
#endregion
#region Constructor
public MainWindow()
{
InitializeComponent();
//Set the credentials on the map.
MyMap.CredentialsProvider = new ApplicationIdCredentialsProvider(BingMapsKey);
//Add a layers for pushpins and lines to the map after it has loaded.
MyMap.Loaded += (s, e) =>
{
MyMap.Children.Add(lineLayer);
MyMap.Children.Add(pinLayer);
};
LoadRequestInsights();
}
#endregion
#region Button Handlers
private void InstructionsBtn_Clicked(object sender, RoutedEventArgs e)
{
MessageBox.Show("Instructions:\n\n1. Click \"Calculate itinerary\" to make a Multi-route optimization request.\n2. Hover over pins to see some details.\n3. Click \"Calculate route path\" to calculate and show the route path along the roads.\n4. Optionally export/import requests and results.");
}
private async void CalculateBtn_Clicked(object sender, RoutedEventArgs e)
{
result = null;
//Show loading screen and clear output.
LoadingScreen.Visibility = Visibility.Visible;
OutputTbx.Text = string.Empty;
CalculateRoutePathBtn.IsEnabled = false;
//Clear data on map.
lineLayer.Children.Clear();
pinLayer.Children.Clear();
try
{
//Ensure request has credentials set.
request.BingMapsKey = BingMapsKey;
//Execute the request.
var response = await request.Execute();
//Ensure the response contains results.
if (Response.HasResource(response))
{
//Get the result.
result = Response.GetFirstResource(response) as OptimizeItinerary;
ShowResultOnMap();
}
else
{
MessageBox.Show("Unable to calculate optimized route itinerary.");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
//Hide loading screen.
LoadingScreen.Visibility = Visibility.Collapsed;
}
private async void CalculateRoutePathBtn_Clicked(object sender, RoutedEventArgs e)
{
//Remove any existing lines.
lineLayer.Children.Clear();
//Loop through each agent and calculate a route along the roads.
for (int i = 0; i < result.AgentItineraries.Length; i++)
{
var a = result.AgentItineraries[i];
//Create a route request to get a route paths along a road.
var r = new RouteRequest()
{
//Customize these options based on agents.
RouteOptions = new RouteOptions()
{
Avoid = new List<AvoidType>()
{
AvoidType.MinimizeTolls
},
TravelMode = TravelModeType.Driving,
DistanceUnits = DistanceUnitType.Miles,
Heading = 45,
RouteAttributes = new List<RouteAttributeType>()
{
//Only retrieving route path information for visualization. Change this to "All" if you want the instructions too.
RouteAttributeType.RoutePath
},
Optimize = RouteOptimizationType.TimeWithTraffic
},
Waypoints = a.Route.GetAllWaypoints(),
BingMapsKey = BingMapsKey
};
var route = await r.Execute();
//Show the route on the map.
ShowRouteOnMap(route, AgentColors[i]);
}
}
[STAThread]
private void ExportRequestBtn_Clicked(object sender, RoutedEventArgs e)
{
//Searilize the request object into a string and save as a JSON file.
//Remove credendtials from request for security reasons.
request.BingMapsKey = string.Empty;
var sfd = new SaveFileDialog();
sfd.FileName = "MOIRequest.json";
sfd.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*";
sfd.RestoreDirectory = true;
var dl = sfd.ShowDialog();
if (dl.HasValue && dl.Value)
{
using (var fs = sfd.OpenFile())
{
try
{
requestSerializer.WriteObject(fs, request);
}
catch
{
MessageBox.Show("Error exporting request.");
}
}
}
}
[STAThread]
private void ImportRequestBtn_Clicked(object sender, RoutedEventArgs e)
{
//Load a request from a JSON file.
var ofd = new OpenFileDialog();
ofd.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*";
ofd.RestoreDirectory = true;
var dl = ofd.ShowDialog();
if (dl.HasValue && dl.Value)
{
using (var fs = ofd.OpenFile())
{
try
{
request = requestSerializer.ReadObject(fs) as OptimizeItineraryRequest;
LoadRequestInsights();
}
catch(Exception ex)
{
MessageBox.Show("Error importing request.");
}
}
}
}
[STAThread]
private void ExportResultBtn_Clicked(object sender, RoutedEventArgs e)
{
if(result == null)
{
MessageBox.Show("No result to export.");
return;
}
//Searilize the result object into a string and save as a JSON file.
var sfd = new SaveFileDialog();
sfd.FileName = "OptimizedItinerary.json";
sfd.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*";
sfd.RestoreDirectory = true;
var dl = sfd.ShowDialog();
if (dl.HasValue && dl.Value)
{
using (var fs = sfd.OpenFile())
{
try
{
resultSerializer.WriteObject(fs, result);
}
catch
{
MessageBox.Show("Error exporting result.");
}
}
}
}
[STAThread]
private void ImportResultBtn_Clicked(object sender, RoutedEventArgs e)
{
//Load a request from a JSON file.
var ofd = new OpenFileDialog();
ofd.Filter = "JSON files (*.json)|*.json|All files (*.*)|*.*";
ofd.RestoreDirectory = true;
var dl = ofd.ShowDialog();
if (dl.HasValue && dl.Value)
{
using (var fs = ofd.OpenFile())
{
try
{
result = resultSerializer.ReadObject(fs) as OptimizeItinerary;
ShowResultOnMap();
}
catch
{
MessageBox.Show("Error importing result.");
}
}
}
}
#endregion
#region Private Methods
private void ShowResultOnMap()
{
//Get the order of stops for each agent.
var sb = new StringBuilder();
foreach (var a in result.AgentItineraries)
{
sb.AppendLine("Stops for agent " + a.Agent.Name);
int cnt = 1;
foreach (var i in a.Instructions)
{
switch (i.InstructionType)
{
case OptimizeInstructionType.LeaveFromStartPoint:
sb.Append("\tStart\n");
break;
case OptimizeInstructionType.TakeABreak:
sb.AppendFormat("\t{0}) Break\n", cnt);
cnt++;
break;
case OptimizeInstructionType.VisitLocation:
sb.AppendFormat("\t{0}) {1}\n", cnt, i.ItineraryItem.Name);
cnt++;
break;
case OptimizeInstructionType.ArriveToEndPoint:
sb.Append("\tEnd\n");
break;
case OptimizeInstructionType.TravelBetweenLocations:
break;
}
}
}
if (result.UnscheduledItems != null && result.UnscheduledItems.Length > 0)
{
sb.AppendLine("\nUnscheduled stops:");
foreach (var ui in result.UnscheduledItems)
{
sb.AppendLine(ui.Name);
}
}
if (result.UnusedAgents != null && result.UnusedAgents.Length > 0)
{
sb.AppendLine("\nUnscheduled agents:");
foreach (var ua in result.UnusedAgents)
{
sb.AppendLine(ua.Name);
}
}
OutputTbx.Text = sb.ToString();
//Show the response information on the map.
var allLocations = new List<Microsoft.Maps.MapControl.WPF.Location>();
//Loop through each agent.
for (int i = 0; i < result.AgentItineraries.Length; i++)
{
var ai = result.AgentItineraries[i];
var tooltipInfo = new StringBuilder();
foreach (var ins in ai.Instructions)
{
tooltipInfo.Clear();
string txt = string.Empty;
Microsoft.Maps.MapControl.WPF.Location loc = null;
//Show Start/End, and stop locations as pushpins.
switch (ins.InstructionType)
{
case OptimizeInstructionType.LeaveFromStartPoint:
loc = CoordToLoc(ins.ItineraryItem.Waypoint.Coordinate);
txt = ai.Agent.Name + ": Start";
break;
case OptimizeInstructionType.ArriveToEndPoint:
loc = CoordToLoc(ins.ItineraryItem.Waypoint.Coordinate);
txt = ai.Agent.Name + ": End";
break;
case OptimizeInstructionType.VisitLocation:
loc = CoordToLoc(ins.ItineraryItem.Waypoint.Coordinate);
txt = ins.ItineraryItem.Name;
break;
}
if (loc != null)
{
tooltipInfo.AppendFormat("Agent: {0}\n", ai.Agent.Name);
tooltipInfo.AppendFormat("Instruction type: {0}\n", ins.InstructionType);
tooltipInfo.AppendFormat("Instruction: {0}\n", txt);
tooltipInfo.AppendFormat("Start time: {0}\n", ins.StartTimeUtc);
tooltipInfo.AppendFormat("End time: {0}\n", ins.EndTimeUtc);
tooltipInfo.AppendFormat("Duration: {0:g}", ins.DurationTimeSpan);
/*pinLayer.Children.Add(new Pushpin()
{
Location = loc,
Content = ins.ItineraryItem.Name
});*/
//Create custom pushpin for location.
var pin = new Grid();
pin.Children.Add(new Ellipse()
{
Stroke = new SolidColorBrush(Colors.White),
StrokeThickness = 3,
Fill = new SolidColorBrush(AgentColors[i]),
Width = 20,
Height = 20,
HorizontalAlignment = HorizontalAlignment.Center
});
pin.Children.Add(new TextBlock()
{
Text = txt,
FontSize = 14,
FontWeight = FontWeights.Bold,
HorizontalAlignment = HorizontalAlignment.Center,
Margin = new Thickness(0,0,0,40),
Background = new SolidColorBrush(Colors.White)
});
MapLayer.SetPosition(pin, loc);
MapLayer.SetPositionOrigin(pin, PositionOrigin.Center);
pinLayer.Children.Add(pin);
//Create a tooltip for the pushpin.
ToolTipService.SetToolTip(pin, new ToolTip()
{
Content = tooltipInfo.ToString(),
Style = Application.Current.Resources["CustomInfoboxStyle"] as Style
});
}
}
//Get the ordered coordinates between the start/stops/breaks/end.
var lc = new LocationCollection();
lc.Add(CoordToLoc(ai.Route.StartLocation));
foreach (var wp in ai.Route.Waypoints)
{
lc.Add(CoordToLoc(wp));
}
lc.Add(CoordToLoc(ai.Route.EndLocation));
//Capture all locations for use later when calculating map view.
allLocations.AddRange(lc);
lineLayer.Children.Clear();
//Create a polyline for the path and add it to the map.
lineLayer.Children.Add(new MapPolyline()
{
Locations = lc,
Stroke = new SolidColorBrush(AgentColors[i]),
StrokeThickness = 5
});
}
//Calculate the best map view to view the results.
Microsoft.Maps.MapControl.WPF.Location center;
double zoom;
GetBestMapView(allLocations, MyMap.ActualWidth, MyMap.ActualHeight, 30, out center, out zoom);
MyMap.Center = center;
MyMap.ZoomLevel = zoom;
//Since there is a result now, enable route path calculation.
CalculateRoutePathBtn.IsEnabled = true;
}
private void ShowRouteOnMap(Response routeResponse, Color agentColor)
{
if(Response.HasResource(routeResponse))
{
var route = Response.GetFirstResource(routeResponse) as Route;
if (route != null)
{
var lc = new LocationCollection();
var coords = route.RoutePath.GetCoordinates();
if (coords != null)
{
foreach (var c in coords)
{
lc.Add(CoordToLoc(c));
}
//Create a polyline for the path and add it to the map.
lineLayer.Children.Add(new MapPolyline()
{
Locations = lc,
Stroke = new SolidColorBrush(agentColor),
StrokeThickness = 5
});
}
}
}
}
/// <summary>
/// Converts a Coordinate from toolkit into a WPF Location.
/// </summary>
/// <param name="coord"></param>
/// <returns></returns>
private Microsoft.Maps.MapControl.WPF.Location CoordToLoc(Coordinate coord)
{
return new Microsoft.Maps.MapControl.WPF.Location(coord.Latitude, coord.Longitude);
}
/// <summary>
/// Calculates the best map view for a list of locations for a map. Based on https://rbrundritt.wordpress.com/2009/07/21/determining-best-map-view-for-an-array-of-locations/
/// </summary>
/// <param name="locations">List of location objects</param>
/// <param name="mapWidth">Map width in pixels</param>
/// <param name="mapHeight">Map height in pixels</param>
/// <param name="buffer">Width in pixels to use to create a buffer around the map. This is to keep pushpins from being cut off on the edge</param>
/// <returns>The best center and zoom level for the specified set of locations.</returns>
public void GetBestMapView(List<Microsoft.Maps.MapControl.WPF.Location> locations, double mapWidth, double mapHeight, int buffer, out Microsoft.Maps.MapControl.WPF.Location center, out double zoomLevel)
{
center = new Microsoft.Maps.MapControl.WPF.Location();
zoomLevel = 0;
double maxLat = -85;
double minLat = 85;
double maxLon = -180;
double minLon = 180;
//calculate bounding rectangle
for (int i = 0; i < locations.Count; i++)
{
if (locations[i].Latitude > maxLat)
{
maxLat = locations[i].Latitude;
}
if (locations[i].Latitude < minLat)
{
minLat = locations[i].Latitude;
}
if (locations[i].Longitude > maxLon)
{
maxLon = locations[i].Longitude;
}
if (locations[i].Longitude < minLon)
{
minLon = locations[i].Longitude;
}
}
center.Latitude = (maxLat + minLat) / 2;
center.Longitude = (maxLon + minLon) / 2;
double zoom1 = 0, zoom2 = 0;
//Determine the best zoom level based on the map scale and bounding coordinate information
if (maxLon != minLon && maxLat != minLat)
{
//best zoom level based on map width
zoom1 = Math.Log(360.0 / 256.0 * (mapWidth - 2 * buffer) / (maxLon - minLon)) / Math.Log(2);
//best zoom level based on map height
zoom2 = Math.Log(180.0 / 256.0 * (mapHeight - 2 * buffer) / (maxLat - minLat)) / Math.Log(2);
}
//use the most zoomed out of the two zoom levels
zoomLevel = (zoom1 < zoom2) ? zoom1 : zoom2;
}
public void LoadRequestInsights()
{
if(request != null)
{
//Define agent table.
DataTable agentDataTable = new DataTable();
agentDataTable.Columns.Add("Agent", typeof(string));
agentDataTable.Columns.Add("Shift Start", typeof(string));
agentDataTable.Columns.Add("Start Location", typeof(string));
agentDataTable.Columns.Add("Shift End", typeof(string));
agentDataTable.Columns.Add("End Location", typeof(string));
agentDataTable.Columns.Add("Capacity", typeof(string));
agentDataTable.Columns.Add("Fixed Price", typeof(double));
agentDataTable.Columns.Add("Price / KM", typeof(double));
agentDataTable.Columns.Add("Price / Hour", typeof(double));
//Add data.
foreach(var a in request.Agents)
{
var firstShift = a.Shifts[0];
var lastShift = a.Shifts[a.Shifts.Count - 1];
agentDataTable.Rows.Add(
a.Name,
firstShift.StartTimeUtc.ToString(),
firstShift.StartLocation.ToString(),
lastShift.EndTimeUtc.ToString(),
lastShift.EndLocation.ToString(),
(a.Capacity != null) ? "[" + string.Join(",", a.Capacity) + "]" : "",
a.Price.FixedPrice,
a.Price.PricePerKM,
a.Price.PricePerHour
);
}
var ds = new DataSet();
ds.Tables.Add(agentDataTable);
AgentTable.ItemsSource = ds.Tables[0].DefaultView;
//Load itinerary stops.
//Define itinerary table.
DataTable itineraryDataTable = new DataTable();
itineraryDataTable.Columns.Add("Stop", typeof(int));
itineraryDataTable.Columns.Add("Name", typeof(string));
itineraryDataTable.Columns.Add("Opening", typeof(string));
itineraryDataTable.Columns.Add("Closing", typeof(string));
itineraryDataTable.Columns.Add("Dwell", typeof(string));
itineraryDataTable.Columns.Add("Priority", typeof(int));
itineraryDataTable.Columns.Add("Location", typeof(string));
itineraryDataTable.Columns.Add("Quantity", typeof(string));
itineraryDataTable.Columns.Add("Drop Off", typeof(string));
//Add data.
for(int i=0;i<request.ItineraryItems.Count;i++)
{
var stop = request.ItineraryItems[i];
itineraryDataTable.Rows.Add(
i,
stop.Name,
(stop.OpeningTimeUtc.HasValue) ? stop.OpeningTimeUtc.Value.ToShortTimeString(): "",
(stop.ClosingTimeUtc.HasValue) ? stop.ClosingTimeUtc.Value.ToShortTimeString() : "",
(stop.DwellTimeSpan.HasValue) ? stop.DwellTimeSpan.Value.ToString() : "",
stop.Priority,
stop.Waypoint.ToString(),
(stop.Quantity != null) ? "[" + string.Join(",", stop.Quantity) + "]" : "",
(stop.DropOffFrom != null) ? "[" + string.Join(",", stop.DropOffFrom) + "]" : ""
);
}
var ds2 = new DataSet();
ds2.Tables.Add(itineraryDataTable);
IniteraryStopTable.ItemsSource = ds2.Tables[0].DefaultView;
}
}
#endregion
}
}

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

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0-windows</TargetFramework>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Maps.MapControl.WPF" Version="1.0.0.3" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Source\BingMapsRESTToolkit.csproj" />
</ItemGroup>
</Project>

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

@ -25,11 +25,18 @@
<StackPanel>
<Button Content="Geocode" Click="GeocodeBtn_Clicked" Height="30"/>
<Button Content="Reverse Geocode" Click="ReverseGeocodeBtn_Clicked" Height="30"/>
<Button Content="Local Search" Click="LocalSearchBtn_Clicked" Height="30"/>
<Button Content="Local Search (types)" Click="LocalSearchTypeBtn_Clicked" Height="30"/>
<Button Content="Local Insights" Click="LocalInsightsBtn_Clicked" Height="30"/>
<Button Content="Location Recognition" Click="LocationRecogBtn_Clicked" Height="30"/>
<Button Content="Autosuggest" Click="AutosuggestBtn_Clicked" Height="30"/>
<Button Content="Elevation" Click="ElevationBtn_Clicked" Height="30"/>
<Button Content="Elevations by bounding box" Click="ElevationByBboxBtn_Clicked" Height="30"/>
<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="Multi-Itinerary Optimization" Click="OptimizeItineraryBtn_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"/>

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

@ -107,6 +107,71 @@ namespace RESTToolkitTestApp
ProcessRequest(r);
}
private void LocalSearchBtn_Clicked(object sender, RoutedEventArgs e)
{
var r = new LocalSearchRequest()
{
Query = "coffee",
MaxResults = 25,
UserLocation = new Coordinate(47.602038, -122.333964),
BingMapsKey = BingMapsKey
};
ProcessRequest(r);
}
private void LocalSearchTypeBtn_Clicked(object sender, RoutedEventArgs e)
{
var r = new LocalSearchRequest()
{
Types = new List<string>() { "CoffeeAndTea" },
MaxResults = 25,
UserLocation = new Coordinate(47.602038, -122.333964),
BingMapsKey = BingMapsKey
};
ProcessRequest(r);
}
private void LocalInsightsBtn_Clicked(object sender, RoutedEventArgs e)
{
var r = new LocalInsightsRequest()
{
Types = new List<string>() { "CoffeeAndTea" },
Waypoint = new SimpleWaypoint("Bellevue, WA"),
MaxTime = 60,
TimeUnit = TimeUnitType.Minute,
DateTime = DateTime.Now.AddMinutes(15),
TravelMode = TravelModeType.Driving,
BingMapsKey = BingMapsKey
};
ProcessRequest(r);
}
private void LocationRecogBtn_Clicked(object sender, RoutedEventArgs e)
{
var r = new LocationRecogRequest() {
BingMapsKey = BingMapsKey,
CenterPoint = new Coordinate(47.668697, -122.376373)
};
ProcessRequest(r);
}
private void AutosuggestBtn_Clicked(object sender, RoutedEventArgs e)
{
var r = new AutosuggestRequest()
{
BingMapsKey = BingMapsKey,
Query = "El Bur",
UserLocation = new CircularView(47.668697, -122.376373, 5),
};
ProcessRequest(r);
}
/// <summary>
/// Demostrates how to make an Elevation Request.
/// </summary>
@ -126,6 +191,23 @@ namespace RESTToolkitTestApp
ProcessRequest(r);
}
/// <summary>
/// Demostrates how to make an Elevation Request for a bounding box.
/// </summary>
private void ElevationByBboxBtn_Clicked(object sender, RoutedEventArgs e)
{
var r = new ElevationRequest()
{
Bounds = new BoundingBox(new double[] {50.995391, -1.320763, 52.000577, -2.311836}),
Row = 50,
Col = 4,
BingMapsKey = BingMapsKey
};
ProcessRequest(r);
}
/// <summary>
/// Demostrates how to make a Driving Route Request.
/// </summary>
@ -317,6 +399,116 @@ namespace RESTToolkitTestApp
ProcessRequest(r);
}
/// <summary>
/// Demostrates how to make a Multi-route optimization Request.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OptimizeItineraryBtn_Clicked(object sender, RoutedEventArgs e)
{
var r = new OptimizeItineraryRequest()
{
Agents = new List<Agent>()
{
new Agent()
{
Name = "agent1",
Shifts = new List<Shift>()
{
new Shift()
{
StartTimeUtc = new DateTime(2022, 1, 1, 8, 0, 0), //8 am
StartLocation = new SimpleWaypoint("1603 NW 89th St, Seattle, WA 98117, US"),
EndTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
EndLocation = new SimpleWaypoint(47.7070790545669, -122.355226696231),
Breaks = new Break[]
{
new Break()
{
StartTimeUtc = new DateTime(2022, 1, 1, 12, 0, 0), //12pm/noon
EndTimeUtc = new DateTime(2022, 1, 1, 14, 0, 0), //2pm
DurationTimeSpan = new TimeSpan(0, 30, 0) //30 minutes.
},
new Break()
{
StartTimeUtc = new DateTime(2022, 1, 1, 16, 0, 0), //4pm
EndTimeUtc = new DateTime(2022, 1, 1, 16, 30, 0) //4:30pm
}
}
}
},
Price = new Price()
{
FixedPrice = 100,
PricePerHour = 5,
PricePerKM = 1
},
Capacity = new int[] { 16 }
}
},
ItineraryItems = new List<OptimizeItineraryItem>()
{
new OptimizeItineraryItem()
{
Name = "Customer 1",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 32, 0), //32 minutes
Priority = 5,
Quantity = new int[] { 4 },
//Waypoint = new SimpleWaypoint(47.692290770423,-122.385954752402),
Waypoint = new SimpleWaypoint("8712 Jones Pl NW, Seattle, WA 98117, US")
},
new OptimizeItineraryItem()
{
Name = "Customer 2",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(1, 34, 0), //1 hour 34 minutes
Priority = 16,
Quantity = new int[] { -3 },
Waypoint = new SimpleWaypoint(47.6962193175262,-122.342180147243),
DropOffFrom = new string[] { "Customer 3" }
},
new OptimizeItineraryItem()
{
Name = "Customer 3",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(1, 0, 0), //1 hour
Priority = 88,
Quantity = new int[] { 3 },
Waypoint = new SimpleWaypoint(47.6798098928389,-122.383036445391)
},
new OptimizeItineraryItem()
{
Name = "Customer 4",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 25, 0), //25 minutes
Priority = 3,
Quantity = new int[] { -3 },
Waypoint = new SimpleWaypoint(47.6867440824094,-122.354711700877),
DropOffFrom = new string[] { "Customer 1" }
},
new OptimizeItineraryItem()
{
Name = "Customer 5",
OpeningTimeUtc = new DateTime(2022, 1, 1, 9, 0, 0), //9am
ClosingTimeUtc = new DateTime(2022, 1, 1, 18, 0, 0), //6pm
DwellTimeSpan = new TimeSpan(0, 18, 0), //18 minutes
Priority = 1,
Quantity = new int[] { -1 },
Waypoint = new SimpleWaypoint(47.6846639223203,-122.364839942855),
DropOffFrom = new string[] { "Customer 1" }
}
},
BingMapsKey = BingMapsKey
};
ProcessRequest(r);
}
/// <summary>
/// Demostrates how to make a Traffic Request.
/// </summary>
@ -628,7 +820,10 @@ namespace RESTToolkitTestApp
{
_time = TimeSpan.FromSeconds(remainingTime);
Application.Current.Dispatcher.Invoke(() =>
{
RequestProgressBarText.Text = string.Format("Time remaining {0} ", _time);
});
_timer.Start();
}

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

@ -209,10 +209,10 @@ namespace RESTToolkitTestApp
object v = p.GetValue(value, null);
IEnumerable arr = v as IEnumerable;
ObjectNode arrayNode = new ObjectNode(p.Name, arr.ToString(), typeof(object));
if (arr != null)
{
ObjectNode arrayNode = new ObjectNode(p.Name, arr.ToString(), typeof(object));
int i = 0, k = 0;
ObjectNode arrayNode2;
@ -241,11 +241,12 @@ namespace RESTToolkitTestApp
i++;
}
}
Children.Add(arrayNode);
}
catch { }
}
catch (Exception e){
var t = e;
}
}
else
{

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

@ -18,8 +18,6 @@ namespace TravellingSalesmenRouteSample
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()
@ -181,17 +179,7 @@ namespace TravellingSalesmenRouteSample
{
if (!string.IsNullOrWhiteSpace(p))
{
var m = CoordinateRx.Match(p);
if (m.Success)
{
waypoints.Add(new SimpleWaypoint(double.Parse(m.Groups[1].Value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture),
double.Parse(m.Groups[3].Value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture)));
}
else
{
waypoints.Add(new SimpleWaypoint(p));
}
waypoints.Add(SimpleWaypoint.Parse(p));
}
}

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

@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Version>1.1.4</Version>
<Version>1.1.5</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,7 +13,7 @@
<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.1.4.0</AssemblyVersion>
<AssemblyVersion>1.1.5.0</AssemblyVersion>
<FileVersion>1.1.4.0</FileVersion>
<AssemblyName>BingMapsRESTToolkit</AssemblyName>
<RootNamespace>BingMapsRESTToolkit</RootNamespace>
@ -26,6 +26,7 @@
<Compile Include="..\Enums\AutosuggestLocationType.cs" Link="Enums\AutosuggestLocationType.cs" />
<Compile Include="..\Enums\AvoidType.cs" Link="Enums\AvoidType.cs" />
<Compile Include="..\Enums\ConfidenceLevelType.cs" Link="Enums\ConfidenceLevelType.cs" />
<Compile Include="..\Enums\CostValueType.cs" Link="CostValueType.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" />
@ -37,6 +38,8 @@
<Compile Include="..\Enums\ImageryType.cs" Link="Enums\ImageryType.cs" />
<Compile Include="..\Enums\ManeuverType.cs" Link="Enums\ManeuverType.cs" />
<Compile Include="..\Enums\LocationRecogEntityTypes.cs" Link="Enums\LocationRecogEntityTypes.cs" />
<Compile Include="..\Enums\OptimizationType.cs" Link="OptimizationType.cs" />
<Compile Include="..\Enums\OptimizeInstructionType.cs" Link="OptimizeInstructionType.cs" />
<Compile Include="..\Enums\TimeZoneStandardType.cs" Link="Enums\TimeZoneStandardType.cs" />
<Compile Include="..\Enums\RouteAttributeType.cs" Link="Enums\RouteAttributeType.cs" />
@ -61,7 +64,9 @@
<Compile Include="..\Internal\ServiceHelper.cs" Link="Internal\ServiceHelper.cs" />
<Compile Include="..\Internal\SpatialTools.cs" Link="Internal\SpatialTools.cs" />
<Compile Include="..\Internal\TruckDistanceMatrixGenerator.cs" Link="Internal\TruckDistanceMatrixGenerator.cs" />
<Compile Include="..\Models\Agent.cs" Link="Agent.cs" />
<Compile Include="..\Models\BoundingBox.cs" Link="Models\BoundingBox.cs" />
<Compile Include="..\Models\Break.cs" Link="Break.cs" />
<Compile Include="..\Models\Coordinate.cs" Link="Models\Coordinate.cs" />
<Compile Include="..\Models\CustomMapStyles\BorderedMapElementStyle.cs" Link="Models\CustomMapStyles\BorderedMapElementStyle.cs" />
<Compile Include="..\Models\CustomMapStyles\CustomMapStyle.cs" Link="Models\CustomMapStyles\CustomMapStyle.cs" />
@ -70,10 +75,15 @@
<Compile Include="..\Models\CustomMapStyles\SettingsStyle.cs" Link="Models\CustomMapStyles\SettingsStyle.cs" />
<Compile Include="..\Models\CircularView.cs" Link="Models\CircularView.cs" />
<Compile Include="..\Models\ImageryPushpin.cs" Link="Models\ImageryPushpin.cs" />
<Compile Include="..\Models\OptimizeItineraryItem.cs" Link="OptimizeItineraryItem.cs" />
<Compile Include="..\Models\PointCompression.cs" Link="Models\PointCompression.cs" />
<Compile Include="..\Models\Price.cs" Link="Price.cs" />
<Compile Include="..\Models\ResponseModels\Address.cs" Link="Models\ResponseModels\Address.cs" />
<Compile Include="..\Models\ResponseModels\AgentItinerary.cs" Link="AgentItinerary.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\BusinessAtLocation.cs" Link="BusinessAtLocation.cs" />
<Compile Include="..\Models\ResponseModels\CategoryTypeResult.cs" Link="CategoryTypeResult.cs" />
<Compile Include="..\Models\ResponseModels\CompressedPointList.cs" Link="Models\ResponseModels\CompressedPointList.cs" />
<Compile Include="..\Models\ResponseModels\CoverageArea.cs" Link="Models\ResponseModels\CoverageArea.cs" />
<Compile Include="..\Models\ResponseModels\Detail.cs" Link="Models\ResponseModels\Detail.cs" />
@ -81,6 +91,7 @@
<Compile Include="..\Models\ResponseModels\DistanceMatrixAsyncStatus.cs" Link="Models\ResponseModels\DistanceMatrixAsyncStatus.cs" />
<Compile Include="..\Models\ResponseModels\DistanceMatrixCell.cs" Link="Models\ResponseModels\DistanceMatrixCell.cs" />
<Compile Include="..\Models\ResponseModels\ElevationData.cs" Link="Models\ResponseModels\ElevationData.cs" />
<Compile Include="..\Models\ResponseModels\Entity.cs" Link="Entity.cs" />
<Compile Include="..\Models\ResponseModels\Generalization.cs" Link="Models\ResponseModels\Generalization.cs" />
<Compile Include="..\Models\ResponseModels\GeospatialEndpointResponse.cs" Link="Models\ResponseModels\GeospatialEndpointResponse.cs" />
<Compile Include="..\Models\ResponseModels\GeospatialService.cs" Link="Models\ResponseModels\GeospatialService.cs" />
@ -91,12 +102,17 @@
<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\LocalInsightsResponse.cs" Link="LocalInsightsResponse.cs" />
<Compile Include="..\Models\ResponseModels\Location.cs" Link="Models\ResponseModels\Location.cs" />
<Compile Include="..\Models\ResponseModels\OptimizeInstruction.cs" Link="OptimizeInstruction.cs" />
<Compile Include="..\Models\ResponseModels\OptimizeItinerary.cs" Link="OptimizeItinerary.cs" />
<Compile Include="..\Models\ResponseModels\OptimizeRoute.cs" Link="OptimizeRoute.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\RegionTravelSummary.cs" Link="RegionTravelSummary.cs" />
<Compile Include="..\Models\ResponseModels\Resource.cs" Link="Models\ResponseModels\Resource.cs" />
<Compile Include="..\Models\ResponseModels\ResourceSet.cs" Link="Models\ResponseModels\ResourceSet.cs" />
<Compile Include="..\Models\ResponseModels\Response.cs" Link="Models\ResponseModels\Response.cs" />
@ -107,6 +123,7 @@
<Compile Include="..\Models\ResponseModels\RouteProxyAsyncResult.cs" Link="Models\ResponseModels\RouteProxyAsyncResult.cs" />
<Compile Include="..\Models\ResponseModels\RouteSubLeg.cs" Link="Models\ResponseModels\RouteSubLeg.cs" />
<Compile Include="..\Models\ResponseModels\SeaLevelData.cs" Link="Models\ResponseModels\SeaLevelData.cs" />
<Compile Include="..\Models\ResponseModels\SearchResult.cs" Link="SearchResult.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" />
@ -120,18 +137,21 @@
<Compile Include="..\Models\ResponseModels\NaturalPOIAtLocationEntity.cs" Link="Models\ResponseModels\NaturalPOIAtLocationEntity.cs" />
<Compile Include="..\Models\ResponseModels\LocationRecog.cs" Link="Models\ResponseModels\LocationRecog.cs" />
<Compile Include="..\Models\ResponseModels\LocalBusiness.cs" Link="Models\ResponseModels\LocalBusiness.cs" />
<Compile Include="..\Models\ResponseModels\BusinessInfoEntity.cs" Link="Models\ResponseModels\BusinessInfoEntity.cs" />
<Compile Include="..\Models\ResponseModels\DstRuleResource.cs" Link="Models\ResponseModels\DstRuleResource.cs" />
<Compile Include="..\Models\ResponseModels\ConvertedTimeResource.cs" Link="Models\ResponseModels\ConvertedTimeResource.cs" />
<Compile Include="..\Models\ResponseModels\TimeZoneResponse.cs" Link="Models\ResponseModels\TimeZoneResponse.cs" />
<Compile Include="..\Models\ResponseModels\RESTTimeZone.cs" Link="Models\ResponseModels\RESTTimeZone.cs" />
<Compile Include="..\Models\ResponseModels\AutosuggestResource.cs" Link="Models\ResponseModels\AutosuggestResource.cs" />
<Compile Include="..\Models\ResponseModels\AutosuggestResource.cs" Link="AutosuggestResource.cs" />
<Compile Include="..\Models\RouteOptions.cs" Link="Models\RouteOptions.cs" />
<Compile Include="..\Models\Shift.cs" Link="Shift.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" />
@ -145,6 +165,9 @@
<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\LocalInsightsRequest.cs" Link="LocalInsightsRequest.cs" />
<Compile Include="..\Requests\LocalSearchRequest.cs" Link="LocalSearchRequest.cs" />
<Compile Include="..\Requests\OptimizeItineraryRequest.cs" Link="OptimizeItineraryRequest.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" />

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

@ -43,6 +43,7 @@
<Compile Include="Enums\AutosuggestLocationType.cs" />
<Compile Include="Enums\AvoidType.cs" />
<Compile Include="Enums\ConfidenceLevelType.cs" />
<Compile Include="Enums\CostValueType.cs" />
<Compile Include="Enums\DimensionUnitType.cs" />
<Compile Include="Enums\HazardousMaterialPermitType.cs" />
<Compile Include="Enums\HazardousMaterialType.cs" />
@ -51,6 +52,8 @@
<Compile Include="Enums\ImageryType.cs" />
<Compile Include="Enums\LocationRecogEntityTypes.cs" />
<Compile Include="Enums\ManeuverType.cs" />
<Compile Include="Enums\OptimizationType.cs" />
<Compile Include="Enums\OptimizeInstructionType.cs" />
<Compile Include="Enums\RouteAttributeType.cs" />
<Compile Include="Enums\RouteOptimizationType.cs" />
<Compile Include="Enums\RouteTimeType.cs" />
@ -72,6 +75,14 @@
<Compile Include="Internal\DateTimeHelper.cs" />
<Compile Include="Internal\EnumHelper.cs" />
<Compile Include="Internal\InternalSettings.cs" />
<Compile Include="Models\Agent.cs" />
<Compile Include="Models\Break.cs" />
<Compile Include="Models\OptimizeItineraryItem.cs" />
<Compile Include="Models\Price.cs" />
<Compile Include="Models\ResponseModels\RegionTravelSummary.cs" />
<Compile Include="Models\Shift.cs" />
<Compile Include="Models\ResponseModels\AgentItinerary.cs" />
<Compile Include="Models\ResponseModels\Entity.cs" />
<Compile Include="Models\ResponseModels\AsyncStatus.cs" />
<Compile Include="Models\BoundingBox.cs" />
<Compile Include="CustomMapStyleManager.cs" />
@ -101,9 +112,13 @@
<Compile Include="Models\ResponseModels\ImageryMetadata.cs" />
<Compile Include="Models\ResponseModels\ImageryProvider.cs" />
<Compile Include="Models\ResponseModels\Instruction.cs" />
<Compile Include="Models\ResponseModels\LocalBusiness.cs" />
<Compile Include="Models\ResponseModels\BusinessAtLocation.cs" />
<Compile Include="Models\ResponseModels\LocalInsightsResponse.cs" />
<Compile Include="Models\ResponseModels\LocationRecog.cs" />
<Compile Include="Models\ResponseModels\NaturalPOIAtLocationEntity.cs" />
<Compile Include="Models\ResponseModels\OptimizeInstruction.cs" />
<Compile Include="Models\ResponseModels\OptimizeRoute.cs" />
<Compile Include="Models\ResponseModels\OptimizeItinerary.cs" />
<Compile Include="Models\ResponseModels\RouteProxyAsyncResult.cs" />
<Compile Include="Models\ResponseModels\IsochroneResponse.cs" />
<Compile Include="Models\ResponseModels\ItineraryItem.cs" />
@ -138,6 +153,7 @@
<Compile Include="Models\ResponseModels\Warning.cs" />
<Compile Include="Models\ResponseModels\Waypoint.cs" />
<Compile Include="Models\RouteOptions.cs" />
<Compile Include="Models\ResponseModels\CategoryTypeResult.cs" />
<Compile Include="Models\VehicleSpec.cs" />
<Compile Include="Requests\AutosuggestRequest.cs" />
<Compile Include="Requests\ConvertTimeZoneRequest.cs" />
@ -156,7 +172,10 @@
<Compile Include="Internal\ServiceHelper.cs" />
<Compile Include="Requests\IsochroneRequest.cs" />
<Compile Include="Requests\ListTimeZonesRequest.cs" />
<Compile Include="Requests\LocalInsightsRequest.cs" />
<Compile Include="Requests\LocalSearchRequest.cs" />
<Compile Include="Requests\LocationRecogRequest.cs" />
<Compile Include="Requests\OptimizeItineraryRequest.cs" />
<Compile Include="Requests\SnapToRoadRequest.cs" />
<Compile Include="Internal\SpatialTools.cs" />
<Compile Include="Models\SimpleAddress.cs" />

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

@ -22,12 +22,6 @@
* THE SOFTWARE.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace BingMapsRESTToolkit
{
/// <summary>
@ -46,6 +40,6 @@ namespace BingMapsRESTToolkit
/// <summary>
/// Location Business Resource
/// </summary>
LocalBusiness
Business
}
}

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

@ -0,0 +1,47 @@
/*
* Copyright(c) 2018 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>
/// A parameter used to optimize itineraries in addition to maximizing the sum of item priorities.
/// </summary>
public enum CostValueType
{
/// <summary>
/// Optimize according to travel time.
/// </summary>
TravelTime,
/// <summary>
/// Optimize according to distance traveled.
/// </summary>
Distance,
/// <summary>
/// Optimize according to the agents price definition used to build the service response, the secondary objective, along side maximizing the sum of priorities will be to minimize the overall solution price.
/// </summary>
Price
}
}

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

@ -21,11 +21,6 @@
* 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.Text;
using System.Threading.Tasks;
namespace BingMapsRESTToolkit
{

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

@ -0,0 +1,42 @@
/*
* Copyright(c) 2018 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>
/// Specifies whether traffic data should used to optimize the order of waypoint items.
/// </summary>
public enum OptimizationType
{
/// <summary>
/// No traffic data is used.
/// </summary>
SimpleRequest,
/// <summary>
/// Traffic data is used.
/// </summary>
TrafficRequest
}
}

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

@ -0,0 +1,39 @@
/*
* 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>
/// Instruction type from optimized route.
/// </summary>
public enum OptimizeInstructionType
{
LeaveFromStartPoint
,TravelBetweenLocations
,VisitLocation
,TakeABreak
,ArriveToEndPoint
}
}

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

@ -52,6 +52,11 @@ namespace BingMapsRESTToolkit
/// <summary>
/// Include information about transit stops for transit routes.
/// </summary>
TransitStops
TransitStops,
/// <summary>
/// Include travel summary of distance, time, and toll road distance by two entity types: country (e.g. US, Canada) and administrative division or subregion (e.g. “state” in US and “province” in Canada).
/// </summary>
RegionTravelSummary
}
}

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

@ -68,11 +68,13 @@ namespace BingMapsRESTToolkit.Extensions
/// <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)
if(waypoints == null || waypoints.Count == 0)
{
throw new Exception("No waypoints specified.");
}
//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)
{
@ -84,7 +86,6 @@ namespace BingMapsRESTToolkit.Extensions
if (tspOptimization.Value == TspOptimizationType.StraightLineDistance)
{
//Calculate a distance matrix based on straight line distances (haversine).
dm = await DistanceMatrix.CreateStraightLineNxNMatrix(waypoints, DistanceUnitType.Kilometers, bingMapsKey).ConfigureAwait(false);
}
else
@ -119,11 +120,13 @@ namespace BingMapsRESTToolkit.Extensions
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)
if (Response.HasResource(r))
{
dm = r.ResourceSets[0].Resources[0] as DistanceMatrix;
var res = Response.GetFirstResource(r);
if (res is DistanceMatrix)
{
dm = res as DistanceMatrix;
}
}
}
}

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

@ -77,7 +77,7 @@ namespace BingMapsRESTToolkit
// /Date(1235764800000)/
// /Date(1467298867000-0700)/
jsonDate = jsonDate.Replace("/Date(", "").Replace(")/", "");
jsonDate = jsonDate.Replace("\\/Date(", "").Replace("/Date(", "").Replace(")/", "").Replace(")\\/", "");
long ms = 0; // number of milliseconds since midnight Jan 1, 1970
long hours = 0;

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

@ -24,11 +24,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Threading.Tasks;
namespace BingMapsRESTToolkit
@ -417,11 +417,12 @@ namespace BingMapsRESTToolkit
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.HasResource(response))
{
if (response.ResourceSets[0].Resources[0] is AsyncStatus && !string.IsNullOrEmpty((response.ResourceSets[0].Resources[0] as AsyncStatus).RequestId))
var res = Response.GetFirstResource(response);
if (res is AsyncStatus && !string.IsNullOrEmpty((res as AsyncStatus).RequestId))
{
var status = response.ResourceSets[0].Resources[0] as AsyncStatus;
var status = res as AsyncStatus;
status = await ServiceHelper.ProcessAsyncStatus(status, remainingTimeCallback).ConfigureAwait(false);
@ -442,11 +443,11 @@ namespace BingMapsRESTToolkit
return response;
}
else if (response.ResourceSets[0].Resources[0] is AsyncStatus && !string.IsNullOrEmpty((response.ResourceSets[0].Resources[0] as AsyncStatus).ErrorMessage))
else if (res is AsyncStatus && !string.IsNullOrEmpty((res as AsyncStatus).ErrorMessage))
{
throw new Exception((response.ResourceSets[0].Resources[0] as AsyncStatus).ErrorMessage);
throw new Exception((res as AsyncStatus).ErrorMessage);
}
else if (response.ResourceSets[0].Resources[0] is Resource && !(response.ResourceSets[0].Resources[0] is AsyncStatus))
else if (res is Resource && !(res is AsyncStatus))
{
return response;
}
@ -466,11 +467,12 @@ namespace BingMapsRESTToolkit
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.HasResource(response))
{
if (response.ResourceSets[0].Resources[0] is AsyncStatus && !string.IsNullOrEmpty((response.ResourceSets[0].Resources[0] as AsyncStatus).RequestId))
var res = Response.GetFirstResource(response);
if (res is AsyncStatus && !string.IsNullOrEmpty((res as AsyncStatus).RequestId))
{
var status = response.ResourceSets[0].Resources[0] as AsyncStatus;
var status = res as AsyncStatus;
status = await ServiceHelper.ProcessAsyncStatus(status, remainingTimeCallback).ConfigureAwait(false);
@ -479,11 +481,40 @@ namespace BingMapsRESTToolkit
try
{
using (var resultStream = await ServiceHelper.GetStreamAsync(new Uri(status.ResultUrl)).ConfigureAwait(false))
{
if (typeof(T) == typeof(DistanceMatrix))
{
//There is a bug in the distance matrix service that when some options are set, the response isn't wrapped with a resourceSet->resources like all other services.
using (var sr = new StreamReader(resultStream))
{
var r = sr.ReadToEnd();
//Remove first character from string.
r = r.Remove(0, 1);
//Add namespace type to JSON object.
r = "{\"__type\":\"DistanceMatrix:http://schemas.microsoft.com/search/local/ws/rest/v1\"," + r;
var bytes = Encoding.UTF8.GetBytes(r);
using (var stream = new MemoryStream(bytes))
{
var resource = ServiceHelper.DeserializeStream<T>(stream);
response.ResourceSets[0].Resources[0] = resource;
}
}
}
else if (typeof(T) == typeof(SnapToRoadResponse))
{
//Snap to road for some reason includes a full resource set response while other async services don't.
response = ServiceHelper.DeserializeStream<Response>(resultStream);
}
else
{
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);
@ -492,11 +523,11 @@ namespace BingMapsRESTToolkit
return response;
}
else if (response.ResourceSets[0].Resources[0] is AsyncStatus && !string.IsNullOrEmpty((response.ResourceSets[0].Resources[0] as AsyncStatus).ErrorMessage))
else if (res is AsyncStatus && !string.IsNullOrEmpty((res as AsyncStatus).ErrorMessage))
{
throw new Exception((response.ResourceSets[0].Resources[0] as AsyncStatus).ErrorMessage);
throw new Exception((res as AsyncStatus).ErrorMessage);
}
else if (response.ResourceSets[0].Resources[0] is Resource && !(response.ResourceSets[0].Resources[0] is AsyncStatus))
else if (res is Resource && !(res is AsyncStatus))
{
return response;
}
@ -525,10 +556,6 @@ namespace BingMapsRESTToolkit
status = await ServiceHelper.MonitorAsyncStatus(statusUrl, 0, remainingTimeCallback).ConfigureAwait(false);
}
else
{
return status;
}
if (status != null)
{
@ -538,7 +565,7 @@ namespace BingMapsRESTToolkit
}
else if (!status.IsAccepted)
{
throw new Exception("The request was not accepted.");
throw new Exception("The request was not accepted. " + (!string.IsNullOrEmpty(status.ErrorMessage) ? status.ErrorMessage : ""));
}
else if (!string.IsNullOrEmpty(status.ErrorMessage))
{
@ -546,7 +573,7 @@ namespace BingMapsRESTToolkit
}
}
return null;
return status;
}
/// <summary>
@ -572,9 +599,12 @@ namespace BingMapsRESTToolkit
{
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 AsyncStatus)
else if (Response.HasResource(r))
{
status = r.ResourceSets[0].Resources[0] as AsyncStatus;
var res = Response.GetFirstResource(r);
if (res is AsyncStatus)
{
status = res as AsyncStatus;
if (!status.IsCompleted && status.CallbackInSeconds > 0)
{
@ -585,6 +615,23 @@ namespace BingMapsRESTToolkit
return await MonitorAsyncStatus(statusUrl, 0, remainingTimeCallback).ConfigureAwait(false);
}
}
else if (res is OptimizeItinerary)
{
var oi = res as OptimizeItinerary;
status = new AsyncStatus()
{
CallbackInSeconds = -1,
IsCompleted = oi.IsCompleted,
IsAccepted = oi.IsAccepted,
CallbackUrl = statusUrl.OriginalString,
ResultUrl = oi.IsCompleted ? statusUrl.OriginalString: null,
};
} else
{
var t = "";
}
}
}
}
}

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

@ -92,18 +92,17 @@ namespace BingMapsRESTToolkit.Extensions
if(firstResponse != null && firstResponse.ErrorDetails != null && firstResponse.ErrorDetails.Length > 0){
return firstResponse;
}
else if (firstResponse == null || firstResponse.ResourceSets == null || firstResponse.ResourceSets.Length == 0 ||
firstResponse.ResourceSets[0].Resources == null || firstResponse.ResourceSets[0].Resources.Length == 0)
else if (!Response.HasResource(firstResponse))
{
return new Response()
{
ErrorDetails = new string[] { "Unabble to calculate distance matrix." },
ErrorDetails = new string[] { "Unable to calculate distance matrix." },
StatusCode = 400,
StatusDescription = "Bad request"
};
}
var truckRoute = firstResponse.ResourceSets[0].Resources[0] as Route;
var truckRoute = Response.GetFirstResource(firstResponse) as Route;
MatrixCells.Add(new DistanceMatrixCell()
{
@ -204,10 +203,9 @@ namespace BingMapsRESTToolkit.Extensions
{
var response = await CalculateTruckRoute(dmRequest.Origins[originIdx], dmRequest.Destinations[destIdx], timeIdx, dmRequest).ConfigureAwait(false);
if (response != null && response.ResourceSets != null && response.ResourceSets.Length > 0 &&
response.ResourceSets[0].Resources != null && response.ResourceSets[0].Resources.Length > 0)
if (Response.HasResource(response))
{
var truckRoute = response.ResourceSets[0].Resources[0] as Route;
var truckRoute = Response.GetFirstResource(response) as Route;
MatrixCells.Add(new DistanceMatrixCell()
{

124
Source/Models/Agent.cs Normal file
Просмотреть файл

@ -0,0 +1,124 @@
/*
* 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.Runtime.Serialization;
using System.Text;
namespace BingMapsRESTToolkit
{
/// <summary>
/// An agent (delivery person/vehicle).
/// </summary>
[DataContract]
public class Agent
{
/// <summary>
/// Maximum number of shifts a single agent can have (when using an enterprise account).
/// </summary>
internal static int maxShifts = 14;
/// <summary>
/// An agent (delivery person/vehicle).
/// </summary>
public Agent()
{
//Default the name as a Guid so that we start off with a unique name, even if not specified by the user.
Name = Guid.NewGuid().ToString();
}
/// <summary>
/// A unique identifier for the agent. Default is a Guid.
/// </summary>
[DataMember(Name = "name")]
public string Name { get; set; }
/// <summary>
/// Optional. Shift parameter allows you to defined a break window during the shift without specifying a location for it, the break
/// will be inserted in the agents itinerary alongside scheduled items. For example a lunch break of 30 min at noon between 12:00 and 14:00.
/// </summary>
[DataMember(Name = "shifts")]
public List<Shift> Shifts { get; set; }
/// <summary>
/// Optional. Price parameter allows you to define a combination of fixed and variable prices for each agent to be used as
/// the optimization objective when the costvalue parameter is set to price. For example the fixedPrice can be used to denote the
/// one time cost of using a vehicle and pricePerKm or pricePerHour can be used to model the cost of how expensive that vehicle is to use.
/// </summary>
[DataMember(Name = "price")]
public Price Price { get; set; }
/// <summary>
/// Optional. Capacity parameter is defined by numeric values that represent the vehicle capacity in terms of volume, weight,
/// pallet or case count, or passenger count.
/// </summary>
[DataMember(Name = "capacity")]
public int[] Capacity { get; set; }
public override string ToString()
{
var sb = new StringBuilder("{");
sb.AppendFormat("\"name\":\"{0}\",", Name);
if (Shifts != null && Shifts.Count > 0)
{
if(Shifts.Count > Agent.maxShifts)
{
throw new Exception(string.Format("Agent has more than the max of {0} shifts specified.", Agent.maxShifts));
}
sb.AppendFormat("\"shifts\":[{0}],", string.Join(",", Shifts));
}
if (Price != null)
{
sb.AppendFormat("\"price\":{0},", Price.ToString());
}
if (Capacity != null && Capacity.Length > 0)
{
sb.Append("\"capacity\":[");
//Loop through an append Capacity values with invariant culture.
foreach (var item in Capacity)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}", item);
sb.Append(',');
}
sb.Length -= 1;
sb.Append("],");
}
//Remove trailing comma.
sb.Length--;
sb.Append("}");
return sb.ToString();
}
}
}

164
Source/Models/Break.cs Normal file
Просмотреть файл

@ -0,0 +1,164 @@
using System;
using System.Runtime.Serialization;
using System.Text;
namespace BingMapsRESTToolkit
{
/// <summary>
/// A break period
/// </summary>
[DataContract]
public class Break
{
/// <summary>
/// The start of the time window for a break.
/// </summary>
[DataMember(Name = "startTime")]
internal string StartTime { get; set; }
/// <summary>
/// The start of the time window for a break.
/// </summary>
public DateTime StartTimeUtc
{
get
{
if (string.IsNullOrEmpty(StartTime))
{
return DateTime.Now;
}
else
{
return DateTimeHelper.GetDateTimeFromUTCString(StartTime);
}
}
set
{
if (value == null)
{
StartTime = string.Empty;
}
else
{
var v = DateTimeHelper.GetUTCString(value);
if (v != null)
{
StartTime = v;
}
else
{
StartTime = string.Empty;
}
}
}
}
/// <summary>
/// The end of the time window for a break.
/// </summary>
[DataMember(Name = "endTime")]
internal string EndTime { get; set; }
/// <summary>
/// The end of the time window for a break.
/// </summary>
public DateTime EndTimeUtc
{
get
{
if (string.IsNullOrEmpty(EndTime))
{
return DateTime.Now;
}
else
{
return DateTimeHelper.GetDateTimeFromUTCString(EndTime);
}
}
set
{
if (value == null)
{
EndTime = string.Empty;
}
else
{
var v = DateTimeHelper.GetUTCString(value);
if (v != null)
{
EndTime = v;
}
else
{
EndTime = string.Empty;
}
}
}
}
/// <summary>
/// The duration of the break period within the time window. If not specified, all time between start and end time will be used as the duration.
/// </summary>
[DataMember(Name = "duration")]
public string Duration { get; set; }
/// <summary>
/// The duration of the break period within the time window. If not specified, all time between start and end time will be used as the duration.
/// </summary>
public TimeSpan? DurationTimeSpan
{
get
{
if (TimeSpan.TryParse(Duration, out TimeSpan ts))
{
return ts;
}
return null;
}
set
{
if (value == null)
{
Duration = string.Empty;
}
else
{
Duration = string.Format("{0:g}",value);
}
}
}
public override string ToString()
{
if(StartTimeUtc == null)
{
throw new Exception("Start time must be specified for break.");
}
if (EndTimeUtc == null)
{
throw new Exception("End time must be specified for break.");
}
var sb = new StringBuilder("{");
sb.AppendFormat("\"startTime\":\"{0}\",", StartTime);
sb.AppendFormat("\"endTime\":\"{0}\",", EndTime);
if (DurationTimeSpan == null || !DurationTimeSpan.HasValue)
{
DurationTimeSpan = EndTimeUtc - StartTimeUtc;
}
//https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-timespan-format-strings
sb.AppendFormat("\"duration\":\"{0}\"", Duration);
sb.Append("}");
return sb.ToString();
}
}
}

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

@ -29,10 +29,12 @@ using System.Runtime.Serialization;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Used by AutoSuggest API, for a Circular Screen Search Area
/// A Circular Screen Search Area.
/// NOTE: someone created this without looking around for similar classes (CoordwithRadius) does the same thing.
/// This class has been modified to wrap CoordwithRadius, to be backwards compatible.
/// </summary>
[DataContract]
public class CircularView
public class CircularView : Coordinate
{
/// <summary>
/// Default Constructor
@ -40,35 +42,32 @@ namespace BingMapsRESTToolkit
/// <param name="latitude">Latitude of point</param>
/// <param name="longitude">Longitude of point</param>
/// <param name="radius">Radius, in meters</param>
CircularView(double latitude, double longitude, int radius)
public CircularView(double latitude, double longitude, int radius): base()
{
if (radius >= 0)
this.radius = radius;
this.Radius = radius;
else
throw new System.Exception("Radius in UserCircularMapView Constructor must be greater than 0");
this.coords.Latitude = latitude;
this.coords.Longitude = longitude;
this.Latitude = latitude;
this.Longitude = longitude;
}
/// <summary>
/// To String used for exporting Coords to URL parameter
/// </summary>
/// <returns></returns>
public override string ToString()
{
return string.Format(CultureInfo.InvariantCulture, "{0:0.#####},{1:0.#####},{2}", coords.Latitude, coords.Longitude, radius);
}
/// <summary>
/// The Locaiton of Circular Region
/// </summary>
public Coordinate coords { get; set; }
/// <summary>
/// Radius (Meters) of Circular Region
/// </summary>
public int radius { get; set; }
[DataMember(Name="radius")]
public int? Radius { get; set; }
public override string ToString()
{
if (Radius.HasValue)
{
return string.Format(CultureInfo.InvariantCulture, "{0:0.######},{1:0.######},{2}", Latitude, Longitude, Radius.Value);
} else
{
return string.Format(CultureInfo.InvariantCulture, "{0:0.######},{1:0.######}", Latitude, Longitude);
}
}
}
}

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

@ -25,6 +25,7 @@
using System;
using System.Globalization;
using System.Runtime.Serialization;
using System.Text.RegularExpressions;
namespace BingMapsRESTToolkit
{
@ -38,6 +39,8 @@ namespace BingMapsRESTToolkit
private double _latitude, _longitude;
private static 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
#region Constructor
@ -155,5 +158,29 @@ namespace BingMapsRESTToolkit
}
#endregion
#region Public Static Methods
/// <summary>
/// Parses a coordinate value from a string with the format "latitude,longitude".
/// </summary>
/// <param name="coordinateString">Coordinate string to parse</param>
/// <returns>A coordinate or null.</returns>
public static Coordinate Parse(string coordinateString)
{
var m = CoordinateRx.Match(coordinateString);
if (m.Success)
{
if(double.TryParse(m.Groups[1].Value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out double latitude) &&
double.TryParse(m.Groups[3].Value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out double longitude)) {
return new Coordinate(latitude, longitude);
}
}
return null;
}
#endregion
}
}

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

@ -0,0 +1,343 @@
/*
* 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.Runtime.Serialization;
using System.Text;
namespace BingMapsRESTToolkit
{
/// <summary>
/// A stop or delivery location.
/// </summary>
[DataContract]
public class OptimizeItineraryItem
{
/// <summary>
/// A stop or delivery location.
/// </summary>
public OptimizeItineraryItem()
{
//Default the name as a Guid so that we start off with a unique name, even if not specified by the user.
Name = Guid.NewGuid().ToString();
Priority = 1;
DwellTimeSpan = new TimeSpan(0, 15, 0);
}
/// <summary>
/// A unique identifier for the itinerary item (stop). Default is a Guid.
/// </summary>
[DataMember(Name = "name")]
public string Name { get; set; }
/// <summary>
/// Opening time of location. Must arrive after this time.
/// </summary>
[DataMember(Name = "openingTime")]
internal string OpeningTime { get; set; }
/// <summary>
/// Opening time of location. Must arrive after this time.
/// </summary>
public DateTime? OpeningTimeUtc
{
get
{
if (string.IsNullOrEmpty(OpeningTime))
{
return null;
}
else
{
return DateTimeHelper.GetDateTimeFromUTCString(OpeningTime);
}
}
set
{
if (value == null)
{
OpeningTime = string.Empty;
}
else
{
var v = DateTimeHelper.GetUTCString(value.Value);
if (v != null)
{
OpeningTime = v;
}
else
{
OpeningTime = null;
}
}
}
}
/// <summary>
/// Closing time of location. Must arrive before this time.
/// </summary>
[DataMember(Name = "closingTime")]
internal string ClosingTime { get; set; }
/// <summary>
/// Closing time of location. Must arrive before this time.
/// </summary>
public DateTime? ClosingTimeUtc
{
get
{
if (string.IsNullOrEmpty(ClosingTime))
{
return null;
}
else
{
return DateTimeHelper.GetDateTimeFromUTCString(ClosingTime);
}
}
set
{
if (value == null)
{
ClosingTime = string.Empty;
}
else
{
var v = DateTimeHelper.GetUTCString(value.Value);
if (v != null)
{
ClosingTime = v;
}
else
{
ClosingTime = null;
}
}
}
}
/// <summary>
/// How long the agent is expected to stay at this location. Default is 15 minutes.
/// </summary>
[DataMember(Name = "dwellTime")]
internal string DwellTime { get; set; }
/// <summary>
/// How long the agent is expected to stay at this location. Default is 15 minutes.
/// </summary>
public TimeSpan? DwellTimeSpan
{
get
{
if (TimeSpan.TryParse(DwellTime, out TimeSpan ts))
{
return ts;
}
return null;
}
set
{
if (value == null)
{
DwellTime = string.Empty;
}
else
{
DwellTime = string.Format("{0:g}", value);
}
}
}
/// <summary>
/// The priority takes an integer value from 1 to 100. Use larger values for priority to indicate higher priority itinerary items. Default: 1
/// </summary>
[DataMember(Name = "priority")]
public int Priority { get; set; }
/// <summary>
/// The location of the itinerary item (stop).
/// </summary>
[DataMember(Name = "location")]
internal Coordinate Location
{
get
{
if (Waypoint != null)
{
return Waypoint.Coordinate;
}
return null;
}
set
{
if (Waypoint == null)
{
Waypoint = new SimpleWaypoint();
}
Waypoint.Coordinate = value;
}
}
/// <summary>
/// The location of the itinerary item (stop). Can be used instead of location.
/// </summary>
[DataMember(Name = "address")]
internal string Address
{
get
{
if(Waypoint != null)
{
return Waypoint.Address;
}
return string.Empty;
}
set
{
if(Waypoint == null)
{
Waypoint = new SimpleWaypoint();
}
Waypoint.Address = value;
}
}
/// <summary>
/// The location waypoint.
/// </summary>
public SimpleWaypoint Waypoint { get; set; }
/// <summary>
/// Optional. The quantity parameter defines the numeric values that represent the load quantity in terms of volume, weight,
/// pallets or case count, or passenger count, etc., that the vehicle delivers to or picks up from each location.
/// A positive value denotes pick up, while a negative value denotes drop off.
/// </summary>
[DataMember(Name = "quantity")]
public int[] Quantity { get; set; }
/// <summary>
/// Optional. The depot parameter is either true or false, to signify if a location (e.g., a warehouse) can be visited more than
/// once for picking up loads. Default: false
/// </summary>
[DataMember(Name = "depot")]
public bool Depot { get; set; }
/// <summary>
/// Optional. The dropOffFrom parameter defines the location(s) that the agent needs to visit before visting the current location.
/// This should be a list of itinerary item names.
/// </summary>
[DataMember(Name = "dropOffFrom")]
public string[] DropOffFrom { get; set; }
public override string ToString()
{
var sb = new StringBuilder();
sb.Append("{");
sb.AppendFormat("\"name\":\"{0}\",", Name);
if (OpeningTimeUtc.HasValue)
{
sb.AppendFormat("\"openingTime\":\"{0}\",", DateTimeHelper.GetUTCString(OpeningTimeUtc.Value));
}
else
{
throw new Exception("No opening time specified.");
}
if (ClosingTimeUtc.HasValue)
{
sb.AppendFormat("\"closingTime\":\"{0}\",", DateTimeHelper.GetUTCString(ClosingTimeUtc.Value));
}
else
{
throw new Exception("No closing time specified.");
}
if (DwellTime != null) {
sb.AppendFormat("\"dwellTime\":\"{0:g}\",", DwellTime);
}
if(Priority <= 0 || Priority > 100)
{
throw new Exception("Priority must be between 1 and 100.");
}
sb.AppendFormat("\"priority\":{0},", Priority);
if (Location != null)
{
sb.Append("\"location\":{");
sb.AppendFormat(CultureInfo.InvariantCulture, "\"latitude\":{0:0.#####},\"longitude\":{1:0.#####}", Location.Latitude, Location.Longitude);
sb.Append("},");
}
else if (!string.IsNullOrWhiteSpace(Address))
{
sb.AppendFormat("\"address\":\"{0}\",", Address);
}
else
{
throw new Exception("Itinerary item location must be specified in shift.");
}
if(Quantity != null && Quantity.Length > 0)
{
sb.Append("\"quantity\":[");
//Loop through an append Quantity values with invariant culture.
foreach (var item in Quantity)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "{0}", item);
sb.Append(',');
}
sb.Length -= 1;
sb.Append("],");
}
sb.AppendFormat("\"depot\":{0},", Depot.ToString().ToLowerInvariant());
if (DropOffFrom != null && DropOffFrom.Length > 0)
{
sb.AppendFormat("\"dropOffFrom\":[\"{0}\"],", string.Join("\",\"", DropOffFrom));
}
//Remove trailing comma.
sb.Length--;
sb.Append("}");
return sb.ToString();
}
}
}

88
Source/Models/Price.cs Normal file
Просмотреть файл

@ -0,0 +1,88 @@
/*
* 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.Globalization;
using System.Runtime.Serialization;
using System.Text;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Price of an Agent.
/// </summary>
[DataContract]
public class Price
{
/// <summary>
/// Fixed price cost.
/// </summary>
[DataMember(Name = "fixedPrice")]
public double? FixedPrice { get; set; }
/// <summary>
/// Cost per Kilometer.
/// </summary>
[DataMember(Name = "pricePerKM")]
public double? PricePerKM { get; set; }
/// <summary>
/// Cost per hour.
/// </summary>
[DataMember(Name = "pricePerHour")]
public double? PricePerHour { get; set; }
public override string ToString()
{
if(FixedPrice.HasValue || PricePerKM.HasValue || PricePerHour.HasValue)
{
var sb = new StringBuilder("{");
if (FixedPrice.HasValue)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "\"fixedPrice\":{0},", FixedPrice);
}
if (PricePerKM.HasValue)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "\"pricePerKM\":{0},", PricePerKM);
}
if (PricePerHour.HasValue)
{
sb.AppendFormat(CultureInfo.InvariantCulture, "\"pricePerHour\":{0},", PricePerHour);
}
//Remove trailing comma.
sb.Length--;
sb.Append("}");
return sb.ToString();
}
return null;
}
}
}

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

@ -98,5 +98,17 @@ namespace BingMapsRESTToolkit
/// </summary>
[DataMember(Name = "landmark", EmitDefaultValue = false)]
public string Landmark { get; set; }
/// <summary>
/// Only returned by Autosuggest API.
/// </summary>
[DataMember(Name = "houseNumber", EmitDefaultValue = false)]
public string HouseNumber { get; set; }
/// <summary>
/// Only returned by Autosuggest API.
/// </summary>
[DataMember(Name = "streetName", EmitDefaultValue = false)]
public string StreetName { get; set; }
}
}

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

@ -0,0 +1,50 @@
/*
* 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
{
[DataContract]
public class AgentItinerary
{
/// <summary>
/// Agent resource associated with the this itinerary, as defined in the request.
/// </summary>
[DataMember(Name = "agent")]
public Agent Agent { get; set; }
/// <summary>
/// A sorted array containing the itinerary Instructions.
/// </summary>
[DataMember(Name = "instructions")]
public OptimizeInstruction[] Instructions { get; set; }
/// <summary>
/// The itinerary route summary information.
/// </summary>
[DataMember(Name = "route")]
public OptimizeRoute Route { get; set; }
}
}

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

@ -34,7 +34,6 @@ namespace BingMapsRESTToolkit
[KnownType(typeof(RouteProxyAsyncResult))]
public class AsyncStatus: Resource
{
#region Public Properties
/// <summary>

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

@ -31,46 +31,32 @@ namespace BingMapsRESTToolkit
/// Autosuggest Resource Enity: Used for `Place`, `Address`, and `LocalBusiness`
/// </summary>
[DataContract]
public class AutosuggestEntityResource : Resource
public class AutosuggestEntityResource
{
/// <summary>
/// Address of the Entity
/// </summary>
[DataMember(Name ="address", EmitDefaultValue = false)]
public Address EntityAddress { get; set; }
}
public Address Address { get; set; }
[DataContract(Name= "LocalBusiness")]
public class AutoSuggestLocalBusinessResource : AutosuggestEntityResource
{
/// <summary>
/// Name of Entity
/// </summary>
[DataMember(Name = "name", EmitDefaultValue = false)]
public string Name { get; set; }
}
[DataContract(Name = "Place")]
public class AutoSuggestPlaceResource : AutosuggestEntityResource
{
/// <summary>
/// Name of Entity
/// The type of the entity
/// </summary>
[DataMember(Name = "name", EmitDefaultValue = false)]
public string Name { get; set; }
}
[DataContract(Name = "Address")]
public class AutosuggestAddressResource : AutosuggestEntityResource
{
[DataMember(Name = "type", EmitDefaultValue = false)]
public string Type { get; set; }
}
/// <summary>
/// Resource returned by Autosuggest API
/// </summary>
[DataContract(Name ="Autosuggest", Namespace ="http://schemas.microsoft.com/search/local/ws/rest/v1")]
public class AutosuggestResource : Resource
public class Autosuggest : Resource
{
/// <summary>
/// List if Autosuggest Entities

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

@ -31,7 +31,7 @@ namespace BingMapsRESTToolkit
/// Local Business Resoruce, used by Location Recognition
/// </summary>
[DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
public class LocalBusiness
public class BusinessAtLocation
{
/// <summary>
/// Busisness Address `Address` Resource

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

@ -68,5 +68,11 @@ namespace BingMapsRESTToolkit
/// </summary>
[DataMember(Name = "otherTypeIds", EmitDefaultValue = false)]
public int[] OtherTypeIds { get; set; }
[DataMember(Name = "type", EmitDefaultValue = false)]
public string Type { get; set; }
[DataMember(Name = "otherType", EmitDefaultValue = false)]
public string[] OtherType { get; set; }
}
}

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

@ -0,0 +1,50 @@
/*
* 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
{
[DataContract]
public class CategoryTypeResult
{
/// <summary>
/// String name/ID for the specified category.
/// </summary>
[DataMember(Name = "categoryTypeName", EmitDefaultValue = false)]
public string CategoryTypeName { get; set; }
/// <summary>
/// Summary of how many entities fall under this type, given the specified time or driving limits.
/// </summary>
[DataMember(Name = "categoryTypeSummary", EmitDefaultValue = false)]
public string CategoryTypeSummary { get; set; }
/// <summary>
/// String name/ID for the specified category.
/// </summary>
[DataMember(Name = "entities", EmitDefaultValue = false)]
public Entity[] Entities { get; set; }
}
}

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

@ -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 Business Entity Resource object.
/// </summary>
[DataContract]
public class Entity: Coordinate
{
/// <summary>
/// Name of entity.
/// </summary>
[DataMember(Name = "entityName", EmitDefaultValue = false)]
public string EntityName { get; set; }
}
}

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

@ -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.
*/
using System.Runtime.Serialization;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Represents the response from an LocalInsightsRequest.
/// </summary>
[DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
public class LocalInsightsResponse : Resource
{
/// <summary>
/// Latitude and longitude of the center of the isochrone.
/// </summary>
[DataMember(Name = "origin", EmitDefaultValue = false)]
public Coordinate Origin { get; set; }
/// <summary>
/// List of business type resources.
/// </summary>
[DataMember(Name = "categoryTypeResults", EmitDefaultValue = false)]
public CategoryTypeResult[] CategoryTypeResults { get; set; }
}
}

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

@ -59,7 +59,7 @@ namespace BingMapsRESTToolkit
/// Array of LocalBusiness Resources
/// </summary>
[DataMember(Name = "businessesAtLocation", EmitDefaultValue = false)]
public LocalBusiness[] BusinessAtLocation { get; set; }
public BusinessAtLocation[] BusinessAtLocation { get; set; }
/// <summary>
/// Array of Business Addressess

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

@ -0,0 +1,198 @@
/*
* 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
{
[DataContract]
public class OptimizeInstruction
{
/// <summary>
/// Type of instruction, any of the following:
///- LeaveFromStartPoint
///- TravelBetweenLocations
///- VisitLocation
///- TakeABreak
///- ArriveToEndPoint
/// </summary>
public OptimizeInstructionType InstructionType { get; set; }
/// <summary>
/// The unit used for distance.
/// </summary>
[DataMember(Name = "instructionType", EmitDefaultValue = false)]
internal string instructionType
{
get
{
return System.Enum.GetName(typeof(OptimizeInstructionType), InstructionType);
}
set
{
if (!string.IsNullOrWhiteSpace(value) && System.Enum.TryParse<OptimizeInstructionType>(value, out OptimizeInstructionType x))
{
InstructionType = x;
return;
}
InstructionType = OptimizeInstructionType.TravelBetweenLocations;
}
}
/// <summary>
/// Estimated travel time. Applies only for TravelBetweenLocations instructions.
/// </summary>
[DataMember(Name = "duration")]
internal string Duration { get; set; }
/// <summary>
/// Estimated travel time. Applies only for TravelBetweenLocations instructions.
/// </summary>
public TimeSpan? DurationTimeSpan
{
get
{
if (TimeSpan.TryParse(Duration, out TimeSpan ts))
{
return ts;
}
return null;
}
set
{
if (value == null)
{
Duration = string.Empty;
}
else
{
Duration = string.Format("{0:g}", value);
}
}
}
/// <summary>
/// Estimate travel distance, in meters.
/// </summary>
[DataMember(Name = "distance")]
public double Distance { get; set; }
/// <summary>
/// The estimated start time of the instruction.
/// </summary>
[DataMember(Name = "startTime")]
internal string StartTime { get; set; }
/// <summary>
/// The estimated start time of the instruction.
/// </summary>
public DateTime StartTimeUtc
{
get
{
if (string.IsNullOrEmpty(StartTime))
{
return DateTime.Now;
}
else
{
return DateTimeHelper.GetDateTimeFromUTCString(StartTime);
}
}
set
{
if (value == null)
{
StartTime = string.Empty;
}
else
{
var v = DateTimeHelper.GetUTCString(value);
if (v != null)
{
StartTime = v;
}
else
{
StartTime = string.Empty;
}
}
}
}
/// <summary>
/// The estimated end time of the instruction.
/// </summary>
[DataMember(Name = "endTime")]
internal string EndTime { get; set; }
/// <summary>
/// The end of the time window for a break.
/// </summary>
public DateTime EndTimeUtc
{
get
{
if (string.IsNullOrEmpty(EndTime))
{
return DateTime.Now;
}
else
{
return DateTimeHelper.GetDateTimeFromUTCString(EndTime);
}
}
set
{
if (value == null)
{
EndTime = string.Empty;
}
else
{
var v = DateTimeHelper.GetUTCString(value);
if (v != null)
{
EndTime = v;
}
else
{
EndTime = string.Empty;
}
}
}
}
/// <summary>
/// Optional value present when the instruction type references a location, agent shift start/end point, or a defined itinerary item as defined in the request.
/// </summary>
[DataMember(Name = "itineraryItem")]
public OptimizeItineraryItem ItineraryItem { get; set; }
}
}

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

@ -0,0 +1,65 @@
/*
* 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 OptimizeItineraryRequest.
/// </summary>
[DataContract(Namespace = "http://schemas.microsoft.com/search/local/ws/rest/v1")]
public class OptimizeItinerary : Resource
{
/// <summary>
/// Name of entity.
/// </summary>
[DataMember(Name = "agentItineraries", EmitDefaultValue = false)]
public AgentItinerary[] AgentItineraries { get; set; }
/// <summary>
/// Name of entity.
/// </summary>
[DataMember(Name = "isAccepted", EmitDefaultValue = false)]
public bool IsAccepted { get; set; }
/// <summary>
/// Name of entity.
/// </summary>
[DataMember(Name = "isCompleted", EmitDefaultValue = false)]
public bool IsCompleted { get; set; }
/// <summary>
/// Name of entity.
/// </summary>
[DataMember(Name = "unscheduledItems", EmitDefaultValue = false)]
public OptimizeItineraryItem[] UnscheduledItems { get; set; }
/// <summary>
/// List of Agent items that were not used to construct the current solution.
/// </summary>
[DataMember(Name = "unusedAgents", EmitDefaultValue = false)]
public Agent[] UnusedAgents { get; set; }
}
}

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

@ -0,0 +1,199 @@
/*
* 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.Runtime.Serialization;
namespace BingMapsRESTToolkit
{
[DataContract]
public class OptimizeRoute
{
/// <summary>
/// The estimated start time of the route.
/// </summary>
[DataMember(Name = "startTime")]
internal string StartTime { get; set; }
/// <summary>
/// The estimated start time of the route.
/// </summary>
public DateTime StartTimeUtc
{
get
{
if (string.IsNullOrEmpty(StartTime))
{
return DateTime.Now;
}
else
{
return DateTimeHelper.GetDateTimeFromUTCString(StartTime);
}
}
set
{
if (value == null)
{
StartTime = string.Empty;
}
else
{
var v = DateTimeHelper.GetUTCString(value);
if (v != null)
{
StartTime = v;
}
else
{
StartTime = string.Empty;
}
}
}
}
/// <summary>
/// The coordinates for the start location of the agent's first shift.
/// </summary>
[DataMember(Name = "startLocation")]
public Coordinate StartLocation { get; set; }
/// <summary>
/// The estimated end time of the route.
/// </summary>
[DataMember(Name = "endTime")]
internal string EndTime { get; set; }
/// <summary>
/// The estimated start time of the instruction.
/// </summary>
public DateTime EndTimeUtc
{
get
{
if (string.IsNullOrEmpty(EndTime))
{
return DateTime.Now;
}
else
{
return DateTimeHelper.GetDateTimeFromUTCString(EndTime);
}
}
set
{
if (value == null)
{
EndTime = string.Empty;
}
else
{
var v = DateTimeHelper.GetUTCString(value);
if (v != null)
{
EndTime = v;
}
else
{
EndTime = string.Empty;
}
}
}
}
/// <summary>
/// The coordinates for the ending location of the agent's last shift.
/// </summary>
[DataMember(Name = "endLocation")]
public Coordinate EndLocation { get; set; }
/// <summary>
/// Sorted list of coordinate resources representing the waypoints of the constructed route between the agent's starting and ending locations.
/// </summary>
[DataMember(Name = "wayPoints")]
public Coordinate[] Waypoints { get; set; }
/// <summary>
/// The estimated total travel distance for the agent itinerary in meters.
/// </summary>
[DataMember(Name = "totalTravelDistance")]
public double TotalTravelDistance { get; set; }
/// <summary>
/// The estimated total travel time for the agent itinerary.
/// </summary>
[DataMember(Name = "totalTravelTime")]
internal string TotalTravelTime { get; set; }
/// <summary>
/// The estimated total travel time for the agent itinerary.
/// </summary>
public TimeSpan? TotalTravelTimeSpan
{
get
{
if (TimeSpan.TryParse(TotalTravelTime, out TimeSpan ts))
{
return ts;
}
return null;
}
set
{
if (value == null)
{
TotalTravelTime = string.Empty;
}
else
{
TotalTravelTime = string.Format("{0:g}", value);
}
}
}
/// <summary>
/// Gets the waypoints from start, stops, to end. This can easily be passed into a route request.
/// </summary>
/// <returns>The waypoints from start, stops, to end.</returns>
public List<SimpleWaypoint> GetAllWaypoints()
{
var points = new List<SimpleWaypoint>();
points.Add(new SimpleWaypoint(StartLocation));
foreach(var wp in Waypoints)
{
points.Add(new SimpleWaypoint(wp));
}
points.Add(new SimpleWaypoint(EndLocation));
return points;
}
}
}

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

@ -0,0 +1,57 @@
/*
* 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
{
[DataContract]
public class RegionTravelSummary
{
[DataMember(Name = "name", EmitDefaultValue = false)]
public string Name { get; set; }
[DataMember(Name = "subregions", EmitDefaultValue = false)]
public RegionTravelSummary subregions { get; set; }
/// <summary>
/// The physical distance covered by a route leg.
/// </summary>
[DataMember(Name = "travelDistance", EmitDefaultValue = false)]
public double TravelDistance { get; set; }
/// <summary>
/// The time that it takes, in seconds, to travel a corresponding TravelDistance.
/// </summary>
[DataMember(Name = "travelDuration", EmitDefaultValue = false)]
public double TravelDuration { get; set; }
/// <summary>
/// The time that it takes, in seconds, to travel a corresponding TravelDistance.
/// </summary>
[DataMember(Name = "travelDurationTraffic", EmitDefaultValue = false)]
public double TravelDurationTraffic { get; set; }
}
}

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

@ -44,13 +44,11 @@ namespace BingMapsRESTToolkit
[KnownType(typeof(IsochroneResponse))]
[KnownType(typeof(SnapToRoadResponse))]
[KnownType(typeof(LocationRecog))]
[KnownType(typeof(LocalInsightsResponse))]
[KnownType(typeof(TimeZoneResponse))]
[KnownType(typeof(RESTTimeZone))]
[KnownType(typeof(AutosuggestResource))]
[KnownType(typeof(AutosuggestEntityResource))]
[KnownType(typeof(AutoSuggestLocalBusinessResource))]
[KnownType(typeof(AutoSuggestPlaceResource))]
[KnownType(typeof(AutosuggestAddressResource))]
[KnownType(typeof(Autosuggest))]
[KnownType(typeof(OptimizeItinerary))]
public class Resource
{
/// <summary>

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

@ -80,5 +80,34 @@ namespace BingMapsRESTToolkit
/// </summary>
[DataMember(Name = "resourceSets", EmitDefaultValue = false)]
public ResourceSet[] ResourceSets { get; set; }
/// <summary>
/// Check that a response has one or more resources. This is a helper class to save on having to check all the parts of the response tree.
/// </summary>
/// <param name="response">A response object.</param>
/// <returns>Boolean indicating if the response has one or more resources.</returns>
public static bool HasResource(Response response)
{
return response.ResourceSets != null &&
response.ResourceSets.Length > 0 &&
response.ResourceSets[0].Resources != null &&
response.ResourceSets[0].Resources.Length > 0 &&
response.ResourceSets[0].Resources[0] != null;
}
/// <summary>
/// Gets the first resource in a response.
/// </summary>
/// <param name="response">A response object.</param>
/// <returns>The first resource in a response, or null.</returns>
public static Resource GetFirstResource(Response response)
{
if (HasResource(response))
{
return response.ResourceSets[0].Resources[0];
}
return null;
}
}
}

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

@ -185,5 +185,11 @@ namespace BingMapsRESTToolkit
}
}
}
/// <summary>
/// Regional travel information.
/// </summary>
[DataMember(Name = "regionTravelSummary", EmitDefaultValue = false)]
public RegionTravelSummary RegionTravelSummary { get; set; }
}
}

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

@ -44,5 +44,26 @@ namespace BingMapsRESTToolkit
/// </summary>
[DataMember(Name = "generalizations", EmitDefaultValue = false)]
public Generalization[] Generalizations { get; set; }
/// <summary>
/// Gets an array of coordinate objects for the route path.
/// </summary>
/// <returns>An array of coordinate objects for the route path.</returns>
public Coordinate[] GetCoordinates()
{
if(Line != null && Line.Coordinates != null && Line.Coordinates.Length > 0)
{
var coords = new Coordinate[Line.Coordinates.Length];
for(int i = 0; i < Line.Coordinates.Length; i++)
{
coords[i] = new Coordinate(Line.Coordinates[i][0], Line.Coordinates[i][1]);
}
return coords;
}
return null;
}
}
}

219
Source/Models/Shift.cs Normal file
Просмотреть файл

@ -0,0 +1,219 @@
/*
* 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.Globalization;
using System.Runtime.Serialization;
using System.Text;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Details about an agents shift.
/// </summary>
[DataContract]
public class Shift
{
/// <summary>
/// Time that the shift starts for agent.
/// </summary>
[DataMember(Name = "startTime")]
internal string StartTime { get; set; }
/// <summary>
/// Time that the shift starts for agent.
/// </summary>
public DateTime StartTimeUtc
{
get
{
if (string.IsNullOrEmpty(StartTime))
{
return DateTime.Now;
}
else
{
return DateTimeHelper.GetDateTimeFromUTCString(StartTime);
}
}
set
{
if (value == null)
{
StartTime = string.Empty;
}
else
{
var v = DateTimeHelper.GetUTCString(value);
if (v != null)
{
StartTime = v;
}
else
{
StartTime = string.Empty;
}
}
}
}
/// <summary>
/// Location of the agent at start of shift.
/// </summary>
[DataMember(Name = "startLocation")]
public SimpleWaypoint StartLocation { get; set; }
/// <summary>
/// Time that the shift ends for agent.
/// </summary>
[DataMember(Name = "endTime")]
internal string EndTime { get; set; }
/// <summary>
/// Time that the shift ends for agent.
/// </summary>
public DateTime EndTimeUtc
{
get
{
if (string.IsNullOrEmpty(EndTime))
{
return DateTime.Now;
}
else
{
return DateTimeHelper.GetDateTimeFromUTCString(EndTime);
}
}
set
{
if (value == null)
{
EndTime = string.Empty;
}
else
{
var v = DateTimeHelper.GetUTCString(value);
if (v != null)
{
EndTime = v;
}
else
{
EndTime = string.Empty;
}
}
}
}
/// <summary>
/// Location of the agent at end of shift.
/// </summary>
[DataMember(Name = "endLocation")]
public SimpleWaypoint EndLocation { get; set; }
/// <summary>
/// Breaks the agent has during the shift.
/// </summary>
[DataMember(Name = "breaks")]
public Break[] Breaks { get; set; }
public override string ToString()
{
var sb = new StringBuilder();
sb.Append("{");
if (StartTimeUtc != null)
{
sb.AppendFormat("\"startTime\":\"{0}\",", StartTime);
}
else
{
throw new Exception("No start time for shift specified.");
}
if (StartLocation.Coordinate != null)
{
sb.Append("\"startLocation\":{");
sb.AppendFormat(CultureInfo.InvariantCulture, "\"latitude\":{0:0.#####},\"longitude\":{1:0.#####}", StartLocation.Latitude, StartLocation.Longitude);
sb.Append("},");
}
else if (!string.IsNullOrWhiteSpace(StartLocation.Address))
{
sb.AppendFormat("\"startAddress\":\"{0}\",", StartLocation.Address);
}
else
{
throw new Exception("Start location must be specified in shift.");
}
if (EndTimeUtc != null)
{
sb.AppendFormat("\"endTime\":\"{0}\",", EndTime);
}
else
{
throw new Exception("No end time for shift specified.");
}
if (EndLocation.Coordinate != null)
{
sb.Append("\"endLocation\":{");
sb.AppendFormat(CultureInfo.InvariantCulture, "\"latitude\":{0:0.#####},\"longitude\":{1:0.#####}", EndLocation.Latitude, EndLocation.Longitude);
sb.Append("},");
}
else if (!string.IsNullOrWhiteSpace(EndLocation.Address))
{
sb.AppendFormat("\"endAddress\":\"{0}\",", EndLocation.Address);
}
else
{
throw new Exception("End location must be specified in shift.");
}
if(Breaks != null && Breaks.Length > 0)
{
sb.Append("\"breaks\":[");
foreach(var b in Breaks)
{
sb.Append(b.ToString());
sb.Append(",");
}
sb.Length--;
sb.Append("],");
}
//Remove trailing comma.
sb.Length--;
sb.Append("}");
return sb.ToString();
}
}
}

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

@ -164,11 +164,13 @@ namespace BingMapsRESTToolkit
/// <summary>
/// The address query for the waypoint.
/// </summary>
[DataMember(Name = "address")]
public string Address { get; set; }
/// <summary>
/// A bool indicating whether the waypoint is a via point.
/// </summary>
[DataMember(Name = "isViaPoint")]
public bool IsViaPoint { get; set; }
#endregion
@ -257,12 +259,9 @@ namespace BingMapsRESTToolkit
{
var r = await ServiceManager.GetResponseAsync(request).ConfigureAwait(false);
if (r != null && r.ResourceSets != null &&
r.ResourceSets.Length > 0 &&
r.ResourceSets[0].Resources != null &&
r.ResourceSets[0].Resources.Length > 0)
if (Response.HasResource(r))
{
var l = r.ResourceSets[0].Resources[0] as Location;
var l = Response.GetFirstResource(r) as Location;
waypoint.Coordinate = new Coordinate(l.Point.Coordinates[0], l.Point.Coordinates[1]);
}
@ -315,5 +314,36 @@ namespace BingMapsRESTToolkit
}
#endregion
#region Public Static Methods
/// <summary>
/// Parses a simple waypoint value from a string. If it has the format "latitude,longitude", it will be used as a coordinate, otherwise as an address.
/// </summary>
/// <param name="waypointString">String containing a coordinate or address</param>
/// <returns>A simple waypoint.</returns>
public static SimpleWaypoint Parse(string waypointString)
{
var c = Coordinate.Parse(waypointString);
if (c == null)
{
return new SimpleWaypoint(waypointString);
}
return new SimpleWaypoint(c);
}
#endregion
public override string ToString()
{
if(!string.IsNullOrWhiteSpace(Address))
{
return Address;
}
return string.Format(CultureInfo.InvariantCulture, "{0:0.######}, {1:0.######}", Latitude, Longitude);
}
}
}

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

@ -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.1.4.0")]
[assembly: AssemblyFileVersion("1.1.4.0")]
[assembly: AssemblyVersion("1.1.5.0")]
[assembly: AssemblyFileVersion("1.1.5.0")]

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

@ -24,182 +24,163 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text;
using System.Threading.Tasks;
namespace BingMapsRESTToolkit
{
public class CoordWithRadius : Coordinate
{
/// <summary>
/// Radius in Meters
/// Returns a list of suggested entities which the user is most likely searching for.
/// </summary>
public int Radius { get; set; }
/// <summary>
/// Default Constuctor
/// </summary>
public CoordWithRadius() : base()
{
}
/// <summary>
/// Return Comma-separated list of Lat,Lon,Radius
/// </summary>
/// <returns></returns>
public override string ToString() => string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0},{1},{2}", Latitude.ToString(), Longitude.ToString(), Radius.ToString());
}
public class AutosuggestRequest : BaseRestRequest
{
#region Private Properties
private const int max_maxResults = 10;
private int maxResults = 7;
#endregion
#region Constructor
/// <summary>
/// Returns a list of suggested entities which the user is most likely searching for.
/// </summary>
public AutosuggestRequest()
{
AutoLocation = AutosuggestLocationType.userLocation;
IncludeEntityTypes = new List<AutosuggestEntityType>()
{
AutosuggestEntityType.Address,
AutosuggestEntityType.LocalBusiness,
AutosuggestEntityType.Place,
AutosuggestEntityType.Business,
AutosuggestEntityType.Place
};
Culture = "en-US";
UserRegion = "US";
CountryFilter = null;
Query = "";
UserLoc = null;
}
#endregion
#region Public Properties
public CoordWithRadius UserLoc { get; set; }
public string CountryFilter { get; set; }
public List<AutosuggestEntityType> IncludeEntityTypes {get; set;}
public AutosuggestLocationType AutoLocation { get; set; }
/// <summary>
/// A free form string address or Landmark. Overrides the Address values if both are specified.
/// </summary>
public string Query { get; set; }
public int? MaxResults { get; set; }
/// <summary>
/// Used to constrain entity suggestions to a single country denoted by a 2-letter country code abbreviation.
/// </summary>
public string CountryFilter { get; set; }
/// <summary>
/// A list of returned entity types.
/// </summary>
public List<AutosuggestEntityType> IncludeEntityTypes { get; set; }
/// <summary>
/// Specifies the maximum number of locations to return in the response.
/// </summary>
public int MaxResults
{
get { return maxResults; }
set
{
if (value > 0 && value <= 20)
{
maxResults = value;
}
}
}
#endregion
#region Public Methods
public override Task<Response> Execute()
/// <summary>
/// Executes the request.
/// </summary>
/// <returns>A response containing the requested data.</returns>
public override async Task<Response> Execute()
{
return Execute(null);
return await this.Execute(null).ConfigureAwait(false);
}
/// <summary>
/// Executes the request.
/// </summary>
/// <param name="remainingTimeCallback">A callback function in which the estimated remaining time in seconds is sent.</param>
/// <returns>A response containing the requested data.</returns>
public override async Task<Response> Execute(Action<int> remainingTimeCallback)
{
Stream responseStream = null;
Response r = null;
responseStream = await ServiceHelper.GetStreamAsync(new Uri(GetRequestUrl())).ConfigureAwait(false);
if (responseStream != null)
using (var responseStream = await ServiceHelper.GetStreamAsync(new Uri(GetRequestUrl())).ConfigureAwait(false))
{
var r = ServiceHelper.DeserializeStream<Response>(responseStream);
responseStream.Dispose();
return r;
using (var sr = new StreamReader(responseStream))
{
var s = sr.ReadToEnd();
//Replace "__type" with "type" for Entities to work around inconsistent logic used in Bing Maps REST APIs.
s = s.Replace("\"__type\":\"Address\"", "\"type\":\"Address\"")
.Replace("\"__type\":\"LocalBusiness\"", "\"type\":\"LocalBusiness\"")
.Replace("\"__type\":\"Place\"", "\"type\":\"Place\"");
var bytes = Encoding.UTF8.GetBytes(s);
using (var stream = new MemoryStream(bytes))
{
r = ServiceHelper.DeserializeStream<Response>(stream);
}
}
}
return null;
return r;
}
public override string GetRequestUrl()
{
if (Query == "")
throw new Exception("Empty Query value in Autosuggest REST Request");
string queryStr = string.Format("q={0}", Uri.EscapeDataString(Query));
string maxStr = string.Format("maxRes={0}", (max_maxResults < MaxResults) ? max_maxResults : MaxResults);
string locStr = null;
switch(AutoLocation)
if (string.IsNullOrWhiteSpace(Query))
{
case AutosuggestLocationType.userCircularMapView:
locStr = string.Format("ucmv={0}", UserCircularMapView.ToString());
break;
case AutosuggestLocationType.userMapView:
locStr = string.Format("umv={0}", UserMapView.ToString());
break;
case AutosuggestLocationType.userLocation:
if (UserLoc == null)
throw new Exception("User Location is Requred");
locStr = string.Format("ul={0}", UserLoc.ToString());
break;
throw new Exception("A Query value must specified.");
}
string inclEntityStr = string.Format("inclenttype={0}", getIncludeEntityTypeString());
string cultureStr = string.Format("c={0}", Culture.ToString());
List<string> param_list = new List<string>
if(UserCircularMapView == null && UserLocation == null && UserMapView == null)
{
queryStr,
locStr,
inclEntityStr,
cultureStr,
maxStr,
string.Format("key={0}", BingMapsKey)
};
if (CountryFilter != null)
{
string country_filterStr = string.Format("cf={0}", CountryFilter.ToString());
param_list.Add(country_filterStr);
throw new Exception("A UserLocation, UserCircularMapView, UserMapView must specified.");
}
return Domain + "Autosuggest?" + string.Join("&", param_list);
var sb = new StringBuilder(this.Domain);
sb.Append("Autosuggest");
sb.AppendFormat("?q={0}", Uri.EscapeDataString(Query));
if (maxResults != 5)
{
sb.AppendFormat("&maxResults={0}", maxResults);
}
if (!string.IsNullOrWhiteSpace(CountryFilter))
{
sb.AppendFormat("&countryFilter={0}", CountryFilter);
}
if (IncludeEntityTypes != null && IncludeEntityTypes.Count > 0)
{
sb.Append("&includeEntityTypes=");
var t = typeof(AutosuggestEntityType);
foreach (var iet in IncludeEntityTypes)
{
sb.AppendFormat("{0},", Enum.GetName(t, iet));
}
//Remove trailing comma.
sb.Length--;
}
sb.Append(GetBaseRequestUrl());
return sb.ToString();
}
#endregion
#region Private Methods
private string getIncludeEntityTypeString()
{
List<string> vals = new List<string>();
foreach(var entity_type in IncludeEntityTypes.Distinct())
{
switch(entity_type)
{
case AutosuggestEntityType.Address:
vals.Add("Address");
break;
case AutosuggestEntityType.LocalBusiness:
vals.Add("Business");
break;
case AutosuggestEntityType.Place:
vals.Add("Place");
break;
}
}
return string.Join(",", vals);
}
#endregion
}
}

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

@ -144,6 +144,12 @@ namespace BingMapsRESTToolkit
url += string.Format("&umv={0}", UserMapView.ToString());
}
if (UserCircularMapView != null)
{
//latitude, longitude, radius
url += string.Format("&ucmv={0}", UserCircularMapView.ToString());
}
if (UserLocation != null)
{
url += string.Format("&ul={0}", UserLocation);

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

@ -150,7 +150,7 @@ namespace BingMapsRESTToolkit
var response = await ServiceHelper.MakeAsyncPostRequest<DistanceMatrix>(requestUrl, requestBody, remainingTimeCallback).ConfigureAwait(false);
var dm = response.ResourceSets[0].Resources[0] as DistanceMatrix;
var dm = Response.GetFirstResource(response) 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;

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

@ -350,7 +350,7 @@ namespace BingMapsRESTToolkit
{
x = Bounds.WestLongitude + (dLon * c);
int idx = r * row + c;
int idx = r * col + c;
coords[idx] = new Coordinate()
{

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

@ -0,0 +1,219 @@
/*
* Copyright(c) 2018 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>
/// Returns a list of local entities within the specified maximum driving time or distance traveled from a specified point on Earth.
/// </summary>
public class LocalInsightsRequest : BaseRestRequest
{
#region Constructor
/// <summary>
/// Constructor with default values
/// </summary>
public LocalInsightsRequest() : base()
{
Optimize = RouteOptimizationType.Time;
TimeUnit = TimeUnitType.Second;
DistanceUnit = DistanceUnitType.Kilometers;
TravelMode = TravelModeType.Driving;
}
#endregion
#region Public Properties
/// <summary>
/// The query or coordinates for a location around which the isochrone is created.
/// </summary>
public SimpleWaypoint Waypoint { get; set; }
/// <summary>
/// Required, if optimize is Time or TimeWithTraffic. The longest possible travel time used to generate the isochrone.
/// Any positive integer less than or equal to the maximum time, which is 60 minutes.
/// Note: Cannot be used when maxDistance is specified.
/// </summary>
public double? MaxTime { get; set; }
/// <summary>
/// The unit of time for the parameter maxTime.
/// Default: Second
/// </summary>
public TimeUnitType TimeUnit { get; set; }
/// <summary>
/// If travelModel is Driving. The datetime parameter identifies the desired departure time used to return the list of local entities
/// within the specified maximum driving time as specified using the maxTime parameter.
/// </summary>
public DateTime? DateTime { get; set; }
/// <summary>
/// Required, if travelMode is Driving or Walking. The longest possible distance used define the geographic region in which to search for local entities.
/// Any positive integer less than or equal to 50 miles.
/// Note: Distance-based Local Insight API calls are unavailable for transit.
/// Note: Cannot be used when maxTime is specified.
/// </summary>
public double? MaxDistance { get; set; }
/// <summary>
/// The unit of distance for the maxDistance parameter.
/// Default: Kilometers.
/// </summary>
public DistanceUnitType DistanceUnit { get; set; }
/// <summary>
/// Specifies what parameters to use to optimize the isochrone route.
/// </summary>
public RouteOptimizationType Optimize { get; set; }
/// <summary>
/// Indicates the which routing profile to snap the points to.
/// </summary>
public TravelModeType TravelMode { get; set; }
/// <summary>
/// Required. The specified types used to filter the local entities returned by the Local Search API.
/// A comma-separated list of string type identifiers.
/// See the list of available Type IDs https://docs.microsoft.com/en-us/bingmaps/rest-services/common-parameters-and-types/type-identifiers/
/// </summary>
public List<string> Types { 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).ConfigureAwait(false);
}
/// <summary>
/// Executes the request.
/// </summary>
/// <param name="remainingTimeCallback">A callback function in which the estimated remaining time in seconds is sent.</param>
/// <returns>A response containing the requested data.</returns>
public override async Task<Response> Execute(Action<int> remainingTimeCallback)
{
var requestUrl = GetRequestUrl();
return await ServiceHelper.MakeAsyncGetRequest(requestUrl, remainingTimeCallback).ConfigureAwait(false);
}
public override string GetRequestUrl()
{
if (Waypoint == null || (Waypoint.Coordinate == null && string.IsNullOrWhiteSpace(Waypoint.Address)))
{
throw new Exception("A waypoiny must be specified.");
}
if (Types == null || Types.Count == 0)
{
throw new Exception("One or more types must be specified.");
}
//Truck mode is not supported, so fall back to driving.
if (TravelMode == TravelModeType.Truck)
{
TravelMode = TravelModeType.Driving;
}
var sb = new StringBuilder(this.Domain);
sb.AppendFormat("Routes/LocalInsightsAsync?travelMode={0}", Enum.GetName(typeof(TravelModeType), TravelMode));
if (Waypoint.Coordinate != null)
{
sb.AppendFormat("&waypoint={0}", Waypoint.Coordinate.ToString());
}
else if (!string.IsNullOrWhiteSpace(Waypoint.Address))
{
sb.AppendFormat("&waypoint={0}", string.Join(",", Waypoint.Address));
}
if (MaxTime > 0)
{
if (TimeUnit == TimeUnitType.Second && MaxTime > 3600)
{
throw new Exception("MaxTime value must be <= 3600 seconds.");
}
else if (TimeUnit == TimeUnitType.Minute && MaxTime > 60)
{
throw new Exception("MaxTime value must be <= 60 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);
}
//Can only optimize based on time or time with traffic when generating time based isochrones.
if (Optimize != RouteOptimizationType.Time && Optimize != RouteOptimizationType.TimeWithTraffic)
{
Optimize = 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(CultureInfo.InvariantCulture, "&maxDistance={0}&distanceUnit={1}", MaxDistance, EnumHelper.DistanceUnitTypeToString(DistanceUnit));
//Can only optimize based on distance when generating distance based isochrones.
if (Optimize != RouteOptimizationType.Distance)
{
Optimize = RouteOptimizationType.Distance;
}
}
else
{
throw new Exception("A max time or distance must be specified.");
}
sb.AppendFormat("&optimize={0}", Enum.GetName(typeof(RouteOptimizationType), Optimize));
sb.AppendFormat("&type={0}", string.Join(",", Types));
sb.Append(GetBaseRequestUrl());
return sb.ToString();
}
#endregion
}
}

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

@ -0,0 +1,123 @@
/*
* Copyright(c) 2018 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.Text;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Returns a list of business entities centered around a location or a geographic region.
/// </summary>
public class LocalSearchRequest : BaseRestRequest
{
#region Private Properties
private int maxResults = 5;
#endregion
#region Constructor
/// <summary>
/// Constructor with default values
/// </summary>
public LocalSearchRequest() : base()
{
}
#endregion
#region Public Properties
/// <summary>
/// The specified types used to filter the local entities returned by the Local Search API.
/// A string that contains information about a location, such as an address or landmark name.
/// </summary>
public string Query { get; set; }
/// <summary>
/// Specifies the maximum number of locations to return in the response.
/// </summary>
public int MaxResults
{
get { return maxResults; }
set
{
if (value > 0 && value <= 20)
{
maxResults = value;
}
}
}
/// <summary>
/// The specified types used to filter the local entities returned by the Local Search API.
/// A comma-separated list of string type identifiers.
/// See the list of available Type IDs https://docs.microsoft.com/en-us/bingmaps/rest-services/common-parameters-and-types/type-identifiers/
/// </summary>
public List<string> Types { get; set; }
#endregion
#region Public Methods
public override string GetRequestUrl()
{
if(UserCircularMapView == null && UserLocation == null && UserMapView == null)
{
throw new Exception("A user location must be specified.");
}
var sb = new StringBuilder(this.Domain);
sb.Append("LocalSearch/");
if (!string.IsNullOrWhiteSpace(Query))
{
sb.AppendFormat("?query={0}", Query);
}
else if(Types != null && Types.Count > 0)
{
sb.AppendFormat("?type={0}", string.Join(",", Types));
}
else
{
throw new Exception("A query or types must be specified.");
}
if (maxResults != 5)
{
sb.AppendFormat("&maxResults={0}", maxResults);
}
sb.Append(GetBaseRequestUrl());
return sb.ToString();
}
#endregion
}
}

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

@ -220,22 +220,11 @@ namespace BingMapsRESTToolkit
string du;
switch (DistanceUnits)
{
case DistanceUnitType.Miles:
du = "mile";
break;
case DistanceUnitType.Kilometers:
default:
du = "kilometer";
break;
}
List<string> param_list = new List<string>
{
string.Format("r={0}", Radius.ToString(System.Globalization.CultureInfo.InvariantCulture)),
string.Format("top={0}", Top.ToString()),
string.Format("distanceUnit={0}", du),
string.Format("distanceUnit={0}", EnumHelper.DistanceUnitTypeToString(DistanceUnits)),
string.Format("verboseplacenames={0}", VerbosePlaceNames.ToString().ToLower()),
string.Format("key={0}", BingMapsKey.ToString()),
string.Format("includeEntityTypes={0}", IncludeEntityTypes)

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

@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace BingMapsRESTToolkit
{
/// <summary>
/// Request for Bing Maps Multi-Itinerary Optimization API.
/// </summary>
public class OptimizeItineraryRequest : BaseRestRequest
{
#region Private Properties
/// <summary>
/// Maximum number of agents supported in an asynchronous Optimize Itinerary request from an enterprise account.
/// </summary>
private int maxAgents = 200;
/// <summary>
/// Maximum number of itinerary items supported in an asynchronous Optimize Itinerary request from an enterprise account.
/// </summary>
private int maxItineraryItems = 2000;
#endregion
#region Constructor
/// <summary>
/// Request for Bing Maps Multi-Itinerary Optimization API.
/// </summary>
public OptimizeItineraryRequest() : base()
{
CostValue = CostValueType.TravelTime;
}
#endregion
#region Public Properties
/// <summary>
/// List of agent itinerary information: including the agent name, shift starting and ending locations for agent, and capacity of the agent's vehicle.
/// </summary>
public List<Agent> Agents { get; set; }
/// <summary>
/// List of itinerary items to be scheduled among the specified agents, including the location name, location (lat/lon), priority, dwell time, business closing and opening times for each item to be scheduled, quantity to be delivered to or picked up from each location, and pickup/drop off sequence dependency with other itineraryItems.
/// </summary>
public List<OptimizeItineraryItem> ItineraryItems { get; set; }
private OptimizationType _type = OptimizationType.SimpleRequest;
/// <summary>
/// Specifies whether traffic data should used to optimize the order of waypoint items. Default: SimpleRequest
/// Note: If the type parameter is set to TrafficRequest, it will automatically use true as the roadnetwork parameter value.
/// </summary>
public OptimizationType Type
{
get
{
return _type;
}
set
{
_type = value;
if (value == OptimizationType.TrafficRequest) {
RoadNetwork = true;
}
}
}
/// <summary>
/// Optional.
/// If true, uses actual road network information, and both travel distances and travel times between the itinerary locations to calculate optimizations.
/// If false, a constant radius is used to measure distances and a constant travel speed is used to calculate travel times between locations.
/// </summary>
public bool RoadNetwork { get; set; }
/// <summary>
/// A parameter used to optimize itineraries in addition to maximizing the sum of item priorities. Default: TravelTime
/// </summary>
public CostValueType CostValue { 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).ConfigureAwait(false);
}
/// <summary>
/// Executes the request.
/// </summary>
/// <param name="remainingTimeCallback">A callback function in which the estimated remaining time in seconds 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(requestUrl, requestBody, remainingTimeCallback).ConfigureAwait(false);
}
/// <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(Agents == null || Agents.Count == 0)
{
throw new Exception("Agents not specified.");
}
else if (Agents.Count > maxAgents)
{
throw new Exception(string.Format("More than {0} Agents specified.", maxAgents));
}
if (ItineraryItems == null || ItineraryItems.Count == 0)
{
throw new Exception("ItineraryItems not specified.");
}
else if (ItineraryItems.Count > maxItineraryItems)
{
throw new Exception(string.Format("More than {0} ItineraryItems specified.", maxItineraryItems));
}
//Make an async request.
return this.Domain + "Routes/OptimizeItineraryAsync?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.AppendFormat("\"agents\":[{0}],", string.Join(",",Agents));
sb.AppendFormat("\"itineraryItems\":[{0}],", string.Join(",", ItineraryItems));
sb.AppendFormat("\"type\":\"{0}\",", Enum.GetName(typeof(OptimizationType), Type));
sb.AppendFormat("\"roadnetwork\":{0},", RoadNetwork.ToString().ToLowerInvariant());
sb.AppendFormat("\"costvalue\":\"{0}\"", Enum.GetName(typeof(CostValueType), CostValue));
sb.Append("}");
return sb.ToString();
}
#endregion
}
}

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

@ -579,7 +579,8 @@ namespace BingMapsRESTToolkit
sb.AppendFormat(",\"heading\":{0}", RouteOptions.Heading.Value);
}
if (RouteOptions.MaxSolutions > 1 && RouteOptions.MaxSolutions <= 3)
//Truck routing doesn't support max solutions and throws an error if included in the request.
if (RouteOptions.TravelMode != TravelModeType.Truck && RouteOptions.MaxSolutions > 1 && RouteOptions.MaxSolutions <= 3)
{
sb.AppendFormat(",\"maxSolutions\":{0}", RouteOptions.MaxSolutions);
}
@ -601,23 +602,50 @@ namespace BingMapsRESTToolkit
if (RouteOptions.RouteAttributes != null && RouteOptions.RouteAttributes.Count > 0)
{
sb.Append(",\"routeAttributes\":\"");
string rt = "";
if (RouteOptions.TravelMode == TravelModeType.Truck) {
//Truck supports routePath and regionTravelSummary, and only allows one to be specified.
if(RouteOptions.RouteAttributes.Contains(RouteAttributeType.RoutePath) || RouteOptions.RouteAttributes.Contains(RouteAttributeType.All))
{
rt += "routePath,";
}
else if (RouteOptions.RouteAttributes.Contains(RouteAttributeType.RegionTravelSummary))
{
rt += "regionTravelSummary,";
}
else
{
rt += ",";
}
} else {
if (RouteOptions.RouteAttributes.Contains(RouteAttributeType.RoutePath) || RouteOptions.RouteAttributes.Contains(RouteAttributeType.All))
{
rt += "routePath,";
}
//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,");
rt += "routeSummariesOnly,";
}
if (RouteOptions.RouteAttributes.Contains(RouteAttributeType.RoutePath) || RouteOptions.RouteAttributes.Contains(RouteAttributeType.All))
if (RouteOptions.RouteAttributes.Contains(RouteAttributeType.RegionTravelSummary))
{
sb.Append("routePath,");
rt += "regionTravelSummary,";
}
}
if (!string.IsNullOrEmpty(rt))
{
sb.Append(",\"routeAttributes\":\"");
sb.Append(rt);
//Remove trailing comma.
sb.Length--;
sb.Append("\"");
}
}
if (RouteOptions.DistanceUnits == DistanceUnitType.Kilometers)
{
@ -782,10 +810,9 @@ namespace BingMapsRESTToolkit
}
}
if (r != null && r.ErrorDetails == null && r.ResourceSets != null && r.ResourceSets.Length > 0 &&
r.ResourceSets[0].Resources != null && r.ResourceSets[0].Resources.Length > 0)
if (Response.HasResource(r))
{
routes[idx] = r.ResourceSets[0].Resources[0] as Route;
routes[idx] = Response.GetFirstResource(r) as Route;
return;
}

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

@ -124,7 +124,7 @@ namespace BingMapsRESTToolkit
var requestUrl = GetRequestUrl();
var requestBody = GetPostRequestBody();
return await ServiceHelper.MakeAsyncPostRequest<Route>(requestUrl, requestBody, remainingTimeCallback).ConfigureAwait(false);
return await ServiceHelper.MakeAsyncPostRequest<SnapToRoadResponse>(requestUrl, requestBody, remainingTimeCallback).ConfigureAwait(false);
}
/// <summary>