This commit is contained in:
runette committed 2024-04-22 15:52:51 +01:00
commit e0afef912e
1285 files changed
+83219

No files matched your search

@@ -0,0 +1,74 @@
//-----------------------------------------------------------------------
// <copyright file="MapMatcher.cs" company="Mapbox">
// Copyright (c) 2017 Mapbox. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace Mapbox.MapMatching
{
using System;
using System.Text;
using Mapbox.Json;
using Mapbox.Platform;
using Mapbox.Utils.JsonConverters;
/// <summary>
/// Wrapper around the <see href="https://www.mapbox.com/api-documentation/navigation/#map-matching">
/// Mapbox Map Matching API</see>.
/// </summary>
public class MapMatcher
{
private readonly IFileSource _fileSource;
private int _timeout;
/// <summary> Initializes a new instance of the <see cref="MapMatcher" /> class. </summary>
/// <param name="fileSource"> Network access abstraction. </param>
public MapMatcher(IFileSource fileSource, int timeout)
{
_fileSource = fileSource;
_timeout = timeout;
}
/// <summary> Performs asynchronously a geocoding lookup. </summary>
/// <param name="geocode"> Geocode resource. </param>
/// <param name="callback"> Callback to be called after the request is completed. </param>
/// <typeparam name="T"> String or LngLat. Should be automatically inferred. </typeparam>
/// <returns>
/// Returns a <see cref="IAsyncRequest" /> that can be used for canceling a pending
/// request. This handle can be completely ignored if there is no intention of ever
/// canceling the request.
/// </returns>
public IAsyncRequest Match(MapMatchingResource match, Action<MapMatchingResponse> callback)
{
string url = match.GetUrl();
return _fileSource.Request(
url,
(Response response) =>
{
var str = Encoding.UTF8.GetString(response.Data);
var data = Deserialize<MapMatchingResponse>(str);
if (response.HasError)
{
data.SetRequestExceptions(response.Exceptions);
}
callback(data);
},
_timeout
);
}
/// <summary>
/// Deserialize the map match response string into a <see cref="MapMatchingResponse"/>.
/// </summary>
/// <param name="str">JSON String.</param>
/// <returns>A <see cref="MapMatchingResponse"/>.</returns>
/// <typeparam name="T">Map Matcher. </typeparam>
internal T Deserialize<T>(string str)
{
return JsonConvert.DeserializeObject<T>(str, JsonConverters.Converters);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: dfdfc6d95bc72494e8ae78580d2e6b44
timeCreated: 1508239177
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,115 @@
//-----------------------------------------------------------------------
// <copyright file="MapMatchingParameters.cs" company="Mapbox">
// Copyright (c) 2017 Mapbox. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
using System;
using System.ComponentModel;
using Mapbox.VectorTile.Geometry;
namespace Mapbox.MapMatching
{
/// <summary>Directions profile id</summary>
public enum Profile
{
[Description("mapbox/driving")]
MapboxDriving,
[Description("mapbox/driving-traffic")]
MapboxDrivingTraffic,
[Description("mapbox/walking")]
MapboxWalking,
[Description("mapbox/cycling")]
MapboxCycling
}
/// <summary>Format of the returned geometry. Default value 'Polyline' with precision 5.</summary>
public enum Geometries
{
/// <summary>Default, precision 5.</summary>
[Description("polyline")]
Polyline,
/// <summary>Precision 6.</summary>
[Description("polyline6")]
Polyline6,
/// <summary>Geojson.</summary>
[Description("geojson")]
GeoJson
}
/// <summary>Type of returned overview geometry. </summary>
public enum Overview
{
/// <summary>The most detailed geometry available </summary>
[Description("full")]
Full,
/// <summary>A simplified version of the full geometry</summary>
[Description("simplified")]
Simplified,
/// <summary>No overview geometry </summary>
[Description("false")]
None
}
/// <summary>Whether or not to return additional metadata along the route. Several annotations can be used.</summary>
[System.Flags]
public enum Annotations
{
[Description("duration")]
Duration,
[Description("distance")]
Distance,
[Description("speed")]
Speed,
[Description("congestion")]
Congestion
}
/// <summary>
/// https://www.mapbox.com/api-documentation/navigation/#retrieve-directions
/// </summary>
public enum InstructionLanguages
{
[Description("de")]
German,
[Description("en")]
English,
[Description("eo")]
Esperanto,
[Description("es")]
Spanish,
[Description("es-ES")]
SpanishSpain,
[Description("fr")]
French,
[Description("id")]
Indonesian,
[Description("it")]
Italian,
[Description("nl")]
Dutch,
[Description("pl")]
Polish,
[Description("pt-BR")]
PortugueseBrazil,
[Description("ro")]
Romanian,
[Description("ru")]
Russian,
[Description("sv")]
Swedish,
[Description("tr")]
Turkish,
[Description("uk")]
Ukrainian,
[Description("vi")]
Vietnamese,
[Description("zh-Hans")]
ChineseSimplified
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 991f42eef2c18204cb4a6b79c6f98eed
timeCreated: 1508237904
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,209 @@
//-----------------------------------------------------------------------
// <copyright file="MapMatchingResource.cs" company="Mapbox">
// Copyright (c) 2017 Mapbox. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace Mapbox.MapMatching
{
using System;
using System.Collections.Generic;
using System.Linq;
using Mapbox.Platform;
using Mapbox.Utils;
using Mapbox.VectorTile.ExtensionMethods;
/// <summary> Base geocode class. </summary>
/// <typeparam name="T"> Type of Query field (either string or LatLng). </typeparam>
public class MapMatchingResource : Resource
{
private readonly string _apiEndpoint = "matching/v5/";
private Vector2d[] _coordinates;
private uint[] _radiuses;
private long[] _timestamps;
/// <summary> Gets the API endpoint as a partial URL path. </summary>
public override string ApiEndpoint
{
get { return _apiEndpoint; }
}
/// <summary>A directions profile ID.</summary>
public Profile Profile = Profile.MapboxDriving;
/// <summary> Coordinate to visit in order; there can be between 2 and 100 coordinates. </summary>
public Vector2d[] Coordinates
{
get { return _coordinates; }
set
{
if (null == value)
{
throw new Exception("Coordinates cannot be null.");
}
if (value.Length < 2 || value.Length > 100)
{
throw new Exception("Must be between 2 and 100 elements in coordinates array");
}
_coordinates = value;
}
}
/// <summary>
/// <para>Format of the returned geometry.</para>
/// <para>Allowed values are: geojson (as LineString ), polyline with precision 5, polyline6 (polyline with precision 6).</para>
/// <para>The default value is polyline.</para>
/// </summary>
public Nullable<Geometries> Geometries;
/// <summary>
/// <para>A list of uints in meters indicating the assumed precision of the used tracking device.</para>
/// <para>There must be as many radiuses as there are coordinates in the request.</para>
/// <para>Values can be a number between 0 and 30.</para>
/// <para>Use higher numbers (20-30) for noisy traces and lower numbers (1-10) for clean traces.</para>
/// <para>The default value is 5.</para>
/// </summary>
public uint[] Radiuses
{
get { return _radiuses; }
set
{
if (null == _coordinates) { throw new Exception("Coordinates not set"); }
//allow for nulling radiuses
if (null == value)
{
_radiuses = null;
return;
}
if (value.Length != _coordinates.Length) { throw new Exception("There must be as many radiuses as there are coordinates in the request."); }
if (value.Where(r => r == 0).Count() > 0) { throw new Exception("Radius must be greater than 0"); }
_radiuses = value;
}
}
/// <summary>
/// <para>Whether to return steps and turn-by-turn instructions.</para>
/// <para>Can be true or false.</para>
/// <para>The default is false.</para>
/// </summary>
public bool? Steps;
/// <summary>
/// <para>Type of returned overview geometry.</para>
/// <para>Can be full (the most detailed geometry available), simplified (a simplified version of the full geometry), or none (no overview geometry).</para>
/// <para>The default is simplified.</para>
/// </summary>
public Nullable<Overview> Overview;
/// <summary>
/// <para>Timestamps corresponding to each coordinate provided in the request.</para>
/// <para>Must be numbers in Unix time (seconds since the Unix epoch).</para>
/// <para>There must be as many timestamps as there are coordinates in the request.</para>
/// </summary>
public long[] Timestamps
{
get { return _timestamps; }
set
{
if (null == _coordinates) { throw new Exception("Coordinates not set"); }
//allow for nulling timestamps
if (null == value)
{
_timestamps = null;
return;
}
if (value.Length != _coordinates.Length) { throw new Exception("There must be as many timestapms as there are coordinates in the request."); }
_timestamps = value;
}
}
/// <summary>
/// <para>Whether or not to return additional metadata along the route.</para>
/// <para>Possible values are: duration, distance and speed.</para>
/// <para>Several annotations can be used.</para>
/// <para>Combine via '|'.</para>
/// </summary>
public Nullable<Annotations> Annotations;
/// <summary>
/// <para>Whether or not to transparently remove clusters and re-sample traces for improved map matching results.</para>
/// <para>Removed tracepoints are set to 'null' in the response!</para>
/// <para>Can be true or false.</para>
/// <para>The default is false.</para>
/// </summary>
public bool? Tidy;
/// <summary>
/// <para>Language of returned turn-by-turn text instructions.</para>
/// <para>The default is English.</para>
/// </summary>
public Nullable<InstructionLanguages> Language;
public override string GetUrl()
{
if (null == _coordinates)
{
throw new Exception("Coordinates cannot be null.");
}
Dictionary<string, string> options = new Dictionary<string, string>();
if (Geometries.HasValue) { options.Add("geometries", Geometries.Value.Description()); }
if (null != _radiuses) { options.Add("radiuses", GetUrlQueryFromArray(_radiuses, ";")); }
if (Steps.HasValue) { options.Add("steps", Steps.ToString().ToLower()); }
if (Overview.HasValue) { options.Add("overview", Overview.Value.Description()); }
if (null != _timestamps) { options.Add("timestamps", GetUrlQueryFromArray(_timestamps, ";")); }
if (Annotations.HasValue) { options.Add("annotations", getUrlQueryFromAnnotations(Annotations.Value, ",")); }
if (Tidy.HasValue) { options.Add("tidy", Tidy.Value.ToString().ToLower()); }
if (Language.HasValue) { options.Add("language", Language.Value.Description()); }
return
Constants.BaseAPI
+ _apiEndpoint
+ Profile.Description() + "/"
+ GetUrlQueryFromArray<Vector2d>(_coordinates, ";")
+ ".json"
+ EncodeQueryString(options);
}
/// <summary>
/// Convert Annotations (several could be combined) into a string of their descriptions.
/// </summary>
/// <param name="annotation">Current annotation</param>
/// <param name="separator">Character to use for separating items in string.</param>
/// <returns></returns>
private string getUrlQueryFromAnnotations(Annotations anno, string separator)
{
List<string> descriptions = new List<string>();
//iterate through all possible 'Annotations' values
foreach (var a in Enum.GetValues(typeof(Annotations)).Cast<Annotations>())
{
//if current value is set, add its description
if (a == (anno & a)) { descriptions.Add(a.Description()); }
}
return string.Join(separator, descriptions.ToArray());
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 8762d1b8a83c7ba4b91f9a1c64717bee
timeCreated: 1508240506
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,72 @@
//-----------------------------------------------------------------------
// <copyright file="MapMatchingResponse.cs" company="Mapbox">
// Copyright (c) 2016 Mapbox. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace Mapbox.MapMatching
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Mapbox.Json;
/// <summary> Base geocode response. </summary>
#if !WINDOWS_UWP
//http://stackoverflow.com/a/12903628
[Serializable]
#endif
public class MapMatchingResponse
{
/// <summary>Simple constructor for deserialization </summary>
public MapMatchingResponse() { }
[JsonProperty("code")]
public string Code;
[JsonProperty("message")]
public string Message;
[JsonProperty("tracepoints")]
public Tracepoint[] Tracepoints;
[JsonProperty("matchings")]
public MatchObject[] Matchings;
#if !WINDOWS_UWP
/// <summary>Error occured during matching</summary>
public bool HasMatchingError { get { return !"ok".Equals(Code, StringComparison.InvariantCultureIgnoreCase); } }
#else
/// <summary>Error occured during matching</summary>
public bool HasMatchingError { get { return !"ok".Equals(Code, StringComparison.OrdinalIgnoreCase); } }
#endif
public string MatchingError
{
get
{
string matchCode = Code.ToLower();
switch (matchCode)
{
case "ok": return "";
case "nomatch": return "The input did not produce any matches. features will be an empty array.";
case "toomanycoordinates": return "There are to many points in the request.";
case "InvalidInput": return "Invalid input: 'message' will hold an explanation of the invalid input.";
case "ProfileNotFound": return "Invalid profile.";
case "nosegment": return "Could not find a matching segment for input coordinates.";
default:
return "Unexpected error: check 'message'";
}
}
}
/// <summary>Errors occured during web request </summary>
public bool HasRequestError { get { return _requestExceptions.Count > 0; } }
private ReadOnlyCollection<Exception> _requestExceptions = new List<Exception>().AsReadOnly();
/// <summary>Errors of underlying web request </summary>
public ReadOnlyCollection<Exception> RequestExceptions { get { return _requestExceptions; } }
/// <summary>Assign errors of underlying web request </summary>
public void SetRequestExceptions(ReadOnlyCollection<Exception> exceptions) { _requestExceptions = exceptions; }
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 6b0f824b73d2d8f41aeed79f2a15666d
timeCreated: 1508247612
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,25 @@
//-----------------------------------------------------------------------
// <copyright file="MatchObject.cs" company="Mapbox">
// Copyright (c) 2017 Mapbox. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace Mapbox.MapMatching
{
using Mapbox.Directions;
using Mapbox.Json;
/// <summary>
/// A Match object from a Map Matching API call.
/// </summary>
public class MatchObject : Route
{
/// <summary>
/// A number between 0 (low) and 1 (high) indicating level of confidence in the returned match
/// </summary>
[JsonProperty("confidence")]
public float Confidence { get; set; }
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: d6d1f89031e0a60479b516a76cf1a96a
timeCreated: 1508309612
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,39 @@
//-----------------------------------------------------------------------
// <copyright file="Tracepoint.cs" company="Mapbox">
// Copyright (c) 2017 Mapbox. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace Mapbox.MapMatching
{
using Mapbox.Directions;
using Mapbox.Json;
using Mapbox.Utils;
using Mapbox.Utils.JsonConverters;
/// <summary>
/// A Waypoint from a Directions API call.
/// </summary>
public class Tracepoint: Waypoint
{
/// <summary>
/// Index of the waypoint inside the matched route.
/// </summary>
[JsonProperty("waypoint_index")]
public int WaypointIndex { get; set; }
/// <summary>
/// Index to the match object in matchings the sub-trace was matched to.
/// </summary>
[JsonProperty("matchings_index")]
public int MatchingsIndex { get; set; }
/// <summary>
/// Number of probable alternative matchings for this trace point. A value of zero indicates that this point was matched unambiguously. Split the trace at these points for incremental map matching.
/// </summary>
[JsonProperty("alternatives_count")]
public int AlternativesCount { get; set; }
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: cd23eaecbb5aa1947ad2b7a595c2393e
timeCreated: 1508251969
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: