Skip to content

Commit

Permalink
feat(here): adding support for encoding flexible polylines for the au…
Browse files Browse the repository at this point in the history
…tosuggest, browse, and discover endpoints (#56)

* feat(here): adding a polyline encoder/decoder

* feat(here): adding tests for polyline support

* feat(here): adding polyline encoding support for the autosuggest, browse, and discover endpoints
  • Loading branch information
JustinCanton authored Apr 3, 2023
1 parent 2fd4107 commit 98c7dd9
Show file tree
Hide file tree
Showing 24 changed files with 16,549 additions and 62 deletions.
24 changes: 12 additions & 12 deletions src/Geo.ArcGIS/Services/ArcGISGeocoding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,18 @@ public async Task<GeocodingResponse> GeocodingAsync(
return await CallAsync<GeocodingResponse, ArcGISException>(uri, ApiName, cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Adds the ArcGIS storage flag to the query parameters.
/// </summary>
/// <param name="parameters">A <see cref="StorageParameters"/> with the storage information.</param>
/// <param name="query">A <see cref="QueryString"/> with the query parameters.</param>
internal static void AddStorageParameter(StorageParameters parameters, ref QueryString query)
{
#pragma warning disable CA1308 // Normalize strings to uppercase
query = query.Add("forStorage", parameters.ForStorage.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
#pragma warning restore CA1308 // Normalize strings to uppercase
}

/// <summary>
/// Validates the uri and builds it based on the parameter type.
/// </summary>
Expand Down Expand Up @@ -476,18 +488,6 @@ internal async Task<Uri> BuildGeocodingRequest(GeocodingParameters parameters, C
return uriBuilder.Uri;
}

/// <summary>
/// Adds the ArcGIS storage flag to the query parameters.
/// </summary>
/// <param name="parameters">A <see cref="StorageParameters"/> with the storage information.</param>
/// <param name="query">A <see cref="QueryString"/> with the query parameters.</param>
internal void AddStorageParameter(StorageParameters parameters, ref QueryString query)
{
#pragma warning disable CA1308 // Normalize strings to uppercase
query = query.Add("forStorage", parameters.ForStorage.ToString(CultureInfo.InvariantCulture).ToLowerInvariant());
#pragma warning restore CA1308 // Normalize strings to uppercase
}

/// <summary>
/// Adds the ArcGIS token to the query parameters.
/// If the token cannot be generated, it will not be added to the request.
Expand Down
38 changes: 19 additions & 19 deletions src/Geo.Google/Services/GoogleGeocoding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,25 @@ public async Task<AutocompleteResponse<QueryAutocomplete>> QueryAutocompleteAsyn
return await CallAsync<AutocompleteResponse<QueryAutocomplete>, GoogleException>(uri, ApiName, cancellationToken).ConfigureAwait(false);
}

/// <summary>
/// Gets the ccTLD representation of a <see cref="RegionInfo"/> object.
/// </summary>
/// <param name="regionInfo">A <see cref="RegionInfo"/> with the region information to convert.</param>
/// <returns>A <see cref="string"/> with the ccTLD.</returns>
internal static string RegionInfoToCCTLD(RegionInfo regionInfo)
{
if (regionInfo.GeoId == new RegionInfo("GB").GeoId)
{
return "uk";
}
else
{
#pragma warning disable CA1308 // Normalize strings to uppercase
return regionInfo.TwoLetterISORegionName.ToLowerInvariant();
#pragma warning restore CA1308 // Normalize strings to uppercase
}
}

/// <summary>
/// Validates the uri and builds it based on the parameter type.
/// </summary>
Expand Down Expand Up @@ -759,24 +778,5 @@ internal void AddGoogleKey(ref QueryString query)
{
query = query.Add("key", _keyContainer.GetKey());
}

/// <summary>
/// Gets the ccTLD representation of a <see cref="RegionInfo"/> object.
/// </summary>
/// <param name="regionInfo">A <see cref="RegionInfo"/> with the region information to convert.</param>
/// <returns>A <see cref="string"/> with the ccTLD.</returns>
internal string RegionInfoToCCTLD(RegionInfo regionInfo)
{
if (regionInfo.GeoId == new RegionInfo("GB").GeoId)
{
return "uk";
}
else
{
#pragma warning disable CA1308 // Normalize strings to uppercase
return regionInfo.TwoLetterISORegionName.ToLowerInvariant();
#pragma warning restore CA1308 // Normalize strings to uppercase
}
}
}
}
9 changes: 8 additions & 1 deletion src/Geo.Here/Models/Parameters/AreaParameters.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,15 @@ public class AreaParameters : BaseFilterParameters
/// BFoz5xJ67i1B1B7PzIhaxL7Y
/// BFoz5xJ67i1B1B7PzIhaxL7Y; w=5000
/// BlD05xgKuy2xCCx9B7vUCl0OhnRC54EqSCzpEl-HCxjD3pBCiGnyGCi2CvwFCsgD3nDC4vB6eC;w=2000
/// These can be encoded and decoded using the python app found at https://github.com/heremaps/flexible-polyline/tree/master/python.
/// More information can be found at https://github.com/heremaps/flexible-polyline.
/// </summary>
/// <remarks>Only one of <see cref="Route"/> or <see cref="FlexiblePolyline"/> will be applied to the request. If both are present, only <see cref="FlexiblePolyline"/> will be used.</remarks>
public string Route { get; set; }

/// <summary>
/// Gets or sets the polyline information to be added as a filter.
/// </summary>
/// <remarks>Only one of <see cref="Route"/> or <see cref="FlexiblePolyline"/> will be applied to the request. If both are present, only <see cref="FlexiblePolyline"/> will be used.</remarks>
public FlexiblePolyline FlexiblePolyline { get; set; }
}
}
36 changes: 36 additions & 0 deletions src/Geo.Here/Models/Parameters/FlexiblePolyline.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// <copyright file="FlexiblePolyline.cs" company="Geo.NET">
// Copyright (c) Geo.NET.
// Licensed under the MIT license. See the LICENSE file in the solution root for full license information.
// </copyright>

