//-----------------------------------------------------------------------
//
// 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());
}
}
}