//----------------------------------------------------------------------- // // Copyright (c) 2017 Mapbox. All rights reserved. // //----------------------------------------------------------------------- namespace Mapbox.MapMatching { using System; using System.Collections.Generic; using System.Linq; using Mapbox.Platform; using Mapbox.Utils; using Mapbox.VectorTile.ExtensionMethods; /// Base geocode class. /// Type of Query field (either string or LatLng). public class MapMatchingResource : Resource { private readonly string _apiEndpoint = "matching/v5/"; private Vector2d[] _coordinates; private uint[] _radiuses; private long[] _timestamps; /// Gets the API endpoint as a partial URL path. public override string ApiEndpoint { get { return _apiEndpoint; } } /// A directions profile ID. public Profile Profile = Profile.MapboxDriving; /// Coordinate to visit in order; there can be between 2 and 100 coordinates. 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; } } /// /// Format of the returned geometry. /// Allowed values are: geojson (as LineString ), polyline with precision 5, polyline6 (polyline with precision 6). /// The default value is polyline. /// public Nullable Geometries; /// /// A list of uints in meters indicating the assumed precision of the used tracking device. /// There must be as many radiuses as there are coordinates in the request. /// Values can be a number between 0 and 30. /// Use higher numbers (20-30) for noisy traces and lower numbers (1-10) for clean traces. /// The default value is 5. /// 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; } } /// /// Whether to return steps and turn-by-turn instructions. /// Can be true or false. /// The default is false. /// public bool? Steps; /// /// Type of returned overview geometry. /// Can be full (the most detailed geometry available), simplified (a simplified version of the full geometry), or none (no overview geometry). /// The default is simplified. /// public Nullable Overview; /// /// Timestamps corresponding to each coordinate provided in the request. /// Must be numbers in Unix time (seconds since the Unix epoch). /// There must be as many timestamps as there are coordinates in the request. /// 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; } } /// /// Whether or not to return additional metadata along the route. /// Possible values are: duration, distance and speed. /// Several annotations can be used. /// Combine via '|'. /// public Nullable Annotations; /// /// Whether or not to transparently remove clusters and re-sample traces for improved map matching results. /// Removed tracepoints are set to 'null' in the response! /// Can be true or false. /// The default is false. /// public bool? Tidy; /// /// Language of returned turn-by-turn text instructions. /// The default is English. /// public Nullable Language; public override string GetUrl() { if (null == _coordinates) { throw new Exception("Coordinates cannot be null."); } Dictionary options = new Dictionary(); 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(_coordinates, ";") + ".json" + EncodeQueryString(options); } /// /// Convert Annotations (several could be combined) into a string of their descriptions. /// /// Current annotation /// Character to use for separating items in string. /// private string getUrlQueryFromAnnotations(Annotations anno, string separator) { List descriptions = new List(); //iterate through all possible 'Annotations' values foreach (var a in Enum.GetValues(typeof(Annotations)).Cast()) { //if current value is set, add its description if (a == (anno & a)) { descriptions.Add(a.Description()); } } return string.Join(separator, descriptions.ToArray()); } } }