namespace Geo.Here.Models.Parameters
{
using System;
using System.Collections.Generic;

/// <summary>
/// The polyline information to be added as a filter in the geocoding request.
/// </summary>
public class FlexiblePolyline
{
/// <summary>
/// Gets or sets the coordinates that make up the polyline.
/// </summary>
public IEnumerable<LatLngZ> Coordinates { get; set; } = Array.Empty<LatLngZ>();

/// <summary>
/// Gets or sets the precision of the coordinate to be encoded.
/// </summary>
public int Precision { get; set; }

/// <summary>
/// Gets or sets the third dimension, which may be a level, altitude, elevation or some other custom value.
/// </summary>
public ThirdDimension ThirdDimension { get; set; }

/// <summary>
/// Gets or sets precision for <see cref="ThirdDimension"/> value.
/// </summary>
public int ThirdDimensionPrecision { get; set; }
}
}
74 changes: 74 additions & 0 deletions src/Geo.Here/Models/Parameters/LatLngZ.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// <copyright file="LatLngZ.cs" company="Geo.NET">
// Copyright (c) Geo.NET.
// Licensed under the MIT license. See the LICENSE file in the solution root for full license information.
// </copyright>

namespace Geo.Here.Models.Parameters
{
using System;

/// <summary>
/// A coordinate triple.
/// </summary>
public class LatLngZ
{
/// <summary>
/// Initializes a new instance of the <see cref="LatLngZ"/> class.
/// </summary>
/// <param name="latitude">The latitude of the point.</param>
/// <param name="longitude">The longitude of the point.</param>
/// <param name="thirdDimension">Optional. The Z dimension of the point. Default = 0.</param>
public LatLngZ(double latitude, double longitude, double thirdDimension = 0)
{
Latitude = latitude;
Longitude = longitude;
Z = thirdDimension;
}

/// <summary>
/// Gets the latitude of the point.
/// </summary>
public double Latitude { get; }

/// <summary>
/// Gets the longitude of the point.
/// </summary>
public double Longitude { get; }

/// <summary>
/// Gets the Z dimension of the point.
/// </summary>
public double Z { get; }

/// <inheritdoc/>
public override string ToString()
{
return "LatLngZ [Latitude=" + Latitude + ", Longitude=" + Longitude + ", Z=" + Z + "]";
}

/// <inheritdoc/>
public override bool Equals(object obj)
{
if (this == obj)
{
return true;
}

if (obj is LatLngZ latLngZ)
{
if (latLngZ.Latitude == Latitude && latLngZ.Longitude == Longitude && latLngZ.Z == Z)
{
return true;
}
}

return false;
}

/// <inheritdoc/>
public override int GetHashCode()
{
return HashCode.Combine(Latitude, Longitude, Z);
}
}
}
55 changes: 55 additions & 0 deletions src/Geo.Here/Models/Parameters/ThirdDimension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// <copyright file="ThirdDimension.cs" company="Geo.NET">
// Copyright (c) Geo.NET.
// Licensed under the MIT license. See the LICENSE file in the solution root for full license information.
// </copyright>

namespace Geo.Here.Models.Parameters
{
/// <summary>
/// 3rd dimension specification.
/// Example a level, altitude, elevation or some other custom value.
/// ABSENT is default when there is no third dimension en/decoding required.
/// </summary>
public enum ThirdDimension
{
/// <summary>
/// The third dimension is absent.
/// </summary>
Absent = 0,

/// <summary>
/// The third dimension is level.
/// </summary>
Level = 1,

/// <summary>
/// The third dimension uses altitude.
/// </summary>
Altitude = 2,

/// <summary>
/// The third dimension uses elevation.
/// </summary>
Elevation = 3,

/// <summary>
/// A reserved number.
/// </summary>
Reserved1 = 4,

/// <summary>
/// A reserved number.
/// </summary>
Reserved2 = 5,

/// <summary>
/// A custom number.
/// </summary>
Custom1 = 6,

/// <summary>
/// A custom number.
/// </summary>
Custom2 = 7,
}
}
2 changes: 1 addition & 1 deletion src/Geo.Here/Resources/Services/HereGeocoding.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion src/Geo.Here/Resources/Services/HereGeocoding.en.resx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
<value>The query cannot be null or empty.</value>
</data>
<data name="Invalid Route" xml:space="preserve">
<value>The route is invalid and will not be used.</value>
<value>The route and flexible polyline are invalid and will not be used.</value>
</data>
<data name="Invalid Terms Limit" xml:space="preserve">
<value>The terms limit is invalid and will not be used.</value>
Expand Down
2 changes: 1 addition & 1 deletion src/Geo.Here/Resources/Services/HereGeocoding.resx
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
<value>The query cannot be null or empty.</value>
</data>
<data name="Invalid Route" xml:space="preserve">
<value>The route is invalid and will not be used.</value>
<value>The route and flexible polyline are invalid and will not be used.</value>
</data>
<data name="Invalid Terms Limit" xml:space="preserve">
<value>The terms limit is invalid and will not be used.</value>
Expand Down
12 changes: 11 additions & 1 deletion src/Geo.Here/Services/HereGeocoding.cs
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,17 @@ internal void AddBoundingParameters(AreaParameters parameters, ref QueryString q
_logger.HereDebug(_resourceStringProvider.GetString("Invalid In Bounding Box"));
}

if (!string.IsNullOrWhiteSpace(parameters.Route))
if (parameters.FlexiblePolyline != null)
{
var route = PolylineEncoderDecoder.Encode(
parameters.FlexiblePolyline.Coordinates,
parameters.FlexiblePolyline.Precision,
parameters.FlexiblePolyline.ThirdDimension,
parameters.FlexiblePolyline.ThirdDimensionPrecision);

query = query.Add("route", route);
}
else if (!string.IsNullOrWhiteSpace(parameters.Route))
{
query = query.Add("route", parameters.Route);
}
Expand Down
Loading

0 comments on commit 98c7dd9

Please sign in to comment.