From a94f7c7f194754782d429a469a8b75ec3c169d5d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 5 Apr 2026 20:35:02 +0000
Subject: [PATCH 01/24] refactor: replace fixed lat/lon pair contract with
N-value GetValues/CreateItem/ValuesPerItem
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- AbstractPolylineEncoder: remove GetLatitude/GetLongitude, add ValuesPerItem + GetValues(item, Span)
- AbstractPolylineDecoder: remove CreateCoordinate(lat, lon), add ValuesPerItem + CreateItem(ReadOnlyMemory)
- CoordinateDelta: generalize from lat/lon pair to N-value array with Next(ReadOnlySpan) and Deltas property
- LogDebugExtensions: rename LogDecodedCoordinateDebug → LogDecodedValuesDebug(count, position)
- Update all tests, samples, benchmarks, and utilities to new API
- Declare new protected abstract members in PublicAPI.Unshipped.txt
Agent-Logs-Url: https://github.com/petesramek/polyline-algorithm-csharp/sessions/b28a38c3-82b5-4aea-87ac-240d0503f978
Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com>
---
.../PolylineDecoderBenchmark.cs | 18 ++-
.../PolylineEncoderBenchmark.cs | 7 +-
.../NetTopologyPolylineDecoder.cs | 17 ++-
.../NetTopologyPolylineEncoder.cs | 35 +++---
.../Abstraction/AbstractPolylineDecoder.cs | 77 ++++++++----
.../Abstraction/AbstractPolylineEncoder.cs | 98 +++++++++------
.../Internal/CoordinateDelta.cs | 88 ++++++++------
.../Diagnostics/LogDebugExtensions.cs | 11 +-
src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 8 ++
.../AbstractPolylineDecoderTests.cs | 12 +-
.../AbstractPolylineEncoderTests.cs | 7 +-
.../PolylineDecoderExtensionsTests.cs | 12 +-
.../PolylineEncoderExtensionsTests.cs | 7 +-
.../Internal/CoordinateDeltaTests.cs | 112 ++++++++++++------
.../Diagnostics/LogDebugExtensionsTests.cs | 35 +++---
.../RandomValueProvider.cs | 11 +-
16 files changed, 349 insertions(+), 206 deletions(-)
diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
index f28c8141..b6b54081 100644
--- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
+++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
@@ -93,8 +93,10 @@ public void PolylineDecoder_Decode_Memory() {
}
private sealed class StringPolylineDecoder : AbstractPolylineDecoder {
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
- return (latitude, longitude);
+ protected override int ValuesPerItem => 2;
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) {
@@ -103,8 +105,10 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) {
}
private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder {
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
- return (latitude, longitude);
+ protected override int ValuesPerItem => 2;
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) {
@@ -113,8 +117,10 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) {
}
private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> {
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
- return (latitude, longitude);
+ protected override int ValuesPerItem => 2;
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) {
diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
index e0b97c5c..c4b9d5a8 100644
--- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
+++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
@@ -85,8 +85,11 @@ public void PolylineEncoder_Encode_List() {
}
private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
+ protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
- protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
+ protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
+ destination[0] = item.Latitude;
+ destination[1] = item.Longitude;
+ }
}
}
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
index d7dcb13e..dd05ca88 100644
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
@@ -14,14 +14,21 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample;
///
internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder {
///
- /// Creates a NetTopologySuite point from latitude and longitude.
+ /// Gets the number of encoded values per item: latitude (index 0) and longitude (index 1).
///
- /// Latitude value.
- /// Longitude value.
+ protected override int ValuesPerItem => 2;
+
+ ///
+ /// Creates a NetTopologySuite point from the decoded values.
+ ///
+ ///
+ /// A memory region containing two values: index 0 is latitude, index 1 is longitude.
+ ///
/// Point instance.
- protected override Point CreateCoordinate(double latitude, double longitude) {
+ protected override Point CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
// NetTopologySuite Point: x = longitude, y = latitude
- return new Point(longitude, latitude);
+ return new Point(span[1], span[0]);
}
///
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
index c6719000..5a7b5529 100644
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
@@ -7,11 +7,17 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample;
using global::NetTopologySuite.Geometries;
using PolylineAlgorithm.Abstraction;
+using System;
///
/// Polyline encoder using NetTopologySuite's Point type.
///
internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder {
+ ///
+ /// Gets the number of values per item: latitude (index 0) and longitude (index 1).
+ ///
+ protected override int ValuesPerItem => 2;
+
///
/// Creates encoded polyline string from memory.
///
@@ -26,26 +32,15 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) {
}
///
- /// Gets latitude from point.
+ /// Fills destination with latitude (index 0) and longitude (index 1) from the point.
///
- /// Point instance.
- /// Latitude value.
- protected override double GetLatitude(Point current) {
- ArgumentNullException.ThrowIfNull(current);
-
- // NetTopologySuite Point: Y = latitude
- return current.Y;
- }
-
- ///
- /// Gets longitude from point.
- ///
- /// Point instance.
- /// Longitude value.
- protected override double GetLongitude(Point current) {
- ArgumentNullException.ThrowIfNull(current);
-
- // NetTopologySuite Point: X = longitude
- return current.X;
+ /// Point instance.
+ /// Span of length 2 to fill.
+ protected override void GetValues(Point item, Span destination) {
+ ArgumentNullException.ThrowIfNull(item);
+
+ // NetTopologySuite Point: Y = latitude, X = longitude
+ destination[0] = item.Y;
+ destination[1] = item.X;
}
}
\ No newline at end of file
diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
index 1059abb9..ea087776 100644
--- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
+++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
@@ -6,19 +6,27 @@
using Microsoft.Extensions.Logging;
using PolylineAlgorithm.Internal;
using PolylineAlgorithm.Internal.Diagnostics;
+using System.Buffers;
using System.Runtime.CompilerServices;
namespace PolylineAlgorithm.Abstraction;
///
-/// Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
+/// Provides a base implementation for decoding encoded polyline strings into sequences of items.
///
///
-/// Derive from this class to implement a decoder for a specific polyline type. Override
-/// and to provide type-specific behavior.
+/// Derive from this class to implement a decoder for a specific polyline type. Override
+/// , , and to provide
+/// type-specific behavior.
+///
+/// The polyline format encodes each item as a fixed-length run of delta-compressed
+/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS decoder
+/// sets to 2 (latitude, longitude), while a 3D GPS decoder sets it to 3
+/// (latitude, longitude, altitude).
+///
///
/// The type that represents the encoded polyline input.
-/// The type that represents a decoded geographic coordinate.
+/// The type that represents a decoded item.
public abstract class AbstractPolylineDecoder : IPolylineDecoder {
private readonly ILogger> _logger;
@@ -53,6 +61,16 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
///
public PolylineEncodingOptions Options { get; }
+ ///
+ /// Gets the number of encoded values that make up a single decoded item.
+ ///
+ ///
+ /// Override this property to specify the arity of each item. For example, return 2 for
+ /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count
+ /// that matches the encoding scheme used to produce the polyline.
+ ///
+ protected abstract int ValuesPerItem { get; }
+
///
/// Decodes an encoded into a sequence of instances,
/// with support for cancellation.
@@ -64,7 +82,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
/// A that can be used to cancel the decoding operation.
///
///
- /// An of representing the decoded latitude and longitude pairs.
+ /// An of representing the decoded items.
///
///
/// Thrown when is .
@@ -90,30 +108,45 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can
ValidateSequence(sequence, _logger);
ValidateFormat(sequence, _logger);
+ int valuesPerItem = ValuesPerItem;
int position = 0;
- int encodedLatitude = 0;
- int encodedLongitude = 0;
+
+ int[]? runningRent = ArrayPool.Shared.Rent(valuesPerItem);
+ // Zero-initialize so delta decoding starts from 0 for all dimensions.
+ for (int j = 0; j < valuesPerItem; j++) {
+ runningRent[j] = 0;
+ }
try {
while (position < sequence.Length) {
cancellationToken.ThrowIfCancellationRequested();
- if (!PolylineEncoding.TryReadValue(ref encodedLatitude, sequence, ref position)
- || !PolylineEncoding.TryReadValue(ref encodedLongitude, sequence, ref position)) {
+ bool allRead = true;
+ for (int j = 0; j < valuesPerItem; j++) {
+ if (!PolylineEncoding.TryReadValue(ref runningRent[j], sequence, ref position)) {
+ allRead = false;
+ break;
+ }
+ }
+
+ if (!allRead) {
_logger?.LogOperationFailedDebug(OperationName);
_logger?.LogInvalidPolylineWarning(position);
ExceptionGuard.ThrowInvalidPolylineFormat(position);
}
- double decodedLatitude = PolylineEncoding.Denormalize(encodedLatitude, Options.Precision);
- double decodedLongitude = PolylineEncoding.Denormalize(encodedLongitude, Options.Precision);
+ double[] decoded = new double[valuesPerItem];
+ for (int j = 0; j < valuesPerItem; j++) {
+ decoded[j] = PolylineEncoding.Denormalize(runningRent[j], Options.Precision);
+ }
- _logger?.LogDecodedCoordinateDebug(decodedLatitude, decodedLongitude, position);
+ _logger?.LogDecodedValuesDebug(valuesPerItem, position);
- yield return CreateCoordinate(decodedLatitude, decodedLongitude);
+ yield return CreateItem(decoded.AsMemory());
}
} finally {
+ ArrayPool.Shared.Return(runningRent!);
_logger?.LogOperationFinishedDebug(OperationName);
}
}
@@ -188,17 +221,19 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo
protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline);
///
- /// Creates a instance from the specified latitude and longitude values.
+ /// Creates a instance from the specified decoded values.
///
- ///
- /// The latitude component of the coordinate, in degrees.
- ///
- ///
- /// The longitude component of the coordinate, in degrees.
+ ///
+ /// A of containing exactly
+ /// decoded values for this item, in the same order they were encoded.
///
///
- /// A instance representing the specified geographic coordinate.
+ /// A instance representing the decoded item.
///
+ ///
+ /// Implementations should read all required values from and construct the
+ /// immediately. The memory is valid only for the duration of this call.
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected abstract TCoordinate CreateCoordinate(double latitude, double longitude);
+ protected abstract TCoordinate CreateItem(ReadOnlyMemory values);
}
diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
index 1bcdb0ee..dff4eac3 100644
--- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
+++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
@@ -16,13 +16,19 @@ namespace PolylineAlgorithm.Abstraction;
using System.Threading;
///
-/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
+/// Provides a base implementation for encoding sequences of items into encoded polyline strings.
///
///
-/// Derive from this class to implement an encoder for a specific coordinate and polyline type. Override
-/// , , and to provide type-specific behavior.
+/// Derive from this class to implement an encoder for a specific item and polyline type. Override
+/// , , and to provide type-specific behavior.
+///
+/// The polyline format encodes each item as a fixed-length run of delta-compressed
+/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS encoder
+/// sets to 2 (latitude, longitude), while a 3D GPS encoder sets it to 3
+/// (latitude, longitude, altitude).
+///
///
-/// The type that represents a geographic coordinate to encode.
+/// The type that represents an item to encode.
/// The type that represents the encoded polyline output.
public abstract class AbstractPolylineEncoder : IPolylineEncoder {
private readonly ILogger> _logger;
@@ -56,6 +62,16 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) {
///
public PolylineEncodingOptions Options { get; }
+ ///
+ /// Gets the number of values that make up a single encoded item.
+ ///
+ ///
+ /// Override this property to specify the arity of each item. For example, return 2 for
+ /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count
+ /// that matches your encoding scheme.
+ ///
+ protected abstract int ValuesPerItem { get; }
+
///
/// Encodes a collection of instances into an encoded string.
///
@@ -88,11 +104,12 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
ValidateEmptyCoordinates(ref coordinates, _logger);
- CoordinateDelta delta = new();
+ int valuesPerItem = ValuesPerItem;
+ CoordinateDelta delta = new(valuesPerItem);
int position = 0;
int consumed = 0;
- int length = GetMaxBufferLength(coordinates.Length);
+ int length = GetMaxBufferLength(coordinates.Length, valuesPerItem);
char[]? temp = length <= Options.StackAllocLimit
? null
@@ -100,29 +117,37 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length);
+ int[]? normalizedRent = ArrayPool.Shared.Rent(valuesPerItem);
+ Span normalized = normalizedRent.AsSpan(0, valuesPerItem);
+
+ double[]? valuesRent = ArrayPool.Shared.Rent(valuesPerItem);
+ Span values = valuesRent.AsSpan(0, valuesPerItem);
+
string encodedResult;
try {
for (var i = 0; i < coordinates.Length; i++) {
cancellationToken.ThrowIfCancellationRequested();
- delta
- .Next(
- PolylineEncoding.Normalize(GetLatitude(coordinates[i]), Options.Precision),
- PolylineEncoding.Normalize(GetLongitude(coordinates[i]), Options.Precision)
- );
+ GetValues(coordinates[i], values);
+
+ for (int j = 0; j < valuesPerItem; j++) {
+ normalized[j] = PolylineEncoding.Normalize(values[j], Options.Precision);
+ }
- if (!PolylineEncoding.TryWriteValue(delta.Latitude, buffer, ref position)
- || !PolylineEncoding.TryWriteValue(delta.Longitude, buffer, ref position)
- ) {
- // This shouldn't happen, but if it does, log the error and throw an exception.
- _logger
- .LogOperationFailedDebug(OperationName);
- _logger
- .LogCannotWriteValueToBufferWarning(position, consumed);
+ delta.Next(normalized);
- ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer();
+ ReadOnlySpan deltas = delta.Deltas;
+ for (int j = 0; j < deltas.Length; j++) {
+ if (!PolylineEncoding.TryWriteValue(deltas[j], buffer, ref position)) {
+ // This shouldn't happen, but if it does, log the error and throw an exception.
+ _logger
+ .LogOperationFailedDebug(OperationName);
+ _logger
+ .LogCannotWriteValueToBufferWarning(position, consumed);
+ ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer();
+ }
}
consumed++;
@@ -130,6 +155,8 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
encodedResult = buffer[..position].ToString();
} finally {
+ ArrayPool.Shared.Return(valuesRent!);
+ ArrayPool.Shared.Return(normalizedRent!);
if (temp is not null) {
ArrayPool.Shared.Return(temp);
}
@@ -141,10 +168,10 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
return CreatePolyline(encodedResult.AsMemory());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- static int GetMaxBufferLength(int count) {
+ static int GetMaxBufferLength(int count, int perItem) {
Debug.Assert(count > 0, "Count must be greater than zero.");
- int requestedBufferLength = count * 2 * Defaults.Polyline.Block.Length.Max;
+ int requestedBufferLength = count * perItem * Defaults.Polyline.Block.Length.Max;
Debug.Assert(requestedBufferLength > 0, "Requested buffer length must be greater than zero.");
@@ -175,23 +202,18 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates,
protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline);
///
- /// Extracts the longitude value from the specified coordinate.
- ///
- /// The coordinate from which to extract the longitude.
- ///
- /// The longitude value as a .
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected abstract double GetLongitude(TCoordinate current);
-
- ///
- /// Extracts the latitude value from the specified coordinate.
+ /// Fills with the values to encode for the specified item.
///
- /// The coordinate from which to extract the latitude.
- ///
- /// The latitude value as a .
- ///
+ /// The item from which to extract values.
+ ///
+ /// A of length to fill with the item's values,
+ /// in the order they should be encoded.
+ ///
+ ///
+ /// Implementations should write exactly values into .
+ /// For example, a 2D GPS encoder writes destination[0] = latitude; destination[1] = longitude;.
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected abstract double GetLatitude(TCoordinate current);
+ protected abstract void GetValues(TCoordinate item, Span destination);
}
diff --git a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
index ae217c57..70826216 100644
--- a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
+++ b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
@@ -5,68 +5,82 @@
namespace PolylineAlgorithm.Internal;
+using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
+using System.Text;
///
-/// Represents the difference (delta) in latitude and longitude between consecutive geographic coordinates.
+/// Represents the running delta state for an arbitrary number of encoded values between consecutive items.
///
///
-/// This struct computes and stores the change in coordinate values as integer deltas between successive coordinates.
+/// This struct computes and stores the change in each value dimension as integer deltas between successive items.
+/// The number of dimensions is specified at construction time, enabling support for any number of encoded fields
+/// (e.g. latitude/longitude, latitude/longitude/altitude, or arbitrary sensor fields).
///
[DebuggerDisplay("{ToString(),nq}")]
[StructLayout(LayoutKind.Auto)]
internal struct CoordinateDelta {
- private (int Latitude, int Longitude) _current;
+ private readonly int[] _current;
+ private readonly int[] _deltas;
///
- /// Initializes a new instance of the struct with the default latitude and longitude deltas.
+ /// Initializes a new instance of the struct for the specified number of value dimensions.
///
- public CoordinateDelta() {
- _current = (default, default);
- }
+ /// The number of value dimensions to track. Must be greater than zero.
+ public CoordinateDelta(int count) {
+ Debug.Assert(count > 0, "Count must be greater than zero.");
- ///
- /// Gets the current delta in latitude between the most recent and previous coordinate.
- ///
- public int Latitude { get; private set; }
+ _current = new int[count];
+ _deltas = new int[count];
+ }
///
- /// Gets the current delta in longitude between the most recent and previous coordinate.
+ /// Gets the current deltas computed by the most recent call to .
///
- public int Longitude { get; private set; }
+ public ReadOnlySpan Deltas => _deltas;
///
- /// Updates the delta values based on the next latitude and longitude, and sets the current coordinate as next delta baseline.
+ /// Updates the delta values based on the next set of values, and sets them as the baseline for the next call.
///
- /// The next latitude value.
- /// The next longitude value.
- public void Next(int latitude, int longitude) {
- Latitude = Delta(_current.Latitude, latitude);
- Longitude = Delta(_current.Longitude, longitude);
+ ///
+ /// The next normalized integer values. Must have the same length as the count passed to the constructor.
+ ///
+ public void Next(ReadOnlySpan values) {
+ Debug.Assert(values.Length == _current.Length, "Values length must match the delta dimension count.");
- _current.Latitude = latitude;
- _current.Longitude = longitude;
+ for (int i = 0; i < values.Length; i++) {
+ _deltas[i] = values[i] - _current[i];
+ _current[i] = values[i];
+ }
}
///
- /// Calculates the delta between two coordinate values.
- ///
- ///
- /// This method computes the difference between two integer coordinate values, handling cases where the values may be positive or negative.
- ///
- /// The previous coordinate value.
- /// The next coordinate value.
- /// The computed delta between and .
- private static int Delta(int initial, int next) => next - initial;
-
- ///
- /// Returns a string representation of the current coordinate delta.
+ /// Returns a string representation of the current values and deltas.
///
///
- /// A string in the format { Coordinate: { Latitude: [int], Longitude: [int] }, Delta: { Latitude: [int], Longitude: [int] } } representing the current coordinate and deltas to previous coordinate.
+ /// A string in the format { Values: [v0, v1, ...], Deltas: [d0, d1, ...] }.
///
- public override readonly string ToString() =>
- $"{{ Coordinate: {{ Latitude: {_current.Latitude}, Longitude: {_current.Longitude} }}, " +
- $"Delta: {{ Latitude: {Latitude}, Longitude: {Longitude} }} }}";
+ public override readonly string ToString() {
+ var sb = new StringBuilder("{ Values: [");
+ for (int i = 0; i < _current.Length; i++) {
+ if (i > 0) {
+ sb.Append(", ");
+ }
+
+ sb.Append(_current[i]);
+ }
+
+ sb.Append("], Deltas: [");
+ for (int i = 0; i < _deltas.Length; i++) {
+ if (i > 0) {
+ sb.Append(", ");
+ }
+
+ sb.Append(_deltas[i]);
+ }
+
+ sb.Append("] }");
+ return sb.ToString();
+ }
}
\ No newline at end of file
diff --git a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
index cc58c702..9a422a73 100644
--- a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
+++ b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
@@ -46,12 +46,11 @@ internal static partial class LogDebugExtensions {
internal static partial void LogOperationFinishedDebug(this ILogger logger, string operationName);
///
- /// Logs a debug message containing the decoded coordinate values and position.
+ /// Logs a debug message containing the number of decoded values and position.
///
/// The used to write the log entry.
- /// The decoded latitude value.
- /// The decoded longitude value.
- /// The position in the polyline buffer at which the coordinate was decoded.
- [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}.")]
- internal static partial void LogDecodedCoordinateDebug(this ILogger logger, double latitude, double longitude, int position);
+ /// The number of values that were decoded for this item.
+ /// The position in the polyline buffer at which the item was decoded.
+ [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded {count} values at position {position}.")]
+ internal static partial void LogDecodedValuesDebug(this ILogger logger, int count, int position);
}
diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
index 7dc5c581..4033ef24 100644
--- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
+++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
@@ -1 +1,9 @@
#nullable enable
+abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.CreateItem(System.ReadOnlyMemory values) -> TCoordinate
+abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory
+abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValuesPerItem.get -> int
+abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.GetValues(TCoordinate item, System.Span destination) -> void
+abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.ValuesPerItem.get -> int
+virtual PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValidateFormat(System.ReadOnlyMemory sequence, Microsoft.Extensions.Logging.ILogger? logger) -> void
+PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void
+PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void
diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
index c6734c6c..b5a64627 100644
--- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
@@ -16,16 +16,24 @@ namespace PolylineAlgorithm.Tests.Abstraction;
[TestClass]
public sealed class AbstractPolylineDecoderTests {
private sealed class TestStringDecoder : AbstractPolylineDecoder {
+ protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
+ }
}
private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder {
public TestStringDecoderWithOptions(PolylineEncodingOptions options)
: base(options) { }
+ protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
+ }
}
///
diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
index f537dda2..1500b0de 100644
--- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
@@ -21,9 +21,12 @@ public TestStringEncoder()
public TestStringEncoder(PolylineEncodingOptions options)
: base(options) { }
+ protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
- protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
+ protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
+ destination[0] = item.Latitude;
+ destination[1] = item.Longitude;
+ }
}
///
diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
index c44c914d..069c639f 100644
--- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
@@ -17,13 +17,21 @@ namespace PolylineAlgorithm.Tests.Extensions;
[TestClass]
public sealed class PolylineDecoderExtensionsTests {
private sealed class TestStringDecoder : AbstractPolylineDecoder {
+ protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
+ }
}
private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> {
+ protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline;
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
+ }
}
// ----- Decode(char[]) for IPolylineDecoder -----
diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
index da8a622e..874f168c 100644
--- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
@@ -17,9 +17,12 @@ namespace PolylineAlgorithm.Tests.Extensions;
[TestClass]
public sealed class PolylineEncoderExtensionsTests {
private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
+ protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
- protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
+ protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
+ destination[0] = item.Latitude;
+ destination[1] = item.Longitude;
+ }
}
// ----- Encode(List) -----
diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
index 1e915fe2..03ef5e66 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
@@ -6,7 +6,6 @@
namespace PolylineAlgorithm.Tests.Internal;
using PolylineAlgorithm.Internal;
-using System.Globalization;
///
/// Tests for .
@@ -14,20 +13,22 @@ namespace PolylineAlgorithm.Tests.Internal;
[TestClass]
public sealed class CoordinateDeltaTests {
///
- /// Tests that the default constructor initializes delta values to zero.
+ /// Tests that a newly constructed instance reports all-zero deltas.
///
[TestMethod]
- public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() {
+ public void Constructor_Default_Initializes_Deltas_To_Zero() {
// Act
- CoordinateDelta delta = new();
+ CoordinateDelta delta = new(2);
// Assert
- Assert.AreEqual(0, delta.Latitude);
- Assert.AreEqual(0, delta.Longitude);
+ ReadOnlySpan deltas = delta.Deltas;
+ Assert.AreEqual(2, deltas.Length);
+ Assert.AreEqual(0, deltas[0]);
+ Assert.AreEqual(0, deltas[1]);
}
///
- /// Tests that a single call to Next computes the correct delta from the initial zero state.
+ /// Tests that a single call to Next computes the correct delta from the initial zero state for 2 values.
///
[TestMethod]
[DataRow(10, 20, 10, 20)]
@@ -35,59 +36,94 @@ public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() {
[DataRow(0, 0, 0, 0)]
[DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)]
[DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)]
- public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int longitude, int expectedLatitude, int expectedLongitude) {
+ public void Next_Single_Call_From_Zero_Computes_Expected_Delta_For_Two_Values(int v0, int v1, int expectedD0, int expectedD1) {
// Arrange
- CoordinateDelta delta = new();
+ CoordinateDelta delta = new(2);
// Act
- delta.Next(latitude, longitude);
+ delta.Next([v0, v1]);
// Assert
- Assert.AreEqual(expectedLatitude, delta.Latitude);
- Assert.AreEqual(expectedLongitude, delta.Longitude);
+ ReadOnlySpan deltas = delta.Deltas;
+ Assert.AreEqual(expectedD0, deltas[0]);
+ Assert.AreEqual(expectedD1, deltas[1]);
}
///
- /// Tests that two consecutive calls to Next compute the delta relative to the previous value.
+ /// Tests that two consecutive calls to Next compute the delta relative to the previous value for 2 values.
///
[TestMethod]
[DataRow(10, 20, 15, 30, 5, 10)]
[DataRow(100, 200, 50, 150, -50, -50)]
[DataRow(42, 84, 42, 84, 0, 0)]
[DataRow(-50, 100, 25, -75, 75, -175)]
- public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value(
- int firstLatitude, int firstLongitude,
- int secondLatitude, int secondLongitude,
- int expectedLatitude, int expectedLongitude) {
+ public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value_For_Two_Values(
+ int first0, int first1,
+ int second0, int second1,
+ int expectedD0, int expectedD1) {
// Arrange
- CoordinateDelta delta = new();
- delta.Next(firstLatitude, firstLongitude);
+ CoordinateDelta delta = new(2);
+ delta.Next([first0, first1]);
// Act
- delta.Next(secondLatitude, secondLongitude);
+ delta.Next([second0, second1]);
// Assert
- Assert.AreEqual(expectedLatitude, delta.Latitude);
- Assert.AreEqual(expectedLongitude, delta.Longitude);
+ ReadOnlySpan deltas = delta.Deltas;
+ Assert.AreEqual(expectedD0, deltas[0]);
+ Assert.AreEqual(expectedD1, deltas[1]);
}
///
- /// Tests that ToString on a default instance returns a string containing expected structural keywords and a zero value.
+ /// Tests that Next works correctly for a single value dimension.
+ ///
+ [TestMethod]
+ public void Next_Single_Dimension_Computes_Correct_Delta() {
+ // Arrange
+ CoordinateDelta delta = new(1);
+ delta.Next([100]);
+
+ // Act
+ delta.Next([150]);
+
+ // Assert
+ Assert.AreEqual(50, delta.Deltas[0]);
+ }
+
+ ///
+ /// Tests that Next works correctly for three value dimensions.
+ ///
+ [TestMethod]
+ public void Next_Three_Dimensions_Computes_Correct_Deltas() {
+ // Arrange
+ CoordinateDelta delta = new(3);
+ delta.Next([10, 20, 30]);
+
+ // Act
+ delta.Next([15, 25, 25]);
+
+ // Assert
+ ReadOnlySpan deltas = delta.Deltas;
+ Assert.AreEqual(5, deltas[0]);
+ Assert.AreEqual(5, deltas[1]);
+ Assert.AreEqual(-5, deltas[2]);
+ }
+
+ ///
+ /// Tests that ToString on a default instance returns a non-null string containing structural keywords.
///
[TestMethod]
public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zeros() {
// Arrange
- CoordinateDelta delta = new();
+ CoordinateDelta delta = new(2);
// Act
string result = delta.ToString();
// Assert
Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains("Coordinate", StringComparison.Ordinal));
- Assert.IsTrue(result.Contains("Delta", StringComparison.Ordinal));
- Assert.IsTrue(result.Contains("Latitude", StringComparison.Ordinal));
- Assert.IsTrue(result.Contains("Longitude", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Values", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Deltas", StringComparison.Ordinal));
Assert.Contains('0', result);
}
@@ -97,20 +133,18 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero
[TestMethod]
[DataRow(42, 84)]
[DataRow(-100, -200)]
- [DataRow(int.MaxValue, int.MaxValue)]
- [DataRow(int.MinValue, int.MinValue)]
- public void ToString_After_Next_Contains_Expected_Values(int latitude, int longitude) {
+ public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) {
// Arrange
- CoordinateDelta delta = new();
- delta.Next(latitude, longitude);
+ CoordinateDelta delta = new(2);
+ delta.Next([v0, v1]);
// Act
string result = delta.ToString();
// Assert
Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains(latitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
- Assert.IsTrue(result.Contains(longitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains(v0.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains(v1.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal));
}
///
@@ -119,9 +153,9 @@ public void ToString_After_Next_Contains_Expected_Values(int latitude, int longi
[TestMethod]
public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() {
// Arrange
- CoordinateDelta delta = new();
- delta.Next(10, 20);
- delta.Next(30, 50);
+ CoordinateDelta delta = new(2);
+ delta.Next([10, 20]);
+ delta.Next([30, 50]);
// Act
string result = delta.ToString();
@@ -132,5 +166,5 @@ public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Lat
Assert.IsTrue(result.Contains("50", StringComparison.Ordinal));
Assert.IsTrue(result.Contains("20", StringComparison.Ordinal));
}
-
}
+
diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
index 0dff7193..c9daaa1f 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
@@ -80,20 +80,21 @@ public void LogOperationFinishedDebug_With_Operation_Name_Logs_Finished_Message(
}
///
- /// Tests that LogDecodedCoordinateDebug WithCoordinatesAndPosition LogsDecodedCoordinateMessage.
+ /// Tests that LogDecodedValuesDebug WithCountAndPosition LogsDecodedValuesMessage.
///
[TestMethod]
- public void LogDecodedCoordinateDebug_With_Coordinates_And_Position_Logs_Decoded_Coordinate_Message() {
+ public void LogDecodedValuesDebug_With_Count_And_Position_Logs_Decoded_Values_Message() {
var logger = new TestLogger();
- const double latitude = 38.5;
- const double longitude = -120.2;
+ const int count = 2;
const int position = 42;
- logger.LogDecodedCoordinateDebug(latitude, longitude, position);
+ logger.LogDecodedValuesDebug(count, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}."), logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains(position.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
}
///
@@ -142,37 +143,35 @@ public void LogOperationFinishedDebug_With_Null_Operation_Name_Logs_Message() {
}
///
- /// Tests that LogDecodedCoordinateDebug WithZeroCoordinates LogsMessage.
+ /// Tests that LogDecodedValuesDebug WithZeroCountAndPosition LogsMessage.
///
[TestMethod]
- public void LogDecodedCoordinateDebug_With_Zero_Coordinates_Logs_Message() {
+ public void LogDecodedValuesDebug_With_Zero_Count_Logs_Message() {
var logger = new TestLogger();
- const double latitude = 0.0;
- const double longitude = 0.0;
+ const int count = 0;
const int position = 0;
- logger.LogDecodedCoordinateDebug(latitude, longitude, position);
+ logger.LogDecodedValuesDebug(count, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains("Decoded coordinate", logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal);
}
///
- /// Tests that LogDecodedCoordinateDebug WithNegativeCoordinates LogsMessage.
+ /// Tests that LogDecodedValuesDebug WithLargeCount LogsMessage.
///
[TestMethod]
- public void LogDecodedCoordinateDebug_With_Negative_Coordinates_Logs_Message() {
+ public void LogDecodedValuesDebug_With_Large_Count_Logs_Message() {
var logger = new TestLogger();
- const double latitude = -90.0;
- const double longitude = -180.0;
+ const int count = 5;
const int position = 100;
- logger.LogDecodedCoordinateDebug(latitude, longitude, position);
+ logger.LogDecodedValuesDebug(count, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Latitude: {latitude}, Longitude: {longitude}"), logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
}
///
diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
index d3d83b9e..0ca40426 100644
--- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
+++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
@@ -105,16 +105,15 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat
private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
+ protected override int ValuesPerItem => 2;
+
protected override string CreatePolyline(ReadOnlyMemory polyline) {
return polyline.ToString();
}
- protected override double GetLatitude((double Latitude, double Longitude) current) {
- return current.Latitude;
- }
-
- protected override double GetLongitude((double Latitude, double Longitude) current) {
- return current.Longitude;
+ protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
+ destination[0] = item.Latitude;
+ destination[1] = item.Longitude;
}
}
}
\ No newline at end of file
From 89a6a24401b883dcfdec0d69a8237b3e41a42c02 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Sun, 5 Apr 2026 22:01:10 +0000
Subject: [PATCH 02/24] reset: revert all previous changes, clean slate
identical to main
Co-authored-by: petesramek <2333452+petesramek@users.noreply.github.com>
---
.editorconfig | 3 -
.github/CODEOWNERS | 5 -
.github/ISSUE_TEMPLATE/bug_report.md | 32 +-
.github/ISSUE_TEMPLATE/config.yml | 5 -
.github/ISSUE_TEMPLATE/feature_request.md | 4 +-
.github/PULL_REQUEST_TEMPLATE.md | 19 -
.github/actions/source/compile/action.yml | 2 +-
.github/dependabot.yml | 12 -
.github/release.yml | 23 -
.github/workflows/build.yml | 2 +-
.github/workflows/publish-documentation.yml | 21 +-
.github/workflows/pull-request.yml | 47 +-
.github/workflows/release.yml | 202 +------
CHANGELOG.md | 10 -
CODE_OF_CONDUCT.md | 47 --
Directory.Build.props | 3 -
PolylineAlgorithm.slnx | 1 -
README.md | 81 +--
SECURITY.md | 23 -
....Abstraction.AbstractPolylineDecoder-2.yml | 233 --------
....Abstraction.AbstractPolylineEncoder-2.yml | 219 --------
...gorithm.Abstraction.IPolylineDecoder-2.yml | 90 ---
...gorithm.Abstraction.IPolylineEncoder-2.yml | 142 -----
.../0.0/PolylineAlgorithm.Abstraction.yml | 34 --
...m.Extensions.PolylineDecoderExtensions.yml | 195 -------
...m.Extensions.PolylineEncoderExtensions.yml | 139 -----
.../0.0/PolylineAlgorithm.Extensions.yml | 19 -
...lineAlgorithm.InvalidPolylineException.yml | 102 ----
.../PolylineAlgorithm.PolylineEncoding.yml | 529 ------------------
...ylineAlgorithm.PolylineEncodingOptions.yml | 127 -----
...gorithm.PolylineEncodingOptionsBuilder.yml | 141 -----
api-reference/0.0/PolylineAlgorithm.yml | 38 --
api-reference/0.0/toc.yml | 34 --
api-reference/guide/benchmarks.md | 11 -
api-reference/guide/toc.yml | 2 -
.../PolylineDecoderBenchmark.cs | 18 +-
.../PolylineEncoderBenchmark.cs | 7 +-
docs/local-development.md | 21 -
docs/workflows.md | 1 -
.../NetTopologyPolylineDecoder.cs | 19 +-
.../NetTopologyPolylineEncoder.cs | 41 +-
...neAlgorithm.NetTopologySuite.Sample.csproj | 3 +-
.../Program.cs | 46 --
...PolylineAlgorithm.SensorData.Sample.csproj | 16 -
.../Program.cs | 49 --
.../Properties/CodeCoverage.cs | 8 -
.../SensorDataDecoder.cs | 107 ----
.../SensorDataEncoder.cs | 135 -----
.../SensorReading.cs | 16 -
.../Abstraction/AbstractPolylineDecoder.cs | 77 +--
.../Abstraction/AbstractPolylineEncoder.cs | 98 ++--
.../Internal/CoordinateDelta.cs | 88 ++-
.../Diagnostics/LogDebugExtensions.cs | 11 +-
.../PolylineAlgorithm.csproj | 7 -
src/PolylineAlgorithm/PolylineEncoding.cs | 7 +-
src/PolylineAlgorithm/PublicAPI.Shipped.txt | 2 +-
src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 8 -
src/PolylineAlgorithm/README.md | 30 +-
.../AbstractPolylineDecoderTests.cs | 12 +-
.../AbstractPolylineEncoderTests.cs | 7 +-
.../PolylineDecoderExtensionsTests.cs | 12 +-
.../PolylineEncoderExtensionsTests.cs | 7 +-
.../Internal/CoordinateDeltaTests.cs | 112 ++--
.../Diagnostics/LogDebugExtensionsTests.cs | 35 +-
.../RandomValueProvider.cs | 11 +-
65 files changed, 334 insertions(+), 3274 deletions(-)
delete mode 100644 .github/CODEOWNERS
delete mode 100644 .github/ISSUE_TEMPLATE/config.yml
delete mode 100644 .github/PULL_REQUEST_TEMPLATE.md
delete mode 100644 .github/release.yml
delete mode 100644 CHANGELOG.md
delete mode 100644 CODE_OF_CONDUCT.md
delete mode 100644 SECURITY.md
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.yml
delete mode 100644 api-reference/0.0/toc.yml
delete mode 100644 api-reference/guide/benchmarks.md
delete mode 100644 samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs
delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj
delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/Program.cs
delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs
delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs
delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs
delete mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs
diff --git a/.editorconfig b/.editorconfig
index 7282c0f7..75d9084f 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -274,6 +274,3 @@ dotnet_naming_style.underscore_camel_case.capitalization = camel_case
# Public API analyzer
dotnet_public_api_analyzer.require_api_files = true
-
-# RS0017: Symbol removed from public API - error severity (IDE guidance; build enforcement via WarningsAsErrors in .csproj)
-dotnet_diagnostic.RS0017.severity = error
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
deleted file mode 100644
index 880b45f7..00000000
--- a/.github/CODEOWNERS
+++ /dev/null
@@ -1,5 +0,0 @@
-* @petesramek
-
-.github/ @petesramek
-src/ @petesramek
-tests/ @petesramek
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 6236e3a0..dd84ea78 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,8 +1,8 @@
---
name: Bug report
about: Create a report to help us improve
-title: '[Bug]: '
-labels: 'bug'
+title: ''
+labels: ''
assignees: ''
---
@@ -11,22 +11,28 @@ assignees: ''
A clear and concise description of what the bug is.
**To Reproduce**
-Minimal code snippet that reproduces the issue:
-
-```csharp
-// paste reproduction code here
-```
+Steps to reproduce the behavior:
+1. Go to '...'
+2. Click on '....'
+3. Scroll down to '....'
+4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
-**Actual behavior**
-A clear and concise description of what actually happens (include exception messages/stack traces if applicable).
+**Screenshots**
+If applicable, add screenshots to help explain your problem.
+
+**Desktop (please complete the following information):**
+ - OS: [e.g. iOS]
+ - Browser [e.g. chrome, safari]
+ - Version [e.g. 22]
-**Environment**
- - Package version: [e.g. 2.1.0]
- - .NET version: [e.g. net8.0]
- - OS: [e.g. Windows 11, Ubuntu 24.04]
+**Smartphone (please complete the following information):**
+ - Device: [e.g. iPhone6]
+ - OS: [e.g. iOS8.1]
+ - Browser [e.g. stock browser, safari]
+ - Version [e.g. 22]
**Additional context**
Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
deleted file mode 100644
index 2afb950d..00000000
--- a/.github/ISSUE_TEMPLATE/config.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-blank_issues_enabled: false
-contact_links:
- - name: Ask a question
- url: https://github.com/petesramek/polyline-algorithm-csharp/discussions
- about: Use GitHub Discussions for questions, ideas, or general feedback.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index 5c8a425a..bbcbbe7d 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,8 +1,8 @@
---
name: Feature request
about: Suggest an idea for this project
-title: '[Feature]: '
-labels: 'enhancement'
+title: ''
+labels: ''
assignees: ''
---
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
deleted file mode 100644
index 70eda657..00000000
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ /dev/null
@@ -1,19 +0,0 @@
-## Summary
-
-
-
-## Type of change
-
-- [ ] Bug fix
-- [ ] New feature
-- [ ] Breaking change
-- [ ] Documentation / samples only
-
-## Checklist
-
-- [ ] Unit tests added or updated (`/tests`)
-- [ ] Benchmarks added or updated (`/benchmarks`) — if performance-impacting
-- [ ] XML doc comments updated for all public API changes
-- [ ] `dotnet format` run with no issues
-- [ ] README and `/samples` updated — if public API changed
-- [ ] PR label added (`breaking` / `feat` / `fix` / `docs`) — for changelog categorization
diff --git a/.github/actions/source/compile/action.yml b/.github/actions/source/compile/action.yml
index dbe88dd5..0af331ee 100644
--- a/.github/actions/source/compile/action.yml
+++ b/.github/actions/source/compile/action.yml
@@ -12,7 +12,7 @@ inputs:
file-version:
description: 'Assembly file version.'
required: true
- treat-warnings-as-error:
+ treat-warnins-as-error:
description: 'Treat warnings as errors.'
required: true
project-path:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index b00ae422..02a54502 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,23 +4,11 @@ updates:
directory: "/"
schedule:
interval: "weekly"
- labels:
- - "dependencies"
- assignees:
- - "petesramek"
- package-ecosystem: "nuget"
directory: "/"
schedule:
interval: "weekly"
- labels:
- - "dependencies"
- assignees:
- - "petesramek"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
- labels:
- - "dependencies"
- assignees:
- - "petesramek"
diff --git a/.github/release.yml b/.github/release.yml
deleted file mode 100644
index e7b05735..00000000
--- a/.github/release.yml
+++ /dev/null
@@ -1,23 +0,0 @@
-changelog:
- exclude:
- labels:
- - ignore-for-release
- categories:
- - title: Breaking Changes
- labels:
- - breaking
- - title: New Features
- labels:
- - feat
- - enhancement
- - title: Bug Fixes
- labels:
- - fix
- - bug
- - title: Documentation
- labels:
- - docs
- - documentation
- - title: Other Changes
- labels:
- - '*'
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 5abb7df8..047d4afd 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -130,7 +130,7 @@ jobs:
assembly-version: ${{ env.assembly-version }}
assembly-informational-version: ${{ env.assembly-informational-version }}
file-version: ${{ env.file-version }}
- treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }}
+ treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }}
test:
name: 'Run tests'
diff --git a/.github/workflows/publish-documentation.yml b/.github/workflows/publish-documentation.yml
index 7f01504d..85d8f21a 100644
--- a/.github/workflows/publish-documentation.yml
+++ b/.github/workflows/publish-documentation.yml
@@ -96,21 +96,6 @@ jobs:
run: |
cp -r api-reference/guide api-reference/${{ env.friendly-version }}/guide
- - name: 'Download benchmark results'
- uses: actions/download-artifact@v8
- with:
- pattern: benchmark-*
- path: /tmp/benchmarks
- merge-multiple: true
-
- - name: 'Inject benchmark results into guide for v${{ env.friendly-version }}'
- shell: bash
- run: |
- find /tmp/benchmarks -name "*-report-github.md" | sort | xargs -r cat > /tmp/benchmark_results.md
- awk '/{benchmarks_section}/{while((getline line < "/tmp/benchmark_results.md") > 0) print line; close("/tmp/benchmark_results.md"); next} {print}' \
- "api-reference/${{ env.friendly-version }}/guide/benchmarks.md" > /tmp/benchmarks.md
- mv /tmp/benchmarks.md "api-reference/${{ env.friendly-version }}/guide/benchmarks.md"
-
- name: 'Discover all versions'
id: discover-versions
shell: bash
@@ -166,15 +151,15 @@ jobs:
{
echo "## Released Versions"
echo ""
- echo "| Version | Guide | API Reference | Release Notes |"
- echo "|---------|-------|---------------|---------------|"
+ echo "| Version | Guide | API Reference |"
+ echo "|---------|-------|---------------|"
for ver in $(echo "${{ steps.discover-versions.outputs.versions }}" | tr ',' '\n' | sort -Vr); do
if [ "$ver" = "$latest" ]; then
label="v${ver} (latest)"
else
label="v${ver}"
fi
- echo "| ${label} | [Guide](${ver}/guide/getting-started.html) | [API Reference](${ver}/PolylineAlgorithm.html) | [Release Notes](https://github.com/petesramek/polyline-algorithm-csharp/releases/tag/v${ver}) |"
+ echo "| ${label} | [Guide](${ver}/guide/getting-started.html) | [API Reference](${ver}/PolylineAlgorithm.html) |"
done
} > /tmp/versions_section.md
awk '/{versions_section}/{while((getline line < "/tmp/versions_section.md") > 0) print line; close("/tmp/versions_section.md"); next} {print}' \
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index c99f254d..4f8917b0 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -18,8 +18,8 @@ permissions:
id-token: write
contents: write
-concurrency:
- group: pull-request-${{ github.head_ref || github.ref }}
+concurrency:
+ group: pull-request-${{ github.head_ref || github.ref }}
cancel-in-progress: true
env:
@@ -120,7 +120,7 @@ jobs:
assembly-version: ${{ env.assembly-version }}
assembly-informational-version: ${{ env.assembly-informational-version }}
file-version: ${{ env.file-version }}
- treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }}
+ treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }}
test:
name: 'Run tests'
@@ -189,7 +189,7 @@ jobs:
- name: Pack with .NET
run: |
dotnet pack ${{ vars.SRC_DEFAULT_GLOB_PATTERN }} --configuration ${{ env.build-configuration }} /p:Platform="${{ env.build-platform }}" /p:PackageVersion=${{ env.release-version }} /p:Version=${{ env.assembly-version }} /p:AssemblyInformationalVersion=${{ env.assembly-informational-version }} /p:FileVersion=${{ env.file-version }} --output ${{ runner.temp }}/${{ env.nuget-packages-directory }}
-
+
- name: Upload Package
uses: actions/upload-artifact@v7
with:
@@ -222,20 +222,39 @@ jobs:
nuget-feed-api-key: ${{ secrets.NUGET_PACKAGE_FEED_API_KEY }}
nuget-feed-server: 'AzureArtifacts'
working-directory: ${{ runner.temp }}/${{ env.nuget-packages-directory }}
- dotnet-sdk-version: ${{ env.dotnet-sdk-version }}
+ dotnet-sdk-version: ${{ env.dotnet-sdk-version }}'
- security:
- name: 'Check for vulnerable packages'
+ benchmark:
+ if: ${{ github.env.is_release || vars.BENCHMARKDOTNET_RUN_OVERRIDE == 'true' }}
+ name: Benchmark with .NET CLI on ${{ matrix.os }}
needs: [build]
- runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ os: [ubuntu-latest, windows-latest, macos-latest]
+ runs-on: ${{ matrix.os }}
steps:
- name: 'Checkout ${{ github.head_ref || github.ref }}'
uses: actions/checkout@v6
-
- - name: 'Setup .NET'
+ - name: Install .NET SDK
uses: actions/setup-dotnet@v5
with:
- dotnet-version: ${{ env.dotnet-sdk-version }}
-
- - name: 'Check for vulnerable packages'
- run: dotnet list src/PolylineAlgorithm/PolylineAlgorithm.csproj package --vulnerable --include-transitive
+ dotnet-version: |
+ 8.x
+ 10.x
+ - name: Download Build
+ uses: actions/download-artifact@v8
+ with:
+ name: build
+ - name: Benchmark
+ working-directory: ${{ vars.BENCHMARKDOTNET_WORKING_DIRECTORY }}
+ run: dotnet run --configuration ${{ env.build-configuration }} /p:Platform=${{ env.build-platform }} --framework ${{ vars.DEFAULT_BUILD_FRAMEWORK }} --runtimes ${{ vars.BENCHMARKDOTNET_RUNTIMES }} --filter ${{ vars.BENCHMARKDOTNET_FILTER }} --artifacts ${{ runner.temp }}/benchmarks/ --exporters GitHub --memory --iterationTime 100 --join
+ - name: Upload Benchmark Results
+ uses: actions/upload-artifact@v7
+ with:
+ name: benchmark-${{ matrix.os }}
+ path: |
+ ${{ runner.temp }}/benchmarks/**/*-report-github.md
+ - name: Write Benchmark Summary
+ shell: bash
+ run: cat **/*-report-github.md > $GITHUB_STEP_SUMMARY
+ working-directory: ${{ runner.temp }}/benchmarks/
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index b0bd5699..0d2808a8 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -129,7 +129,7 @@ jobs:
assembly-version: ${{ env.assembly-version }}
assembly-informational-version: ${{ env.assembly-informational-version }}
file-version: ${{ env.file-version }}
- treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }}
+ treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }}
test:
name: 'Run tests'
@@ -169,89 +169,6 @@ jobs:
- name: Write code coverage report summary
run: cat ${{ steps.code-coverage-report.outputs.code-coverage-report-file }} >> $GITHUB_STEP_SUMMARY
- update-api-unshipped:
- name: 'Update PublicAPI.Unshipped.txt'
- needs: [workflow-variables, validate-release]
- # Run even when build fails — the build may fail solely because a dropped preview API is still
- # listed in Unshipped.txt (RS0017). This job fixes exactly that, so it must not be gated on build.
- if: ${{ needs.workflow-variables.outputs.is-preview == 'true' && needs.validate-release.result == 'success' }}
- runs-on: ubuntu-latest
- steps:
- - name: 'Checkout ${{ github.ref }}'
- uses: actions/checkout@v6
-
- - name: 'Setup .NET'
- uses: actions/setup-dotnet@v5
- with:
- dotnet-version: ${{ env.dotnet-sdk-version }}
-
- - name: 'Snapshot PublicAPI.Shipped.txt'
- shell: bash
- run: cp src/PolylineAlgorithm/PublicAPI.Shipped.txt src/PolylineAlgorithm/PublicAPI.Shipped.txt.bak
-
- - name: 'Sync PublicAPI.Unshipped.txt (add new + remove dropped preview APIs)'
- shell: bash
- run: dotnet format analyzers src/PolylineAlgorithm/PolylineAlgorithm.csproj --diagnostics RS0016 RS0017
-
- - name: 'Guard against accidental shipped API removal'
- shell: bash
- run: |
- SHIPPED="src/PolylineAlgorithm/PublicAPI.Shipped.txt"
- if ! diff -q "$SHIPPED" "$SHIPPED.bak" > /dev/null 2>&1; then
- echo "::error::Breaking change detected — a shipped API was removed from PublicAPI.Shipped.txt."
- echo "::error::This requires a major version bump. Reverting the unintended change."
- cp "$SHIPPED.bak" "$SHIPPED"
- exit 1
- fi
- rm -f "$SHIPPED.bak"
-
- - name: 'Configure git identity'
- uses: './.github/actions/git/configure-identity'
-
- - name: 'Commit and push updated API files'
- shell: bash
- run: |
- git add src/PolylineAlgorithm/PublicAPI.Unshipped.txt
- git diff --staged --quiet || (
- git commit -m "Sync PublicAPI.Unshipped.txt (add new, remove dropped preview APIs)" &&
- git pull --rebase origin ${{ github.ref_name }} &&
- git push
- )
-
- promote-api-files:
- name: 'Promote PublicAPI files (Unshipped -> Shipped)'
- needs: [workflow-variables, test, validate-release]
- if: ${{ needs.workflow-variables.outputs.is-release == 'true' }}
- runs-on: ubuntu-latest
- steps:
- - name: 'Checkout ${{ github.ref }}'
- uses: actions/checkout@v6
-
- - name: 'Promote Unshipped.txt into Shipped.txt'
- shell: bash
- run: |
- UNSHIPPED="src/PolylineAlgorithm/PublicAPI.Unshipped.txt"
- SHIPPED="src/PolylineAlgorithm/PublicAPI.Shipped.txt"
-
- # Append every non-blank, non-header line from Unshipped into Shipped
- tail -n +2 "$UNSHIPPED" | grep -v '^[[:space:]]*$' >> "$SHIPPED" || true
-
- # Reset Unshipped to just the nullable-enable header (with BOM to match convention)
- printf '\xef\xbb\xbf#nullable enable\n' > "$UNSHIPPED"
-
- - name: 'Configure git identity'
- uses: './.github/actions/git/configure-identity'
-
- - name: 'Commit and push promoted API files'
- shell: bash
- run: |
- git add src/PolylineAlgorithm/PublicAPI.Shipped.txt src/PolylineAlgorithm/PublicAPI.Unshipped.txt
- git diff --staged --quiet || (
- git commit -m "Promote PublicAPI.Unshipped.txt into PublicAPI.Shipped.txt for release" &&
- git pull --rebase origin ${{ github.ref_name }} &&
- git push
- )
-
pack:
name: 'Package binaries'
needs: [versioning, build, test, validate-release]
@@ -290,44 +207,9 @@ jobs:
${{ runner.temp }}/${{ env.nuget-packages-directory }}/**/*.nupkg
${{ runner.temp }}/${{ env.nuget-packages-directory }}/**/*.snupkg
- benchmark:
- name: Benchmark with .NET CLI on ${{ matrix.os }}
- needs: [workflow-variables, build, validate-release]
- if: ${{ needs.workflow-variables.outputs.is-release == 'true' || vars.BENCHMARKDOTNET_RUN_OVERRIDE == 'true' }}
- strategy:
- matrix:
- os: [ubuntu-latest, windows-latest, macos-latest]
- runs-on: ${{ matrix.os }}
- steps:
- - name: 'Checkout ${{ github.head_ref || github.ref }}'
- uses: actions/checkout@v6
- - name: Install .NET SDK
- uses: actions/setup-dotnet@v5
- with:
- dotnet-version: |
- 8.x
- 10.x
- - name: Download Build
- uses: actions/download-artifact@v8
- with:
- name: build
- - name: Benchmark
- working-directory: ${{ vars.BENCHMARKDOTNET_WORKING_DIRECTORY }}
- run: dotnet run --configuration ${{ env.build-configuration }} /p:Platform=${{ env.build-platform }} --framework ${{ vars.DEFAULT_BUILD_FRAMEWORK }} --runtimes ${{ vars.BENCHMARKDOTNET_RUNTIMES }} --filter ${{ vars.BENCHMARKDOTNET_FILTER }} --artifacts ${{ runner.temp }}/benchmarks/ --exporters GitHub --memory --iterationTime 100 --join
- - name: Upload Benchmark Results
- uses: actions/upload-artifact@v7
- with:
- name: benchmark-${{ matrix.os }}
- path: |
- ${{ runner.temp }}/benchmarks/**/*-report-github.md
- - name: Write Benchmark Summary
- shell: bash
- run: cat **/*-report-github.md > $GITHUB_STEP_SUMMARY
- working-directory: ${{ runner.temp }}/benchmarks/
-
publish-documentation:
name: 'Publish documentation'
- needs: [pack, benchmark, validate-release, workflow-variables]
+ needs: [pack, validate-release, workflow-variables]
if: ${{ needs.workflow-variables.outputs.is-release == 'true' }}
uses: ./.github/workflows/publish-documentation.yml
permissions:
@@ -337,14 +219,8 @@ jobs:
publish-package:
name: 'Publish package'
- needs: [pack, validate-release, publish-documentation, update-api-unshipped, promote-api-files]
- if: |
- always() &&
- needs.pack.result == 'success' &&
- needs.validate-release.result == 'success' &&
- (needs.publish-documentation.result == 'success' || needs.publish-documentation.result == 'skipped') &&
- (needs.promote-api-files.result == 'success' || needs.promote-api-files.result == 'skipped') &&
- (needs.update-api-unshipped.result == 'success' || needs.update-api-unshipped.result == 'skipped')
+ needs: [pack, validate-release, publish-documentation]
+ if: ${{ always() && needs.pack.result == 'success' && needs.validate-release.result == 'success' && (needs.publish-documentation.result == 'success' || needs.publish-documentation.result == 'skipped') }}
env:
package-artifact-name: ${{ needs.pack.outputs.package-artifact-name }}
runs-on: ubuntu-latest
@@ -396,68 +272,9 @@ jobs:
is-preview: ${{ env.is-preview }}
notes-start-tag: ${{ steps.determine-notes-start-tag.outputs.notes-start-tag }}
- update-changelog:
- name: 'Update CHANGELOG.md'
- needs: [workflow-variables, release, versioning]
- if: ${{ needs.workflow-variables.outputs.is-release == 'true' }}
- runs-on: ubuntu-latest
- env:
- GH_TOKEN: ${{ github.token }}
- release-version: ${{ needs.versioning.outputs.release-version }}
- steps:
- - name: 'Checkout ${{ github.ref }}'
- uses: actions/checkout@v6
- with:
- ref: ${{ github.ref }}
-
- - name: 'Fetch release notes'
- shell: bash
- run: |
- gh release view ${{ env.release-version }} --json body --jq '.body' > /tmp/release-notes.txt
-
- - name: 'Prepend entry to CHANGELOG.md'
- shell: bash
- run: |
- release_date=$(date -u +%Y-%m-%d)
- {
- echo "## ${{ env.release-version }} — ${release_date}"
- echo ""
- cat /tmp/release-notes.txt
- echo ""
- } > /tmp/new-entry.txt
- awk '
- // {
- print
- print ""
- while ((getline line < "/tmp/new-entry.txt") > 0) print line
- close("/tmp/new-entry.txt")
- next
- }
- { print }
- ' CHANGELOG.md > /tmp/changelog-new.md
- mv /tmp/changelog-new.md CHANGELOG.md
-
- - name: 'Configure git identity'
- uses: './.github/actions/git/configure-identity'
-
- - name: 'Commit and push CHANGELOG.md'
- shell: bash
- run: |
- git add CHANGELOG.md
- git diff --staged --quiet || (
- git commit -m "Update CHANGELOG.md for ${{ env.release-version }}" &&
- git pull --rebase origin ${{ github.ref_name }} &&
- git push
- )
-
- - name: 'Write changelog summary'
- shell: bash
- run: |
- echo "✅ CHANGELOG.md updated for **${{ env.release-version }}**." >> $GITHUB_STEP_SUMMARY
-
merge-to-main:
name: 'Merge ${{ github.ref_name }} into main'
- needs: [workflow-variables, release, versioning, update-changelog]
+ needs: [workflow-variables, release, versioning]
if: ${{ needs.workflow-variables.outputs.is-release == 'true' }}
runs-on: ubuntu-latest
permissions:
@@ -554,10 +371,17 @@ jobs:
git checkout -b "${{ steps.resolve-support-branch.outputs.support-branch }}"
git push --set-upstream origin "${{ steps.resolve-support-branch.outputs.support-branch }}"
+ - name: 'Lock support branch'
+ if: ${{ steps.check-support-branch.outputs.support-branch-exists == 'false' }}
+ uses: './.github/actions/github/branch-protection/lock'
+ with:
+ branch: ${{ steps.resolve-support-branch.outputs.support-branch }}
+ token: ${{ secrets.GH_ADMIN_TOKEN }}
+
- name: 'Write support branch summary'
run: |
if [[ "${{ steps.check-support-branch.outputs.support-branch-exists }}" == "false" ]]; then
- echo "✅ Created support branch **${{ steps.resolve-support-branch.outputs.support-branch }}**." >> $GITHUB_STEP_SUMMARY
+ echo "✅ Created and locked support branch **${{ steps.resolve-support-branch.outputs.support-branch }}**." >> $GITHUB_STEP_SUMMARY
else
echo "⏭️ Support branch **${{ steps.resolve-support-branch.outputs.support-branch }}** already exists." >> $GITHUB_STEP_SUMMARY
fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index 9264cdaa..00000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Changelog
-
-All notable changes to this project will be documented in this file.
-
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
-and release notes are generated automatically from merged pull requests.
-
-See all releases at:
-
-
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
deleted file mode 100644
index d0b9d1d8..00000000
--- a/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,47 +0,0 @@
-# Contributor Covenant Code of Conduct
-
-## Our Commitment
-
-We are committed to providing a welcoming and inspiring community for all. We pledge to create an environment in which every individual feels valued, respected, and free from harassment and discrimination.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment include:
-
-- Using welcoming and inclusive language
-- Being respectful of differing opinions, viewpoints, and experiences
-- Gracefully accepting constructive criticism
-- Focusing on what is best for the community
-- Showing empathy towards other community members
-
-Examples of unacceptable behavior include:
-
-- The use of sexualized language or imagery and unwelcome sexual attention or advances
-- Trolling, insulting/derogatory comments, and personal or political attacks
-- Public or private harassment
-- Publishing others' private information, such as a physical or electronic address, without explicit permission
-- Other conduct which could reasonably be considered inappropriate in a professional setting
-
-## Enforcement
-
-Community leaders are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
-
-Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for behaviors that they deem inappropriate, threatening, offensive, or harmful.
-
-## Reporting
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project maintainer responsible for enforcement. All complaints will be reviewed and investigated promptly and fairly.
-
-All community leaders are obligated to respect the privacy and security of the reporter of any incident.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
-
-Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
-
-[homepage]: https://www.contributor-covenant.org
-
-For answers to common questions about this code of conduct, see the FAQ at
-https://www.contributor-covenant.org/faq. Translations are available at
-https://www.contributor-covenant.org/translations.
diff --git a/Directory.Build.props b/Directory.Build.props
index 80c3886e..96ebb124 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -6,8 +6,6 @@
enable
true
en
- true
- embedded
@@ -22,7 +20,6 @@
-
diff --git a/PolylineAlgorithm.slnx b/PolylineAlgorithm.slnx
index 3c54b2a7..29fa9445 100644
--- a/PolylineAlgorithm.slnx
+++ b/PolylineAlgorithm.slnx
@@ -7,7 +7,6 @@
-
diff --git a/README.md b/README.md
index 0555c16f..9dfb8a18 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,6 @@
# PolylineAlgorithm for .NET
-[](https://www.nuget.org/packages/PolylineAlgorithm)
-[](https://github.com/petesramek/polyline-algorithm-csharp/actions/workflows/build.yml)
-[](./LICENSE)
-
-Google's Encoded Polyline Algorithm compresses sequences of geographic coordinates into a compact ASCII string, widely used in mapping APIs. This library provides a fully compliant .NET implementation with extensible, type-safe encoding and decoding APIs.
+Lightweight .NET Standard 2.1 library implementing Google-compliant Encoded Polyline Algorithm with strong input validation, modern API patterns, and extensibility for custom coordinate types.
## Table of Contents
@@ -21,16 +17,15 @@ Google's Encoded Polyline Algorithm compresses sequences of geographic coordinat
## Features
- Fully compliant Google Encoded Polyline Algorithm for .NET Standard 2.1+
-- Extensible APIs — implement your own encoder/decoder for any coordinate or polyline type
-- Robust input validation with descriptive exceptions for malformed or out-of-range data
+- Extensible encoding and decoding APIs for custom coordinate and polyline types (`IPolylineEncoder`, `IPolylineDecoder`, `AbstractPolylineEncoder`, `AbstractPolylineDecoder`)
+- Extension methods for encoding from `List` and arrays (`PolylineEncoderExtensions`)
+- Robust input validation with descriptive exceptions for malformed/invalid data
- Advanced configuration via `PolylineEncodingOptions` (precision, buffer size, logging)
-- Extension methods for encoding directly from `List` and arrays
-- Logging and diagnostic support via `Microsoft.Extensions.Logging`
-- Low-level utilities for normalization, validation, and bit-level operations via static `PolylineEncoding` class
-- Thread-safe, stateless APIs
+- Logging and diagnostic support for CI/CD and developer diagnostics via `Microsoft.Extensions.Logging`
+- Low-level utilities for normalization, validation, encoding and decoding via static `PolylineEncoding` class
- Thorough unit tests and benchmarks for correctness and performance
- Auto-generated API documentation ([API Reference](https://petesramek.github.io/polyline-algorithm-csharp/))
-- Supports .NET Core, .NET 5+, Xamarin, Unity, Blazor, and any platform targeting `netstandard2.1`
+- Support for .NET Core, .NET 5+, Xamarin, Unity, Blazor, and other platforms supporting `netstandard2.1`
## Installation
@@ -48,19 +43,7 @@ Install-Package PolylineAlgorithm
## Usage
-The library provides abstract base classes to implement your own encoder and decoder for any coordinate and polyline type. Inherit from `AbstractPolylineEncoder` or `AbstractPolylineDecoder`, override the coordinate accessors, then call `Encode` or `Decode`.
-
-### Quick Start
-
-```csharp
-// 1. Implement a minimal encoder (see full example below)
-var encoder = new MyPolylineEncoder();
-string encoded = encoder.Encode(coordinates); // e.g. "yseiHoc_MwacOjnwM"
-
-// 2. Implement a minimal decoder (see full example below)
-var decoder = new MyPolylineDecoder();
-IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encoded);
-```
+The library provides abstract base classes to implement your own encoder and decoder for any coordinate and polyline type.
### Custom encoder and decoder
@@ -73,9 +56,23 @@ using PolylineAlgorithm;
using PolylineAlgorithm.Abstraction;
public sealed class MyPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
- protected override double GetLatitude((double Latitude, double Longitude) coordinate) => coordinate.Latitude;
- protected override double GetLongitude((double Latitude, double Longitude) coordinate) => coordinate.Longitude;
- protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
+ public MyPolylineEncoder()
+ : base() { }
+
+ public MyPolylineEncoder(PolylineEncodingOptions options)
+ : base(options) { }
+
+ protected override double GetLatitude((double Latitude, double Longitude) coordinate) {
+ return coordinate.Latitude;
+ }
+
+ protected override double GetLongitude((double Latitude, double Longitude) coordinate) {
+ return coordinate.Longitude;
+ }
+
+ protected override string CreatePolyline(ReadOnlyMemory polyline) {
+ return polyline.ToString();
+ }
}
```
@@ -105,8 +102,19 @@ using PolylineAlgorithm;
using PolylineAlgorithm.Abstraction;
public sealed class MyPolylineDecoder : AbstractPolylineDecoder {
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
- protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
+ public MyPolylineDecoder()
+ : base() { }
+
+ public MyPolylineDecoder(PolylineEncodingOptions options)
+ : base(options) { }
+
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
+ return (latitude, longitude);
+ }
+
+ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) {
+ return polyline.AsMemory();
+ }
}
```
@@ -128,13 +136,8 @@ Full API docs and guides (auto-generated from source) are available at [API Refe
## Benchmarks
-- See [`/benchmarks`](./benchmarks) in the repo for benchmark projects.
-- Run benchmarks with:
- ```shell
- dotnet run --project benchmarks/PolylineAlgorithm.Benchmarks --configuration Release
- ```
-- For guidance on writing and interpreting benchmarks, see [docs/benchmarks.md](./docs/benchmarks.md).
-- Contributors: update benchmarks and document results for performance-impacting PRs.
+- See `/benchmarks` in the repo for performance evaluation.
+- Contributors: Update benchmarks and document results for performance-impacting PRs.
## FAQ
@@ -170,13 +173,13 @@ A: Currently, only batch encode/decode is supported. For streaming scenarios, im
## Contributing
-- Follow code style and PR instructions in [CONTRIBUTING.md](./CONTRIBUTING.md).
+- Follow code style and PR instructions in [AGENTS.md](./AGENTS.md).
- Ensure all features are covered by tests and XML doc comments.
- For questions or suggestions, open an issue and use the provided templates.
## Support
-Have a question, bug, or feature request? [Open an issue](https://github.com/petesramek/polyline-algorithm-csharp/issues/new/choose) — bug report and feature request templates are available to guide you.
+Have a question, bug, or feature request? [Open an issue!](https://github.com/petesramek/polyline-algorithm-csharp/issues)
---
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index 8ca1471a..00000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Security Policy
-
-## Supported Versions
-
-| Version | Supported |
-| ------- | --------- |
-| Latest | ✅ |
-| Older | ❌ |
-
-Only the latest published version receives security fixes. If you are on an older version, please upgrade.
-
-## Reporting a Vulnerability
-
-**Please do not open a public GitHub issue for security vulnerabilities.**
-
-Report security issues privately via [GitHub Security Advisories](https://github.com/petesramek/polyline-algorithm-csharp/security/advisories/new).
-
-Include:
-- A description of the vulnerability
-- Steps to reproduce or a proof-of-concept
-- Potential impact assessment
-
-You can expect an initial response within 5 business days. Once confirmed, a fix will be prioritized and a patch release issued. You will be credited in the release notes unless you prefer to remain anonymous.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
deleted file mode 100644
index b5693066..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
+++ /dev/null
@@ -1,233 +0,0 @@
-### YamlMime:ApiPage
-title: Class AbstractPolylineDecoder
-body:
-- api1: Class AbstractPolylineDecoder
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2
- commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm.Abstraction
- url: PolylineAlgorithm.Abstraction.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
-- code: 'public abstract class AbstractPolylineDecoder : IPolylineDecoder'
-- h4: Type Parameters
-- parameters:
- - name: TPolyline
- description: The type that represents the encoded polyline input.
- - name: TCoordinate
- description: The type that represents a decoded geographic coordinate.
-- h4: Inheritance
-- inheritance:
- - text: object
- url: https://learn.microsoft.com/dotnet/api/system.object
- - text: AbstractPolylineDecoder
- url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html
-- h4: Implements
-- list:
- - text: IPolylineDecoder
- url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
-- h4: Inherited Members
-- list:
- - text: object.Equals(object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
- - text: object.Equals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
- - text: object.GetHashCode()
- url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
- - text: object.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.object.gettype
- - text: object.MemberwiseClone()
- url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
- - text: object.ReferenceEquals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
- - text: object.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.object.tostring
-- h2: Remarks
-- markdown: >-
- Derive from this class to implement a decoder for a specific polyline type. Override
-
- and to provide type-specific behavior.
-- h2: Constructors
-- api3: AbstractPolylineDecoder()
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor
-- markdown: Initializes a new instance of the class with default encoding options.
-- code: protected AbstractPolylineDecoder()
-- api3: AbstractPolylineDecoder(PolylineEncodingOptions)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
-- markdown: Initializes a new instance of the class with the specified encoding options.
-- code: protected AbstractPolylineDecoder(PolylineEncodingOptions options)
-- h4: Parameters
-- parameters:
- - name: options
- type:
- - text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
- description: The to use for encoding operations.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when options is null.
-- h2: Properties
-- api3: Options
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Options
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options
- commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options
-- markdown: Gets the encoding options used by this polyline decoder.
-- code: public PolylineEncodingOptions Options { get; }
-- h4: Property Value
-- parameters:
- - type:
- - text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
-- h2: Methods
-- api3: CreateCoordinate(double, double)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateCoordinate_System_Double_System_Double_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double)
-- markdown: Creates a TCoordinate instance from the specified latitude and longitude values.
-- code: protected abstract TCoordinate CreateCoordinate(double latitude, double longitude)
-- h4: Parameters
-- parameters:
- - name: latitude
- type:
- - text: double
- url: https://learn.microsoft.com/dotnet/api/system.double
- description: The latitude component of the coordinate, in degrees.
- - name: longitude
- type:
- - text: double
- url: https://learn.microsoft.com/dotnet/api/system.double
- description: The longitude component of the coordinate, in degrees.
-- h4: Returns
-- parameters:
- - type:
- - TCoordinate
- description: A TCoordinate instance representing the specified geographic coordinate.
-- api3: Decode(TPolyline, CancellationToken)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
-- markdown: >-
- Decodes an encoded TPolyline into a sequence of TCoordinate instances,
-
- with support for cancellation.
-- code: public IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - TPolyline
- description: The TPolyline instance containing the encoded polyline string to decode.
- - name: cancellationToken
- type:
- - text: CancellationToken
- url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
- description: A that can be used to cancel the decoding operation.
- optional: true
-- h4: Returns
-- parameters:
- - type:
- - text: IEnumerable
- url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
- - <
- - TCoordinate
- - '>'
- description: An of TCoordinate representing the decoded latitude and longitude pairs.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when polyline is null.
- - type:
- - text: ArgumentException
- url: https://learn.microsoft.com/dotnet/api/system.argumentexception
- description: Thrown when polyline is empty.
- - type:
- - text: InvalidPolylineException
- url: PolylineAlgorithm.InvalidPolylineException.html
- description: Thrown when the polyline format is invalid or malformed at a specific position.
- - type:
- - text: OperationCanceledException
- url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception
- description: Thrown when cancellationToken is canceled during decoding.
-- api3: GetReadOnlyMemory(in TPolyline)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@)
-- markdown: Extracts the underlying read-only memory region of characters from the specified polyline instance.
-- code: protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - TPolyline
- description: The TPolyline instance from which to extract the character sequence.
-- h4: Returns
-- parameters:
- - type:
- - text: ReadOnlyMemory
- url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: A of representing the encoded polyline characters.
-- api3: ValidateFormat(ReadOnlyMemory, ILogger?)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger)
-- markdown: Validates the format of the polyline character sequence, ensuring all characters are within the allowed range.
-- code: protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? logger)
-- h4: Parameters
-- parameters:
- - name: sequence
- type:
- - text: ReadOnlyMemory
- url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: The read-only memory region of characters representing the polyline to validate.
- - name: logger
- type:
- - text: ILogger
- url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger
- - '?'
- description: An optional used to log a warning when format validation fails.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentException
- url: https://learn.microsoft.com/dotnet/api/system.argumentexception
- description: Thrown when the polyline contains characters outside the valid encoding range or has an invalid block structure.
-languageId: csharp
-metadata:
- description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
deleted file mode 100644
index 64e97b11..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
+++ /dev/null
@@ -1,219 +0,0 @@
-### YamlMime:ApiPage
-title: Class AbstractPolylineEncoder
-body:
-- api1: Class AbstractPolylineEncoder
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2
- commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm.Abstraction
- url: PolylineAlgorithm.Abstraction.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
-- code: 'public abstract class AbstractPolylineEncoder : IPolylineEncoder'
-- h4: Type Parameters
-- parameters:
- - name: TCoordinate
- description: The type that represents a geographic coordinate to encode.
- - name: TPolyline
- description: The type that represents the encoded polyline output.
-- h4: Inheritance
-- inheritance:
- - text: object
- url: https://learn.microsoft.com/dotnet/api/system.object
- - text: AbstractPolylineEncoder
- url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html
-- h4: Implements
-- list:
- - text: IPolylineEncoder
- url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html
-- h4: Inherited Members
-- list:
- - text: object.Equals(object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
- - text: object.Equals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
- - text: object.GetHashCode()
- url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
- - text: object.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.object.gettype
- - text: object.MemberwiseClone()
- url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
- - text: object.ReferenceEquals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
- - text: object.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.object.tostring
-- h4: Extension Methods
-- list:
- - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List)
- url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__
- - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TCoordinate[])
- url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___
-- h2: Remarks
-- markdown: >-
- Derive from this class to implement an encoder for a specific coordinate and polyline type. Override
-
- , , and to provide type-specific behavior.
-- h2: Constructors
-- api3: AbstractPolylineEncoder()
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor
-- markdown: Initializes a new instance of the class with default encoding options.
-- code: protected AbstractPolylineEncoder()
-- api3: AbstractPolylineEncoder(PolylineEncodingOptions)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
-- markdown: Initializes a new instance of the class with the specified encoding options.
-- code: protected AbstractPolylineEncoder(PolylineEncodingOptions options)
-- h4: Parameters
-- parameters:
- - name: options
- type:
- - text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
- description: The to use for encoding operations.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when options is null
-- h2: Properties
-- api3: Options
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Options
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options
- commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options
-- markdown: Gets the encoding options used by this polyline encoder.
-- code: public PolylineEncodingOptions Options { get; }
-- h4: Property Value
-- parameters:
- - type:
- - text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
-- h2: Methods
-- api3: CreatePolyline(ReadOnlyMemory)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char})
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char})
-- markdown: Creates a polyline instance from the provided read-only sequence of characters.
-- code: protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - text: ReadOnlyMemory
- url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: A containing the encoded polyline characters.
-- h4: Returns
-- parameters:
- - type:
- - TPolyline
- description: An instance of TPolyline representing the encoded polyline.
-- api3: Encode(ReadOnlySpan, CancellationToken)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
-- markdown: Encodes a collection of TCoordinate instances into an encoded TPolyline string.
-- code: >-
- [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")]
-
- public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default)
-- h4: Parameters
-- parameters:
- - name: coordinates
- type:
- - text: ReadOnlySpan
- url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
- - <
- - TCoordinate
- - '>'
- description: The collection of TCoordinate objects to encode.
- - name: cancellationToken
- type:
- - text: CancellationToken
- url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
- description: A that can be used to cancel the encoding operation.
- optional: true
-- h4: Returns
-- parameters:
- - type:
- - TPolyline
- description: An instance of TPolyline representing the encoded coordinates.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when coordinates is null.
- - type:
- - text: ArgumentException
- url: https://learn.microsoft.com/dotnet/api/system.argumentexception
- description: Thrown when coordinates is an empty enumeration.
- - type:
- - text: InvalidOperationException
- url: https://learn.microsoft.com/dotnet/api/system.invalidoperationexception
- description: Thrown when the internal encoding buffer cannot accommodate the encoded value.
-- api3: GetLatitude(TCoordinate)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLatitude__0_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0)
-- markdown: Extracts the latitude value from the specified coordinate.
-- code: protected abstract double GetLatitude(TCoordinate current)
-- h4: Parameters
-- parameters:
- - name: current
- type:
- - TCoordinate
- description: The coordinate from which to extract the latitude.
-- h4: Returns
-- parameters:
- - type:
- - text: double
- url: https://learn.microsoft.com/dotnet/api/system.double
- description: The latitude value as a .
-- api3: GetLongitude(TCoordinate)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLongitude__0_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0)
-- markdown: Extracts the longitude value from the specified coordinate.
-- code: protected abstract double GetLongitude(TCoordinate current)
-- h4: Parameters
-- parameters:
- - name: current
- type:
- - TCoordinate
- description: The coordinate from which to extract the longitude.
-- h4: Returns
-- parameters:
- - type:
- - text: double
- url: https://learn.microsoft.com/dotnet/api/system.double
- description: The longitude value as a .
-languageId: csharp
-metadata:
- description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
deleted file mode 100644
index 733987cb..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
+++ /dev/null
@@ -1,90 +0,0 @@
-### YamlMime:ApiPage
-title: Interface IPolylineDecoder
-body:
-- api1: Interface IPolylineDecoder
- id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22
- metadata:
- uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2
- commentId: T:PolylineAlgorithm.Abstraction.IPolylineDecoder`2
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm.Abstraction
- url: PolylineAlgorithm.Abstraction.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates.
-- code: public interface IPolylineDecoder
-- h4: Type Parameters
-- parameters:
- - name: TPolyline
- description: >-
- The type that represents the encoded polyline input. Common implementations use ,
-
- but custom wrapper types are allowed to carry additional metadata.
- - name: TValue
- description: >-
- The coordinate type returned by the decoder. Typical implementations return a struct or class that
-
- contains latitude and longitude (for example a LatLng type or a ValueTuple<double,double>).
-- h2: Methods
-- api3: Decode(TPolyline, CancellationToken)
- id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48
- metadata:
- uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
- commentId: M:PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
-- markdown: >-
- Decodes the specified encoded polyline into an ordered sequence of geographic coordinates.
-
- The sequence preserves the original vertex order encoded by the polyline.
-- code: IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - TPolyline
- description: >-
- The TPolyline instance containing the encoded polyline to decode.
-
- Implementations SHOULD validate the input and may throw
-
- or for invalid formats.
- - name: cancellationToken
- type:
- - text: CancellationToken
- url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
- description: >-
- A to observe while decoding. If cancellation is requested,
-
- implementations SHOULD stop work and throw an .
- optional: true
-- h4: Returns
-- parameters:
- - type:
- - text: IEnumerable
- url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
- - <
- - TValue
- - '>'
- description: >-
- An of TValue representing the decoded
-
- latitude/longitude pairs (or equivalent coordinates) in the same order they were encoded.
-- h4: Remarks
-- markdown: >-
- Implementations commonly follow the Google Encoded Polyline Algorithm Format, but this interface
-
- does not mandate a specific encoding. Consumers should rely on a concrete decoder's documentation
-
- to understand the exact encoding supported.
-- h4: Exceptions
-- parameters:
- - type:
- - text: OperationCanceledException
- url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception
- description: Thrown when the provided cancellationToken requests cancellation.
-languageId: csharp
-metadata:
- description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
deleted file mode 100644
index 341a9de7..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
+++ /dev/null
@@ -1,142 +0,0 @@
-### YamlMime:ApiPage
-title: Interface IPolylineEncoder
-body:
-- api1: Interface IPolylineEncoder
- id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36
- metadata:
- uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2
- commentId: T:PolylineAlgorithm.Abstraction.IPolylineEncoder`2
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm.Abstraction
- url: PolylineAlgorithm.Abstraction.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: >-
- Contract for encoding a sequence of geographic coordinates into an encoded polyline representation.
-
- Implementations interpret the generic TValue type and produce an encoded
-
- representation of those coordinates as TPolyline.
-- code: public interface IPolylineEncoder
-- h4: Type Parameters
-- parameters:
- - name: TValue
- description: >-
- The concrete coordinate representation used by the encoder (for example a struct or class containing
-
- Latitude and Longitude values). Implementations must document the expected shape,
-
- units (typically decimal degrees), and any required fields for TValue.
-
- Common shapes:
-
- - A struct or class with two double properties named Latitude and Longitude.
-
- - A tuple-like type (for example ValueTuple<double,double>) where the encoder documents
- which element represents latitude and longitude.
- - name: TPolyline
- description: >-
- The encoded polyline representation returned by the encoder (for example string,
-
- ReadOnlyMemory<char>, or a custom wrapper type). Concrete implementations should document
-
- the chosen representation and any memory / ownership expectations.
-- h4: Extension Methods
-- list:
- - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List)
- url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__
- - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TValue[])
- url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___
-- h2: Remarks
-- markdown: >-
- - This interface is intentionally minimal to allow different encoding strategies (Google encoded polyline,
- precision/scale variants, or custom compressed formats) to be expressed behind a common contract.
- - Implementations should document:
- - Coordinate precision and rounding rules (for example 1e-5 for 5-decimal precision).
- - Coordinate ordering and whether altitude or additional dimensions are supported.
- - Thread-safety guarantees: whether instances are safe to reuse concurrently or must be instantiated per-call.
- - Implementations are encouraged to be memory-efficient; the API accepts a
- to avoid forced allocations when callers already have contiguous memory.
-- h2: Methods
-- api3: Encode(ReadOnlySpan, CancellationToken)
- id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76
- metadata:
- uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
- commentId: M:PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
-- markdown: >-
- Encodes a sequence of geographic coordinates into an encoded polyline representation.
-
- The order of coordinates in coordinates is preserved in the encoded result.
-- code: TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default)
-- h4: Parameters
-- parameters:
- - name: coordinates
- type:
- - text: ReadOnlySpan
- url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
- - <
- - TValue
- - '>'
- description: >-
- The collection of TValue instances to encode into a polyline.
-
- The span may be empty; implementations should return an appropriate empty encoded representation
-
- (for example an empty string or an empty memory slice) rather than null.
- - name: cancellationToken
- type:
- - text: CancellationToken
- url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
- description: >-
- A that can be used to cancel the encoding operation.
-
- Implementations should observe this token and throw
-
- when cancellation is requested. For fast, in-memory encoders cancellation may be best-effort.
- optional: true
-- h4: Returns
-- parameters:
- - type:
- - TPolyline
- description: >-
- A TPolyline containing the encoded polyline that represents the input coordinates.
-
- The exact format and any delimiting/terminating characters are implementation-specific and must be
-
- documented by concrete encoder types.
-- h4: Examples
-- markdown: >-
- // Example pseudocode for typical usage with a string-based encoder:
-
- var coords = new[] {
- new Coordinate { Latitude = 47.6219, Longitude = -122.3503 },
- new Coordinate { Latitude = 47.6220, Longitude = -122.3504 }
- };
-
- IPolylineEncoder<Coordinate,string> encoder = new GoogleEncodedPolylineEncoder();
-
- string encoded = encoder.Encode(coords, CancellationToken.None);
-- h4: Remarks
-- markdown: >-
- - Implementations should validate input as appropriate and document any preconditions (for example
- if coordinates must be within [-90,90] latitude and [-180,180] longitude).
- - For large input sequences, implementations may provide streaming or incremental encoders; those
- variants can still implement this interface by materializing the final encoded result.
-- h4: Exceptions
-- parameters:
- - type:
- - text: OperationCanceledException
- url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception
- description: Thrown if the operation is canceled via cancellationToken.
-languageId: csharp
-metadata:
- description: >-
- Contract for encoding a sequence of geographic coordinates into an encoded polyline representation.
-
- Implementations interpret the generic TValue type and produce an encoded
-
- representation of those coordinates as TPolyline.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.yml
deleted file mode 100644
index e9de48f7..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-### YamlMime:ApiPage
-title: Namespace PolylineAlgorithm.Abstraction
-body:
-- api1: Namespace PolylineAlgorithm.Abstraction
- id: PolylineAlgorithm_Abstraction
- metadata:
- uid: PolylineAlgorithm.Abstraction
- commentId: N:PolylineAlgorithm.Abstraction
-- h3: Classes
-- parameters:
- - type:
- text: AbstractPolylineDecoder
- url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html
- description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
- - type:
- text: AbstractPolylineEncoder
- url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html
- description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
-- h3: Interfaces
-- parameters:
- - type:
- text: IPolylineDecoder
- url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
- description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates.
- - type:
- text: IPolylineEncoder
- url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html
- description: >-
- Contract for encoding a sequence of geographic coordinates into an encoded polyline representation.
-
- Implementations interpret the generic TValue type and produce an encoded
-
- representation of those coordinates as TPolyline.
-languageId: csharp
diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
deleted file mode 100644
index 8356b63c..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
+++ /dev/null
@@ -1,195 +0,0 @@
-### YamlMime:ApiPage
-title: Class PolylineDecoderExtensions
-body:
-- api1: Class PolylineDecoderExtensions
- id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16
- metadata:
- uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions
- commentId: T:PolylineAlgorithm.Extensions.PolylineDecoderExtensions
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm.Extensions
- url: PolylineAlgorithm.Extensions.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Provides extension methods for the interface to facilitate decoding encoded polylines.
-- code: public static class PolylineDecoderExtensions
-- h4: Inheritance
-- inheritance:
- - text: object
- url: https://learn.microsoft.com/dotnet/api/system.object
- - text: PolylineDecoderExtensions
- url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html
-- h4: Inherited Members
-- list:
- - text: object.Equals(object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
- - text: object.Equals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
- - text: object.GetHashCode()
- url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
- - text: object.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.object.gettype
- - text: object.MemberwiseClone()
- url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
- - text: object.ReferenceEquals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
- - text: object.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.object.tostring
-- h2: Methods
-- api3: Decode(IPolylineDecoder, char[])
- id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_Char___
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33
- metadata:
- uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[])
- commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[])
-- markdown: Decodes an encoded polyline represented as a character array into a sequence of geographic coordinates.
-- code: public static IEnumerable Decode(this IPolylineDecoder decoder, char[] polyline)
-- h4: Parameters
-- parameters:
- - name: decoder
- type:
- - text: IPolylineDecoder
- url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
- - <
- - text: string
- url: https://learn.microsoft.com/dotnet/api/system.string
- - ','
- - " "
- - TValue
- - '>'
- description: The instance used to perform the decoding operation.
- - name: polyline
- type:
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '['
- - ']'
- description: The encoded polyline as a character array to decode. The array is converted to a string internally.
-- h4: Returns
-- parameters:
- - type:
- - text: IEnumerable
- url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
- - <
- - TValue
- - '>'
- description: An of TValue containing the decoded coordinate pairs.
-- h4: Type Parameters
-- parameters:
- - name: TValue
- description: The coordinate type returned by the decoder.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when decoder or polyline is null.
-- api3: Decode(IPolylineDecoder, ReadOnlyMemory)
- id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_ReadOnlyMemory_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61
- metadata:
- uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char})
- commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char})
-- markdown: Decodes an encoded polyline represented as a read-only memory of characters into a sequence of geographic coordinates.
-- code: public static IEnumerable Decode(this IPolylineDecoder decoder, ReadOnlyMemory polyline)
-- h4: Parameters
-- parameters:
- - name: decoder
- type:
- - text: IPolylineDecoder
- url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
- - <
- - text: string
- url: https://learn.microsoft.com/dotnet/api/system.string
- - ','
- - " "
- - TValue
- - '>'
- description: The instance used to perform the decoding operation.
- - name: polyline
- type:
- - text: ReadOnlyMemory
- url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: The encoded polyline as a read-only memory of characters to decode. The memory is converted to a string internally.
-- h4: Returns
-- parameters:
- - type:
- - text: IEnumerable
- url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
- - <
- - TValue
- - '>'
- description: An of TValue containing the decoded coordinate pairs.
-- h4: Type Parameters
-- parameters:
- - name: TValue
- description: The coordinate type returned by the decoder.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when decoder is null.
-- api3: Decode(IPolylineDecoder, TValue>, string)
- id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_ReadOnlyMemory_System_Char____0__System_String_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86
- metadata:
- uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String)
- commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String)
-- markdown: >-
- Decodes an encoded polyline string into a sequence of geographic coordinates,
-
- using a decoder that accepts of .
-- code: public static IEnumerable Decode(this IPolylineDecoder, TValue> decoder, string polyline)
-- h4: Parameters
-- parameters:
- - name: decoder
- type:
- - text: IPolylineDecoder
- url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
- - <
- - text: ReadOnlyMemory
- url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- - ','
- - " "
- - TValue
- - '>'
- description: The instance used to perform the decoding operation.
- - name: polyline
- type:
- - text: string
- url: https://learn.microsoft.com/dotnet/api/system.string
- description: The encoded polyline string to decode. The string is converted to internally.
-- h4: Returns
-- parameters:
- - type:
- - text: IEnumerable
- url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
- - <
- - TValue
- - '>'
- description: An of TValue containing the decoded coordinate pairs.
-- h4: Type Parameters
-- parameters:
- - name: TValue
- description: The coordinate type returned by the decoder.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when decoder or polyline is null.
-languageId: csharp
-metadata:
- description: Provides extension methods for the interface to facilitate decoding encoded polylines.
diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
deleted file mode 100644
index e5296518..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
+++ /dev/null
@@ -1,139 +0,0 @@
-### YamlMime:ApiPage
-title: Class PolylineEncoderExtensions
-body:
-- api1: Class PolylineEncoderExtensions
- id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19
- metadata:
- uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions
- commentId: T:PolylineAlgorithm.Extensions.PolylineEncoderExtensions
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm.Extensions
- url: PolylineAlgorithm.Extensions.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines.
-- code: public static class PolylineEncoderExtensions
-- h4: Inheritance
-- inheritance:
- - text: object
- url: https://learn.microsoft.com/dotnet/api/system.object
- - text: PolylineEncoderExtensions
- url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html
-- h4: Inherited Members
-- list:
- - text: object.Equals(object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
- - text: object.Equals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
- - text: object.GetHashCode()
- url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
- - text: object.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.object.gettype
- - text: object.MemberwiseClone()
- url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
- - text: object.ReferenceEquals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
- - text: object.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.object.tostring
-- h2: Methods
-- api3: Encode(IPolylineEncoder, List)
- id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37
- metadata:
- uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0})
- commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0})
-- markdown: Encodes a of TCoordinate instances into an encoded polyline.
-- code: >-
- [SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "We need a list as we do need to marshal it as span.")]
-
- [SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "We need a list as we do need to marshal it as span.")]
-
- public static TPolyline Encode(this IPolylineEncoder encoder, List coordinates)
-- h4: Parameters
-- parameters:
- - name: encoder
- type:
- - text: IPolylineEncoder
- url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html
- - <
- - TCoordinate
- - ','
- - " "
- - TPolyline
- - '>'
- description: The instance used to perform the encoding operation.
- - name: coordinates
- type:
- - text: List
- url: https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1
- - <
- - TCoordinate
- - '>'
- description: The list of TCoordinate objects to encode.
-- h4: Returns
-- parameters:
- - type:
- - TPolyline
- description: A TPolyline instance representing the encoded polyline for the provided coordinates.
-- h4: Type Parameters
-- parameters:
- - name: TCoordinate
- description: The type that represents a geographic coordinate to encode.
- - name: TPolyline
- description: The type that represents the encoded polyline output.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when encoder or coordinates is null.
-- api3: Encode(IPolylineEncoder, TCoordinate[])
- id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73
- metadata:
- uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[])
- commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[])
-- markdown: Encodes an array of TCoordinate instances into an encoded polyline.
-- code: public static TPolyline Encode(this IPolylineEncoder encoder, TCoordinate[] coordinates)
-- h4: Parameters
-- parameters:
- - name: encoder
- type:
- - text: IPolylineEncoder
- url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html
- - <
- - TCoordinate
- - ','
- - " "
- - TPolyline
- - '>'
- description: The instance used to perform the encoding operation.
- - name: coordinates
- type:
- - TCoordinate
- - '['
- - ']'
- description: The array of TCoordinate objects to encode.
-- h4: Returns
-- parameters:
- - type:
- - TPolyline
- description: A TPolyline instance representing the encoded polyline for the provided coordinates.
-- h4: Type Parameters
-- parameters:
- - name: TCoordinate
- description: The type that represents a geographic coordinate to encode.
- - name: TPolyline
- description: The type that represents the encoded polyline output.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when encoder or coordinates is null.
-languageId: csharp
-metadata:
- description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines.
diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.yml
deleted file mode 100644
index c39da0ca..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Extensions.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-### YamlMime:ApiPage
-title: Namespace PolylineAlgorithm.Extensions
-body:
-- api1: Namespace PolylineAlgorithm.Extensions
- id: PolylineAlgorithm_Extensions
- metadata:
- uid: PolylineAlgorithm.Extensions
- commentId: N:PolylineAlgorithm.Extensions
-- h3: Classes
-- parameters:
- - type:
- text: PolylineDecoderExtensions
- url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html
- description: Provides extension methods for the interface to facilitate decoding encoded polylines.
- - type:
- text: PolylineEncoderExtensions
- url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html
- description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines.
-languageId: csharp
diff --git a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml
deleted file mode 100644
index 2c4e3cc1..00000000
--- a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml
+++ /dev/null
@@ -1,102 +0,0 @@
-### YamlMime:ApiPage
-title: Class InvalidPolylineException
-body:
-- api1: Class InvalidPolylineException
- id: PolylineAlgorithm_InvalidPolylineException
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L17
- metadata:
- uid: PolylineAlgorithm.InvalidPolylineException
- commentId: T:PolylineAlgorithm.InvalidPolylineException
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm
- url: PolylineAlgorithm.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Exception thrown when a polyline is determined to be malformed or invalid during processing.
-- code: 'public sealed class InvalidPolylineException : Exception, ISerializable'
-- h4: Inheritance
-- inheritance:
- - text: object
- url: https://learn.microsoft.com/dotnet/api/system.object
- - text: Exception
- url: https://learn.microsoft.com/dotnet/api/system.exception
- - text: InvalidPolylineException
- url: PolylineAlgorithm.InvalidPolylineException.html
-- h4: Implements
-- list:
- - text: ISerializable
- url: https://learn.microsoft.com/dotnet/api/system.runtime.serialization.iserializable
-- h4: Inherited Members
-- list:
- - text: Exception.GetBaseException()
- url: https://learn.microsoft.com/dotnet/api/system.exception.getbaseexception
- - text: Exception.GetObjectData(SerializationInfo, StreamingContext)
- url: https://learn.microsoft.com/dotnet/api/system.exception.getobjectdata
- - text: Exception.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.exception.gettype
- - text: Exception.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.exception.tostring
- - text: Exception.Data
- url: https://learn.microsoft.com/dotnet/api/system.exception.data
- - text: Exception.HelpLink
- url: https://learn.microsoft.com/dotnet/api/system.exception.helplink
- - text: Exception.HResult
- url: https://learn.microsoft.com/dotnet/api/system.exception.hresult
- - text: Exception.InnerException
- url: https://learn.microsoft.com/dotnet/api/system.exception.innerexception
- - text: Exception.Message
- url: https://learn.microsoft.com/dotnet/api/system.exception.message
- - text: Exception.Source
- url: https://learn.microsoft.com/dotnet/api/system.exception.source
- - text: Exception.StackTrace
- url: https://learn.microsoft.com/dotnet/api/system.exception.stacktrace
- - text: Exception.TargetSite
- url: https://learn.microsoft.com/dotnet/api/system.exception.targetsite
- - text: object.Equals(object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
- - text: object.Equals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
- - text: object.GetHashCode()
- url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
- - text: object.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.object.gettype
- - text: object.ReferenceEquals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
- - text: object.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.object.tostring
-- h2: Remarks
-- markdown: This exception is used internally to indicate that a polyline string does not conform to the expected format or contains errors.
-- h2: Constructors
-- api3: InvalidPolylineException()
- id: PolylineAlgorithm_InvalidPolylineException__ctor
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L22
- metadata:
- uid: PolylineAlgorithm.InvalidPolylineException.#ctor
- commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor
-- markdown: Initializes a new instance of the class.
-- code: public InvalidPolylineException()
-- api3: InvalidPolylineException(string, Exception)
- id: PolylineAlgorithm_InvalidPolylineException__ctor_System_String_System_Exception_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L43
- metadata:
- uid: PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception)
- commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception)
-- markdown: Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
-- code: public InvalidPolylineException(string message, Exception innerException)
-- h4: Parameters
-- parameters:
- - name: message
- type:
- - text: string
- url: https://learn.microsoft.com/dotnet/api/system.string
- description: The error message that explains the reason for the exception.
- - name: innerException
- type:
- - text: Exception
- url: https://learn.microsoft.com/dotnet/api/system.exception
- description: The exception that is the cause of the current exception, or a null reference if no inner exception is specified.
-languageId: csharp
-metadata:
- description: Exception thrown when a polyline is determined to be malformed or invalid during processing.
diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml
deleted file mode 100644
index 1add8147..00000000
--- a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml
+++ /dev/null
@@ -1,529 +0,0 @@
-### YamlMime:ApiPage
-title: Class PolylineEncoding
-body:
-- api1: Class PolylineEncoding
- id: PolylineAlgorithm_PolylineEncoding
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L23
- metadata:
- uid: PolylineAlgorithm.PolylineEncoding
- commentId: T:PolylineAlgorithm.PolylineEncoding
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm
- url: PolylineAlgorithm.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: >-
- Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing
-
- geographic coordinate values.
-- code: public static class PolylineEncoding
-- h4: Inheritance
-- inheritance:
- - text: object
- url: https://learn.microsoft.com/dotnet/api/system.object
- - text: PolylineEncoding
- url: PolylineAlgorithm.PolylineEncoding.html
-- h4: Inherited Members
-- list:
- - text: object.Equals(object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
- - text: object.Equals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
- - text: object.GetHashCode()
- url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
- - text: object.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.object.gettype
- - text: object.MemberwiseClone()
- url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
- - text: object.ReferenceEquals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
- - text: object.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.object.tostring
-- h2: Remarks
-- markdown: >-
- The class includes functionality for working with encoded polyline
- data, such as reading and writing encoded values, as well as methods for normalizing and de-normalizing geographic
- coordinates. It also provides validation utilities to ensure values conform to expected ranges for latitude and
- longitude.
-- h2: Methods
-- api3: Denormalize(int, uint)
- id: PolylineAlgorithm_PolylineEncoding_Denormalize_System_Int32_System_UInt32_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L122
- metadata:
- uid: PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32)
- commentId: M:PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32)
-- markdown: Converts a normalized integer coordinate value back to its floating-point representation based on the specified precision.
-- code: public static double Denormalize(int value, uint precision = 5)
-- h4: Parameters
-- parameters:
- - name: value
- type:
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- description: The integer value to denormalize. Typically produced by the method.
- - name: precision
- type:
- - text: uint
- url: https://learn.microsoft.com/dotnet/api/system.uint32
- description: The number of decimal places used during normalization. Default is 5, matching standard polyline encoding precision.
- optional: true
-- h4: Returns
-- parameters:
- - type:
- - text: double
- url: https://learn.microsoft.com/dotnet/api/system.double
- description: The denormalized floating-point coordinate value.
-- h4: Remarks
-- markdown: >-
-
-
- This method reverses the normalization performed by . It takes an integer value and converts it
-
- to a double by dividing it by 10 raised to the power of the specified precision. If precision is 0,
-
- the value is returned as a double without division.
-
-
-
-
-
- The calculation is performed inside a checked block to ensure that any arithmetic overflow is detected
-
- and an is thrown.
-
-
-
-
-
- For example, with a precision of 5:
-
-
-
- A value of 3778903 becomes 37.78903
- A value of -12241230 becomes -122.4123
-
-
-
-
-
- If the input value is 0, the method returns 0.0 immediately.
-
-
-- h4: Exceptions
-- parameters:
- - type:
- - text: OverflowException
- url: https://learn.microsoft.com/dotnet/api/system.overflowexception
- description: Thrown if the arithmetic operation overflows during conversion.
-- api3: GetRequiredBufferSize(int)
- id: PolylineAlgorithm_PolylineEncoding_GetRequiredBufferSize_System_Int32_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L298
- metadata:
- uid: PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32)
- commentId: M:PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32)
-- markdown: Calculates the number of characters required to encode a delta value in polyline format.
-- code: public static int GetRequiredBufferSize(int delta)
-- h4: Parameters
-- parameters:
- - name: delta
- type:
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- description: >-
- The integer delta value to calculate the encoded size for. This value typically represents the difference between
-
- consecutive coordinate values in polyline encoding.
-- h4: Returns
-- parameters:
- - type:
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- description: The number of characters required to encode the specified delta value. The minimum return value is 1.
-- h4: Remarks
-- markdown: >-
-
-
- This method determines how many characters will be needed to represent an integer delta value when encoded
-
- using the polyline encoding algorithm. It performs the same zigzag encoding transformation as
-
- but only calculates the required buffer size without actually writing any data.
-
-
-
-
-
- The calculation process:
-
-
-
- Applies zigzag encoding: left-shifts the value by 1 bit, then inverts all bits if the original value was negative
- Counts how many 5-bit chunks are needed to represent the encoded value
- Each chunk requires one character, with a minimum of 1 character for any value
-
-
-
-
-
- This method is useful for pre-allocating buffers of the correct size before encoding polyline data, helping to avoid
-
- buffer overflow checks during the actual encoding process.
-
-
-
-
-
- The method uses a long internally to prevent overflow during the left-shift operation on large negative values.
-
-
-- h4: See Also
-- list:
- - - text: PolylineEncoding
- url: PolylineAlgorithm.PolylineEncoding.html
- - .
- - text: TryWriteValue
- url: PolylineAlgorithm.PolylineEncoding.html#PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__
- - (
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- - ','
- - " "
- - text: Span
- url: https://learn.microsoft.com/dotnet/api/system.span-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- - ','
- - " "
- - ref
- - " "
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- - )
-- api3: Normalize(double, uint)
- id: PolylineAlgorithm_PolylineEncoding_Normalize_System_Double_System_UInt32_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L61
- metadata:
- uid: PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32)
- commentId: M:PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32)
-- markdown: Normalizes a geographic coordinate value to an integer representation based on the specified precision.
-- code: public static int Normalize(double value, uint precision = 5)
-- h4: Parameters
-- parameters:
- - name: value
- type:
- - text: double
- url: https://learn.microsoft.com/dotnet/api/system.double
- description: The numeric value to normalize. Must be a finite number (not NaN or infinity).
- - name: precision
- type:
- - text: uint
- url: https://learn.microsoft.com/dotnet/api/system.uint32
- description: >-
- The number of decimal places of precision to preserve in the normalized value.
-
- The value is multiplied by 10^precision before rounding.
-
- Default is 5, which is standard for polyline encoding.
- optional: true
-- h4: Returns
-- parameters:
- - type:
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- description: An integer representing the normalized value. Returns 0 if the input value is 0.0.
-- h4: Remarks
-- markdown: >-
-
-
- This method converts a floating-point coordinate value into a normalized integer by multiplying it by 10 raised
-
- to the power of the specified precision, then truncating the result to an integer.
-
-
-
-
-
- For example, with the default precision of 5:
-
-
-
- A value of 37.78903 becomes 3778903
- A value of -122.4123 becomes -12241230
-
-
-
-
-
- The method validates that the input value is finite (not NaN or infinity) before performing normalization.
-
- If the precision is 0, the value is rounded without multiplication.
-
-
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentOutOfRangeException
- url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception
- description: Thrown when value is not a finite number (NaN or infinity).
- - type:
- - text: OverflowException
- url: https://learn.microsoft.com/dotnet/api/system.overflowexception
- description: Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int.
-- api3: TryReadValue(ref int, ReadOnlyMemory, ref int)
- id: PolylineAlgorithm_PolylineEncoding_TryReadValue_System_Int32__System_ReadOnlyMemory_System_Char__System_Int32__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L169
- metadata:
- uid: PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@)
- commentId: M:PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@)
-- markdown: Attempts to read an encoded integer value from a polyline buffer, updating the specified delta and position.
-- code: public static bool TryReadValue(ref int delta, ReadOnlyMemory buffer, ref int position)
-- h4: Parameters
-- parameters:
- - name: delta
- type:
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- description: Reference to the integer accumulator that will be updated with the decoded value.
- - name: buffer
- type:
- - text: ReadOnlyMemory
- url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: The buffer containing polyline-encoded characters.
- - name: position
- type:
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- description: Reference to the current position in the buffer. This value is updated as characters are read.
-- h4: Returns
-- parameters:
- - type:
- - text: bool
- url: https://learn.microsoft.com/dotnet/api/system.boolean
- description: true if a value was successfully read and decoded; false if the buffer ended before a complete value was read.
-- h4: Remarks
-- markdown: >-
-
-
- This method decodes a value from a polyline-encoded character buffer, starting at the given position. It reads
-
- characters sequentially, applying the polyline decoding algorithm, and updates the delta with
-
- the decoded value. The position is advanced as characters are processed.
-
-
-
-
-
- The decoding process continues until a character with a value less than the algorithm's space constant is encountered,
-
- which signals the end of the encoded value. If the buffer is exhausted before a complete value is read, the method returns false.
-
-
-
-
-
- The decoded value is added to delta using zigzag decoding, which handles both positive and negative values.
-
-
-- api3: TryWriteValue(int, Span, ref int)
- id: PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L237
- metadata:
- uid: PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@)
- commentId: M:PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@)
-- markdown: Attempts to write an encoded integer value to a polyline buffer, updating the specified position.
-- code: public static bool TryWriteValue(int delta, Span buffer, ref int position)
-- h4: Parameters
-- parameters:
- - name: delta
- type:
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- description: >-
- The integer value to encode and write to the buffer. This value typically represents the difference between consecutive
-
- coordinate values in polyline encoding.
- - name: buffer
- type:
- - text: Span
- url: https://learn.microsoft.com/dotnet/api/system.span-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: The destination buffer where the encoded characters will be written. Must have sufficient capacity to hold the encoded value.
- - name: position
- type:
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- description: >-
- Reference to the current position in the buffer. This value is updated as characters are written to reflect the new position
-
- after encoding is complete.
-- h4: Returns
-- parameters:
- - type:
- - text: bool
- url: https://learn.microsoft.com/dotnet/api/system.boolean
- description: >-
- true if the value was successfully encoded and written to the buffer; false if the buffer
-
- does not have sufficient remaining capacity to hold the encoded value.
-- h4: Remarks
-- markdown: >-
-
-
- This method encodes an integer delta value into a polyline-encoded format and writes it to the provided character buffer,
-
- starting at the given position. It applies zigzag encoding followed by the polyline encoding algorithm to represent
-
- both positive and negative values efficiently.
-
-
-
-
-
- The encoding process first converts the value using zigzag encoding (left shift by 1, with bitwise inversion for negative values),
-
- then writes it as a sequence of characters. Each character encodes 5 bits of data, with continuation bits indicating whether
-
- more characters follow. The position is advanced as characters are written.
-
-
-
-
-
- Before writing, the method validates that sufficient space is available in the buffer by calling .
-
- If the buffer does not have enough remaining capacity, the method returns false without modifying the buffer or position.
-
-
-
-
-
- This method is the inverse of and can be used to encode coordinate deltas for polyline serialization.
-
-
-- api3: ValidateBlockLength(ReadOnlySpan)
- id: PolylineAlgorithm_PolylineEncoding_ValidateBlockLength_System_ReadOnlySpan_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L438
- metadata:
- uid: PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char})
- commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char})
-- markdown: Validates the block structure of a polyline segment, ensuring each encoded value does not exceed 7 characters and the polyline ends correctly.
-- code: public static void ValidateBlockLength(ReadOnlySpan polyline)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - text: ReadOnlySpan
- url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: A span representing the polyline segment to validate.
-- h4: Remarks
-- markdown: >-
-
-
- Iterates through the polyline, counting the length of each block (a sequence of characters representing an encoded value).
-
- Throws an if any block exceeds 7 characters or if the polyline does not end with a valid block terminator.
-
-
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentException
- url: https://learn.microsoft.com/dotnet/api/system.argumentexception
- description: Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator.
-- api3: ValidateCharRange(ReadOnlySpan)
- id: PolylineAlgorithm_PolylineEncoding_ValidateCharRange_System_ReadOnlySpan_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L392
- metadata:
- uid: PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char})
- commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char})
-- markdown: Validates that all characters in the polyline segment are within the allowed ASCII range for polyline encoding.
-- code: public static void ValidateCharRange(ReadOnlySpan polyline)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - text: ReadOnlySpan
- url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: A span representing the polyline segment to validate.
-- h4: Remarks
-- markdown: >-
-
-
- Uses SIMD vectorization for efficient validation of large spans. Falls back to scalar checks for any block where an invalid character is detected.
-
-
-
-
-
- The valid range is from '?' (63) to '_' (95), inclusive. If an invalid character is found, an is thrown.
-
-
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentException
- url: https://learn.microsoft.com/dotnet/api/system.argumentexception
- description: Thrown when an invalid character is found in the polyline segment.
-- api3: ValidateFormat(ReadOnlySpan)
- id: PolylineAlgorithm_PolylineEncoding_ValidateFormat_System_ReadOnlySpan_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L370
- metadata:
- uid: PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char})
- commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char})
-- markdown: Validates the format of a polyline segment, ensuring all characters are valid and block structure is correct.
-- code: public static void ValidateFormat(ReadOnlySpan polyline)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - text: ReadOnlySpan
- url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: A span representing the polyline segment to validate.
-- h4: Remarks
-- markdown: >-
-
-
- This method performs two levels of validation on the provided polyline segment:
-
-
-
- -
- Character Range Validation: Checks that every character in the polyline is within the valid ASCII range for polyline encoding ('?' [63] to '_' [95], inclusive).
- Uses SIMD acceleration for efficient validation of large segments.
-
-
- Block Structure Validation: Ensures that each encoded value (block) does not exceed 7 characters and that the polyline ends with a valid block terminator.
-
-
-
- If an invalid character or block structure is detected, an is thrown with details about the error.
-
-
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentException
- url: https://learn.microsoft.com/dotnet/api/system.argumentexception
- description: Thrown when an invalid character is found or the block structure is invalid.
-languageId: csharp
-metadata:
- description: >-
- Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing
-
- geographic coordinate values.
diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml
deleted file mode 100644
index 1947eac1..00000000
--- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml
+++ /dev/null
@@ -1,127 +0,0 @@
-### YamlMime:ApiPage
-title: Class PolylineEncodingOptions
-body:
-- api1: Class PolylineEncodingOptions
- id: PolylineAlgorithm_PolylineEncodingOptions
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29
- metadata:
- uid: PolylineAlgorithm.PolylineEncodingOptions
- commentId: T:PolylineAlgorithm.PolylineEncodingOptions
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm
- url: PolylineAlgorithm.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Provides configuration options for polyline encoding operations.
-- code: public sealed class PolylineEncodingOptions
-- h4: Inheritance
-- inheritance:
- - text: object
- url: https://learn.microsoft.com/dotnet/api/system.object
- - text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
-- h4: Inherited Members
-- list:
- - text: object.Equals(object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
- - text: object.Equals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
- - text: object.GetHashCode()
- url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
- - text: object.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.object.gettype
- - text: object.ReferenceEquals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
- - text: object.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.object.tostring
-- h2: Remarks
-- markdown: >-
-
-
- This class allows you to configure various aspects of polyline encoding, including:
-
-
-
- - The level for coordinate encoding
- The for memory allocation strategy
- The for diagnostic logging
-
-
-
- All properties have internal setters and should be configured through a builder or factory pattern.
-
-
-- h2: Properties
-- api3: LoggerFactory
- id: PolylineAlgorithm_PolylineEncodingOptions_LoggerFactory
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41
- metadata:
- uid: PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory
- commentId: P:PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory
-- markdown: Gets the logger factory used for diagnostic logging during encoding operations.
-- code: public ILoggerFactory LoggerFactory { get; }
-- h4: Property Value
-- parameters:
- - type:
- - text: ILoggerFactory
- url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory
-- h4: Remarks
-- markdown: >-
- The default logger factory is , which does not log any messages.
-
- To enable logging, provide a custom implementation.
-- api3: Precision
- id: PolylineAlgorithm_PolylineEncodingOptions_Precision
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60
- metadata:
- uid: PolylineAlgorithm.PolylineEncodingOptions.Precision
- commentId: P:PolylineAlgorithm.PolylineEncodingOptions.Precision
-- markdown: Gets the precision level used for encoding coordinate values.
-- code: public uint Precision { get; }
-- h4: Property Value
-- parameters:
- - type:
- - text: uint
- url: https://learn.microsoft.com/dotnet/api/system.uint32
-- h4: Remarks
-- markdown: >-
-
-
- The precision determines the number of decimal places to which each coordinate value (latitude or longitude)
-
- is multiplied and truncated (not rounded) before encoding. For example, a precision of 5 means each coordinate is multiplied by 10^5
-
- and truncated to an integer before encoding.
-
-
-
-
-
- This setting does not directly correspond to a physical distance or accuracy in meters, but rather controls
-
- the granularity of the encoded values.
-
-
-- api3: StackAllocLimit
- id: PolylineAlgorithm_PolylineEncodingOptions_StackAllocLimit
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73
- metadata:
- uid: PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit
- commentId: P:PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit
-- markdown: Gets the maximum buffer size (in characters) that can be allocated on the stack for encoding operations.
-- code: public int StackAllocLimit { get; }
-- h4: Property Value
-- parameters:
- - type:
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
-- h4: Remarks
-- markdown: >-
- When the required buffer size for encoding exceeds this limit, memory will be allocated on the heap instead of the stack.
-
- This setting specifically applies to stack allocation of character arrays (stackalloc char[]) used during polyline encoding,
-
- balancing performance and stack safety.
-languageId: csharp
-metadata:
- description: Provides configuration options for polyline encoding operations.
diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
deleted file mode 100644
index 66ae63b8..00000000
--- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
+++ /dev/null
@@ -1,141 +0,0 @@
-### YamlMime:ApiPage
-title: Class PolylineEncodingOptionsBuilder
-body:
-- api1: Class PolylineEncodingOptionsBuilder
- id: PolylineAlgorithm_PolylineEncodingOptionsBuilder
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15
- metadata:
- uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder
- commentId: T:PolylineAlgorithm.PolylineEncodingOptionsBuilder
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm
- url: PolylineAlgorithm.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Provides a builder for configuring options for polyline encoding operations.
-- code: public sealed class PolylineEncodingOptionsBuilder
-- h4: Inheritance
-- inheritance:
- - text: object
- url: https://learn.microsoft.com/dotnet/api/system.object
- - text: PolylineEncodingOptionsBuilder
- url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
-- h4: Inherited Members
-- list:
- - text: object.Equals(object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
- - text: object.Equals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
- - text: object.GetHashCode()
- url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
- - text: object.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.object.gettype
- - text: object.ReferenceEquals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
- - text: object.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.object.tostring
-- h2: Methods
-- api3: Build()
- id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Build
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38
- metadata:
- uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build
- commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build
-- markdown: Builds a new instance using the configured options.
-- code: public PolylineEncodingOptions Build()
-- h4: Returns
-- parameters:
- - type:
- - text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
- description: A configured instance.
-- api3: Create()
- id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Create
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28
- metadata:
- uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create
- commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create
-- markdown: Creates a new instance for the specified coordinate type.
-- code: public static PolylineEncodingOptionsBuilder Create()
-- h4: Returns
-- parameters:
- - type:
- - text: PolylineEncodingOptionsBuilder
- url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
- description: An instance for configuring polyline encoding options.
-- api3: WithLoggerFactory(ILoggerFactory)
- id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithLoggerFactory_Microsoft_Extensions_Logging_ILoggerFactory_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97
- metadata:
- uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory)
- commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory)
-- markdown: Configures the to be used for logging during polyline encoding operations.
-- code: public PolylineEncodingOptionsBuilder WithLoggerFactory(ILoggerFactory loggerFactory)
-- h4: Parameters
-- parameters:
- - name: loggerFactory
- type:
- - text: ILoggerFactory
- url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory
- description: The instance to use for logging. If null, a will be used instead.
-- h4: Returns
-- parameters:
- - type:
- - text: PolylineEncodingOptionsBuilder
- url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
- description: The current instance for method chaining.
-- api3: WithPrecision(uint)
- id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithPrecision_System_UInt32_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82
- metadata:
- uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32)
- commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32)
-- markdown: Sets the coordinate encoding precision.
-- code: public PolylineEncodingOptionsBuilder WithPrecision(uint precision)
-- h4: Parameters
-- parameters:
- - name: precision
- type:
- - text: uint
- url: https://learn.microsoft.com/dotnet/api/system.uint32
- description: The number of decimal places to use for encoding coordinate values. Default is 5.
-- h4: Returns
-- parameters:
- - type:
- - text: PolylineEncodingOptionsBuilder
- url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
- description: The current instance for method chaining.
-- api3: WithStackAllocLimit(int)
- id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithStackAllocLimit_System_Int32_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61
- metadata:
- uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32)
- commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32)
-- markdown: Configures the buffer size used for stack allocation during polyline encoding operations.
-- code: public PolylineEncodingOptionsBuilder WithStackAllocLimit(int stackAllocLimit)
-- h4: Parameters
-- parameters:
- - name: stackAllocLimit
- type:
- - text: int
- url: https://learn.microsoft.com/dotnet/api/system.int32
- description: The maximum buffer size to use for stack allocation. Must be greater than or equal to 1.
-- h4: Returns
-- parameters:
- - type:
- - text: PolylineEncodingOptionsBuilder
- url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
- description: The current instance for method chaining.
-- h4: Remarks
-- markdown: This method allows customization of the internal buffer size for encoding, which can impact performance and memory usage.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentOutOfRangeException
- url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception
- description: Thrown if stackAllocLimit is less than 1.
-languageId: csharp
-metadata:
- description: Provides a builder for configuring options for polyline encoding operations.
diff --git a/api-reference/0.0/PolylineAlgorithm.yml b/api-reference/0.0/PolylineAlgorithm.yml
deleted file mode 100644
index b60dc3c0..00000000
--- a/api-reference/0.0/PolylineAlgorithm.yml
+++ /dev/null
@@ -1,38 +0,0 @@
-### YamlMime:ApiPage
-title: Namespace PolylineAlgorithm
-body:
-- api1: Namespace PolylineAlgorithm
- id: PolylineAlgorithm
- metadata:
- uid: PolylineAlgorithm
- commentId: N:PolylineAlgorithm
-- h3: Namespaces
-- parameters:
- - type:
- text: PolylineAlgorithm.Abstraction
- url: PolylineAlgorithm.Abstraction.html
- - type:
- text: PolylineAlgorithm.Extensions
- url: PolylineAlgorithm.Extensions.html
-- h3: Classes
-- parameters:
- - type:
- text: InvalidPolylineException
- url: PolylineAlgorithm.InvalidPolylineException.html
- description: Exception thrown when a polyline is determined to be malformed or invalid during processing.
- - type:
- text: PolylineEncoding
- url: PolylineAlgorithm.PolylineEncoding.html
- description: >-
- Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing
-
- geographic coordinate values.
- - type:
- text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
- description: Provides configuration options for polyline encoding operations.
- - type:
- text: PolylineEncodingOptionsBuilder
- url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
- description: Provides a builder for configuring options for polyline encoding operations.
-languageId: csharp
diff --git a/api-reference/0.0/toc.yml b/api-reference/0.0/toc.yml
deleted file mode 100644
index d1ffc58a..00000000
--- a/api-reference/0.0/toc.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-### YamlMime:TableOfContent
-- name: PolylineAlgorithm
- href: PolylineAlgorithm.yml
- items:
- - name: Classes
- - name: InvalidPolylineException
- href: PolylineAlgorithm.InvalidPolylineException.yml
- - name: PolylineEncoding
- href: PolylineAlgorithm.PolylineEncoding.yml
- - name: PolylineEncodingOptions
- href: PolylineAlgorithm.PolylineEncodingOptions.yml
- - name: PolylineEncodingOptionsBuilder
- href: PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
-- name: PolylineAlgorithm.Abstraction
- href: PolylineAlgorithm.Abstraction.yml
- items:
- - name: Classes
- - name: AbstractPolylineDecoder
- href: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
- - name: AbstractPolylineEncoder
- href: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
- - name: Interfaces
- - name: IPolylineDecoder
- href: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
- - name: IPolylineEncoder
- href: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
-- name: PolylineAlgorithm.Extensions
- href: PolylineAlgorithm.Extensions.yml
- items:
- - name: Classes
- - name: PolylineDecoderExtensions
- href: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
- - name: PolylineEncoderExtensions
- href: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
diff --git a/api-reference/guide/benchmarks.md b/api-reference/guide/benchmarks.md
deleted file mode 100644
index 47b453f9..00000000
--- a/api-reference/guide/benchmarks.md
+++ /dev/null
@@ -1,11 +0,0 @@
----
-title: Benchmarks
----
-# Benchmarks
-
-Performance benchmarks for **PolylineAlgorithm for .NET** measured using [BenchmarkDotNet](https://benchmarkdotnet.org/).
-
-> [!NOTE]
-> Benchmarks are generated automatically during the release process. Results may vary depending on hardware and runtime version.
-
-{benchmarks_section}
diff --git a/api-reference/guide/toc.yml b/api-reference/guide/toc.yml
index e9d9e716..015a9943 100644
--- a/api-reference/guide/toc.yml
+++ b/api-reference/guide/toc.yml
@@ -8,5 +8,3 @@
href: sample.md
- name: FAQ
href: faq.md
-- name: Benchmarks
- href: benchmarks.md
diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
index b6b54081..f28c8141 100644
--- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
+++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
@@ -93,10 +93,8 @@ public void PolylineDecoder_Decode_Memory() {
}
private sealed class StringPolylineDecoder : AbstractPolylineDecoder {
- protected override int ValuesPerItem => 2;
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
+ return (latitude, longitude);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) {
@@ -105,10 +103,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) {
}
private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder {
- protected override int ValuesPerItem => 2;
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
+ return (latitude, longitude);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) {
@@ -117,10 +113,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) {
}
private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> {
- protected override int ValuesPerItem => 2;
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
+ return (latitude, longitude);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) {
diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
index c4b9d5a8..e0b97c5c 100644
--- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
+++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
@@ -85,11 +85,8 @@ public void PolylineEncoder_Encode_List() {
}
private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
- protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
- destination[0] = item.Latitude;
- destination[1] = item.Longitude;
- }
+ protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
+ protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
}
}
diff --git a/docs/local-development.md b/docs/local-development.md
index ab2da8ab..48fa5f76 100644
--- a/docs/local-development.md
+++ b/docs/local-development.md
@@ -72,24 +72,3 @@ The CI `format` job also runs `dotnet format` automatically on every push to non
## Editor Configuration
Code style rules are stored in `.editorconfig` at the repository root. Any compliant IDE (Visual Studio, VS Code with C# Dev Kit, Rider) will pick these up automatically.
-
-## Required Repository Secrets and Variables
-
-The CI/CD workflows rely on the following GitHub repository secrets and variables.
-
-### Secrets
-
-| Name | Description |
-|------|-------------|
-| `NUGET_PACKAGE_FEED_API_KEY` | API key for the Azure Artifacts NuGet feed |
-
-### Variables
-
-| Name | Description |
-|------|-------------|
-| `NUGET_PACKAGE_FEED_URL` | NuGet feed URL |
-| `BENCHMARKDOTNET_RUN_OVERRIDE` | Set to `true` to force benchmarks to run on non-release PRs |
-| `BENCHMARKDOTNET_RUNTIMES` | Runtimes to benchmark (e.g. `net8.0 net10.0`) |
-| `BENCHMARKDOTNET_FILTER` | Benchmark filter pattern (e.g. `*`) |
-| `DEFAULT_BUILD_FRAMEWORK` | Default target framework for builds (e.g. `net10.0`) |
-| `SRC_DEFAULT_GLOB_PATTERN` | Glob pattern for source project files (e.g. `**/PolylineAlgorithm.csproj`) |
diff --git a/docs/workflows.md b/docs/workflows.md
index 8782270f..4c864783 100644
--- a/docs/workflows.md
+++ b/docs/workflows.md
@@ -87,7 +87,6 @@ Version bumping runs independently via `bump-version.yml` (manual trigger).
| `pack` | `versioning`, `build` | Packages binaries |
| `publish-package` | `pack` | Publishes to NuGet.org (Production environment) |
| `create-release` | `versioning`, `publish-package` | Creates a git tag + GitHub release with auto-generated notes |
-| `update-changelog` | `release` | Fetches release notes and prepends a new entry to `CHANGELOG.md` — stable releases only |
| `generate-docs` | `versioning` | Builds DocFX site |
| `publish-docs` | `generate-docs` | Deploys to GitHub Pages |
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
index dd05ca88..82899203 100644
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
@@ -12,23 +12,16 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample;
///
/// Polyline decoder using NetTopologySuite.
///
-internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder {
+public sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder {
///
- /// Gets the number of encoded values per item: latitude (index 0) and longitude (index 1).
+ /// Creates a NetTopologySuite point from latitude and longitude.
///
- protected override int ValuesPerItem => 2;
-
- ///
- /// Creates a NetTopologySuite point from the decoded values.
- ///
- ///
- /// A memory region containing two values: index 0 is latitude, index 1 is longitude.
- ///
+ /// Latitude value.
+ /// Longitude value.
/// Point instance.
- protected override Point CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
+ protected override Point CreateCoordinate(double latitude, double longitude) {
// NetTopologySuite Point: x = longitude, y = latitude
- return new Point(span[1], span[0]);
+ return new Point(longitude, latitude);
}
///
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
index 5a7b5529..649547bd 100644
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
@@ -7,17 +7,11 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample;
using global::NetTopologySuite.Geometries;
using PolylineAlgorithm.Abstraction;
-using System;
///
/// Polyline encoder using NetTopologySuite's Point type.
///
-internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder {
- ///
- /// Gets the number of values per item: latitude (index 0) and longitude (index 1).
- ///
- protected override int ValuesPerItem => 2;
-
+public sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder {
///
/// Creates encoded polyline string from memory.
///
@@ -32,15 +26,30 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) {
}
///
- /// Fills destination with latitude (index 0) and longitude (index 1) from the point.
+ /// Gets latitude from point.
///
- /// Point instance.
- /// Span of length 2 to fill.
- protected override void GetValues(Point item, Span destination) {
- ArgumentNullException.ThrowIfNull(item);
-
- // NetTopologySuite Point: Y = latitude, X = longitude
- destination[0] = item.Y;
- destination[1] = item.X;
+ /// Point instance.
+ /// Latitude value.
+ protected override double GetLatitude(Point current) {
+ if (current is null) {
+ throw new ArgumentNullException(nameof(current));
+ }
+
+ // NetTopologySuite Point: Y = latitude
+ return current.Y;
+ }
+
+ ///
+ /// Gets longitude from point.
+ ///
+ /// Point instance.
+ /// Longitude value.
+ protected override double GetLongitude(Point current) {
+ if (current is null) {
+ throw new ArgumentNullException(nameof(current));
+ }
+
+ // NetTopologySuite Point: X = longitude
+ return current.X;
}
}
\ No newline at end of file
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj b/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj
index fef82026..57d5f7c1 100644
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj
@@ -1,8 +1,7 @@
- Exe
- net10.0
+ netstandard2.1
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs
deleted file mode 100644
index ca9a8a6f..00000000
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-//
-// Copyright © Pete Sramek. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
-//
-
-using NetTopologySuite.Geometries;
-using PolylineAlgorithm.NetTopologySuite.Sample;
-
-public class Program {
- public static void Main(string[] args) {
- // Sample route: Seattle → Bellevue → Redmond
- var points = new Point[]
- {
- new(x: -122.3503, y: 47.6219), // Seattle (x = longitude, y = latitude)
- new(x: -122.2015, y: 47.6101), // Bellevue
- new(x: -122.1215, y: 47.6740), // Redmond
- };
-
- var encoder = new NetTopologyPolylineEncoder();
- var decoder = new NetTopologyPolylineDecoder();
-
- // Encode
- string encoded = encoder.Encode(points);
-
- Console.WriteLine("=== NetTopologySuite Polyline Sample ===");
- Console.WriteLine();
- Console.WriteLine("Input points (longitude, latitude):");
-
- foreach (Point p in points) {
- Console.WriteLine($" ({p.X}, {p.Y})");
- }
-
- Console.WriteLine();
- Console.WriteLine($"Encoded polyline: {encoded}");
- Console.WriteLine();
-
- // Decode
- IEnumerable decoded = decoder.Decode(encoded);
-
- Console.WriteLine("Decoded points (longitude, latitude):");
-
- foreach (Point p in decoded) {
- Console.WriteLine($" ({p.X}, {p.Y})");
- }
- }
-}
\ No newline at end of file
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj b/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj
deleted file mode 100644
index 3e1bcb63..00000000
--- a/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- Exe
- net10.0
-
-
-
- false
-
-
-
-
-
-
-
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/Program.cs b/samples/PolylineAlgorithm.SensorData.Sample/Program.cs
deleted file mode 100644
index e14977f9..00000000
--- a/samples/PolylineAlgorithm.SensorData.Sample/Program.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-// Copyright © Pete Sramek. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
-//
-
-using PolylineAlgorithm.SensorData.Sample;
-
-public static class Program {
- public static void Main(string[] args) {
- // Sample temperature readings from a sensor over six seconds
- var readings = new SensorReading[]
- {
- new(DateTimeOffset.UtcNow, 23.5),
- new(DateTimeOffset.UtcNow.AddSeconds(1), 23.7),
- new(DateTimeOffset.UtcNow.AddSeconds(2), 24.1),
- new(DateTimeOffset.UtcNow.AddSeconds(3), 25.0),
- new(DateTimeOffset.UtcNow.AddSeconds(4), 24.8),
- new(DateTimeOffset.UtcNow.AddSeconds(5), 24.8),
- new(DateTimeOffset.UtcNow.AddSeconds(6), 22.3),
- };
-
- var encoder = new SensorDataEncoder();
- var decoder = new SensorDataDecoder();
-
- // Encode
- string encoded = encoder.Encode(readings);
-
- Console.WriteLine("=== Sensor Data Polyline Sample ===");
- Console.WriteLine();
- Console.WriteLine("Input readings:");
-
- foreach (SensorReading r in readings) {
- Console.WriteLine($" [{r.Timestamp:HH:mm:ss}] {r.Temperature:F1} °C");
- }
-
- Console.WriteLine();
- Console.WriteLine($"Encoded polyline: {encoded}");
- Console.WriteLine();
-
- // Decode (timestamps and temperatures are both recovered)
- IEnumerable decoded = decoder.Decode(encoded);
-
- Console.WriteLine("Decoded readings:");
-
- foreach (SensorReading r in decoded) {
- Console.WriteLine($" [{r.Timestamp:HH:mm:ss}] {r.Temperature:F1} °C");
- }
- }
-}
\ No newline at end of file
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs b/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs
deleted file mode 100644
index e3468ef6..00000000
--- a/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs
+++ /dev/null
@@ -1,8 +0,0 @@
-//
-// Copyright © Pete Sramek. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
-//
-
-using System.Diagnostics.CodeAnalysis;
-
-[assembly: ExcludeFromCodeCoverage]
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs
deleted file mode 100644
index 9c63d647..00000000
--- a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs
+++ /dev/null
@@ -1,107 +0,0 @@
-//
-// Copyright © Pete Sramek. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
-//
-
-namespace PolylineAlgorithm.SensorData.Sample;
-
-using PolylineAlgorithm.Abstraction;
-using System.Collections.Generic;
-using System.Threading;
-
-///
-/// Decodes a compact polyline string produced by back into a sequence
-/// of values.
-///
-///
-///
-/// This class demonstrates implementing for a custom
-/// scalar type, following the same structural pattern as .
-///
-///
-/// Each encoded pair consists of a delta-compressed Unix timestamp (seconds since Unix epoch, precision 0)
-/// followed by a delta-compressed temperature value (at ).
-/// Both are recovered and used to reconstruct the original .
-///
-///
-[System.Diagnostics.CodeAnalysis.SuppressMessage("Sonar", "S4456:Parameter validation in yielding methods should be wrapped", Justification = "Inlined by design to demonstrate a simple iterator without a wrapper method.")]
-internal sealed class SensorDataDecoder : IPolylineDecoder {
- ///
- /// Initializes a new instance of the class with default encoding options.
- ///
- public SensorDataDecoder()
- : this(new PolylineEncodingOptions()) { }
-
- ///
- /// Initializes a new instance of the class with the specified encoding options.
- ///
- ///
- /// The to use for decoding operations.
- /// The value must match the precision used during encoding.
- ///
- ///
- /// Thrown when is .
- ///
- public SensorDataDecoder(PolylineEncodingOptions options) {
- ArgumentNullException.ThrowIfNull(options);
-
- Options = options;
- }
-
- ///
- /// Gets the encoding options used by this decoder.
- ///
- public PolylineEncodingOptions Options { get; }
-
- ///
- /// Decodes a polyline string back into a sequence of values.
- ///
- ///
- /// The polyline-encoded string produced by .
- ///
- ///
- /// A that can be used to cancel the decoding operation.
- ///
- ///
- /// An of whose
- /// and values
- /// are recovered from the encoded string.
- ///
- ///
- /// Thrown when is .
- ///
- ///
- /// Thrown when is empty.
- ///
- ///
- /// Thrown when requests cancellation.
- ///
- public IEnumerable Decode(string polyline, CancellationToken cancellationToken = default) {
- ArgumentNullException.ThrowIfNull(polyline);
-
- if (polyline.Length < 1) {
- throw new ArgumentException("Encoded polyline must not be empty.", nameof(polyline));
- }
-
- ReadOnlyMemory memory = polyline.AsMemory();
- int position = 0;
- // Mirror the encoder's base epoch so the first delta decodes back to the correct Unix seconds.
- int accumulatedTimestamp = SensorDataEncoder.TimestampBaseEpochSeconds;
- int accumulatedTemperature = 0;
-
- while (position < memory.Length) {
- cancellationToken.ThrowIfCancellationRequested();
-
- // Read Unix timestamp delta (precision 0) then temperature delta.
- if (!PolylineEncoding.TryReadValue(ref accumulatedTimestamp, memory, ref position)
- || !PolylineEncoding.TryReadValue(ref accumulatedTemperature, memory, ref position)) {
- yield break;
- }
-
- long unixSeconds = (long)PolylineEncoding.Denormalize(accumulatedTimestamp, precision: 0);
- double temperature = PolylineEncoding.Denormalize(accumulatedTemperature, Options.Precision);
-
- yield return new SensorReading(DateTimeOffset.FromUnixTimeSeconds(unixSeconds), temperature);
- }
- }
-}
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs
deleted file mode 100644
index be199e4d..00000000
--- a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs
+++ /dev/null
@@ -1,135 +0,0 @@
-//
-// Copyright © Pete Sramek. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
-//
-
-namespace PolylineAlgorithm.SensorData.Sample;
-
-using PolylineAlgorithm.Abstraction;
-using System.Buffers;
-using System.Threading;
-
-///
-/// Encodes a sequence of values into a compact polyline string
-/// using the polyline delta-encoding algorithm applied to both the
-/// and fields.
-///
-///
-///
-/// This class demonstrates implementing for a custom
-/// scalar type, following the same structural pattern as .
-///
-///
-/// Because sensor readings carry two numeric dimensions (timestamp and temperature), the base class designed
-/// for geographic coordinate pairs is not used. Instead, static
-/// helpers are called directly to perform normalisation, delta computation, and character-level encoding.
-///
-///
-/// Each reading is encoded as a pair of delta-compressed values:
-/// the Unix timestamp in seconds (precision 0) followed by the temperature (at ).
-///
-///
-internal sealed class SensorDataEncoder : IPolylineEncoder {
- // 2020-01-01 00:00:00 UTC in Unix seconds. Used as the delta-encoding base for timestamps
- // so that the first absolute delta stays within the int32 safe range of the polyline algorithm.
- internal const int TimestampBaseEpochSeconds = 1_577_836_800;
-
- ///
- /// Initializes a new instance of the class with default encoding options.
- ///
- public SensorDataEncoder()
- : this(new PolylineEncodingOptions()) { }
-
- ///
- /// Initializes a new instance of the class with the specified encoding options.
- ///
- ///
- /// The to use for encoding operations.
- ///
- ///
- /// Thrown when is .
- ///
- public SensorDataEncoder(PolylineEncodingOptions options) {
- ArgumentNullException.ThrowIfNull(options);
-
- Options = options;
- }
-
- ///
- /// Gets the encoding options used by this encoder.
- ///
- public PolylineEncodingOptions Options { get; }
-
- ///
- /// Encodes a sequence of values into a polyline string.
- ///
- ///
- /// The sensor readings to encode. Each reading contributes a delta-compressed Unix timestamp
- /// (seconds since Unix epoch, precision 0) and a delta-compressed temperature value.
- /// Must contain at least one element.
- ///
- ///
- /// A that can be used to cancel the encoding operation.
- ///
- ///
- /// A polyline-encoded string representing the delta-compressed timestamp and temperature series.
- ///
- ///
- /// Thrown when is empty.
- ///
- ///
- /// Thrown when requests cancellation.
- ///
- public string Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) {
- if (coordinates.Length < 1) {
- throw new ArgumentException("Sequence must contain at least one element.", nameof(coordinates));
- }
-
- // Maximum number of ASCII characters required to encode a single 32-bit delta value
- // using the polyline algorithm (ceil(32 bits / 5 bits per chunk) + sign bit = 7).
- const int MaxEncodedCharsPerValue = 7;
-
- // Each reading encodes two values: Unix timestamp (precision 0) + temperature.
- // The polyline algorithm uses signed int32 internally, limiting safe absolute values to ~1.07B.
- // Current Unix time in seconds (~1.74B) exceeds this. We therefore delta-encode relative to
- // 2020-01-01 00:00:00 UTC (= 1 577 836 800 s), keeping the initial delta well within range.
- int previousTimestampNormalized = TimestampBaseEpochSeconds;
- int previousTemperatureNormalized = 0;
- int position = 0;
- int length = coordinates.Length * 2 * MaxEncodedCharsPerValue;
-
- char[]? temp = length <= Options.StackAllocLimit
- ? null
- : ArrayPool.Shared.Rent(length);
-
- Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length);
-
- try {
- for (int i = 0; i < coordinates.Length; i++) {
- cancellationToken.ThrowIfCancellationRequested();
-
- // Encode Unix timestamp in whole seconds (precision 0).
- int normalizedTimestamp = PolylineEncoding.Normalize((double)coordinates[i].Timestamp.ToUnixTimeSeconds(), precision: 0);
- int timestampDelta = normalizedTimestamp - previousTimestampNormalized;
-
- // Encode temperature at the configured precision.
- int normalizedTemperature = PolylineEncoding.Normalize(coordinates[i].Temperature, Options.Precision);
- int temperatureDelta = normalizedTemperature - previousTemperatureNormalized;
-
- if (!PolylineEncoding.TryWriteValue(timestampDelta, buffer, ref position)
- || !PolylineEncoding.TryWriteValue(temperatureDelta, buffer, ref position)) {
- throw new InvalidOperationException("Encoding buffer is too small to hold the encoded value.");
- }
-
- previousTimestampNormalized = normalizedTimestamp;
- previousTemperatureNormalized = normalizedTemperature;
- }
-
- return buffer[..position].ToString();
- } finally {
- if (temp is not null) {
- ArrayPool.Shared.Return(temp);
- }
- }
- }
-}
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs
deleted file mode 100644
index 6903c92f..00000000
--- a/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// Copyright © Pete Sramek. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
-//
-
-namespace PolylineAlgorithm.SensorData.Sample;
-
-using System.Runtime.InteropServices;
-
-///
-/// Represents a single temperature reading captured by a sensor.
-///
-/// The UTC time at which the reading was captured.
-/// The temperature value of the reading, in degrees Celsius.
-[StructLayout(LayoutKind.Auto)]
-internal readonly record struct SensorReading(DateTimeOffset Timestamp, double Temperature);
diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
index ea087776..1059abb9 100644
--- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
+++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
@@ -6,27 +6,19 @@
using Microsoft.Extensions.Logging;
using PolylineAlgorithm.Internal;
using PolylineAlgorithm.Internal.Diagnostics;
-using System.Buffers;
using System.Runtime.CompilerServices;
namespace PolylineAlgorithm.Abstraction;
///
-/// Provides a base implementation for decoding encoded polyline strings into sequences of items.
+/// Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
///
///
-/// Derive from this class to implement a decoder for a specific polyline type. Override
-/// , , and to provide
-/// type-specific behavior.
-///
-/// The polyline format encodes each item as a fixed-length run of delta-compressed
-/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS decoder
-/// sets to 2 (latitude, longitude), while a 3D GPS decoder sets it to 3
-/// (latitude, longitude, altitude).
-///
+/// Derive from this class to implement a decoder for a specific polyline type. Override
+/// and to provide type-specific behavior.
///
/// The type that represents the encoded polyline input.
-/// The type that represents a decoded item.
+/// The type that represents a decoded geographic coordinate.
public abstract class AbstractPolylineDecoder : IPolylineDecoder {
private readonly ILogger> _logger;
@@ -61,16 +53,6 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
///
public PolylineEncodingOptions Options { get; }
- ///
- /// Gets the number of encoded values that make up a single decoded item.
- ///
- ///
- /// Override this property to specify the arity of each item. For example, return 2 for
- /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count
- /// that matches the encoding scheme used to produce the polyline.
- ///
- protected abstract int ValuesPerItem { get; }
-
///
/// Decodes an encoded into a sequence of instances,
/// with support for cancellation.
@@ -82,7 +64,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
/// A that can be used to cancel the decoding operation.
///
///
- /// An of representing the decoded items.
+ /// An of representing the decoded latitude and longitude pairs.
///
///
/// Thrown when is .
@@ -108,45 +90,30 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can
ValidateSequence(sequence, _logger);
ValidateFormat(sequence, _logger);
- int valuesPerItem = ValuesPerItem;
int position = 0;
-
- int[]? runningRent = ArrayPool.Shared.Rent(valuesPerItem);
- // Zero-initialize so delta decoding starts from 0 for all dimensions.
- for (int j = 0; j < valuesPerItem; j++) {
- runningRent[j] = 0;
- }
+ int encodedLatitude = 0;
+ int encodedLongitude = 0;
try {
while (position < sequence.Length) {
cancellationToken.ThrowIfCancellationRequested();
- bool allRead = true;
- for (int j = 0; j < valuesPerItem; j++) {
- if (!PolylineEncoding.TryReadValue(ref runningRent[j], sequence, ref position)) {
- allRead = false;
- break;
- }
- }
-
- if (!allRead) {
+ if (!PolylineEncoding.TryReadValue(ref encodedLatitude, sequence, ref position)
+ || !PolylineEncoding.TryReadValue(ref encodedLongitude, sequence, ref position)) {
_logger?.LogOperationFailedDebug(OperationName);
_logger?.LogInvalidPolylineWarning(position);
ExceptionGuard.ThrowInvalidPolylineFormat(position);
}
- double[] decoded = new double[valuesPerItem];
- for (int j = 0; j < valuesPerItem; j++) {
- decoded[j] = PolylineEncoding.Denormalize(runningRent[j], Options.Precision);
- }
+ double decodedLatitude = PolylineEncoding.Denormalize(encodedLatitude, Options.Precision);
+ double decodedLongitude = PolylineEncoding.Denormalize(encodedLongitude, Options.Precision);
- _logger?.LogDecodedValuesDebug(valuesPerItem, position);
+ _logger?.LogDecodedCoordinateDebug(decodedLatitude, decodedLongitude, position);
- yield return CreateItem(decoded.AsMemory());
+ yield return CreateCoordinate(decodedLatitude, decodedLongitude);
}
} finally {
- ArrayPool.Shared.Return(runningRent!);
_logger?.LogOperationFinishedDebug(OperationName);
}
}
@@ -221,19 +188,17 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo
protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline);
///
- /// Creates a instance from the specified decoded values.
+ /// Creates a instance from the specified latitude and longitude values.
///
- ///
- /// A of containing exactly
- /// decoded values for this item, in the same order they were encoded.
+ ///
+ /// The latitude component of the coordinate, in degrees.
+ ///
+ ///
+ /// The longitude component of the coordinate, in degrees.
///
///
- /// A instance representing the decoded item.
+ /// A instance representing the specified geographic coordinate.
///
- ///
- /// Implementations should read all required values from and construct the
- /// immediately. The memory is valid only for the duration of this call.
- ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected abstract TCoordinate CreateItem(ReadOnlyMemory values);
+ protected abstract TCoordinate CreateCoordinate(double latitude, double longitude);
}
diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
index dff4eac3..1bcdb0ee 100644
--- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
+++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
@@ -16,19 +16,13 @@ namespace PolylineAlgorithm.Abstraction;
using System.Threading;
///
-/// Provides a base implementation for encoding sequences of items into encoded polyline strings.
+/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
///
///
-/// Derive from this class to implement an encoder for a specific item and polyline type. Override
-/// , , and to provide type-specific behavior.
-///
-/// The polyline format encodes each item as a fixed-length run of delta-compressed
-/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS encoder
-/// sets to 2 (latitude, longitude), while a 3D GPS encoder sets it to 3
-/// (latitude, longitude, altitude).
-///
+/// Derive from this class to implement an encoder for a specific coordinate and polyline type. Override
+/// , , and to provide type-specific behavior.
///
-/// The type that represents an item to encode.
+/// The type that represents a geographic coordinate to encode.
/// The type that represents the encoded polyline output.
public abstract class AbstractPolylineEncoder : IPolylineEncoder {
private readonly ILogger> _logger;
@@ -62,16 +56,6 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) {
///
public PolylineEncodingOptions Options { get; }
- ///
- /// Gets the number of values that make up a single encoded item.
- ///
- ///
- /// Override this property to specify the arity of each item. For example, return 2 for
- /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count
- /// that matches your encoding scheme.
- ///
- protected abstract int ValuesPerItem { get; }
-
///
/// Encodes a collection of instances into an encoded string.
///
@@ -104,12 +88,11 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
ValidateEmptyCoordinates(ref coordinates, _logger);
- int valuesPerItem = ValuesPerItem;
- CoordinateDelta delta = new(valuesPerItem);
+ CoordinateDelta delta = new();
int position = 0;
int consumed = 0;
- int length = GetMaxBufferLength(coordinates.Length, valuesPerItem);
+ int length = GetMaxBufferLength(coordinates.Length);
char[]? temp = length <= Options.StackAllocLimit
? null
@@ -117,37 +100,29 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length);
- int[]? normalizedRent = ArrayPool.Shared.Rent(valuesPerItem);
- Span normalized = normalizedRent.AsSpan(0, valuesPerItem);
-
- double[]? valuesRent = ArrayPool.Shared.Rent(valuesPerItem);
- Span values = valuesRent.AsSpan(0, valuesPerItem);
-
string encodedResult;
try {
for (var i = 0; i < coordinates.Length; i++) {
cancellationToken.ThrowIfCancellationRequested();
- GetValues(coordinates[i], values);
-
- for (int j = 0; j < valuesPerItem; j++) {
- normalized[j] = PolylineEncoding.Normalize(values[j], Options.Precision);
- }
+ delta
+ .Next(
+ PolylineEncoding.Normalize(GetLatitude(coordinates[i]), Options.Precision),
+ PolylineEncoding.Normalize(GetLongitude(coordinates[i]), Options.Precision)
+ );
- delta.Next(normalized);
+ if (!PolylineEncoding.TryWriteValue(delta.Latitude, buffer, ref position)
+ || !PolylineEncoding.TryWriteValue(delta.Longitude, buffer, ref position)
+ ) {
+ // This shouldn't happen, but if it does, log the error and throw an exception.
+ _logger
+ .LogOperationFailedDebug(OperationName);
+ _logger
+ .LogCannotWriteValueToBufferWarning(position, consumed);
- ReadOnlySpan deltas = delta.Deltas;
- for (int j = 0; j < deltas.Length; j++) {
- if (!PolylineEncoding.TryWriteValue(deltas[j], buffer, ref position)) {
- // This shouldn't happen, but if it does, log the error and throw an exception.
- _logger
- .LogOperationFailedDebug(OperationName);
- _logger
- .LogCannotWriteValueToBufferWarning(position, consumed);
+ ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer();
- ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer();
- }
}
consumed++;
@@ -155,8 +130,6 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
encodedResult = buffer[..position].ToString();
} finally {
- ArrayPool.Shared.Return(valuesRent!);
- ArrayPool.Shared.Return(normalizedRent!);
if (temp is not null) {
ArrayPool.Shared.Return(temp);
}
@@ -168,10 +141,10 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
return CreatePolyline(encodedResult.AsMemory());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- static int GetMaxBufferLength(int count, int perItem) {
+ static int GetMaxBufferLength(int count) {
Debug.Assert(count > 0, "Count must be greater than zero.");
- int requestedBufferLength = count * perItem * Defaults.Polyline.Block.Length.Max;
+ int requestedBufferLength = count * 2 * Defaults.Polyline.Block.Length.Max;
Debug.Assert(requestedBufferLength > 0, "Requested buffer length must be greater than zero.");
@@ -202,18 +175,23 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates,
protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline);
///
- /// Fills with the values to encode for the specified item.
+ /// Extracts the longitude value from the specified coordinate.
///
- /// The item from which to extract values.
- ///
- /// A of length to fill with the item's values,
- /// in the order they should be encoded.
- ///
- ///
- /// Implementations should write exactly values into .
- /// For example, a 2D GPS encoder writes destination[0] = latitude; destination[1] = longitude;.
- ///
+ /// The coordinate from which to extract the longitude.
+ ///
+ /// The longitude value as a .
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected abstract double GetLongitude(TCoordinate current);
+
+ ///
+ /// Extracts the latitude value from the specified coordinate.
+ ///
+ /// The coordinate from which to extract the latitude.
+ ///
+ /// The latitude value as a .
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected abstract void GetValues(TCoordinate item, Span destination);
+ protected abstract double GetLatitude(TCoordinate current);
}
diff --git a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
index 70826216..ae217c57 100644
--- a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
+++ b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
@@ -5,82 +5,68 @@
namespace PolylineAlgorithm.Internal;
-using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
-using System.Text;
///
-/// Represents the running delta state for an arbitrary number of encoded values between consecutive items.
+/// Represents the difference (delta) in latitude and longitude between consecutive geographic coordinates.
///
///
-/// This struct computes and stores the change in each value dimension as integer deltas between successive items.
-/// The number of dimensions is specified at construction time, enabling support for any number of encoded fields
-/// (e.g. latitude/longitude, latitude/longitude/altitude, or arbitrary sensor fields).
+/// This struct computes and stores the change in coordinate values as integer deltas between successive coordinates.
///
[DebuggerDisplay("{ToString(),nq}")]
[StructLayout(LayoutKind.Auto)]
internal struct CoordinateDelta {
- private readonly int[] _current;
- private readonly int[] _deltas;
+ private (int Latitude, int Longitude) _current;
///
- /// Initializes a new instance of the struct for the specified number of value dimensions.
+ /// Initializes a new instance of the struct with the default latitude and longitude deltas.
///
- /// The number of value dimensions to track. Must be greater than zero.
- public CoordinateDelta(int count) {
- Debug.Assert(count > 0, "Count must be greater than zero.");
-
- _current = new int[count];
- _deltas = new int[count];
+ public CoordinateDelta() {
+ _current = (default, default);
}
///
- /// Gets the current deltas computed by the most recent call to .
+ /// Gets the current delta in latitude between the most recent and previous coordinate.
+ ///
+ public int Latitude { get; private set; }
+
+ ///
+ /// Gets the current delta in longitude between the most recent and previous coordinate.
///
- public ReadOnlySpan Deltas => _deltas;
+ public int Longitude { get; private set; }
///
- /// Updates the delta values based on the next set of values, and sets them as the baseline for the next call.
+ /// Updates the delta values based on the next latitude and longitude, and sets the current coordinate as next delta baseline.
///
- ///
- /// The next normalized integer values. Must have the same length as the count passed to the constructor.
- ///
- public void Next(ReadOnlySpan values) {
- Debug.Assert(values.Length == _current.Length, "Values length must match the delta dimension count.");
+ /// The next latitude value.
+ /// The next longitude value.
+ public void Next(int latitude, int longitude) {
+ Latitude = Delta(_current.Latitude, latitude);
+ Longitude = Delta(_current.Longitude, longitude);
- for (int i = 0; i < values.Length; i++) {
- _deltas[i] = values[i] - _current[i];
- _current[i] = values[i];
- }
+ _current.Latitude = latitude;
+ _current.Longitude = longitude;
}
///
- /// Returns a string representation of the current values and deltas.
+ /// Calculates the delta between two coordinate values.
+ ///
+ ///
+ /// This method computes the difference between two integer coordinate values, handling cases where the values may be positive or negative.
+ ///
+ /// The previous coordinate value.
+ /// The next coordinate value.
+ /// The computed delta between and .
+ private static int Delta(int initial, int next) => next - initial;
+
+ ///
+ /// Returns a string representation of the current coordinate delta.
///
///
- /// A string in the format { Values: [v0, v1, ...], Deltas: [d0, d1, ...] }.
+ /// A string in the format { Coordinate: { Latitude: [int], Longitude: [int] }, Delta: { Latitude: [int], Longitude: [int] } } representing the current coordinate and deltas to previous coordinate.
///
- public override readonly string ToString() {
- var sb = new StringBuilder("{ Values: [");
- for (int i = 0; i < _current.Length; i++) {
- if (i > 0) {
- sb.Append(", ");
- }
-
- sb.Append(_current[i]);
- }
-
- sb.Append("], Deltas: [");
- for (int i = 0; i < _deltas.Length; i++) {
- if (i > 0) {
- sb.Append(", ");
- }
-
- sb.Append(_deltas[i]);
- }
-
- sb.Append("] }");
- return sb.ToString();
- }
+ public override readonly string ToString() =>
+ $"{{ Coordinate: {{ Latitude: {_current.Latitude}, Longitude: {_current.Longitude} }}, " +
+ $"Delta: {{ Latitude: {Latitude}, Longitude: {Longitude} }} }}";
}
\ No newline at end of file
diff --git a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
index 9a422a73..cc58c702 100644
--- a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
+++ b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
@@ -46,11 +46,12 @@ internal static partial class LogDebugExtensions {
internal static partial void LogOperationFinishedDebug(this ILogger logger, string operationName);
///
- /// Logs a debug message containing the number of decoded values and position.
+ /// Logs a debug message containing the decoded coordinate values and position.
///
/// The used to write the log entry.
- /// The number of values that were decoded for this item.
- /// The position in the polyline buffer at which the item was decoded.
- [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded {count} values at position {position}.")]
- internal static partial void LogDecodedValuesDebug(this ILogger logger, int count, int position);
+ /// The decoded latitude value.
+ /// The decoded longitude value.
+ /// The position in the polyline buffer at which the coordinate was decoded.
+ [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}.")]
+ internal static partial void LogDecodedCoordinateDebug(this ILogger logger, double latitude, double longitude, int position);
}
diff --git a/src/PolylineAlgorithm/PolylineAlgorithm.csproj b/src/PolylineAlgorithm/PolylineAlgorithm.csproj
index 907a2a15..24504239 100644
--- a/src/PolylineAlgorithm/PolylineAlgorithm.csproj
+++ b/src/PolylineAlgorithm/PolylineAlgorithm.csproj
@@ -8,13 +8,6 @@
True
-
-
- $(WarningsAsErrors);RS0017
-
-
true
diff --git a/src/PolylineAlgorithm/PolylineEncoding.cs b/src/PolylineAlgorithm/PolylineEncoding.cs
index 3d6de5e7..4b8d5312 100644
--- a/src/PolylineAlgorithm/PolylineEncoding.cs
+++ b/src/PolylineAlgorithm/PolylineEncoding.cs
@@ -1,4 +1,4 @@
-//
+//
// Copyright © Pete Sramek. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//
@@ -76,11 +76,10 @@ public static int Normalize(double value, uint precision = 5) {
uint factor = Pow10.GetFactor(precision);
- const double Epsilon = 1e-9;
-
checked {
- return (int)Math.Truncate((value * factor) + (Epsilon * Math.Sign(value)));
+ return (int)(Math.Truncate(value * 10 * factor) / 10);
}
+
}
///
diff --git a/src/PolylineAlgorithm/PublicAPI.Shipped.txt b/src/PolylineAlgorithm/PublicAPI.Shipped.txt
index 7dc5c581..91b0e1a4 100644
--- a/src/PolylineAlgorithm/PublicAPI.Shipped.txt
+++ b/src/PolylineAlgorithm/PublicAPI.Shipped.txt
@@ -1 +1 @@
-#nullable enable
+#nullable enable
\ No newline at end of file
diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
index 4033ef24..7dc5c581 100644
--- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
+++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
@@ -1,9 +1 @@
#nullable enable
-abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.CreateItem(System.ReadOnlyMemory values) -> TCoordinate
-abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory
-abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValuesPerItem.get -> int
-abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.GetValues(TCoordinate item, System.Span destination) -> void
-abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.ValuesPerItem.get -> int
-virtual PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValidateFormat(System.ReadOnlyMemory sequence, Microsoft.Extensions.Logging.ILogger? logger) -> void
-PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void
-PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void
diff --git a/src/PolylineAlgorithm/README.md b/src/PolylineAlgorithm/README.md
index 97c4bb98..d1bf97e0 100644
--- a/src/PolylineAlgorithm/README.md
+++ b/src/PolylineAlgorithm/README.md
@@ -1,8 +1,6 @@
# PolylineAlgorithm for .NET
-[](https://www.nuget.org/packages/PolylineAlgorithm)
-
-Google's Encoded Polyline Algorithm compresses sequences of geographic coordinates into a compact ASCII string, widely used in mapping APIs. This library provides a fully compliant .NET implementation with extensible, type-safe encoding and decoding APIs.
+A modern, fully compliant Google Encoded Polyline Algorithm library for .NET Standard 2.1+, supporting strong input validation, extensibility for custom coordinate types, and robust performance.
## Features
@@ -61,7 +59,6 @@ var encoder = new MyPolylineEncoder();
string encoded = encoder.Encode(coordinates); // extension method for List
Console.WriteLine(encoded);
-// Output: "yseiHoc_MwacOjnwM"
```
### Implement a custom decoder
@@ -87,22 +84,8 @@ IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encode
## Advanced Usage
-Use `PolylineEncodingOptionsBuilder` to customize precision, buffer size, and logging, then pass the built options to the encoder or decoder constructor:
-
-```csharp
-using Microsoft.Extensions.Logging;
-
-PolylineEncodingOptions options = PolylineEncodingOptionsBuilder.Create()
- .WithPrecision(6) // 6 decimal places instead of the default 5
- .WithStackAllocLimit(1024) // increase stack-alloc buffer
- .WithLoggerFactory(loggerFactory) // plug in your ILoggerFactory
- .Build();
-
-var encoder = new MyPolylineEncoder(options);
-var decoder = new MyPolylineDecoder(options);
-```
-
-Use static methods on `PolylineEncoding` for low-level normalization, validation, and bit-level read/write operations.
+- Pass a `PolylineEncodingOptions` (built via `PolylineEncodingOptionsBuilder`) to the encoder/decoder constructor for custom precision, stack-alloc limit, and logging.
+- Use static methods on `PolylineEncoding` for low-level normalization, validation, and bit-level read/write operations.
> See [API Reference](https://petesramek.github.io/polyline-algorithm-csharp/) for full documentation.
@@ -110,8 +93,6 @@ Use static methods on `PolylineEncoding` for low-level normalization, validation
- **What coordinate ranges are valid?**
Latitude: -90..90, Longitude: -180..180 (throws `ArgumentOutOfRangeException` for invalid input)
-- **What happens if I pass malformed input to the decoder?**
- The decoder throws `InvalidPolylineException` with a descriptive message. Wrap calls in a try/catch in your application.
- **What .NET versions are supported?**
Any environment supporting `netstandard2.1`
- **How do I customize encoder options?**
@@ -119,11 +100,6 @@ Use static methods on `PolylineEncoding` for low-level normalization, validation
- **Where can I get help?**
[GitHub issues](https://github.com/petesramek/polyline-algorithm-csharp/issues)
-## Resources
-
-- [GitHub Repository](https://github.com/petesramek/polyline-algorithm-csharp) — source code, issues, changelog, and samples
-- [API Reference](https://petesramek.github.io/polyline-algorithm-csharp/) — full auto-generated documentation
-
## License
MIT License © Pete Sramek
diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
index b5a64627..c6734c6c 100644
--- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
@@ -16,24 +16,16 @@ namespace PolylineAlgorithm.Tests.Abstraction;
[TestClass]
public sealed class AbstractPolylineDecoderTests {
private sealed class TestStringDecoder : AbstractPolylineDecoder {
- protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
- }
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
}
private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder {
public TestStringDecoderWithOptions(PolylineEncodingOptions options)
: base(options) { }
- protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
- }
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
}
///
diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
index 1500b0de..f537dda2 100644
--- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
@@ -21,12 +21,9 @@ public TestStringEncoder()
public TestStringEncoder(PolylineEncodingOptions options)
: base(options) { }
- protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
- destination[0] = item.Latitude;
- destination[1] = item.Longitude;
- }
+ protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
+ protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
}
///
diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
index 069c639f..c44c914d 100644
--- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
@@ -17,21 +17,13 @@ namespace PolylineAlgorithm.Tests.Extensions;
[TestClass]
public sealed class PolylineDecoderExtensionsTests {
private sealed class TestStringDecoder : AbstractPolylineDecoder {
- protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
- }
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
}
private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> {
- protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline;
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
- }
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
}
// ----- Decode(char[]) for IPolylineDecoder -----
diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
index 874f168c..da8a622e 100644
--- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
@@ -17,12 +17,9 @@ namespace PolylineAlgorithm.Tests.Extensions;
[TestClass]
public sealed class PolylineEncoderExtensionsTests {
private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
- protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
- destination[0] = item.Latitude;
- destination[1] = item.Longitude;
- }
+ protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
+ protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
}
// ----- Encode(List) -----
diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
index 03ef5e66..1e915fe2 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
@@ -6,6 +6,7 @@
namespace PolylineAlgorithm.Tests.Internal;
using PolylineAlgorithm.Internal;
+using System.Globalization;
///
/// Tests for .
@@ -13,22 +14,20 @@ namespace PolylineAlgorithm.Tests.Internal;
[TestClass]
public sealed class CoordinateDeltaTests {
///
- /// Tests that a newly constructed instance reports all-zero deltas.
+ /// Tests that the default constructor initializes delta values to zero.
///
[TestMethod]
- public void Constructor_Default_Initializes_Deltas_To_Zero() {
+ public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() {
// Act
- CoordinateDelta delta = new(2);
+ CoordinateDelta delta = new();
// Assert
- ReadOnlySpan deltas = delta.Deltas;
- Assert.AreEqual(2, deltas.Length);
- Assert.AreEqual(0, deltas[0]);
- Assert.AreEqual(0, deltas[1]);
+ Assert.AreEqual(0, delta.Latitude);
+ Assert.AreEqual(0, delta.Longitude);
}
///
- /// Tests that a single call to Next computes the correct delta from the initial zero state for 2 values.
+ /// Tests that a single call to Next computes the correct delta from the initial zero state.
///
[TestMethod]
[DataRow(10, 20, 10, 20)]
@@ -36,94 +35,59 @@ public void Constructor_Default_Initializes_Deltas_To_Zero() {
[DataRow(0, 0, 0, 0)]
[DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)]
[DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)]
- public void Next_Single_Call_From_Zero_Computes_Expected_Delta_For_Two_Values(int v0, int v1, int expectedD0, int expectedD1) {
+ public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int longitude, int expectedLatitude, int expectedLongitude) {
// Arrange
- CoordinateDelta delta = new(2);
+ CoordinateDelta delta = new();
// Act
- delta.Next([v0, v1]);
+ delta.Next(latitude, longitude);
// Assert
- ReadOnlySpan deltas = delta.Deltas;
- Assert.AreEqual(expectedD0, deltas[0]);
- Assert.AreEqual(expectedD1, deltas[1]);
+ Assert.AreEqual(expectedLatitude, delta.Latitude);
+ Assert.AreEqual(expectedLongitude, delta.Longitude);
}
///
- /// Tests that two consecutive calls to Next compute the delta relative to the previous value for 2 values.
+ /// Tests that two consecutive calls to Next compute the delta relative to the previous value.
///
[TestMethod]
[DataRow(10, 20, 15, 30, 5, 10)]
[DataRow(100, 200, 50, 150, -50, -50)]
[DataRow(42, 84, 42, 84, 0, 0)]
[DataRow(-50, 100, 25, -75, 75, -175)]
- public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value_For_Two_Values(
- int first0, int first1,
- int second0, int second1,
- int expectedD0, int expectedD1) {
+ public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value(
+ int firstLatitude, int firstLongitude,
+ int secondLatitude, int secondLongitude,
+ int expectedLatitude, int expectedLongitude) {
// Arrange
- CoordinateDelta delta = new(2);
- delta.Next([first0, first1]);
+ CoordinateDelta delta = new();
+ delta.Next(firstLatitude, firstLongitude);
// Act
- delta.Next([second0, second1]);
+ delta.Next(secondLatitude, secondLongitude);
// Assert
- ReadOnlySpan deltas = delta.Deltas;
- Assert.AreEqual(expectedD0, deltas[0]);
- Assert.AreEqual(expectedD1, deltas[1]);
+ Assert.AreEqual(expectedLatitude, delta.Latitude);
+ Assert.AreEqual(expectedLongitude, delta.Longitude);
}
///
- /// Tests that Next works correctly for a single value dimension.
- ///
- [TestMethod]
- public void Next_Single_Dimension_Computes_Correct_Delta() {
- // Arrange
- CoordinateDelta delta = new(1);
- delta.Next([100]);
-
- // Act
- delta.Next([150]);
-
- // Assert
- Assert.AreEqual(50, delta.Deltas[0]);
- }
-
- ///
- /// Tests that Next works correctly for three value dimensions.
- ///
- [TestMethod]
- public void Next_Three_Dimensions_Computes_Correct_Deltas() {
- // Arrange
- CoordinateDelta delta = new(3);
- delta.Next([10, 20, 30]);
-
- // Act
- delta.Next([15, 25, 25]);
-
- // Assert
- ReadOnlySpan deltas = delta.Deltas;
- Assert.AreEqual(5, deltas[0]);
- Assert.AreEqual(5, deltas[1]);
- Assert.AreEqual(-5, deltas[2]);
- }
-
- ///
- /// Tests that ToString on a default instance returns a non-null string containing structural keywords.
+ /// Tests that ToString on a default instance returns a string containing expected structural keywords and a zero value.
///
[TestMethod]
public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zeros() {
// Arrange
- CoordinateDelta delta = new(2);
+ CoordinateDelta delta = new();
// Act
string result = delta.ToString();
// Assert
Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains("Values", StringComparison.Ordinal));
- Assert.IsTrue(result.Contains("Deltas", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Coordinate", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Delta", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Latitude", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Longitude", StringComparison.Ordinal));
Assert.Contains('0', result);
}
@@ -133,18 +97,20 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero
[TestMethod]
[DataRow(42, 84)]
[DataRow(-100, -200)]
- public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) {
+ [DataRow(int.MaxValue, int.MaxValue)]
+ [DataRow(int.MinValue, int.MinValue)]
+ public void ToString_After_Next_Contains_Expected_Values(int latitude, int longitude) {
// Arrange
- CoordinateDelta delta = new(2);
- delta.Next([v0, v1]);
+ CoordinateDelta delta = new();
+ delta.Next(latitude, longitude);
// Act
string result = delta.ToString();
// Assert
Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains(v0.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal));
- Assert.IsTrue(result.Contains(v1.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains(latitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains(longitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
}
///
@@ -153,9 +119,9 @@ public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) {
[TestMethod]
public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() {
// Arrange
- CoordinateDelta delta = new(2);
- delta.Next([10, 20]);
- delta.Next([30, 50]);
+ CoordinateDelta delta = new();
+ delta.Next(10, 20);
+ delta.Next(30, 50);
// Act
string result = delta.ToString();
@@ -166,5 +132,5 @@ public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Lat
Assert.IsTrue(result.Contains("50", StringComparison.Ordinal));
Assert.IsTrue(result.Contains("20", StringComparison.Ordinal));
}
-}
+}
diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
index c9daaa1f..0dff7193 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
@@ -80,21 +80,20 @@ public void LogOperationFinishedDebug_With_Operation_Name_Logs_Finished_Message(
}
///
- /// Tests that LogDecodedValuesDebug WithCountAndPosition LogsDecodedValuesMessage.
+ /// Tests that LogDecodedCoordinateDebug WithCoordinatesAndPosition LogsDecodedCoordinateMessage.
///
[TestMethod]
- public void LogDecodedValuesDebug_With_Count_And_Position_Logs_Decoded_Values_Message() {
+ public void LogDecodedCoordinateDebug_With_Coordinates_And_Position_Logs_Decoded_Coordinate_Message() {
var logger = new TestLogger();
- const int count = 2;
+ const double latitude = 38.5;
+ const double longitude = -120.2;
const int position = 42;
- logger.LogDecodedValuesDebug(count, position);
+ logger.LogDecodedCoordinateDebug(latitude, longitude, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal);
- Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
- Assert.Contains(position.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}."), logger.Logs[0].Message, StringComparison.Ordinal);
}
///
@@ -143,35 +142,37 @@ public void LogOperationFinishedDebug_With_Null_Operation_Name_Logs_Message() {
}
///
- /// Tests that LogDecodedValuesDebug WithZeroCountAndPosition LogsMessage.
+ /// Tests that LogDecodedCoordinateDebug WithZeroCoordinates LogsMessage.
///
[TestMethod]
- public void LogDecodedValuesDebug_With_Zero_Count_Logs_Message() {
+ public void LogDecodedCoordinateDebug_With_Zero_Coordinates_Logs_Message() {
var logger = new TestLogger();
- const int count = 0;
+ const double latitude = 0.0;
+ const double longitude = 0.0;
const int position = 0;
- logger.LogDecodedValuesDebug(count, position);
+ logger.LogDecodedCoordinateDebug(latitude, longitude, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains("Decoded coordinate", logger.Logs[0].Message, StringComparison.Ordinal);
}
///
- /// Tests that LogDecodedValuesDebug WithLargeCount LogsMessage.
+ /// Tests that LogDecodedCoordinateDebug WithNegativeCoordinates LogsMessage.
///
[TestMethod]
- public void LogDecodedValuesDebug_With_Large_Count_Logs_Message() {
+ public void LogDecodedCoordinateDebug_With_Negative_Coordinates_Logs_Message() {
var logger = new TestLogger();
- const int count = 5;
+ const double latitude = -90.0;
+ const double longitude = -180.0;
const int position = 100;
- logger.LogDecodedValuesDebug(count, position);
+ logger.LogDecodedCoordinateDebug(latitude, longitude, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Latitude: {latitude}, Longitude: {longitude}"), logger.Logs[0].Message, StringComparison.Ordinal);
}
///
diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
index 0ca40426..d3d83b9e 100644
--- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
+++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
@@ -105,15 +105,16 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat
private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
- protected override int ValuesPerItem => 2;
-
protected override string CreatePolyline(ReadOnlyMemory polyline) {
return polyline.ToString();
}
- protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
- destination[0] = item.Latitude;
- destination[1] = item.Longitude;
+ protected override double GetLatitude((double Latitude, double Longitude) current) {
+ return current.Latitude;
+ }
+
+ protected override double GetLongitude((double Latitude, double Longitude) current) {
+ return current.Longitude;
}
}
}
\ No newline at end of file
From a5ee061abc6910470a81a474dd8f9c2734284fd2 Mon Sep 17 00:00:00 2001
From: Pete Sramek <2333452+petesramek@users.noreply.github.com>
Date: Mon, 6 Apr 2026 00:06:31 +0200
Subject: [PATCH 03/24] Revert "reset: revert all previous changes, clean slate
identical to main"
This reverts commit 89a6a24401b883dcfdec0d69a8237b3e41a42c02.
---
.editorconfig | 3 +
.github/CODEOWNERS | 5 +
.github/ISSUE_TEMPLATE/bug_report.md | 32 +-
.github/ISSUE_TEMPLATE/config.yml | 5 +
.github/ISSUE_TEMPLATE/feature_request.md | 4 +-
.github/PULL_REQUEST_TEMPLATE.md | 19 +
.github/actions/source/compile/action.yml | 2 +-
.github/dependabot.yml | 12 +
.github/release.yml | 23 +
.github/workflows/build.yml | 2 +-
.github/workflows/publish-documentation.yml | 21 +-
.github/workflows/pull-request.yml | 47 +-
.github/workflows/release.yml | 202 ++++++-
CHANGELOG.md | 10 +
CODE_OF_CONDUCT.md | 47 ++
Directory.Build.props | 3 +
PolylineAlgorithm.slnx | 1 +
README.md | 81 ++-
SECURITY.md | 23 +
....Abstraction.AbstractPolylineDecoder-2.yml | 233 ++++++++
....Abstraction.AbstractPolylineEncoder-2.yml | 219 ++++++++
...gorithm.Abstraction.IPolylineDecoder-2.yml | 90 +++
...gorithm.Abstraction.IPolylineEncoder-2.yml | 142 +++++
.../0.0/PolylineAlgorithm.Abstraction.yml | 34 ++
...m.Extensions.PolylineDecoderExtensions.yml | 195 +++++++
...m.Extensions.PolylineEncoderExtensions.yml | 139 +++++
.../0.0/PolylineAlgorithm.Extensions.yml | 19 +
...lineAlgorithm.InvalidPolylineException.yml | 102 ++++
.../PolylineAlgorithm.PolylineEncoding.yml | 529 ++++++++++++++++++
...ylineAlgorithm.PolylineEncodingOptions.yml | 127 +++++
...gorithm.PolylineEncodingOptionsBuilder.yml | 141 +++++
api-reference/0.0/PolylineAlgorithm.yml | 38 ++
api-reference/0.0/toc.yml | 34 ++
api-reference/guide/benchmarks.md | 11 +
api-reference/guide/toc.yml | 2 +
.../PolylineDecoderBenchmark.cs | 18 +-
.../PolylineEncoderBenchmark.cs | 7 +-
docs/local-development.md | 21 +
docs/workflows.md | 1 +
.../NetTopologyPolylineDecoder.cs | 19 +-
.../NetTopologyPolylineEncoder.cs | 41 +-
...neAlgorithm.NetTopologySuite.Sample.csproj | 3 +-
.../Program.cs | 46 ++
...PolylineAlgorithm.SensorData.Sample.csproj | 16 +
.../Program.cs | 49 ++
.../Properties/CodeCoverage.cs | 8 +
.../SensorDataDecoder.cs | 107 ++++
.../SensorDataEncoder.cs | 135 +++++
.../SensorReading.cs | 16 +
.../Abstraction/AbstractPolylineDecoder.cs | 77 ++-
.../Abstraction/AbstractPolylineEncoder.cs | 98 ++--
.../Internal/CoordinateDelta.cs | 88 +--
.../Diagnostics/LogDebugExtensions.cs | 11 +-
.../PolylineAlgorithm.csproj | 7 +
src/PolylineAlgorithm/PolylineEncoding.cs | 7 +-
src/PolylineAlgorithm/PublicAPI.Shipped.txt | 2 +-
src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 8 +
src/PolylineAlgorithm/README.md | 30 +-
.../AbstractPolylineDecoderTests.cs | 12 +-
.../AbstractPolylineEncoderTests.cs | 7 +-
.../PolylineDecoderExtensionsTests.cs | 12 +-
.../PolylineEncoderExtensionsTests.cs | 7 +-
.../Internal/CoordinateDeltaTests.cs | 112 ++--
.../Diagnostics/LogDebugExtensionsTests.cs | 35 +-
.../RandomValueProvider.cs | 11 +-
65 files changed, 3274 insertions(+), 334 deletions(-)
create mode 100644 .github/CODEOWNERS
create mode 100644 .github/ISSUE_TEMPLATE/config.yml
create mode 100644 .github/PULL_REQUEST_TEMPLATE.md
create mode 100644 .github/release.yml
create mode 100644 CHANGELOG.md
create mode 100644 CODE_OF_CONDUCT.md
create mode 100644 SECURITY.md
create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
create mode 100644 api-reference/0.0/PolylineAlgorithm.yml
create mode 100644 api-reference/0.0/toc.yml
create mode 100644 api-reference/guide/benchmarks.md
create mode 100644 samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs
create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj
create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/Program.cs
create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs
create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs
create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs
create mode 100644 samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs
diff --git a/.editorconfig b/.editorconfig
index 75d9084f..7282c0f7 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -274,3 +274,6 @@ dotnet_naming_style.underscore_camel_case.capitalization = camel_case
# Public API analyzer
dotnet_public_api_analyzer.require_api_files = true
+
+# RS0017: Symbol removed from public API - error severity (IDE guidance; build enforcement via WarningsAsErrors in .csproj)
+dotnet_diagnostic.RS0017.severity = error
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 00000000..880b45f7
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,5 @@
+* @petesramek
+
+.github/ @petesramek
+src/ @petesramek
+tests/ @petesramek
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index dd84ea78..6236e3a0 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,8 +1,8 @@
---
name: Bug report
about: Create a report to help us improve
-title: ''
-labels: ''
+title: '[Bug]: '
+labels: 'bug'
assignees: ''
---
@@ -11,28 +11,22 @@ assignees: ''
A clear and concise description of what the bug is.
**To Reproduce**
-Steps to reproduce the behavior:
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See error
+Minimal code snippet that reproduces the issue:
+
+```csharp
+// paste reproduction code here
+```
**Expected behavior**
A clear and concise description of what you expected to happen.
-**Screenshots**
-If applicable, add screenshots to help explain your problem.
-
-**Desktop (please complete the following information):**
- - OS: [e.g. iOS]
- - Browser [e.g. chrome, safari]
- - Version [e.g. 22]
+**Actual behavior**
+A clear and concise description of what actually happens (include exception messages/stack traces if applicable).
-**Smartphone (please complete the following information):**
- - Device: [e.g. iPhone6]
- - OS: [e.g. iOS8.1]
- - Browser [e.g. stock browser, safari]
- - Version [e.g. 22]
+**Environment**
+ - Package version: [e.g. 2.1.0]
+ - .NET version: [e.g. net8.0]
+ - OS: [e.g. Windows 11, Ubuntu 24.04]
**Additional context**
Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 00000000..2afb950d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+ - name: Ask a question
+ url: https://github.com/petesramek/polyline-algorithm-csharp/discussions
+ about: Use GitHub Discussions for questions, ideas, or general feedback.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index bbcbbe7d..5c8a425a 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -1,8 +1,8 @@
---
name: Feature request
about: Suggest an idea for this project
-title: ''
-labels: ''
+title: '[Feature]: '
+labels: 'enhancement'
assignees: ''
---
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 00000000..70eda657
--- /dev/null
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,19 @@
+## Summary
+
+
+
+## Type of change
+
+- [ ] Bug fix
+- [ ] New feature
+- [ ] Breaking change
+- [ ] Documentation / samples only
+
+## Checklist
+
+- [ ] Unit tests added or updated (`/tests`)
+- [ ] Benchmarks added or updated (`/benchmarks`) — if performance-impacting
+- [ ] XML doc comments updated for all public API changes
+- [ ] `dotnet format` run with no issues
+- [ ] README and `/samples` updated — if public API changed
+- [ ] PR label added (`breaking` / `feat` / `fix` / `docs`) — for changelog categorization
diff --git a/.github/actions/source/compile/action.yml b/.github/actions/source/compile/action.yml
index 0af331ee..dbe88dd5 100644
--- a/.github/actions/source/compile/action.yml
+++ b/.github/actions/source/compile/action.yml
@@ -12,7 +12,7 @@ inputs:
file-version:
description: 'Assembly file version.'
required: true
- treat-warnins-as-error:
+ treat-warnings-as-error:
description: 'Treat warnings as errors.'
required: true
project-path:
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index 02a54502..b00ae422 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,11 +4,23 @@ updates:
directory: "/"
schedule:
interval: "weekly"
+ labels:
+ - "dependencies"
+ assignees:
+ - "petesramek"
- package-ecosystem: "nuget"
directory: "/"
schedule:
interval: "weekly"
+ labels:
+ - "dependencies"
+ assignees:
+ - "petesramek"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
+ labels:
+ - "dependencies"
+ assignees:
+ - "petesramek"
diff --git a/.github/release.yml b/.github/release.yml
new file mode 100644
index 00000000..e7b05735
--- /dev/null
+++ b/.github/release.yml
@@ -0,0 +1,23 @@
+changelog:
+ exclude:
+ labels:
+ - ignore-for-release
+ categories:
+ - title: Breaking Changes
+ labels:
+ - breaking
+ - title: New Features
+ labels:
+ - feat
+ - enhancement
+ - title: Bug Fixes
+ labels:
+ - fix
+ - bug
+ - title: Documentation
+ labels:
+ - docs
+ - documentation
+ - title: Other Changes
+ labels:
+ - '*'
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 047d4afd..5abb7df8 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -130,7 +130,7 @@ jobs:
assembly-version: ${{ env.assembly-version }}
assembly-informational-version: ${{ env.assembly-informational-version }}
file-version: ${{ env.file-version }}
- treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }}
+ treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }}
test:
name: 'Run tests'
diff --git a/.github/workflows/publish-documentation.yml b/.github/workflows/publish-documentation.yml
index 85d8f21a..7f01504d 100644
--- a/.github/workflows/publish-documentation.yml
+++ b/.github/workflows/publish-documentation.yml
@@ -96,6 +96,21 @@ jobs:
run: |
cp -r api-reference/guide api-reference/${{ env.friendly-version }}/guide
+ - name: 'Download benchmark results'
+ uses: actions/download-artifact@v8
+ with:
+ pattern: benchmark-*
+ path: /tmp/benchmarks
+ merge-multiple: true
+
+ - name: 'Inject benchmark results into guide for v${{ env.friendly-version }}'
+ shell: bash
+ run: |
+ find /tmp/benchmarks -name "*-report-github.md" | sort | xargs -r cat > /tmp/benchmark_results.md
+ awk '/{benchmarks_section}/{while((getline line < "/tmp/benchmark_results.md") > 0) print line; close("/tmp/benchmark_results.md"); next} {print}' \
+ "api-reference/${{ env.friendly-version }}/guide/benchmarks.md" > /tmp/benchmarks.md
+ mv /tmp/benchmarks.md "api-reference/${{ env.friendly-version }}/guide/benchmarks.md"
+
- name: 'Discover all versions'
id: discover-versions
shell: bash
@@ -151,15 +166,15 @@ jobs:
{
echo "## Released Versions"
echo ""
- echo "| Version | Guide | API Reference |"
- echo "|---------|-------|---------------|"
+ echo "| Version | Guide | API Reference | Release Notes |"
+ echo "|---------|-------|---------------|---------------|"
for ver in $(echo "${{ steps.discover-versions.outputs.versions }}" | tr ',' '\n' | sort -Vr); do
if [ "$ver" = "$latest" ]; then
label="v${ver} (latest)"
else
label="v${ver}"
fi
- echo "| ${label} | [Guide](${ver}/guide/getting-started.html) | [API Reference](${ver}/PolylineAlgorithm.html) |"
+ echo "| ${label} | [Guide](${ver}/guide/getting-started.html) | [API Reference](${ver}/PolylineAlgorithm.html) | [Release Notes](https://github.com/petesramek/polyline-algorithm-csharp/releases/tag/v${ver}) |"
done
} > /tmp/versions_section.md
awk '/{versions_section}/{while((getline line < "/tmp/versions_section.md") > 0) print line; close("/tmp/versions_section.md"); next} {print}' \
diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml
index 4f8917b0..c99f254d 100644
--- a/.github/workflows/pull-request.yml
+++ b/.github/workflows/pull-request.yml
@@ -18,8 +18,8 @@ permissions:
id-token: write
contents: write
-concurrency:
- group: pull-request-${{ github.head_ref || github.ref }}
+concurrency:
+ group: pull-request-${{ github.head_ref || github.ref }}
cancel-in-progress: true
env:
@@ -120,7 +120,7 @@ jobs:
assembly-version: ${{ env.assembly-version }}
assembly-informational-version: ${{ env.assembly-informational-version }}
file-version: ${{ env.file-version }}
- treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }}
+ treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }}
test:
name: 'Run tests'
@@ -189,7 +189,7 @@ jobs:
- name: Pack with .NET
run: |
dotnet pack ${{ vars.SRC_DEFAULT_GLOB_PATTERN }} --configuration ${{ env.build-configuration }} /p:Platform="${{ env.build-platform }}" /p:PackageVersion=${{ env.release-version }} /p:Version=${{ env.assembly-version }} /p:AssemblyInformationalVersion=${{ env.assembly-informational-version }} /p:FileVersion=${{ env.file-version }} --output ${{ runner.temp }}/${{ env.nuget-packages-directory }}
-
+
- name: Upload Package
uses: actions/upload-artifact@v7
with:
@@ -222,39 +222,20 @@ jobs:
nuget-feed-api-key: ${{ secrets.NUGET_PACKAGE_FEED_API_KEY }}
nuget-feed-server: 'AzureArtifacts'
working-directory: ${{ runner.temp }}/${{ env.nuget-packages-directory }}
- dotnet-sdk-version: ${{ env.dotnet-sdk-version }}'
+ dotnet-sdk-version: ${{ env.dotnet-sdk-version }}
- benchmark:
- if: ${{ github.env.is_release || vars.BENCHMARKDOTNET_RUN_OVERRIDE == 'true' }}
- name: Benchmark with .NET CLI on ${{ matrix.os }}
+ security:
+ name: 'Check for vulnerable packages'
needs: [build]
- strategy:
- matrix:
- os: [ubuntu-latest, windows-latest, macos-latest]
- runs-on: ${{ matrix.os }}
+ runs-on: ubuntu-latest
steps:
- name: 'Checkout ${{ github.head_ref || github.ref }}'
uses: actions/checkout@v6
- - name: Install .NET SDK
+
+ - name: 'Setup .NET'
uses: actions/setup-dotnet@v5
with:
- dotnet-version: |
- 8.x
- 10.x
- - name: Download Build
- uses: actions/download-artifact@v8
- with:
- name: build
- - name: Benchmark
- working-directory: ${{ vars.BENCHMARKDOTNET_WORKING_DIRECTORY }}
- run: dotnet run --configuration ${{ env.build-configuration }} /p:Platform=${{ env.build-platform }} --framework ${{ vars.DEFAULT_BUILD_FRAMEWORK }} --runtimes ${{ vars.BENCHMARKDOTNET_RUNTIMES }} --filter ${{ vars.BENCHMARKDOTNET_FILTER }} --artifacts ${{ runner.temp }}/benchmarks/ --exporters GitHub --memory --iterationTime 100 --join
- - name: Upload Benchmark Results
- uses: actions/upload-artifact@v7
- with:
- name: benchmark-${{ matrix.os }}
- path: |
- ${{ runner.temp }}/benchmarks/**/*-report-github.md
- - name: Write Benchmark Summary
- shell: bash
- run: cat **/*-report-github.md > $GITHUB_STEP_SUMMARY
- working-directory: ${{ runner.temp }}/benchmarks/
+ dotnet-version: ${{ env.dotnet-sdk-version }}
+
+ - name: 'Check for vulnerable packages'
+ run: dotnet list src/PolylineAlgorithm/PolylineAlgorithm.csproj package --vulnerable --include-transitive
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 0d2808a8..b0bd5699 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -129,7 +129,7 @@ jobs:
assembly-version: ${{ env.assembly-version }}
assembly-informational-version: ${{ env.assembly-informational-version }}
file-version: ${{ env.file-version }}
- treat-warnins-as-error: ${{ needs.workflow-variables.outputs.is-release }}
+ treat-warnings-as-error: ${{ needs.workflow-variables.outputs.is-release }}
test:
name: 'Run tests'
@@ -169,6 +169,89 @@ jobs:
- name: Write code coverage report summary
run: cat ${{ steps.code-coverage-report.outputs.code-coverage-report-file }} >> $GITHUB_STEP_SUMMARY
+ update-api-unshipped:
+ name: 'Update PublicAPI.Unshipped.txt'
+ needs: [workflow-variables, validate-release]
+ # Run even when build fails — the build may fail solely because a dropped preview API is still
+ # listed in Unshipped.txt (RS0017). This job fixes exactly that, so it must not be gated on build.
+ if: ${{ needs.workflow-variables.outputs.is-preview == 'true' && needs.validate-release.result == 'success' }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Checkout ${{ github.ref }}'
+ uses: actions/checkout@v6
+
+ - name: 'Setup .NET'
+ uses: actions/setup-dotnet@v5
+ with:
+ dotnet-version: ${{ env.dotnet-sdk-version }}
+
+ - name: 'Snapshot PublicAPI.Shipped.txt'
+ shell: bash
+ run: cp src/PolylineAlgorithm/PublicAPI.Shipped.txt src/PolylineAlgorithm/PublicAPI.Shipped.txt.bak
+
+ - name: 'Sync PublicAPI.Unshipped.txt (add new + remove dropped preview APIs)'
+ shell: bash
+ run: dotnet format analyzers src/PolylineAlgorithm/PolylineAlgorithm.csproj --diagnostics RS0016 RS0017
+
+ - name: 'Guard against accidental shipped API removal'
+ shell: bash
+ run: |
+ SHIPPED="src/PolylineAlgorithm/PublicAPI.Shipped.txt"
+ if ! diff -q "$SHIPPED" "$SHIPPED.bak" > /dev/null 2>&1; then
+ echo "::error::Breaking change detected — a shipped API was removed from PublicAPI.Shipped.txt."
+ echo "::error::This requires a major version bump. Reverting the unintended change."
+ cp "$SHIPPED.bak" "$SHIPPED"
+ exit 1
+ fi
+ rm -f "$SHIPPED.bak"
+
+ - name: 'Configure git identity'
+ uses: './.github/actions/git/configure-identity'
+
+ - name: 'Commit and push updated API files'
+ shell: bash
+ run: |
+ git add src/PolylineAlgorithm/PublicAPI.Unshipped.txt
+ git diff --staged --quiet || (
+ git commit -m "Sync PublicAPI.Unshipped.txt (add new, remove dropped preview APIs)" &&
+ git pull --rebase origin ${{ github.ref_name }} &&
+ git push
+ )
+
+ promote-api-files:
+ name: 'Promote PublicAPI files (Unshipped -> Shipped)'
+ needs: [workflow-variables, test, validate-release]
+ if: ${{ needs.workflow-variables.outputs.is-release == 'true' }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: 'Checkout ${{ github.ref }}'
+ uses: actions/checkout@v6
+
+ - name: 'Promote Unshipped.txt into Shipped.txt'
+ shell: bash
+ run: |
+ UNSHIPPED="src/PolylineAlgorithm/PublicAPI.Unshipped.txt"
+ SHIPPED="src/PolylineAlgorithm/PublicAPI.Shipped.txt"
+
+ # Append every non-blank, non-header line from Unshipped into Shipped
+ tail -n +2 "$UNSHIPPED" | grep -v '^[[:space:]]*$' >> "$SHIPPED" || true
+
+ # Reset Unshipped to just the nullable-enable header (with BOM to match convention)
+ printf '\xef\xbb\xbf#nullable enable\n' > "$UNSHIPPED"
+
+ - name: 'Configure git identity'
+ uses: './.github/actions/git/configure-identity'
+
+ - name: 'Commit and push promoted API files'
+ shell: bash
+ run: |
+ git add src/PolylineAlgorithm/PublicAPI.Shipped.txt src/PolylineAlgorithm/PublicAPI.Unshipped.txt
+ git diff --staged --quiet || (
+ git commit -m "Promote PublicAPI.Unshipped.txt into PublicAPI.Shipped.txt for release" &&
+ git pull --rebase origin ${{ github.ref_name }} &&
+ git push
+ )
+
pack:
name: 'Package binaries'
needs: [versioning, build, test, validate-release]
@@ -207,9 +290,44 @@ jobs:
${{ runner.temp }}/${{ env.nuget-packages-directory }}/**/*.nupkg
${{ runner.temp }}/${{ env.nuget-packages-directory }}/**/*.snupkg
+ benchmark:
+ name: Benchmark with .NET CLI on ${{ matrix.os }}
+ needs: [workflow-variables, build, validate-release]
+ if: ${{ needs.workflow-variables.outputs.is-release == 'true' || vars.BENCHMARKDOTNET_RUN_OVERRIDE == 'true' }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, windows-latest, macos-latest]
+ runs-on: ${{ matrix.os }}
+ steps:
+ - name: 'Checkout ${{ github.head_ref || github.ref }}'
+ uses: actions/checkout@v6
+ - name: Install .NET SDK
+ uses: actions/setup-dotnet@v5
+ with:
+ dotnet-version: |
+ 8.x
+ 10.x
+ - name: Download Build
+ uses: actions/download-artifact@v8
+ with:
+ name: build
+ - name: Benchmark
+ working-directory: ${{ vars.BENCHMARKDOTNET_WORKING_DIRECTORY }}
+ run: dotnet run --configuration ${{ env.build-configuration }} /p:Platform=${{ env.build-platform }} --framework ${{ vars.DEFAULT_BUILD_FRAMEWORK }} --runtimes ${{ vars.BENCHMARKDOTNET_RUNTIMES }} --filter ${{ vars.BENCHMARKDOTNET_FILTER }} --artifacts ${{ runner.temp }}/benchmarks/ --exporters GitHub --memory --iterationTime 100 --join
+ - name: Upload Benchmark Results
+ uses: actions/upload-artifact@v7
+ with:
+ name: benchmark-${{ matrix.os }}
+ path: |
+ ${{ runner.temp }}/benchmarks/**/*-report-github.md
+ - name: Write Benchmark Summary
+ shell: bash
+ run: cat **/*-report-github.md > $GITHUB_STEP_SUMMARY
+ working-directory: ${{ runner.temp }}/benchmarks/
+
publish-documentation:
name: 'Publish documentation'
- needs: [pack, validate-release, workflow-variables]
+ needs: [pack, benchmark, validate-release, workflow-variables]
if: ${{ needs.workflow-variables.outputs.is-release == 'true' }}
uses: ./.github/workflows/publish-documentation.yml
permissions:
@@ -219,8 +337,14 @@ jobs:
publish-package:
name: 'Publish package'
- needs: [pack, validate-release, publish-documentation]
- if: ${{ always() && needs.pack.result == 'success' && needs.validate-release.result == 'success' && (needs.publish-documentation.result == 'success' || needs.publish-documentation.result == 'skipped') }}
+ needs: [pack, validate-release, publish-documentation, update-api-unshipped, promote-api-files]
+ if: |
+ always() &&
+ needs.pack.result == 'success' &&
+ needs.validate-release.result == 'success' &&
+ (needs.publish-documentation.result == 'success' || needs.publish-documentation.result == 'skipped') &&
+ (needs.promote-api-files.result == 'success' || needs.promote-api-files.result == 'skipped') &&
+ (needs.update-api-unshipped.result == 'success' || needs.update-api-unshipped.result == 'skipped')
env:
package-artifact-name: ${{ needs.pack.outputs.package-artifact-name }}
runs-on: ubuntu-latest
@@ -272,9 +396,68 @@ jobs:
is-preview: ${{ env.is-preview }}
notes-start-tag: ${{ steps.determine-notes-start-tag.outputs.notes-start-tag }}
+ update-changelog:
+ name: 'Update CHANGELOG.md'
+ needs: [workflow-variables, release, versioning]
+ if: ${{ needs.workflow-variables.outputs.is-release == 'true' }}
+ runs-on: ubuntu-latest
+ env:
+ GH_TOKEN: ${{ github.token }}
+ release-version: ${{ needs.versioning.outputs.release-version }}
+ steps:
+ - name: 'Checkout ${{ github.ref }}'
+ uses: actions/checkout@v6
+ with:
+ ref: ${{ github.ref }}
+
+ - name: 'Fetch release notes'
+ shell: bash
+ run: |
+ gh release view ${{ env.release-version }} --json body --jq '.body' > /tmp/release-notes.txt
+
+ - name: 'Prepend entry to CHANGELOG.md'
+ shell: bash
+ run: |
+ release_date=$(date -u +%Y-%m-%d)
+ {
+ echo "## ${{ env.release-version }} — ${release_date}"
+ echo ""
+ cat /tmp/release-notes.txt
+ echo ""
+ } > /tmp/new-entry.txt
+ awk '
+ // {
+ print
+ print ""
+ while ((getline line < "/tmp/new-entry.txt") > 0) print line
+ close("/tmp/new-entry.txt")
+ next
+ }
+ { print }
+ ' CHANGELOG.md > /tmp/changelog-new.md
+ mv /tmp/changelog-new.md CHANGELOG.md
+
+ - name: 'Configure git identity'
+ uses: './.github/actions/git/configure-identity'
+
+ - name: 'Commit and push CHANGELOG.md'
+ shell: bash
+ run: |
+ git add CHANGELOG.md
+ git diff --staged --quiet || (
+ git commit -m "Update CHANGELOG.md for ${{ env.release-version }}" &&
+ git pull --rebase origin ${{ github.ref_name }} &&
+ git push
+ )
+
+ - name: 'Write changelog summary'
+ shell: bash
+ run: |
+ echo "✅ CHANGELOG.md updated for **${{ env.release-version }}**." >> $GITHUB_STEP_SUMMARY
+
merge-to-main:
name: 'Merge ${{ github.ref_name }} into main'
- needs: [workflow-variables, release, versioning]
+ needs: [workflow-variables, release, versioning, update-changelog]
if: ${{ needs.workflow-variables.outputs.is-release == 'true' }}
runs-on: ubuntu-latest
permissions:
@@ -371,17 +554,10 @@ jobs:
git checkout -b "${{ steps.resolve-support-branch.outputs.support-branch }}"
git push --set-upstream origin "${{ steps.resolve-support-branch.outputs.support-branch }}"
- - name: 'Lock support branch'
- if: ${{ steps.check-support-branch.outputs.support-branch-exists == 'false' }}
- uses: './.github/actions/github/branch-protection/lock'
- with:
- branch: ${{ steps.resolve-support-branch.outputs.support-branch }}
- token: ${{ secrets.GH_ADMIN_TOKEN }}
-
- name: 'Write support branch summary'
run: |
if [[ "${{ steps.check-support-branch.outputs.support-branch-exists }}" == "false" ]]; then
- echo "✅ Created and locked support branch **${{ steps.resolve-support-branch.outputs.support-branch }}**." >> $GITHUB_STEP_SUMMARY
+ echo "✅ Created support branch **${{ steps.resolve-support-branch.outputs.support-branch }}**." >> $GITHUB_STEP_SUMMARY
else
echo "⏭️ Support branch **${{ steps.resolve-support-branch.outputs.support-branch }}** already exists." >> $GITHUB_STEP_SUMMARY
fi
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 00000000..9264cdaa
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,10 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
+and release notes are generated automatically from merged pull requests.
+
+See all releases at:
+
+
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..d0b9d1d8
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,47 @@
+# Contributor Covenant Code of Conduct
+
+## Our Commitment
+
+We are committed to providing a welcoming and inspiring community for all. We pledge to create an environment in which every individual feels valued, respected, and free from harassment and discrimination.
+
+## Our Standards
+
+Examples of behavior that contributes to creating a positive environment include:
+
+- Using welcoming and inclusive language
+- Being respectful of differing opinions, viewpoints, and experiences
+- Gracefully accepting constructive criticism
+- Focusing on what is best for the community
+- Showing empathy towards other community members
+
+Examples of unacceptable behavior include:
+
+- The use of sexualized language or imagery and unwelcome sexual attention or advances
+- Trolling, insulting/derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or electronic address, without explicit permission
+- Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Enforcement
+
+Community leaders are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
+
+Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for behaviors that they deem inappropriate, threatening, offensive, or harmful.
+
+## Reporting
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the project maintainer responsible for enforcement. All complaints will be reviewed and investigated promptly and fairly.
+
+All community leaders are obligated to respect the privacy and security of the reporter of any incident.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at https://www.contributor-covenant.org/version/2/1/code_of_conduct.html.
+
+Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity).
+
+[homepage]: https://www.contributor-covenant.org
+
+For answers to common questions about this code of conduct, see the FAQ at
+https://www.contributor-covenant.org/faq. Translations are available at
+https://www.contributor-covenant.org/translations.
diff --git a/Directory.Build.props b/Directory.Build.props
index 96ebb124..80c3886e 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -6,6 +6,8 @@
enable
true
en
+ true
+ embedded
@@ -20,6 +22,7 @@
+
diff --git a/PolylineAlgorithm.slnx b/PolylineAlgorithm.slnx
index 29fa9445..3c54b2a7 100644
--- a/PolylineAlgorithm.slnx
+++ b/PolylineAlgorithm.slnx
@@ -7,6 +7,7 @@
+
diff --git a/README.md b/README.md
index 9dfb8a18..0555c16f 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,10 @@
# PolylineAlgorithm for .NET
-Lightweight .NET Standard 2.1 library implementing Google-compliant Encoded Polyline Algorithm with strong input validation, modern API patterns, and extensibility for custom coordinate types.
+[](https://www.nuget.org/packages/PolylineAlgorithm)
+[](https://github.com/petesramek/polyline-algorithm-csharp/actions/workflows/build.yml)
+[](./LICENSE)
+
+Google's Encoded Polyline Algorithm compresses sequences of geographic coordinates into a compact ASCII string, widely used in mapping APIs. This library provides a fully compliant .NET implementation with extensible, type-safe encoding and decoding APIs.
## Table of Contents
@@ -17,15 +21,16 @@ Lightweight .NET Standard 2.1 library implementing Google-compliant Encoded Poly
## Features
- Fully compliant Google Encoded Polyline Algorithm for .NET Standard 2.1+
-- Extensible encoding and decoding APIs for custom coordinate and polyline types (`IPolylineEncoder`, `IPolylineDecoder`, `AbstractPolylineEncoder`, `AbstractPolylineDecoder`)
-- Extension methods for encoding from `List` and arrays (`PolylineEncoderExtensions`)
-- Robust input validation with descriptive exceptions for malformed/invalid data
+- Extensible APIs — implement your own encoder/decoder for any coordinate or polyline type
+- Robust input validation with descriptive exceptions for malformed or out-of-range data
- Advanced configuration via `PolylineEncodingOptions` (precision, buffer size, logging)
-- Logging and diagnostic support for CI/CD and developer diagnostics via `Microsoft.Extensions.Logging`
-- Low-level utilities for normalization, validation, encoding and decoding via static `PolylineEncoding` class
+- Extension methods for encoding directly from `List` and arrays
+- Logging and diagnostic support via `Microsoft.Extensions.Logging`
+- Low-level utilities for normalization, validation, and bit-level operations via static `PolylineEncoding` class
+- Thread-safe, stateless APIs
- Thorough unit tests and benchmarks for correctness and performance
- Auto-generated API documentation ([API Reference](https://petesramek.github.io/polyline-algorithm-csharp/))
-- Support for .NET Core, .NET 5+, Xamarin, Unity, Blazor, and other platforms supporting `netstandard2.1`
+- Supports .NET Core, .NET 5+, Xamarin, Unity, Blazor, and any platform targeting `netstandard2.1`
## Installation
@@ -43,7 +48,19 @@ Install-Package PolylineAlgorithm
## Usage
-The library provides abstract base classes to implement your own encoder and decoder for any coordinate and polyline type.
+The library provides abstract base classes to implement your own encoder and decoder for any coordinate and polyline type. Inherit from `AbstractPolylineEncoder` or `AbstractPolylineDecoder`, override the coordinate accessors, then call `Encode` or `Decode`.
+
+### Quick Start
+
+```csharp
+// 1. Implement a minimal encoder (see full example below)
+var encoder = new MyPolylineEncoder();
+string encoded = encoder.Encode(coordinates); // e.g. "yseiHoc_MwacOjnwM"
+
+// 2. Implement a minimal decoder (see full example below)
+var decoder = new MyPolylineDecoder();
+IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encoded);
+```
### Custom encoder and decoder
@@ -56,23 +73,9 @@ using PolylineAlgorithm;
using PolylineAlgorithm.Abstraction;
public sealed class MyPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
- public MyPolylineEncoder()
- : base() { }
-
- public MyPolylineEncoder(PolylineEncodingOptions options)
- : base(options) { }
-
- protected override double GetLatitude((double Latitude, double Longitude) coordinate) {
- return coordinate.Latitude;
- }
-
- protected override double GetLongitude((double Latitude, double Longitude) coordinate) {
- return coordinate.Longitude;
- }
-
- protected override string CreatePolyline(ReadOnlyMemory polyline) {
- return polyline.ToString();
- }
+ protected override double GetLatitude((double Latitude, double Longitude) coordinate) => coordinate.Latitude;
+ protected override double GetLongitude((double Latitude, double Longitude) coordinate) => coordinate.Longitude;
+ protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
}
```
@@ -102,19 +105,8 @@ using PolylineAlgorithm;
using PolylineAlgorithm.Abstraction;
public sealed class MyPolylineDecoder : AbstractPolylineDecoder {
- public MyPolylineDecoder()
- : base() { }
-
- public MyPolylineDecoder(PolylineEncodingOptions options)
- : base(options) { }
-
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
- return (latitude, longitude);
- }
-
- protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) {
- return polyline.AsMemory();
- }
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
}
```
@@ -136,8 +128,13 @@ Full API docs and guides (auto-generated from source) are available at [API Refe
## Benchmarks
-- See `/benchmarks` in the repo for performance evaluation.
-- Contributors: Update benchmarks and document results for performance-impacting PRs.
+- See [`/benchmarks`](./benchmarks) in the repo for benchmark projects.
+- Run benchmarks with:
+ ```shell
+ dotnet run --project benchmarks/PolylineAlgorithm.Benchmarks --configuration Release
+ ```
+- For guidance on writing and interpreting benchmarks, see [docs/benchmarks.md](./docs/benchmarks.md).
+- Contributors: update benchmarks and document results for performance-impacting PRs.
## FAQ
@@ -173,13 +170,13 @@ A: Currently, only batch encode/decode is supported. For streaming scenarios, im
## Contributing
-- Follow code style and PR instructions in [AGENTS.md](./AGENTS.md).
+- Follow code style and PR instructions in [CONTRIBUTING.md](./CONTRIBUTING.md).
- Ensure all features are covered by tests and XML doc comments.
- For questions or suggestions, open an issue and use the provided templates.
## Support
-Have a question, bug, or feature request? [Open an issue!](https://github.com/petesramek/polyline-algorithm-csharp/issues)
+Have a question, bug, or feature request? [Open an issue](https://github.com/petesramek/polyline-algorithm-csharp/issues/new/choose) — bug report and feature request templates are available to guide you.
---
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000..8ca1471a
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,23 @@
+# Security Policy
+
+## Supported Versions
+
+| Version | Supported |
+| ------- | --------- |
+| Latest | ✅ |
+| Older | ❌ |
+
+Only the latest published version receives security fixes. If you are on an older version, please upgrade.
+
+## Reporting a Vulnerability
+
+**Please do not open a public GitHub issue for security vulnerabilities.**
+
+Report security issues privately via [GitHub Security Advisories](https://github.com/petesramek/polyline-algorithm-csharp/security/advisories/new).
+
+Include:
+- A description of the vulnerability
+- Steps to reproduce or a proof-of-concept
+- Potential impact assessment
+
+You can expect an initial response within 5 business days. Once confirmed, a fix will be prioritized and a patch release issued. You will be credited in the release notes unless you prefer to remain anonymous.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
new file mode 100644
index 00000000..b5693066
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
@@ -0,0 +1,233 @@
+### YamlMime:ApiPage
+title: Class AbstractPolylineDecoder
+body:
+- api1: Class AbstractPolylineDecoder
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2
+ commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2
+- facts:
+ - name: Namespace
+ value:
+ text: PolylineAlgorithm.Abstraction
+ url: PolylineAlgorithm.Abstraction.html
+ - name: Assembly
+ value: PolylineAlgorithm.dll
+- markdown: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
+- code: 'public abstract class AbstractPolylineDecoder : IPolylineDecoder'
+- h4: Type Parameters
+- parameters:
+ - name: TPolyline
+ description: The type that represents the encoded polyline input.
+ - name: TCoordinate
+ description: The type that represents a decoded geographic coordinate.
+- h4: Inheritance
+- inheritance:
+ - text: object
+ url: https://learn.microsoft.com/dotnet/api/system.object
+ - text: AbstractPolylineDecoder
+ url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html
+- h4: Implements
+- list:
+ - text: IPolylineDecoder
+ url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
+- h4: Inherited Members
+- list:
+ - text: object.Equals(object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
+ - text: object.Equals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
+ - text: object.GetHashCode()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
+ - text: object.GetType()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gettype
+ - text: object.MemberwiseClone()
+ url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
+ - text: object.ReferenceEquals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
+ - text: object.ToString()
+ url: https://learn.microsoft.com/dotnet/api/system.object.tostring
+- h2: Remarks
+- markdown: >-
+ Derive from this class to implement a decoder for a specific polyline type. Override
+
+ and to provide type-specific behavior.
+- h2: Constructors
+- api3: AbstractPolylineDecoder()
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor
+- markdown: Initializes a new instance of the class with default encoding options.
+- code: protected AbstractPolylineDecoder()
+- api3: AbstractPolylineDecoder(PolylineEncodingOptions)
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
+- markdown: Initializes a new instance of the class with the specified encoding options.
+- code: protected AbstractPolylineDecoder(PolylineEncodingOptions options)
+- h4: Parameters
+- parameters:
+ - name: options
+ type:
+ - text: PolylineEncodingOptions
+ url: PolylineAlgorithm.PolylineEncodingOptions.html
+ description: The to use for encoding operations.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentNullException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
+ description: Thrown when options is null.
+- h2: Properties
+- api3: Options
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Options
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options
+ commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options
+- markdown: Gets the encoding options used by this polyline decoder.
+- code: public PolylineEncodingOptions Options { get; }
+- h4: Property Value
+- parameters:
+ - type:
+ - text: PolylineEncodingOptions
+ url: PolylineAlgorithm.PolylineEncodingOptions.html
+- h2: Methods
+- api3: CreateCoordinate(double, double)
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateCoordinate_System_Double_System_Double_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double)
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double)
+- markdown: Creates a TCoordinate instance from the specified latitude and longitude values.
+- code: protected abstract TCoordinate CreateCoordinate(double latitude, double longitude)
+- h4: Parameters
+- parameters:
+ - name: latitude
+ type:
+ - text: double
+ url: https://learn.microsoft.com/dotnet/api/system.double
+ description: The latitude component of the coordinate, in degrees.
+ - name: longitude
+ type:
+ - text: double
+ url: https://learn.microsoft.com/dotnet/api/system.double
+ description: The longitude component of the coordinate, in degrees.
+- h4: Returns
+- parameters:
+ - type:
+ - TCoordinate
+ description: A TCoordinate instance representing the specified geographic coordinate.
+- api3: Decode(TPolyline, CancellationToken)
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
+- markdown: >-
+ Decodes an encoded TPolyline into a sequence of TCoordinate instances,
+
+ with support for cancellation.
+- code: public IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default)
+- h4: Parameters
+- parameters:
+ - name: polyline
+ type:
+ - TPolyline
+ description: The TPolyline instance containing the encoded polyline string to decode.
+ - name: cancellationToken
+ type:
+ - text: CancellationToken
+ url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
+ description: A that can be used to cancel the decoding operation.
+ optional: true
+- h4: Returns
+- parameters:
+ - type:
+ - text: IEnumerable
+ url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
+ - <
+ - TCoordinate
+ - '>'
+ description: An of TCoordinate representing the decoded latitude and longitude pairs.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentNullException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
+ description: Thrown when polyline is null.
+ - type:
+ - text: ArgumentException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentexception
+ description: Thrown when polyline is empty.
+ - type:
+ - text: InvalidPolylineException
+ url: PolylineAlgorithm.InvalidPolylineException.html
+ description: Thrown when the polyline format is invalid or malformed at a specific position.
+ - type:
+ - text: OperationCanceledException
+ url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception
+ description: Thrown when cancellationToken is canceled during decoding.
+- api3: GetReadOnlyMemory(in TPolyline)
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@)
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@)
+- markdown: Extracts the underlying read-only memory region of characters from the specified polyline instance.
+- code: protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline)
+- h4: Parameters
+- parameters:
+ - name: polyline
+ type:
+ - TPolyline
+ description: The TPolyline instance from which to extract the character sequence.
+- h4: Returns
+- parameters:
+ - type:
+ - text: ReadOnlyMemory
+ url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ description: A of representing the encoded polyline characters.
+- api3: ValidateFormat(ReadOnlyMemory, ILogger?)
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger)
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger)
+- markdown: Validates the format of the polyline character sequence, ensuring all characters are within the allowed range.
+- code: protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? logger)
+- h4: Parameters
+- parameters:
+ - name: sequence
+ type:
+ - text: ReadOnlyMemory
+ url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ description: The read-only memory region of characters representing the polyline to validate.
+ - name: logger
+ type:
+ - text: ILogger
+ url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger
+ - '?'
+ description: An optional used to log a warning when format validation fails.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentexception
+ description: Thrown when the polyline contains characters outside the valid encoding range or has an invalid block structure.
+languageId: csharp
+metadata:
+ description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
new file mode 100644
index 00000000..64e97b11
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
@@ -0,0 +1,219 @@
+### YamlMime:ApiPage
+title: Class AbstractPolylineEncoder
+body:
+- api1: Class AbstractPolylineEncoder
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2
+ commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2
+- facts:
+ - name: Namespace
+ value:
+ text: PolylineAlgorithm.Abstraction
+ url: PolylineAlgorithm.Abstraction.html
+ - name: Assembly
+ value: PolylineAlgorithm.dll
+- markdown: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
+- code: 'public abstract class AbstractPolylineEncoder : IPolylineEncoder'
+- h4: Type Parameters
+- parameters:
+ - name: TCoordinate
+ description: The type that represents a geographic coordinate to encode.
+ - name: TPolyline
+ description: The type that represents the encoded polyline output.
+- h4: Inheritance
+- inheritance:
+ - text: object
+ url: https://learn.microsoft.com/dotnet/api/system.object
+ - text: AbstractPolylineEncoder
+ url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html
+- h4: Implements
+- list:
+ - text: IPolylineEncoder
+ url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html
+- h4: Inherited Members
+- list:
+ - text: object.Equals(object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
+ - text: object.Equals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
+ - text: object.GetHashCode()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
+ - text: object.GetType()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gettype
+ - text: object.MemberwiseClone()
+ url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
+ - text: object.ReferenceEquals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
+ - text: object.ToString()
+ url: https://learn.microsoft.com/dotnet/api/system.object.tostring
+- h4: Extension Methods
+- list:
+ - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List)
+ url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__
+ - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TCoordinate[])
+ url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___
+- h2: Remarks
+- markdown: >-
+ Derive from this class to implement an encoder for a specific coordinate and polyline type. Override
+
+ , , and to provide type-specific behavior.
+- h2: Constructors
+- api3: AbstractPolylineEncoder()
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor
+- markdown: Initializes a new instance of the class with default encoding options.
+- code: protected AbstractPolylineEncoder()
+- api3: AbstractPolylineEncoder(PolylineEncodingOptions)
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
+- markdown: Initializes a new instance of the class with the specified encoding options.
+- code: protected AbstractPolylineEncoder(PolylineEncodingOptions options)
+- h4: Parameters
+- parameters:
+ - name: options
+ type:
+ - text: PolylineEncodingOptions
+ url: PolylineAlgorithm.PolylineEncodingOptions.html
+ description: The to use for encoding operations.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentNullException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
+ description: Thrown when options is null
+- h2: Properties
+- api3: Options
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Options
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options
+ commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options
+- markdown: Gets the encoding options used by this polyline encoder.
+- code: public PolylineEncodingOptions Options { get; }
+- h4: Property Value
+- parameters:
+ - type:
+ - text: PolylineEncodingOptions
+ url: PolylineAlgorithm.PolylineEncodingOptions.html
+- h2: Methods
+- api3: CreatePolyline(ReadOnlyMemory)
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char})
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char})
+- markdown: Creates a polyline instance from the provided read-only sequence of characters.
+- code: protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline)
+- h4: Parameters
+- parameters:
+ - name: polyline
+ type:
+ - text: ReadOnlyMemory
+ url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ description: A containing the encoded polyline characters.
+- h4: Returns
+- parameters:
+ - type:
+ - TPolyline
+ description: An instance of TPolyline representing the encoded polyline.
+- api3: Encode(ReadOnlySpan, CancellationToken)
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
+- markdown: Encodes a collection of TCoordinate instances into an encoded TPolyline string.
+- code: >-
+ [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")]
+
+ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default)
+- h4: Parameters
+- parameters:
+ - name: coordinates
+ type:
+ - text: ReadOnlySpan
+ url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
+ - <
+ - TCoordinate
+ - '>'
+ description: The collection of TCoordinate objects to encode.
+ - name: cancellationToken
+ type:
+ - text: CancellationToken
+ url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
+ description: A that can be used to cancel the encoding operation.
+ optional: true
+- h4: Returns
+- parameters:
+ - type:
+ - TPolyline
+ description: An instance of TPolyline representing the encoded coordinates.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentNullException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
+ description: Thrown when coordinates is null.
+ - type:
+ - text: ArgumentException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentexception
+ description: Thrown when coordinates is an empty enumeration.
+ - type:
+ - text: InvalidOperationException
+ url: https://learn.microsoft.com/dotnet/api/system.invalidoperationexception
+ description: Thrown when the internal encoding buffer cannot accommodate the encoded value.
+- api3: GetLatitude(TCoordinate)
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLatitude__0_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0)
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0)
+- markdown: Extracts the latitude value from the specified coordinate.
+- code: protected abstract double GetLatitude(TCoordinate current)
+- h4: Parameters
+- parameters:
+ - name: current
+ type:
+ - TCoordinate
+ description: The coordinate from which to extract the latitude.
+- h4: Returns
+- parameters:
+ - type:
+ - text: double
+ url: https://learn.microsoft.com/dotnet/api/system.double
+ description: The latitude value as a .
+- api3: GetLongitude(TCoordinate)
+ id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLongitude__0_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0)
+ commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0)
+- markdown: Extracts the longitude value from the specified coordinate.
+- code: protected abstract double GetLongitude(TCoordinate current)
+- h4: Parameters
+- parameters:
+ - name: current
+ type:
+ - TCoordinate
+ description: The coordinate from which to extract the longitude.
+- h4: Returns
+- parameters:
+ - type:
+ - text: double
+ url: https://learn.microsoft.com/dotnet/api/system.double
+ description: The longitude value as a .
+languageId: csharp
+metadata:
+ description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
new file mode 100644
index 00000000..733987cb
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
@@ -0,0 +1,90 @@
+### YamlMime:ApiPage
+title: Interface IPolylineDecoder
+body:
+- api1: Interface IPolylineDecoder
+ id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2
+ commentId: T:PolylineAlgorithm.Abstraction.IPolylineDecoder`2
+- facts:
+ - name: Namespace
+ value:
+ text: PolylineAlgorithm.Abstraction
+ url: PolylineAlgorithm.Abstraction.html
+ - name: Assembly
+ value: PolylineAlgorithm.dll
+- markdown: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates.
+- code: public interface IPolylineDecoder
+- h4: Type Parameters
+- parameters:
+ - name: TPolyline
+ description: >-
+ The type that represents the encoded polyline input. Common implementations use ,
+
+ but custom wrapper types are allowed to carry additional metadata.
+ - name: TValue
+ description: >-
+ The coordinate type returned by the decoder. Typical implementations return a struct or class that
+
+ contains latitude and longitude (for example a LatLng type or a ValueTuple<double,double>).
+- h2: Methods
+- api3: Decode(TPolyline, CancellationToken)
+ id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
+ commentId: M:PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
+- markdown: >-
+ Decodes the specified encoded polyline into an ordered sequence of geographic coordinates.
+
+ The sequence preserves the original vertex order encoded by the polyline.
+- code: IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default)
+- h4: Parameters
+- parameters:
+ - name: polyline
+ type:
+ - TPolyline
+ description: >-
+ The TPolyline instance containing the encoded polyline to decode.
+
+ Implementations SHOULD validate the input and may throw
+
+ or for invalid formats.
+ - name: cancellationToken
+ type:
+ - text: CancellationToken
+ url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
+ description: >-
+ A to observe while decoding. If cancellation is requested,
+
+ implementations SHOULD stop work and throw an .
+ optional: true
+- h4: Returns
+- parameters:
+ - type:
+ - text: IEnumerable
+ url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
+ - <
+ - TValue
+ - '>'
+ description: >-
+ An of TValue representing the decoded
+
+ latitude/longitude pairs (or equivalent coordinates) in the same order they were encoded.
+- h4: Remarks
+- markdown: >-
+ Implementations commonly follow the Google Encoded Polyline Algorithm Format, but this interface
+
+ does not mandate a specific encoding. Consumers should rely on a concrete decoder's documentation
+
+ to understand the exact encoding supported.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: OperationCanceledException
+ url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception
+ description: Thrown when the provided cancellationToken requests cancellation.
+languageId: csharp
+metadata:
+ description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
new file mode 100644
index 00000000..341a9de7
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
@@ -0,0 +1,142 @@
+### YamlMime:ApiPage
+title: Interface IPolylineEncoder
+body:
+- api1: Interface IPolylineEncoder
+ id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2
+ commentId: T:PolylineAlgorithm.Abstraction.IPolylineEncoder`2
+- facts:
+ - name: Namespace
+ value:
+ text: PolylineAlgorithm.Abstraction
+ url: PolylineAlgorithm.Abstraction.html
+ - name: Assembly
+ value: PolylineAlgorithm.dll
+- markdown: >-
+ Contract for encoding a sequence of geographic coordinates into an encoded polyline representation.
+
+ Implementations interpret the generic TValue type and produce an encoded
+
+ representation of those coordinates as TPolyline.
+- code: public interface IPolylineEncoder
+- h4: Type Parameters
+- parameters:
+ - name: TValue
+ description: >-
+ The concrete coordinate representation used by the encoder (for example a struct or class containing
+
+ Latitude and Longitude values). Implementations must document the expected shape,
+
+ units (typically decimal degrees), and any required fields for TValue.
+
+ Common shapes:
+
+ - A struct or class with two double properties named Latitude and Longitude.
+
+ - A tuple-like type (for example ValueTuple<double,double>) where the encoder documents
+ which element represents latitude and longitude.
+ - name: TPolyline
+ description: >-
+ The encoded polyline representation returned by the encoder (for example string,
+
+ ReadOnlyMemory<char>, or a custom wrapper type). Concrete implementations should document
+
+ the chosen representation and any memory / ownership expectations.
+- h4: Extension Methods
+- list:
+ - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List)
+ url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__
+ - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TValue[])
+ url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___
+- h2: Remarks
+- markdown: >-
+ - This interface is intentionally minimal to allow different encoding strategies (Google encoded polyline,
+ precision/scale variants, or custom compressed formats) to be expressed behind a common contract.
+ - Implementations should document:
+ - Coordinate precision and rounding rules (for example 1e-5 for 5-decimal precision).
+ - Coordinate ordering and whether altitude or additional dimensions are supported.
+ - Thread-safety guarantees: whether instances are safe to reuse concurrently or must be instantiated per-call.
+ - Implementations are encouraged to be memory-efficient; the API accepts a
+ to avoid forced allocations when callers already have contiguous memory.
+- h2: Methods
+- api3: Encode(ReadOnlySpan, CancellationToken)
+ id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76
+ metadata:
+ uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
+ commentId: M:PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
+- markdown: >-
+ Encodes a sequence of geographic coordinates into an encoded polyline representation.
+
+ The order of coordinates in coordinates is preserved in the encoded result.
+- code: TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default)
+- h4: Parameters
+- parameters:
+ - name: coordinates
+ type:
+ - text: ReadOnlySpan
+ url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
+ - <
+ - TValue
+ - '>'
+ description: >-
+ The collection of TValue instances to encode into a polyline.
+
+ The span may be empty; implementations should return an appropriate empty encoded representation
+
+ (for example an empty string or an empty memory slice) rather than null.
+ - name: cancellationToken
+ type:
+ - text: CancellationToken
+ url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
+ description: >-
+ A that can be used to cancel the encoding operation.
+
+ Implementations should observe this token and throw
+
+ when cancellation is requested. For fast, in-memory encoders cancellation may be best-effort.
+ optional: true
+- h4: Returns
+- parameters:
+ - type:
+ - TPolyline
+ description: >-
+ A TPolyline containing the encoded polyline that represents the input coordinates.
+
+ The exact format and any delimiting/terminating characters are implementation-specific and must be
+
+ documented by concrete encoder types.
+- h4: Examples
+- markdown: >-
+ // Example pseudocode for typical usage with a string-based encoder:
+
+ var coords = new[] {
+ new Coordinate { Latitude = 47.6219, Longitude = -122.3503 },
+ new Coordinate { Latitude = 47.6220, Longitude = -122.3504 }
+ };
+
+ IPolylineEncoder<Coordinate,string> encoder = new GoogleEncodedPolylineEncoder();
+
+ string encoded = encoder.Encode(coords, CancellationToken.None);
+- h4: Remarks
+- markdown: >-
+ - Implementations should validate input as appropriate and document any preconditions (for example
+ if coordinates must be within [-90,90] latitude and [-180,180] longitude).
+ - For large input sequences, implementations may provide streaming or incremental encoders; those
+ variants can still implement this interface by materializing the final encoded result.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: OperationCanceledException
+ url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception
+ description: Thrown if the operation is canceled via cancellationToken.
+languageId: csharp
+metadata:
+ description: >-
+ Contract for encoding a sequence of geographic coordinates into an encoded polyline representation.
+
+ Implementations interpret the generic TValue type and produce an encoded
+
+ representation of those coordinates as TPolyline.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.yml
new file mode 100644
index 00000000..e9de48f7
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.yml
@@ -0,0 +1,34 @@
+### YamlMime:ApiPage
+title: Namespace PolylineAlgorithm.Abstraction
+body:
+- api1: Namespace PolylineAlgorithm.Abstraction
+ id: PolylineAlgorithm_Abstraction
+ metadata:
+ uid: PolylineAlgorithm.Abstraction
+ commentId: N:PolylineAlgorithm.Abstraction
+- h3: Classes
+- parameters:
+ - type:
+ text: AbstractPolylineDecoder
+ url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html
+ description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
+ - type:
+ text: AbstractPolylineEncoder
+ url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html
+ description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
+- h3: Interfaces
+- parameters:
+ - type:
+ text: IPolylineDecoder
+ url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
+ description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates.
+ - type:
+ text: IPolylineEncoder
+ url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html
+ description: >-
+ Contract for encoding a sequence of geographic coordinates into an encoded polyline representation.
+
+ Implementations interpret the generic TValue type and produce an encoded
+
+ representation of those coordinates as TPolyline.
+languageId: csharp
diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
new file mode 100644
index 00000000..8356b63c
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
@@ -0,0 +1,195 @@
+### YamlMime:ApiPage
+title: Class PolylineDecoderExtensions
+body:
+- api1: Class PolylineDecoderExtensions
+ id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16
+ metadata:
+ uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions
+ commentId: T:PolylineAlgorithm.Extensions.PolylineDecoderExtensions
+- facts:
+ - name: Namespace
+ value:
+ text: PolylineAlgorithm.Extensions
+ url: PolylineAlgorithm.Extensions.html
+ - name: Assembly
+ value: PolylineAlgorithm.dll
+- markdown: Provides extension methods for the interface to facilitate decoding encoded polylines.
+- code: public static class PolylineDecoderExtensions
+- h4: Inheritance
+- inheritance:
+ - text: object
+ url: https://learn.microsoft.com/dotnet/api/system.object
+ - text: PolylineDecoderExtensions
+ url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html
+- h4: Inherited Members
+- list:
+ - text: object.Equals(object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
+ - text: object.Equals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
+ - text: object.GetHashCode()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
+ - text: object.GetType()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gettype
+ - text: object.MemberwiseClone()
+ url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
+ - text: object.ReferenceEquals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
+ - text: object.ToString()
+ url: https://learn.microsoft.com/dotnet/api/system.object.tostring
+- h2: Methods
+- api3: Decode(IPolylineDecoder, char[])
+ id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_Char___
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33
+ metadata:
+ uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[])
+ commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[])
+- markdown: Decodes an encoded polyline represented as a character array into a sequence of geographic coordinates.
+- code: public static IEnumerable Decode(this IPolylineDecoder decoder, char[] polyline)
+- h4: Parameters
+- parameters:
+ - name: decoder
+ type:
+ - text: IPolylineDecoder
+ url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
+ - <
+ - text: string
+ url: https://learn.microsoft.com/dotnet/api/system.string
+ - ','
+ - " "
+ - TValue
+ - '>'
+ description: The instance used to perform the decoding operation.
+ - name: polyline
+ type:
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '['
+ - ']'
+ description: The encoded polyline as a character array to decode. The array is converted to a string internally.
+- h4: Returns
+- parameters:
+ - type:
+ - text: IEnumerable
+ url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
+ - <
+ - TValue
+ - '>'
+ description: An of TValue containing the decoded coordinate pairs.
+- h4: Type Parameters
+- parameters:
+ - name: TValue
+ description: The coordinate type returned by the decoder.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentNullException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
+ description: Thrown when decoder or polyline is null.
+- api3: Decode(IPolylineDecoder, ReadOnlyMemory)
+ id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_ReadOnlyMemory_System_Char__
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61
+ metadata:
+ uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char})
+ commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char})
+- markdown: Decodes an encoded polyline represented as a read-only memory of characters into a sequence of geographic coordinates.
+- code: public static IEnumerable Decode(this IPolylineDecoder decoder, ReadOnlyMemory polyline)
+- h4: Parameters
+- parameters:
+ - name: decoder
+ type:
+ - text: IPolylineDecoder
+ url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
+ - <
+ - text: string
+ url: https://learn.microsoft.com/dotnet/api/system.string
+ - ','
+ - " "
+ - TValue
+ - '>'
+ description: The instance used to perform the decoding operation.
+ - name: polyline
+ type:
+ - text: ReadOnlyMemory
+ url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ description: The encoded polyline as a read-only memory of characters to decode. The memory is converted to a string internally.
+- h4: Returns
+- parameters:
+ - type:
+ - text: IEnumerable
+ url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
+ - <
+ - TValue
+ - '>'
+ description: An of TValue containing the decoded coordinate pairs.
+- h4: Type Parameters
+- parameters:
+ - name: TValue
+ description: The coordinate type returned by the decoder.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentNullException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
+ description: Thrown when decoder is null.
+- api3: Decode(IPolylineDecoder, TValue>, string)
+ id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_ReadOnlyMemory_System_Char____0__System_String_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86
+ metadata:
+ uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String)
+ commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String)
+- markdown: >-
+ Decodes an encoded polyline string into a sequence of geographic coordinates,
+
+ using a decoder that accepts of .
+- code: public static IEnumerable Decode(this IPolylineDecoder, TValue> decoder, string polyline)
+- h4: Parameters
+- parameters:
+ - name: decoder
+ type:
+ - text: IPolylineDecoder
+ url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
+ - <
+ - text: ReadOnlyMemory
+ url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ - ','
+ - " "
+ - TValue
+ - '>'
+ description: The instance used to perform the decoding operation.
+ - name: polyline
+ type:
+ - text: string
+ url: https://learn.microsoft.com/dotnet/api/system.string
+ description: The encoded polyline string to decode. The string is converted to internally.
+- h4: Returns
+- parameters:
+ - type:
+ - text: IEnumerable
+ url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
+ - <
+ - TValue
+ - '>'
+ description: An of TValue containing the decoded coordinate pairs.
+- h4: Type Parameters
+- parameters:
+ - name: TValue
+ description: The coordinate type returned by the decoder.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentNullException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
+ description: Thrown when decoder or polyline is null.
+languageId: csharp
+metadata:
+ description: Provides extension methods for the interface to facilitate decoding encoded polylines.
diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
new file mode 100644
index 00000000..e5296518
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
@@ -0,0 +1,139 @@
+### YamlMime:ApiPage
+title: Class PolylineEncoderExtensions
+body:
+- api1: Class PolylineEncoderExtensions
+ id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19
+ metadata:
+ uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions
+ commentId: T:PolylineAlgorithm.Extensions.PolylineEncoderExtensions
+- facts:
+ - name: Namespace
+ value:
+ text: PolylineAlgorithm.Extensions
+ url: PolylineAlgorithm.Extensions.html
+ - name: Assembly
+ value: PolylineAlgorithm.dll
+- markdown: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines.
+- code: public static class PolylineEncoderExtensions
+- h4: Inheritance
+- inheritance:
+ - text: object
+ url: https://learn.microsoft.com/dotnet/api/system.object
+ - text: PolylineEncoderExtensions
+ url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html
+- h4: Inherited Members
+- list:
+ - text: object.Equals(object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
+ - text: object.Equals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
+ - text: object.GetHashCode()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
+ - text: object.GetType()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gettype
+ - text: object.MemberwiseClone()
+ url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
+ - text: object.ReferenceEquals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
+ - text: object.ToString()
+ url: https://learn.microsoft.com/dotnet/api/system.object.tostring
+- h2: Methods
+- api3: Encode(IPolylineEncoder, List)
+ id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37
+ metadata:
+ uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0})
+ commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0})
+- markdown: Encodes a of TCoordinate instances into an encoded polyline.
+- code: >-
+ [SuppressMessage("Design", "CA1002:Do not expose generic lists", Justification = "We need a list as we do need to marshal it as span.")]
+
+ [SuppressMessage("Design", "MA0016:Prefer using collection abstraction instead of implementation", Justification = "We need a list as we do need to marshal it as span.")]
+
+ public static TPolyline Encode(this IPolylineEncoder encoder, List coordinates)
+- h4: Parameters
+- parameters:
+ - name: encoder
+ type:
+ - text: IPolylineEncoder
+ url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html
+ - <
+ - TCoordinate
+ - ','
+ - " "
+ - TPolyline
+ - '>'
+ description: The instance used to perform the encoding operation.
+ - name: coordinates
+ type:
+ - text: List
+ url: https://learn.microsoft.com/dotnet/api/system.collections.generic.list-1
+ - <
+ - TCoordinate
+ - '>'
+ description: The list of TCoordinate objects to encode.
+- h4: Returns
+- parameters:
+ - type:
+ - TPolyline
+ description: A TPolyline instance representing the encoded polyline for the provided coordinates.
+- h4: Type Parameters
+- parameters:
+ - name: TCoordinate
+ description: The type that represents a geographic coordinate to encode.
+ - name: TPolyline
+ description: The type that represents the encoded polyline output.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentNullException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
+ description: Thrown when encoder or coordinates is null.
+- api3: Encode(IPolylineEncoder, TCoordinate[])
+ id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73
+ metadata:
+ uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[])
+ commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[])
+- markdown: Encodes an array of TCoordinate instances into an encoded polyline.
+- code: public static TPolyline Encode(this IPolylineEncoder encoder, TCoordinate[] coordinates)
+- h4: Parameters
+- parameters:
+ - name: encoder
+ type:
+ - text: IPolylineEncoder
+ url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html
+ - <
+ - TCoordinate
+ - ','
+ - " "
+ - TPolyline
+ - '>'
+ description: The instance used to perform the encoding operation.
+ - name: coordinates
+ type:
+ - TCoordinate
+ - '['
+ - ']'
+ description: The array of TCoordinate objects to encode.
+- h4: Returns
+- parameters:
+ - type:
+ - TPolyline
+ description: A TPolyline instance representing the encoded polyline for the provided coordinates.
+- h4: Type Parameters
+- parameters:
+ - name: TCoordinate
+ description: The type that represents a geographic coordinate to encode.
+ - name: TPolyline
+ description: The type that represents the encoded polyline output.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentNullException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
+ description: Thrown when encoder or coordinates is null.
+languageId: csharp
+metadata:
+ description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines.
diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.yml
new file mode 100644
index 00000000..c39da0ca
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.Extensions.yml
@@ -0,0 +1,19 @@
+### YamlMime:ApiPage
+title: Namespace PolylineAlgorithm.Extensions
+body:
+- api1: Namespace PolylineAlgorithm.Extensions
+ id: PolylineAlgorithm_Extensions
+ metadata:
+ uid: PolylineAlgorithm.Extensions
+ commentId: N:PolylineAlgorithm.Extensions
+- h3: Classes
+- parameters:
+ - type:
+ text: PolylineDecoderExtensions
+ url: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.html
+ description: Provides extension methods for the interface to facilitate decoding encoded polylines.
+ - type:
+ text: PolylineEncoderExtensions
+ url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html
+ description: Provides extension methods for the interface to facilitate encoding geographic coordinates into polylines.
+languageId: csharp
diff --git a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml
new file mode 100644
index 00000000..2c4e3cc1
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml
@@ -0,0 +1,102 @@
+### YamlMime:ApiPage
+title: Class InvalidPolylineException
+body:
+- api1: Class InvalidPolylineException
+ id: PolylineAlgorithm_InvalidPolylineException
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L17
+ metadata:
+ uid: PolylineAlgorithm.InvalidPolylineException
+ commentId: T:PolylineAlgorithm.InvalidPolylineException
+- facts:
+ - name: Namespace
+ value:
+ text: PolylineAlgorithm
+ url: PolylineAlgorithm.html
+ - name: Assembly
+ value: PolylineAlgorithm.dll
+- markdown: Exception thrown when a polyline is determined to be malformed or invalid during processing.
+- code: 'public sealed class InvalidPolylineException : Exception, ISerializable'
+- h4: Inheritance
+- inheritance:
+ - text: object
+ url: https://learn.microsoft.com/dotnet/api/system.object
+ - text: Exception
+ url: https://learn.microsoft.com/dotnet/api/system.exception
+ - text: InvalidPolylineException
+ url: PolylineAlgorithm.InvalidPolylineException.html
+- h4: Implements
+- list:
+ - text: ISerializable
+ url: https://learn.microsoft.com/dotnet/api/system.runtime.serialization.iserializable
+- h4: Inherited Members
+- list:
+ - text: Exception.GetBaseException()
+ url: https://learn.microsoft.com/dotnet/api/system.exception.getbaseexception
+ - text: Exception.GetObjectData(SerializationInfo, StreamingContext)
+ url: https://learn.microsoft.com/dotnet/api/system.exception.getobjectdata
+ - text: Exception.GetType()
+ url: https://learn.microsoft.com/dotnet/api/system.exception.gettype
+ - text: Exception.ToString()
+ url: https://learn.microsoft.com/dotnet/api/system.exception.tostring
+ - text: Exception.Data
+ url: https://learn.microsoft.com/dotnet/api/system.exception.data
+ - text: Exception.HelpLink
+ url: https://learn.microsoft.com/dotnet/api/system.exception.helplink
+ - text: Exception.HResult
+ url: https://learn.microsoft.com/dotnet/api/system.exception.hresult
+ - text: Exception.InnerException
+ url: https://learn.microsoft.com/dotnet/api/system.exception.innerexception
+ - text: Exception.Message
+ url: https://learn.microsoft.com/dotnet/api/system.exception.message
+ - text: Exception.Source
+ url: https://learn.microsoft.com/dotnet/api/system.exception.source
+ - text: Exception.StackTrace
+ url: https://learn.microsoft.com/dotnet/api/system.exception.stacktrace
+ - text: Exception.TargetSite
+ url: https://learn.microsoft.com/dotnet/api/system.exception.targetsite
+ - text: object.Equals(object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
+ - text: object.Equals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
+ - text: object.GetHashCode()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
+ - text: object.GetType()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gettype
+ - text: object.ReferenceEquals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
+ - text: object.ToString()
+ url: https://learn.microsoft.com/dotnet/api/system.object.tostring
+- h2: Remarks
+- markdown: This exception is used internally to indicate that a polyline string does not conform to the expected format or contains errors.
+- h2: Constructors
+- api3: InvalidPolylineException()
+ id: PolylineAlgorithm_InvalidPolylineException__ctor
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L22
+ metadata:
+ uid: PolylineAlgorithm.InvalidPolylineException.#ctor
+ commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor
+- markdown: Initializes a new instance of the class.
+- code: public InvalidPolylineException()
+- api3: InvalidPolylineException(string, Exception)
+ id: PolylineAlgorithm_InvalidPolylineException__ctor_System_String_System_Exception_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L43
+ metadata:
+ uid: PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception)
+ commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception)
+- markdown: Initializes a new instance of the class with a specified error message and a reference to the inner exception that is the cause of this exception.
+- code: public InvalidPolylineException(string message, Exception innerException)
+- h4: Parameters
+- parameters:
+ - name: message
+ type:
+ - text: string
+ url: https://learn.microsoft.com/dotnet/api/system.string
+ description: The error message that explains the reason for the exception.
+ - name: innerException
+ type:
+ - text: Exception
+ url: https://learn.microsoft.com/dotnet/api/system.exception
+ description: The exception that is the cause of the current exception, or a null reference if no inner exception is specified.
+languageId: csharp
+metadata:
+ description: Exception thrown when a polyline is determined to be malformed or invalid during processing.
diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml
new file mode 100644
index 00000000..1add8147
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml
@@ -0,0 +1,529 @@
+### YamlMime:ApiPage
+title: Class PolylineEncoding
+body:
+- api1: Class PolylineEncoding
+ id: PolylineAlgorithm_PolylineEncoding
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L23
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncoding
+ commentId: T:PolylineAlgorithm.PolylineEncoding
+- facts:
+ - name: Namespace
+ value:
+ text: PolylineAlgorithm
+ url: PolylineAlgorithm.html
+ - name: Assembly
+ value: PolylineAlgorithm.dll
+- markdown: >-
+ Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing
+
+ geographic coordinate values.
+- code: public static class PolylineEncoding
+- h4: Inheritance
+- inheritance:
+ - text: object
+ url: https://learn.microsoft.com/dotnet/api/system.object
+ - text: PolylineEncoding
+ url: PolylineAlgorithm.PolylineEncoding.html
+- h4: Inherited Members
+- list:
+ - text: object.Equals(object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
+ - text: object.Equals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
+ - text: object.GetHashCode()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
+ - text: object.GetType()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gettype
+ - text: object.MemberwiseClone()
+ url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
+ - text: object.ReferenceEquals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
+ - text: object.ToString()
+ url: https://learn.microsoft.com/dotnet/api/system.object.tostring
+- h2: Remarks
+- markdown: >-
+ The class includes functionality for working with encoded polyline
+ data, such as reading and writing encoded values, as well as methods for normalizing and de-normalizing geographic
+ coordinates. It also provides validation utilities to ensure values conform to expected ranges for latitude and
+ longitude.
+- h2: Methods
+- api3: Denormalize(int, uint)
+ id: PolylineAlgorithm_PolylineEncoding_Denormalize_System_Int32_System_UInt32_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L122
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32)
+ commentId: M:PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32)
+- markdown: Converts a normalized integer coordinate value back to its floating-point representation based on the specified precision.
+- code: public static double Denormalize(int value, uint precision = 5)
+- h4: Parameters
+- parameters:
+ - name: value
+ type:
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ description: The integer value to denormalize. Typically produced by the method.
+ - name: precision
+ type:
+ - text: uint
+ url: https://learn.microsoft.com/dotnet/api/system.uint32
+ description: The number of decimal places used during normalization. Default is 5, matching standard polyline encoding precision.
+ optional: true
+- h4: Returns
+- parameters:
+ - type:
+ - text: double
+ url: https://learn.microsoft.com/dotnet/api/system.double
+ description: The denormalized floating-point coordinate value.
+- h4: Remarks
+- markdown: >-
+
+
+ This method reverses the normalization performed by . It takes an integer value and converts it
+
+ to a double by dividing it by 10 raised to the power of the specified precision. If precision is 0,
+
+ the value is returned as a double without division.
+
+
+
+
+
+ The calculation is performed inside a checked block to ensure that any arithmetic overflow is detected
+
+ and an is thrown.
+
+
+
+
+
+ For example, with a precision of 5:
+
+
+
- A value of 3778903 becomes 37.78903
- A value of -12241230 becomes -122.4123
+
+
+
+
+
+ If the input value is 0, the method returns 0.0 immediately.
+
+
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: OverflowException
+ url: https://learn.microsoft.com/dotnet/api/system.overflowexception
+ description: Thrown if the arithmetic operation overflows during conversion.
+- api3: GetRequiredBufferSize(int)
+ id: PolylineAlgorithm_PolylineEncoding_GetRequiredBufferSize_System_Int32_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L298
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32)
+ commentId: M:PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32)
+- markdown: Calculates the number of characters required to encode a delta value in polyline format.
+- code: public static int GetRequiredBufferSize(int delta)
+- h4: Parameters
+- parameters:
+ - name: delta
+ type:
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ description: >-
+ The integer delta value to calculate the encoded size for. This value typically represents the difference between
+
+ consecutive coordinate values in polyline encoding.
+- h4: Returns
+- parameters:
+ - type:
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ description: The number of characters required to encode the specified delta value. The minimum return value is 1.
+- h4: Remarks
+- markdown: >-
+
+
+ This method determines how many characters will be needed to represent an integer delta value when encoded
+
+ using the polyline encoding algorithm. It performs the same zigzag encoding transformation as
+
+ but only calculates the required buffer size without actually writing any data.
+
+
+
+
+
+ The calculation process:
+
+
+
- Applies zigzag encoding: left-shifts the value by 1 bit, then inverts all bits if the original value was negative
- Counts how many 5-bit chunks are needed to represent the encoded value
- Each chunk requires one character, with a minimum of 1 character for any value
+
+
+
+
+
+ This method is useful for pre-allocating buffers of the correct size before encoding polyline data, helping to avoid
+
+ buffer overflow checks during the actual encoding process.
+
+
+
+
+
+ The method uses a long internally to prevent overflow during the left-shift operation on large negative values.
+
+
+- h4: See Also
+- list:
+ - - text: PolylineEncoding
+ url: PolylineAlgorithm.PolylineEncoding.html
+ - .
+ - text: TryWriteValue
+ url: PolylineAlgorithm.PolylineEncoding.html#PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__
+ - (
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ - ','
+ - " "
+ - text: Span
+ url: https://learn.microsoft.com/dotnet/api/system.span-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ - ','
+ - " "
+ - ref
+ - " "
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ - )
+- api3: Normalize(double, uint)
+ id: PolylineAlgorithm_PolylineEncoding_Normalize_System_Double_System_UInt32_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L61
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32)
+ commentId: M:PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32)
+- markdown: Normalizes a geographic coordinate value to an integer representation based on the specified precision.
+- code: public static int Normalize(double value, uint precision = 5)
+- h4: Parameters
+- parameters:
+ - name: value
+ type:
+ - text: double
+ url: https://learn.microsoft.com/dotnet/api/system.double
+ description: The numeric value to normalize. Must be a finite number (not NaN or infinity).
+ - name: precision
+ type:
+ - text: uint
+ url: https://learn.microsoft.com/dotnet/api/system.uint32
+ description: >-
+ The number of decimal places of precision to preserve in the normalized value.
+
+ The value is multiplied by 10^precision before rounding.
+
+ Default is 5, which is standard for polyline encoding.
+ optional: true
+- h4: Returns
+- parameters:
+ - type:
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ description: An integer representing the normalized value. Returns 0 if the input value is 0.0.
+- h4: Remarks
+- markdown: >-
+
+
+ This method converts a floating-point coordinate value into a normalized integer by multiplying it by 10 raised
+
+ to the power of the specified precision, then truncating the result to an integer.
+
+
+
+
+
+ For example, with the default precision of 5:
+
+
+
- A value of 37.78903 becomes 3778903
- A value of -122.4123 becomes -12241230
+
+
+
+
+
+ The method validates that the input value is finite (not NaN or infinity) before performing normalization.
+
+ If the precision is 0, the value is rounded without multiplication.
+
+
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentOutOfRangeException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception
+ description: Thrown when value is not a finite number (NaN or infinity).
+ - type:
+ - text: OverflowException
+ url: https://learn.microsoft.com/dotnet/api/system.overflowexception
+ description: Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int.
+- api3: TryReadValue(ref int, ReadOnlyMemory, ref int)
+ id: PolylineAlgorithm_PolylineEncoding_TryReadValue_System_Int32__System_ReadOnlyMemory_System_Char__System_Int32__
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L169
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@)
+ commentId: M:PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@)
+- markdown: Attempts to read an encoded integer value from a polyline buffer, updating the specified delta and position.
+- code: public static bool TryReadValue(ref int delta, ReadOnlyMemory buffer, ref int position)
+- h4: Parameters
+- parameters:
+ - name: delta
+ type:
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ description: Reference to the integer accumulator that will be updated with the decoded value.
+ - name: buffer
+ type:
+ - text: ReadOnlyMemory
+ url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ description: The buffer containing polyline-encoded characters.
+ - name: position
+ type:
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ description: Reference to the current position in the buffer. This value is updated as characters are read.
+- h4: Returns
+- parameters:
+ - type:
+ - text: bool
+ url: https://learn.microsoft.com/dotnet/api/system.boolean
+ description: true if a value was successfully read and decoded; false if the buffer ended before a complete value was read.
+- h4: Remarks
+- markdown: >-
+
+
+ This method decodes a value from a polyline-encoded character buffer, starting at the given position. It reads
+
+ characters sequentially, applying the polyline decoding algorithm, and updates the delta with
+
+ the decoded value. The position is advanced as characters are processed.
+
+
+
+
+
+ The decoding process continues until a character with a value less than the algorithm's space constant is encountered,
+
+ which signals the end of the encoded value. If the buffer is exhausted before a complete value is read, the method returns false.
+
+
+
+
+
+ The decoded value is added to delta using zigzag decoding, which handles both positive and negative values.
+
+
+- api3: TryWriteValue(int, Span, ref int)
+ id: PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L237
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@)
+ commentId: M:PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@)
+- markdown: Attempts to write an encoded integer value to a polyline buffer, updating the specified position.
+- code: public static bool TryWriteValue(int delta, Span buffer, ref int position)
+- h4: Parameters
+- parameters:
+ - name: delta
+ type:
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ description: >-
+ The integer value to encode and write to the buffer. This value typically represents the difference between consecutive
+
+ coordinate values in polyline encoding.
+ - name: buffer
+ type:
+ - text: Span
+ url: https://learn.microsoft.com/dotnet/api/system.span-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ description: The destination buffer where the encoded characters will be written. Must have sufficient capacity to hold the encoded value.
+ - name: position
+ type:
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ description: >-
+ Reference to the current position in the buffer. This value is updated as characters are written to reflect the new position
+
+ after encoding is complete.
+- h4: Returns
+- parameters:
+ - type:
+ - text: bool
+ url: https://learn.microsoft.com/dotnet/api/system.boolean
+ description: >-
+ true if the value was successfully encoded and written to the buffer; false if the buffer
+
+ does not have sufficient remaining capacity to hold the encoded value.
+- h4: Remarks
+- markdown: >-
+
+
+ This method encodes an integer delta value into a polyline-encoded format and writes it to the provided character buffer,
+
+ starting at the given position. It applies zigzag encoding followed by the polyline encoding algorithm to represent
+
+ both positive and negative values efficiently.
+
+
+
+
+
+ The encoding process first converts the value using zigzag encoding (left shift by 1, with bitwise inversion for negative values),
+
+ then writes it as a sequence of characters. Each character encodes 5 bits of data, with continuation bits indicating whether
+
+ more characters follow. The position is advanced as characters are written.
+
+
+
+
+
+ Before writing, the method validates that sufficient space is available in the buffer by calling .
+
+ If the buffer does not have enough remaining capacity, the method returns false without modifying the buffer or position.
+
+
+
+
+
+ This method is the inverse of and can be used to encode coordinate deltas for polyline serialization.
+
+
+- api3: ValidateBlockLength(ReadOnlySpan)
+ id: PolylineAlgorithm_PolylineEncoding_ValidateBlockLength_System_ReadOnlySpan_System_Char__
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L438
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char})
+ commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char})
+- markdown: Validates the block structure of a polyline segment, ensuring each encoded value does not exceed 7 characters and the polyline ends correctly.
+- code: public static void ValidateBlockLength(ReadOnlySpan polyline)
+- h4: Parameters
+- parameters:
+ - name: polyline
+ type:
+ - text: ReadOnlySpan
+ url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ description: A span representing the polyline segment to validate.
+- h4: Remarks
+- markdown: >-
+
+
+ Iterates through the polyline, counting the length of each block (a sequence of characters representing an encoded value).
+
+ Throws an if any block exceeds 7 characters or if the polyline does not end with a valid block terminator.
+
+
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentexception
+ description: Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator.
+- api3: ValidateCharRange(ReadOnlySpan)
+ id: PolylineAlgorithm_PolylineEncoding_ValidateCharRange_System_ReadOnlySpan_System_Char__
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L392
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char})
+ commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char})
+- markdown: Validates that all characters in the polyline segment are within the allowed ASCII range for polyline encoding.
+- code: public static void ValidateCharRange(ReadOnlySpan polyline)
+- h4: Parameters
+- parameters:
+ - name: polyline
+ type:
+ - text: ReadOnlySpan
+ url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ description: A span representing the polyline segment to validate.
+- h4: Remarks
+- markdown: >-
+
+
+ Uses SIMD vectorization for efficient validation of large spans. Falls back to scalar checks for any block where an invalid character is detected.
+
+
+
+
+
+ The valid range is from '?' (63) to '_' (95), inclusive. If an invalid character is found, an is thrown.
+
+
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentexception
+ description: Thrown when an invalid character is found in the polyline segment.
+- api3: ValidateFormat(ReadOnlySpan)
+ id: PolylineAlgorithm_PolylineEncoding_ValidateFormat_System_ReadOnlySpan_System_Char__
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L370
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char})
+ commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char})
+- markdown: Validates the format of a polyline segment, ensuring all characters are valid and block structure is correct.
+- code: public static void ValidateFormat(ReadOnlySpan polyline)
+- h4: Parameters
+- parameters:
+ - name: polyline
+ type:
+ - text: ReadOnlySpan
+ url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
+ - <
+ - text: char
+ url: https://learn.microsoft.com/dotnet/api/system.char
+ - '>'
+ description: A span representing the polyline segment to validate.
+- h4: Remarks
+- markdown: >-
+
+
+ This method performs two levels of validation on the provided polyline segment:
+
+
+
+ -
+ Character Range Validation: Checks that every character in the polyline is within the valid ASCII range for polyline encoding ('?' [63] to '_' [95], inclusive).
+ Uses SIMD acceleration for efficient validation of large segments.
+
-
+ Block Structure Validation: Ensures that each encoded value (block) does not exceed 7 characters and that the polyline ends with a valid block terminator.
+
+
+
+ If an invalid character or block structure is detected, an is thrown with details about the error.
+
+
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentexception
+ description: Thrown when an invalid character is found or the block structure is invalid.
+languageId: csharp
+metadata:
+ description: >-
+ Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing
+
+ geographic coordinate values.
diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml
new file mode 100644
index 00000000..1947eac1
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml
@@ -0,0 +1,127 @@
+### YamlMime:ApiPage
+title: Class PolylineEncodingOptions
+body:
+- api1: Class PolylineEncodingOptions
+ id: PolylineAlgorithm_PolylineEncodingOptions
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncodingOptions
+ commentId: T:PolylineAlgorithm.PolylineEncodingOptions
+- facts:
+ - name: Namespace
+ value:
+ text: PolylineAlgorithm
+ url: PolylineAlgorithm.html
+ - name: Assembly
+ value: PolylineAlgorithm.dll
+- markdown: Provides configuration options for polyline encoding operations.
+- code: public sealed class PolylineEncodingOptions
+- h4: Inheritance
+- inheritance:
+ - text: object
+ url: https://learn.microsoft.com/dotnet/api/system.object
+ - text: PolylineEncodingOptions
+ url: PolylineAlgorithm.PolylineEncodingOptions.html
+- h4: Inherited Members
+- list:
+ - text: object.Equals(object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
+ - text: object.Equals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
+ - text: object.GetHashCode()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
+ - text: object.GetType()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gettype
+ - text: object.ReferenceEquals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
+ - text: object.ToString()
+ url: https://learn.microsoft.com/dotnet/api/system.object.tostring
+- h2: Remarks
+- markdown: >-
+
+
+ This class allows you to configure various aspects of polyline encoding, including:
+
+
+
+ - The level for coordinate encoding
- The for memory allocation strategy
- The for diagnostic logging
+
+
+
+ All properties have internal setters and should be configured through a builder or factory pattern.
+
+
+- h2: Properties
+- api3: LoggerFactory
+ id: PolylineAlgorithm_PolylineEncodingOptions_LoggerFactory
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory
+ commentId: P:PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory
+- markdown: Gets the logger factory used for diagnostic logging during encoding operations.
+- code: public ILoggerFactory LoggerFactory { get; }
+- h4: Property Value
+- parameters:
+ - type:
+ - text: ILoggerFactory
+ url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory
+- h4: Remarks
+- markdown: >-
+ The default logger factory is , which does not log any messages.
+
+ To enable logging, provide a custom implementation.
+- api3: Precision
+ id: PolylineAlgorithm_PolylineEncodingOptions_Precision
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncodingOptions.Precision
+ commentId: P:PolylineAlgorithm.PolylineEncodingOptions.Precision
+- markdown: Gets the precision level used for encoding coordinate values.
+- code: public uint Precision { get; }
+- h4: Property Value
+- parameters:
+ - type:
+ - text: uint
+ url: https://learn.microsoft.com/dotnet/api/system.uint32
+- h4: Remarks
+- markdown: >-
+
+
+ The precision determines the number of decimal places to which each coordinate value (latitude or longitude)
+
+ is multiplied and truncated (not rounded) before encoding. For example, a precision of 5 means each coordinate is multiplied by 10^5
+
+ and truncated to an integer before encoding.
+
+
+
+
+
+ This setting does not directly correspond to a physical distance or accuracy in meters, but rather controls
+
+ the granularity of the encoded values.
+
+
+- api3: StackAllocLimit
+ id: PolylineAlgorithm_PolylineEncodingOptions_StackAllocLimit
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit
+ commentId: P:PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit
+- markdown: Gets the maximum buffer size (in characters) that can be allocated on the stack for encoding operations.
+- code: public int StackAllocLimit { get; }
+- h4: Property Value
+- parameters:
+ - type:
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+- h4: Remarks
+- markdown: >-
+ When the required buffer size for encoding exceeds this limit, memory will be allocated on the heap instead of the stack.
+
+ This setting specifically applies to stack allocation of character arrays (stackalloc char[]) used during polyline encoding,
+
+ balancing performance and stack safety.
+languageId: csharp
+metadata:
+ description: Provides configuration options for polyline encoding operations.
diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
new file mode 100644
index 00000000..66ae63b8
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
@@ -0,0 +1,141 @@
+### YamlMime:ApiPage
+title: Class PolylineEncodingOptionsBuilder
+body:
+- api1: Class PolylineEncodingOptionsBuilder
+ id: PolylineAlgorithm_PolylineEncodingOptionsBuilder
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder
+ commentId: T:PolylineAlgorithm.PolylineEncodingOptionsBuilder
+- facts:
+ - name: Namespace
+ value:
+ text: PolylineAlgorithm
+ url: PolylineAlgorithm.html
+ - name: Assembly
+ value: PolylineAlgorithm.dll
+- markdown: Provides a builder for configuring options for polyline encoding operations.
+- code: public sealed class PolylineEncodingOptionsBuilder
+- h4: Inheritance
+- inheritance:
+ - text: object
+ url: https://learn.microsoft.com/dotnet/api/system.object
+ - text: PolylineEncodingOptionsBuilder
+ url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
+- h4: Inherited Members
+- list:
+ - text: object.Equals(object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
+ - text: object.Equals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
+ - text: object.GetHashCode()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
+ - text: object.GetType()
+ url: https://learn.microsoft.com/dotnet/api/system.object.gettype
+ - text: object.ReferenceEquals(object, object)
+ url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
+ - text: object.ToString()
+ url: https://learn.microsoft.com/dotnet/api/system.object.tostring
+- h2: Methods
+- api3: Build()
+ id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Build
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build
+ commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build
+- markdown: Builds a new instance using the configured options.
+- code: public PolylineEncodingOptions Build()
+- h4: Returns
+- parameters:
+ - type:
+ - text: PolylineEncodingOptions
+ url: PolylineAlgorithm.PolylineEncodingOptions.html
+ description: A configured instance.
+- api3: Create()
+ id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Create
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create
+ commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create
+- markdown: Creates a new instance for the specified coordinate type.
+- code: public static PolylineEncodingOptionsBuilder Create()
+- h4: Returns
+- parameters:
+ - type:
+ - text: PolylineEncodingOptionsBuilder
+ url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
+ description: An instance for configuring polyline encoding options.
+- api3: WithLoggerFactory(ILoggerFactory)
+ id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithLoggerFactory_Microsoft_Extensions_Logging_ILoggerFactory_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory)
+ commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory)
+- markdown: Configures the to be used for logging during polyline encoding operations.
+- code: public PolylineEncodingOptionsBuilder WithLoggerFactory(ILoggerFactory loggerFactory)
+- h4: Parameters
+- parameters:
+ - name: loggerFactory
+ type:
+ - text: ILoggerFactory
+ url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.iloggerfactory
+ description: The instance to use for logging. If null, a will be used instead.
+- h4: Returns
+- parameters:
+ - type:
+ - text: PolylineEncodingOptionsBuilder
+ url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
+ description: The current instance for method chaining.
+- api3: WithPrecision(uint)
+ id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithPrecision_System_UInt32_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32)
+ commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32)
+- markdown: Sets the coordinate encoding precision.
+- code: public PolylineEncodingOptionsBuilder WithPrecision(uint precision)
+- h4: Parameters
+- parameters:
+ - name: precision
+ type:
+ - text: uint
+ url: https://learn.microsoft.com/dotnet/api/system.uint32
+ description: The number of decimal places to use for encoding coordinate values. Default is 5.
+- h4: Returns
+- parameters:
+ - type:
+ - text: PolylineEncodingOptionsBuilder
+ url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
+ description: The current instance for method chaining.
+- api3: WithStackAllocLimit(int)
+ id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithStackAllocLimit_System_Int32_
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61
+ metadata:
+ uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32)
+ commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32)
+- markdown: Configures the buffer size used for stack allocation during polyline encoding operations.
+- code: public PolylineEncodingOptionsBuilder WithStackAllocLimit(int stackAllocLimit)
+- h4: Parameters
+- parameters:
+ - name: stackAllocLimit
+ type:
+ - text: int
+ url: https://learn.microsoft.com/dotnet/api/system.int32
+ description: The maximum buffer size to use for stack allocation. Must be greater than or equal to 1.
+- h4: Returns
+- parameters:
+ - type:
+ - text: PolylineEncodingOptionsBuilder
+ url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
+ description: The current instance for method chaining.
+- h4: Remarks
+- markdown: This method allows customization of the internal buffer size for encoding, which can impact performance and memory usage.
+- h4: Exceptions
+- parameters:
+ - type:
+ - text: ArgumentOutOfRangeException
+ url: https://learn.microsoft.com/dotnet/api/system.argumentoutofrangeexception
+ description: Thrown if stackAllocLimit is less than 1.
+languageId: csharp
+metadata:
+ description: Provides a builder for configuring options for polyline encoding operations.
diff --git a/api-reference/0.0/PolylineAlgorithm.yml b/api-reference/0.0/PolylineAlgorithm.yml
new file mode 100644
index 00000000..b60dc3c0
--- /dev/null
+++ b/api-reference/0.0/PolylineAlgorithm.yml
@@ -0,0 +1,38 @@
+### YamlMime:ApiPage
+title: Namespace PolylineAlgorithm
+body:
+- api1: Namespace PolylineAlgorithm
+ id: PolylineAlgorithm
+ metadata:
+ uid: PolylineAlgorithm
+ commentId: N:PolylineAlgorithm
+- h3: Namespaces
+- parameters:
+ - type:
+ text: PolylineAlgorithm.Abstraction
+ url: PolylineAlgorithm.Abstraction.html
+ - type:
+ text: PolylineAlgorithm.Extensions
+ url: PolylineAlgorithm.Extensions.html
+- h3: Classes
+- parameters:
+ - type:
+ text: InvalidPolylineException
+ url: PolylineAlgorithm.InvalidPolylineException.html
+ description: Exception thrown when a polyline is determined to be malformed or invalid during processing.
+ - type:
+ text: PolylineEncoding
+ url: PolylineAlgorithm.PolylineEncoding.html
+ description: >-
+ Provides methods for encoding and decoding polyline data, as well as utilities for normalizing and de-normalizing
+
+ geographic coordinate values.
+ - type:
+ text: PolylineEncodingOptions
+ url: PolylineAlgorithm.PolylineEncodingOptions.html
+ description: Provides configuration options for polyline encoding operations.
+ - type:
+ text: PolylineEncodingOptionsBuilder
+ url: PolylineAlgorithm.PolylineEncodingOptionsBuilder.html
+ description: Provides a builder for configuring options for polyline encoding operations.
+languageId: csharp
diff --git a/api-reference/0.0/toc.yml b/api-reference/0.0/toc.yml
new file mode 100644
index 00000000..d1ffc58a
--- /dev/null
+++ b/api-reference/0.0/toc.yml
@@ -0,0 +1,34 @@
+### YamlMime:TableOfContent
+- name: PolylineAlgorithm
+ href: PolylineAlgorithm.yml
+ items:
+ - name: Classes
+ - name: InvalidPolylineException
+ href: PolylineAlgorithm.InvalidPolylineException.yml
+ - name: PolylineEncoding
+ href: PolylineAlgorithm.PolylineEncoding.yml
+ - name: PolylineEncodingOptions
+ href: PolylineAlgorithm.PolylineEncodingOptions.yml
+ - name: PolylineEncodingOptionsBuilder
+ href: PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
+- name: PolylineAlgorithm.Abstraction
+ href: PolylineAlgorithm.Abstraction.yml
+ items:
+ - name: Classes
+ - name: AbstractPolylineDecoder
+ href: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
+ - name: AbstractPolylineEncoder
+ href: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
+ - name: Interfaces
+ - name: IPolylineDecoder
+ href: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
+ - name: IPolylineEncoder
+ href: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
+- name: PolylineAlgorithm.Extensions
+ href: PolylineAlgorithm.Extensions.yml
+ items:
+ - name: Classes
+ - name: PolylineDecoderExtensions
+ href: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
+ - name: PolylineEncoderExtensions
+ href: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
diff --git a/api-reference/guide/benchmarks.md b/api-reference/guide/benchmarks.md
new file mode 100644
index 00000000..47b453f9
--- /dev/null
+++ b/api-reference/guide/benchmarks.md
@@ -0,0 +1,11 @@
+---
+title: Benchmarks
+---
+# Benchmarks
+
+Performance benchmarks for **PolylineAlgorithm for .NET** measured using [BenchmarkDotNet](https://benchmarkdotnet.org/).
+
+> [!NOTE]
+> Benchmarks are generated automatically during the release process. Results may vary depending on hardware and runtime version.
+
+{benchmarks_section}
diff --git a/api-reference/guide/toc.yml b/api-reference/guide/toc.yml
index 015a9943..e9d9e716 100644
--- a/api-reference/guide/toc.yml
+++ b/api-reference/guide/toc.yml
@@ -8,3 +8,5 @@
href: sample.md
- name: FAQ
href: faq.md
+- name: Benchmarks
+ href: benchmarks.md
diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
index f28c8141..b6b54081 100644
--- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
+++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
@@ -93,8 +93,10 @@ public void PolylineDecoder_Decode_Memory() {
}
private sealed class StringPolylineDecoder : AbstractPolylineDecoder {
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
- return (latitude, longitude);
+ protected override int ValuesPerItem => 2;
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) {
@@ -103,8 +105,10 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) {
}
private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder {
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
- return (latitude, longitude);
+ protected override int ValuesPerItem => 2;
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) {
@@ -113,8 +117,10 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) {
}
private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> {
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
- return (latitude, longitude);
+ protected override int ValuesPerItem => 2;
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) {
diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
index e0b97c5c..c4b9d5a8 100644
--- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
+++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
@@ -85,8 +85,11 @@ public void PolylineEncoder_Encode_List() {
}
private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
+ protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
- protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
+ protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
+ destination[0] = item.Latitude;
+ destination[1] = item.Longitude;
+ }
}
}
diff --git a/docs/local-development.md b/docs/local-development.md
index 48fa5f76..ab2da8ab 100644
--- a/docs/local-development.md
+++ b/docs/local-development.md
@@ -72,3 +72,24 @@ The CI `format` job also runs `dotnet format` automatically on every push to non
## Editor Configuration
Code style rules are stored in `.editorconfig` at the repository root. Any compliant IDE (Visual Studio, VS Code with C# Dev Kit, Rider) will pick these up automatically.
+
+## Required Repository Secrets and Variables
+
+The CI/CD workflows rely on the following GitHub repository secrets and variables.
+
+### Secrets
+
+| Name | Description |
+|------|-------------|
+| `NUGET_PACKAGE_FEED_API_KEY` | API key for the Azure Artifacts NuGet feed |
+
+### Variables
+
+| Name | Description |
+|------|-------------|
+| `NUGET_PACKAGE_FEED_URL` | NuGet feed URL |
+| `BENCHMARKDOTNET_RUN_OVERRIDE` | Set to `true` to force benchmarks to run on non-release PRs |
+| `BENCHMARKDOTNET_RUNTIMES` | Runtimes to benchmark (e.g. `net8.0 net10.0`) |
+| `BENCHMARKDOTNET_FILTER` | Benchmark filter pattern (e.g. `*`) |
+| `DEFAULT_BUILD_FRAMEWORK` | Default target framework for builds (e.g. `net10.0`) |
+| `SRC_DEFAULT_GLOB_PATTERN` | Glob pattern for source project files (e.g. `**/PolylineAlgorithm.csproj`) |
diff --git a/docs/workflows.md b/docs/workflows.md
index 4c864783..8782270f 100644
--- a/docs/workflows.md
+++ b/docs/workflows.md
@@ -87,6 +87,7 @@ Version bumping runs independently via `bump-version.yml` (manual trigger).
| `pack` | `versioning`, `build` | Packages binaries |
| `publish-package` | `pack` | Publishes to NuGet.org (Production environment) |
| `create-release` | `versioning`, `publish-package` | Creates a git tag + GitHub release with auto-generated notes |
+| `update-changelog` | `release` | Fetches release notes and prepends a new entry to `CHANGELOG.md` — stable releases only |
| `generate-docs` | `versioning` | Builds DocFX site |
| `publish-docs` | `generate-docs` | Deploys to GitHub Pages |
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
index 82899203..dd05ca88 100644
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
@@ -12,16 +12,23 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample;
///
/// Polyline decoder using NetTopologySuite.
///
-public sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder {
+internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder {
///
- /// Creates a NetTopologySuite point from latitude and longitude.
+ /// Gets the number of encoded values per item: latitude (index 0) and longitude (index 1).
///
- /// Latitude value.
- /// Longitude value.
+ protected override int ValuesPerItem => 2;
+
+ ///
+ /// Creates a NetTopologySuite point from the decoded values.
+ ///
+ ///
+ /// A memory region containing two values: index 0 is latitude, index 1 is longitude.
+ ///
/// Point instance.
- protected override Point CreateCoordinate(double latitude, double longitude) {
+ protected override Point CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
// NetTopologySuite Point: x = longitude, y = latitude
- return new Point(longitude, latitude);
+ return new Point(span[1], span[0]);
}
///
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
index 649547bd..5a7b5529 100644
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
@@ -7,11 +7,17 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample;
using global::NetTopologySuite.Geometries;
using PolylineAlgorithm.Abstraction;
+using System;
///
/// Polyline encoder using NetTopologySuite's Point type.
///
-public sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder {
+internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder {
+ ///
+ /// Gets the number of values per item: latitude (index 0) and longitude (index 1).
+ ///
+ protected override int ValuesPerItem => 2;
+
///
/// Creates encoded polyline string from memory.
///
@@ -26,30 +32,15 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) {
}
///
- /// Gets latitude from point.
+ /// Fills destination with latitude (index 0) and longitude (index 1) from the point.
///
- /// Point instance.
- /// Latitude value.
- protected override double GetLatitude(Point current) {
- if (current is null) {
- throw new ArgumentNullException(nameof(current));
- }
-
- // NetTopologySuite Point: Y = latitude
- return current.Y;
- }
-
- ///
- /// Gets longitude from point.
- ///
- /// Point instance.
- /// Longitude value.
- protected override double GetLongitude(Point current) {
- if (current is null) {
- throw new ArgumentNullException(nameof(current));
- }
-
- // NetTopologySuite Point: X = longitude
- return current.X;
+ /// Point instance.
+ /// Span of length 2 to fill.
+ protected override void GetValues(Point item, Span destination) {
+ ArgumentNullException.ThrowIfNull(item);
+
+ // NetTopologySuite Point: Y = latitude, X = longitude
+ destination[0] = item.Y;
+ destination[1] = item.X;
}
}
\ No newline at end of file
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj b/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj
index 57d5f7c1..fef82026 100644
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/PolylineAlgorithm.NetTopologySuite.Sample.csproj
@@ -1,7 +1,8 @@
- netstandard2.1
+ Exe
+ net10.0
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs
new file mode 100644
index 00000000..ca9a8a6f
--- /dev/null
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/Program.cs
@@ -0,0 +1,46 @@
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+using NetTopologySuite.Geometries;
+using PolylineAlgorithm.NetTopologySuite.Sample;
+
+public class Program {
+ public static void Main(string[] args) {
+ // Sample route: Seattle → Bellevue → Redmond
+ var points = new Point[]
+ {
+ new(x: -122.3503, y: 47.6219), // Seattle (x = longitude, y = latitude)
+ new(x: -122.2015, y: 47.6101), // Bellevue
+ new(x: -122.1215, y: 47.6740), // Redmond
+ };
+
+ var encoder = new NetTopologyPolylineEncoder();
+ var decoder = new NetTopologyPolylineDecoder();
+
+ // Encode
+ string encoded = encoder.Encode(points);
+
+ Console.WriteLine("=== NetTopologySuite Polyline Sample ===");
+ Console.WriteLine();
+ Console.WriteLine("Input points (longitude, latitude):");
+
+ foreach (Point p in points) {
+ Console.WriteLine($" ({p.X}, {p.Y})");
+ }
+
+ Console.WriteLine();
+ Console.WriteLine($"Encoded polyline: {encoded}");
+ Console.WriteLine();
+
+ // Decode
+ IEnumerable decoded = decoder.Decode(encoded);
+
+ Console.WriteLine("Decoded points (longitude, latitude):");
+
+ foreach (Point p in decoded) {
+ Console.WriteLine($" ({p.X}, {p.Y})");
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj b/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj
new file mode 100644
index 00000000..3e1bcb63
--- /dev/null
+++ b/samples/PolylineAlgorithm.SensorData.Sample/PolylineAlgorithm.SensorData.Sample.csproj
@@ -0,0 +1,16 @@
+
+
+
+ Exe
+ net10.0
+
+
+
+ false
+
+
+
+
+
+
+
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/Program.cs b/samples/PolylineAlgorithm.SensorData.Sample/Program.cs
new file mode 100644
index 00000000..e14977f9
--- /dev/null
+++ b/samples/PolylineAlgorithm.SensorData.Sample/Program.cs
@@ -0,0 +1,49 @@
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+using PolylineAlgorithm.SensorData.Sample;
+
+public static class Program {
+ public static void Main(string[] args) {
+ // Sample temperature readings from a sensor over six seconds
+ var readings = new SensorReading[]
+ {
+ new(DateTimeOffset.UtcNow, 23.5),
+ new(DateTimeOffset.UtcNow.AddSeconds(1), 23.7),
+ new(DateTimeOffset.UtcNow.AddSeconds(2), 24.1),
+ new(DateTimeOffset.UtcNow.AddSeconds(3), 25.0),
+ new(DateTimeOffset.UtcNow.AddSeconds(4), 24.8),
+ new(DateTimeOffset.UtcNow.AddSeconds(5), 24.8),
+ new(DateTimeOffset.UtcNow.AddSeconds(6), 22.3),
+ };
+
+ var encoder = new SensorDataEncoder();
+ var decoder = new SensorDataDecoder();
+
+ // Encode
+ string encoded = encoder.Encode(readings);
+
+ Console.WriteLine("=== Sensor Data Polyline Sample ===");
+ Console.WriteLine();
+ Console.WriteLine("Input readings:");
+
+ foreach (SensorReading r in readings) {
+ Console.WriteLine($" [{r.Timestamp:HH:mm:ss}] {r.Temperature:F1} °C");
+ }
+
+ Console.WriteLine();
+ Console.WriteLine($"Encoded polyline: {encoded}");
+ Console.WriteLine();
+
+ // Decode (timestamps and temperatures are both recovered)
+ IEnumerable decoded = decoder.Decode(encoded);
+
+ Console.WriteLine("Decoded readings:");
+
+ foreach (SensorReading r in decoded) {
+ Console.WriteLine($" [{r.Timestamp:HH:mm:ss}] {r.Temperature:F1} °C");
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs b/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs
new file mode 100644
index 00000000..e3468ef6
--- /dev/null
+++ b/samples/PolylineAlgorithm.SensorData.Sample/Properties/CodeCoverage.cs
@@ -0,0 +1,8 @@
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: ExcludeFromCodeCoverage]
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs
new file mode 100644
index 00000000..9c63d647
--- /dev/null
+++ b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataDecoder.cs
@@ -0,0 +1,107 @@
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace PolylineAlgorithm.SensorData.Sample;
+
+using PolylineAlgorithm.Abstraction;
+using System.Collections.Generic;
+using System.Threading;
+
+///
+/// Decodes a compact polyline string produced by back into a sequence
+/// of values.
+///
+///
+///
+/// This class demonstrates implementing for a custom
+/// scalar type, following the same structural pattern as .
+///
+///
+/// Each encoded pair consists of a delta-compressed Unix timestamp (seconds since Unix epoch, precision 0)
+/// followed by a delta-compressed temperature value (at ).
+/// Both are recovered and used to reconstruct the original .
+///
+///
+[System.Diagnostics.CodeAnalysis.SuppressMessage("Sonar", "S4456:Parameter validation in yielding methods should be wrapped", Justification = "Inlined by design to demonstrate a simple iterator without a wrapper method.")]
+internal sealed class SensorDataDecoder : IPolylineDecoder {
+ ///
+ /// Initializes a new instance of the class with default encoding options.
+ ///
+ public SensorDataDecoder()
+ : this(new PolylineEncodingOptions()) { }
+
+ ///
+ /// Initializes a new instance of the class with the specified encoding options.
+ ///
+ ///
+ /// The to use for decoding operations.
+ /// The value must match the precision used during encoding.
+ ///
+ ///
+ /// Thrown when is .
+ ///
+ public SensorDataDecoder(PolylineEncodingOptions options) {
+ ArgumentNullException.ThrowIfNull(options);
+
+ Options = options;
+ }
+
+ ///
+ /// Gets the encoding options used by this decoder.
+ ///
+ public PolylineEncodingOptions Options { get; }
+
+ ///
+ /// Decodes a polyline string back into a sequence of values.
+ ///
+ ///
+ /// The polyline-encoded string produced by .
+ ///
+ ///
+ /// A that can be used to cancel the decoding operation.
+ ///
+ ///
+ /// An of whose
+ /// and values
+ /// are recovered from the encoded string.
+ ///
+ ///
+ /// Thrown when is .
+ ///
+ ///
+ /// Thrown when is empty.
+ ///
+ ///
+ /// Thrown when requests cancellation.
+ ///
+ public IEnumerable Decode(string polyline, CancellationToken cancellationToken = default) {
+ ArgumentNullException.ThrowIfNull(polyline);
+
+ if (polyline.Length < 1) {
+ throw new ArgumentException("Encoded polyline must not be empty.", nameof(polyline));
+ }
+
+ ReadOnlyMemory memory = polyline.AsMemory();
+ int position = 0;
+ // Mirror the encoder's base epoch so the first delta decodes back to the correct Unix seconds.
+ int accumulatedTimestamp = SensorDataEncoder.TimestampBaseEpochSeconds;
+ int accumulatedTemperature = 0;
+
+ while (position < memory.Length) {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ // Read Unix timestamp delta (precision 0) then temperature delta.
+ if (!PolylineEncoding.TryReadValue(ref accumulatedTimestamp, memory, ref position)
+ || !PolylineEncoding.TryReadValue(ref accumulatedTemperature, memory, ref position)) {
+ yield break;
+ }
+
+ long unixSeconds = (long)PolylineEncoding.Denormalize(accumulatedTimestamp, precision: 0);
+ double temperature = PolylineEncoding.Denormalize(accumulatedTemperature, Options.Precision);
+
+ yield return new SensorReading(DateTimeOffset.FromUnixTimeSeconds(unixSeconds), temperature);
+ }
+ }
+}
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs
new file mode 100644
index 00000000..be199e4d
--- /dev/null
+++ b/samples/PolylineAlgorithm.SensorData.Sample/SensorDataEncoder.cs
@@ -0,0 +1,135 @@
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace PolylineAlgorithm.SensorData.Sample;
+
+using PolylineAlgorithm.Abstraction;
+using System.Buffers;
+using System.Threading;
+
+///
+/// Encodes a sequence of values into a compact polyline string
+/// using the polyline delta-encoding algorithm applied to both the
+/// and fields.
+///
+///
+///
+/// This class demonstrates implementing for a custom
+/// scalar type, following the same structural pattern as .
+///
+///
+/// Because sensor readings carry two numeric dimensions (timestamp and temperature), the base class designed
+/// for geographic coordinate pairs is not used. Instead, static
+/// helpers are called directly to perform normalisation, delta computation, and character-level encoding.
+///
+///
+/// Each reading is encoded as a pair of delta-compressed values:
+/// the Unix timestamp in seconds (precision 0) followed by the temperature (at ).
+///
+///
+internal sealed class SensorDataEncoder : IPolylineEncoder {
+ // 2020-01-01 00:00:00 UTC in Unix seconds. Used as the delta-encoding base for timestamps
+ // so that the first absolute delta stays within the int32 safe range of the polyline algorithm.
+ internal const int TimestampBaseEpochSeconds = 1_577_836_800;
+
+ ///
+ /// Initializes a new instance of the class with default encoding options.
+ ///
+ public SensorDataEncoder()
+ : this(new PolylineEncodingOptions()) { }
+
+ ///
+ /// Initializes a new instance of the class with the specified encoding options.
+ ///
+ ///
+ /// The to use for encoding operations.
+ ///
+ ///
+ /// Thrown when is .
+ ///
+ public SensorDataEncoder(PolylineEncodingOptions options) {
+ ArgumentNullException.ThrowIfNull(options);
+
+ Options = options;
+ }
+
+ ///
+ /// Gets the encoding options used by this encoder.
+ ///
+ public PolylineEncodingOptions Options { get; }
+
+ ///
+ /// Encodes a sequence of values into a polyline string.
+ ///
+ ///
+ /// The sensor readings to encode. Each reading contributes a delta-compressed Unix timestamp
+ /// (seconds since Unix epoch, precision 0) and a delta-compressed temperature value.
+ /// Must contain at least one element.
+ ///
+ ///
+ /// A that can be used to cancel the encoding operation.
+ ///
+ ///
+ /// A polyline-encoded string representing the delta-compressed timestamp and temperature series.
+ ///
+ ///
+ /// Thrown when is empty.
+ ///
+ ///
+ /// Thrown when requests cancellation.
+ ///
+ public string Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default) {
+ if (coordinates.Length < 1) {
+ throw new ArgumentException("Sequence must contain at least one element.", nameof(coordinates));
+ }
+
+ // Maximum number of ASCII characters required to encode a single 32-bit delta value
+ // using the polyline algorithm (ceil(32 bits / 5 bits per chunk) + sign bit = 7).
+ const int MaxEncodedCharsPerValue = 7;
+
+ // Each reading encodes two values: Unix timestamp (precision 0) + temperature.
+ // The polyline algorithm uses signed int32 internally, limiting safe absolute values to ~1.07B.
+ // Current Unix time in seconds (~1.74B) exceeds this. We therefore delta-encode relative to
+ // 2020-01-01 00:00:00 UTC (= 1 577 836 800 s), keeping the initial delta well within range.
+ int previousTimestampNormalized = TimestampBaseEpochSeconds;
+ int previousTemperatureNormalized = 0;
+ int position = 0;
+ int length = coordinates.Length * 2 * MaxEncodedCharsPerValue;
+
+ char[]? temp = length <= Options.StackAllocLimit
+ ? null
+ : ArrayPool.Shared.Rent(length);
+
+ Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length);
+
+ try {
+ for (int i = 0; i < coordinates.Length; i++) {
+ cancellationToken.ThrowIfCancellationRequested();
+
+ // Encode Unix timestamp in whole seconds (precision 0).
+ int normalizedTimestamp = PolylineEncoding.Normalize((double)coordinates[i].Timestamp.ToUnixTimeSeconds(), precision: 0);
+ int timestampDelta = normalizedTimestamp - previousTimestampNormalized;
+
+ // Encode temperature at the configured precision.
+ int normalizedTemperature = PolylineEncoding.Normalize(coordinates[i].Temperature, Options.Precision);
+ int temperatureDelta = normalizedTemperature - previousTemperatureNormalized;
+
+ if (!PolylineEncoding.TryWriteValue(timestampDelta, buffer, ref position)
+ || !PolylineEncoding.TryWriteValue(temperatureDelta, buffer, ref position)) {
+ throw new InvalidOperationException("Encoding buffer is too small to hold the encoded value.");
+ }
+
+ previousTimestampNormalized = normalizedTimestamp;
+ previousTemperatureNormalized = normalizedTemperature;
+ }
+
+ return buffer[..position].ToString();
+ } finally {
+ if (temp is not null) {
+ ArrayPool.Shared.Return(temp);
+ }
+ }
+ }
+}
diff --git a/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs b/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs
new file mode 100644
index 00000000..6903c92f
--- /dev/null
+++ b/samples/PolylineAlgorithm.SensorData.Sample/SensorReading.cs
@@ -0,0 +1,16 @@
+//
+// Copyright © Pete Sramek. All rights reserved.
+// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+//
+
+namespace PolylineAlgorithm.SensorData.Sample;
+
+using System.Runtime.InteropServices;
+
+///
+/// Represents a single temperature reading captured by a sensor.
+///
+/// The UTC time at which the reading was captured.
+/// The temperature value of the reading, in degrees Celsius.
+[StructLayout(LayoutKind.Auto)]
+internal readonly record struct SensorReading(DateTimeOffset Timestamp, double Temperature);
diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
index 1059abb9..ea087776 100644
--- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
+++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
@@ -6,19 +6,27 @@
using Microsoft.Extensions.Logging;
using PolylineAlgorithm.Internal;
using PolylineAlgorithm.Internal.Diagnostics;
+using System.Buffers;
using System.Runtime.CompilerServices;
namespace PolylineAlgorithm.Abstraction;
///
-/// Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
+/// Provides a base implementation for decoding encoded polyline strings into sequences of items.
///
///
-/// Derive from this class to implement a decoder for a specific polyline type. Override
-/// and to provide type-specific behavior.
+/// Derive from this class to implement a decoder for a specific polyline type. Override
+/// , , and to provide
+/// type-specific behavior.
+///
+/// The polyline format encodes each item as a fixed-length run of delta-compressed
+/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS decoder
+/// sets to 2 (latitude, longitude), while a 3D GPS decoder sets it to 3
+/// (latitude, longitude, altitude).
+///
///
/// The type that represents the encoded polyline input.
-/// The type that represents a decoded geographic coordinate.
+/// The type that represents a decoded item.
public abstract class AbstractPolylineDecoder : IPolylineDecoder {
private readonly ILogger> _logger;
@@ -53,6 +61,16 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
///
public PolylineEncodingOptions Options { get; }
+ ///
+ /// Gets the number of encoded values that make up a single decoded item.
+ ///
+ ///
+ /// Override this property to specify the arity of each item. For example, return 2 for
+ /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count
+ /// that matches the encoding scheme used to produce the polyline.
+ ///
+ protected abstract int ValuesPerItem { get; }
+
///
/// Decodes an encoded into a sequence of instances,
/// with support for cancellation.
@@ -64,7 +82,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
/// A that can be used to cancel the decoding operation.
///
///
- /// An of representing the decoded latitude and longitude pairs.
+ /// An of representing the decoded items.
///
///
/// Thrown when is .
@@ -90,30 +108,45 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can
ValidateSequence(sequence, _logger);
ValidateFormat(sequence, _logger);
+ int valuesPerItem = ValuesPerItem;
int position = 0;
- int encodedLatitude = 0;
- int encodedLongitude = 0;
+
+ int[]? runningRent = ArrayPool.Shared.Rent(valuesPerItem);
+ // Zero-initialize so delta decoding starts from 0 for all dimensions.
+ for (int j = 0; j < valuesPerItem; j++) {
+ runningRent[j] = 0;
+ }
try {
while (position < sequence.Length) {
cancellationToken.ThrowIfCancellationRequested();
- if (!PolylineEncoding.TryReadValue(ref encodedLatitude, sequence, ref position)
- || !PolylineEncoding.TryReadValue(ref encodedLongitude, sequence, ref position)) {
+ bool allRead = true;
+ for (int j = 0; j < valuesPerItem; j++) {
+ if (!PolylineEncoding.TryReadValue(ref runningRent[j], sequence, ref position)) {
+ allRead = false;
+ break;
+ }
+ }
+
+ if (!allRead) {
_logger?.LogOperationFailedDebug(OperationName);
_logger?.LogInvalidPolylineWarning(position);
ExceptionGuard.ThrowInvalidPolylineFormat(position);
}
- double decodedLatitude = PolylineEncoding.Denormalize(encodedLatitude, Options.Precision);
- double decodedLongitude = PolylineEncoding.Denormalize(encodedLongitude, Options.Precision);
+ double[] decoded = new double[valuesPerItem];
+ for (int j = 0; j < valuesPerItem; j++) {
+ decoded[j] = PolylineEncoding.Denormalize(runningRent[j], Options.Precision);
+ }
- _logger?.LogDecodedCoordinateDebug(decodedLatitude, decodedLongitude, position);
+ _logger?.LogDecodedValuesDebug(valuesPerItem, position);
- yield return CreateCoordinate(decodedLatitude, decodedLongitude);
+ yield return CreateItem(decoded.AsMemory());
}
} finally {
+ ArrayPool.Shared.Return(runningRent!);
_logger?.LogOperationFinishedDebug(OperationName);
}
}
@@ -188,17 +221,19 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo
protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline);
///
- /// Creates a instance from the specified latitude and longitude values.
+ /// Creates a instance from the specified decoded values.
///
- ///
- /// The latitude component of the coordinate, in degrees.
- ///
- ///
- /// The longitude component of the coordinate, in degrees.
+ ///
+ /// A of containing exactly
+ /// decoded values for this item, in the same order they were encoded.
///
///
- /// A instance representing the specified geographic coordinate.
+ /// A instance representing the decoded item.
///
+ ///
+ /// Implementations should read all required values from and construct the
+ /// immediately. The memory is valid only for the duration of this call.
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected abstract TCoordinate CreateCoordinate(double latitude, double longitude);
+ protected abstract TCoordinate CreateItem(ReadOnlyMemory values);
}
diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
index 1bcdb0ee..dff4eac3 100644
--- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
+++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
@@ -16,13 +16,19 @@ namespace PolylineAlgorithm.Abstraction;
using System.Threading;
///
-/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
+/// Provides a base implementation for encoding sequences of items into encoded polyline strings.
///
///
-/// Derive from this class to implement an encoder for a specific coordinate and polyline type. Override
-/// , , and to provide type-specific behavior.
+/// Derive from this class to implement an encoder for a specific item and polyline type. Override
+/// , , and to provide type-specific behavior.
+///
+/// The polyline format encodes each item as a fixed-length run of delta-compressed
+/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS encoder
+/// sets to 2 (latitude, longitude), while a 3D GPS encoder sets it to 3
+/// (latitude, longitude, altitude).
+///
///
-/// The type that represents a geographic coordinate to encode.
+/// The type that represents an item to encode.
/// The type that represents the encoded polyline output.
public abstract class AbstractPolylineEncoder : IPolylineEncoder {
private readonly ILogger> _logger;
@@ -56,6 +62,16 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) {
///
public PolylineEncodingOptions Options { get; }
+ ///
+ /// Gets the number of values that make up a single encoded item.
+ ///
+ ///
+ /// Override this property to specify the arity of each item. For example, return 2 for
+ /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count
+ /// that matches your encoding scheme.
+ ///
+ protected abstract int ValuesPerItem { get; }
+
///
/// Encodes a collection of instances into an encoded string.
///
@@ -88,11 +104,12 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
ValidateEmptyCoordinates(ref coordinates, _logger);
- CoordinateDelta delta = new();
+ int valuesPerItem = ValuesPerItem;
+ CoordinateDelta delta = new(valuesPerItem);
int position = 0;
int consumed = 0;
- int length = GetMaxBufferLength(coordinates.Length);
+ int length = GetMaxBufferLength(coordinates.Length, valuesPerItem);
char[]? temp = length <= Options.StackAllocLimit
? null
@@ -100,29 +117,37 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length);
+ int[]? normalizedRent = ArrayPool.Shared.Rent(valuesPerItem);
+ Span normalized = normalizedRent.AsSpan(0, valuesPerItem);
+
+ double[]? valuesRent = ArrayPool.Shared.Rent(valuesPerItem);
+ Span values = valuesRent.AsSpan(0, valuesPerItem);
+
string encodedResult;
try {
for (var i = 0; i < coordinates.Length; i++) {
cancellationToken.ThrowIfCancellationRequested();
- delta
- .Next(
- PolylineEncoding.Normalize(GetLatitude(coordinates[i]), Options.Precision),
- PolylineEncoding.Normalize(GetLongitude(coordinates[i]), Options.Precision)
- );
+ GetValues(coordinates[i], values);
+
+ for (int j = 0; j < valuesPerItem; j++) {
+ normalized[j] = PolylineEncoding.Normalize(values[j], Options.Precision);
+ }
- if (!PolylineEncoding.TryWriteValue(delta.Latitude, buffer, ref position)
- || !PolylineEncoding.TryWriteValue(delta.Longitude, buffer, ref position)
- ) {
- // This shouldn't happen, but if it does, log the error and throw an exception.
- _logger
- .LogOperationFailedDebug(OperationName);
- _logger
- .LogCannotWriteValueToBufferWarning(position, consumed);
+ delta.Next(normalized);
- ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer();
+ ReadOnlySpan deltas = delta.Deltas;
+ for (int j = 0; j < deltas.Length; j++) {
+ if (!PolylineEncoding.TryWriteValue(deltas[j], buffer, ref position)) {
+ // This shouldn't happen, but if it does, log the error and throw an exception.
+ _logger
+ .LogOperationFailedDebug(OperationName);
+ _logger
+ .LogCannotWriteValueToBufferWarning(position, consumed);
+ ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer();
+ }
}
consumed++;
@@ -130,6 +155,8 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
encodedResult = buffer[..position].ToString();
} finally {
+ ArrayPool.Shared.Return(valuesRent!);
+ ArrayPool.Shared.Return(normalizedRent!);
if (temp is not null) {
ArrayPool.Shared.Return(temp);
}
@@ -141,10 +168,10 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
return CreatePolyline(encodedResult.AsMemory());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- static int GetMaxBufferLength(int count) {
+ static int GetMaxBufferLength(int count, int perItem) {
Debug.Assert(count > 0, "Count must be greater than zero.");
- int requestedBufferLength = count * 2 * Defaults.Polyline.Block.Length.Max;
+ int requestedBufferLength = count * perItem * Defaults.Polyline.Block.Length.Max;
Debug.Assert(requestedBufferLength > 0, "Requested buffer length must be greater than zero.");
@@ -175,23 +202,18 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates,
protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline);
///
- /// Extracts the longitude value from the specified coordinate.
- ///
- /// The coordinate from which to extract the longitude.
- ///
- /// The longitude value as a .
- ///
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected abstract double GetLongitude(TCoordinate current);
-
- ///
- /// Extracts the latitude value from the specified coordinate.
+ /// Fills with the values to encode for the specified item.
///
- /// The coordinate from which to extract the latitude.
- ///
- /// The latitude value as a .
- ///
+ /// The item from which to extract values.
+ ///
+ /// A of length to fill with the item's values,
+ /// in the order they should be encoded.
+ ///
+ ///
+ /// Implementations should write exactly values into .
+ /// For example, a 2D GPS encoder writes destination[0] = latitude; destination[1] = longitude;.
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected abstract double GetLatitude(TCoordinate current);
+ protected abstract void GetValues(TCoordinate item, Span destination);
}
diff --git a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
index ae217c57..70826216 100644
--- a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
+++ b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
@@ -5,68 +5,82 @@
namespace PolylineAlgorithm.Internal;
+using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
+using System.Text;
///
-/// Represents the difference (delta) in latitude and longitude between consecutive geographic coordinates.
+/// Represents the running delta state for an arbitrary number of encoded values between consecutive items.
///
///
-/// This struct computes and stores the change in coordinate values as integer deltas between successive coordinates.
+/// This struct computes and stores the change in each value dimension as integer deltas between successive items.
+/// The number of dimensions is specified at construction time, enabling support for any number of encoded fields
+/// (e.g. latitude/longitude, latitude/longitude/altitude, or arbitrary sensor fields).
///
[DebuggerDisplay("{ToString(),nq}")]
[StructLayout(LayoutKind.Auto)]
internal struct CoordinateDelta {
- private (int Latitude, int Longitude) _current;
+ private readonly int[] _current;
+ private readonly int[] _deltas;
///
- /// Initializes a new instance of the struct with the default latitude and longitude deltas.
+ /// Initializes a new instance of the struct for the specified number of value dimensions.
///
- public CoordinateDelta() {
- _current = (default, default);
- }
+ /// The number of value dimensions to track. Must be greater than zero.
+ public CoordinateDelta(int count) {
+ Debug.Assert(count > 0, "Count must be greater than zero.");
- ///
- /// Gets the current delta in latitude between the most recent and previous coordinate.
- ///
- public int Latitude { get; private set; }
+ _current = new int[count];
+ _deltas = new int[count];
+ }
///
- /// Gets the current delta in longitude between the most recent and previous coordinate.
+ /// Gets the current deltas computed by the most recent call to .
///
- public int Longitude { get; private set; }
+ public ReadOnlySpan Deltas => _deltas;
///
- /// Updates the delta values based on the next latitude and longitude, and sets the current coordinate as next delta baseline.
+ /// Updates the delta values based on the next set of values, and sets them as the baseline for the next call.
///
- /// The next latitude value.
- /// The next longitude value.
- public void Next(int latitude, int longitude) {
- Latitude = Delta(_current.Latitude, latitude);
- Longitude = Delta(_current.Longitude, longitude);
+ ///
+ /// The next normalized integer values. Must have the same length as the count passed to the constructor.
+ ///
+ public void Next(ReadOnlySpan values) {
+ Debug.Assert(values.Length == _current.Length, "Values length must match the delta dimension count.");
- _current.Latitude = latitude;
- _current.Longitude = longitude;
+ for (int i = 0; i < values.Length; i++) {
+ _deltas[i] = values[i] - _current[i];
+ _current[i] = values[i];
+ }
}
///
- /// Calculates the delta between two coordinate values.
- ///
- ///
- /// This method computes the difference between two integer coordinate values, handling cases where the values may be positive or negative.
- ///
- /// The previous coordinate value.
- /// The next coordinate value.
- /// The computed delta between and .
- private static int Delta(int initial, int next) => next - initial;
-
- ///
- /// Returns a string representation of the current coordinate delta.
+ /// Returns a string representation of the current values and deltas.
///
///
- /// A string in the format { Coordinate: { Latitude: [int], Longitude: [int] }, Delta: { Latitude: [int], Longitude: [int] } } representing the current coordinate and deltas to previous coordinate.
+ /// A string in the format { Values: [v0, v1, ...], Deltas: [d0, d1, ...] }.
///
- public override readonly string ToString() =>
- $"{{ Coordinate: {{ Latitude: {_current.Latitude}, Longitude: {_current.Longitude} }}, " +
- $"Delta: {{ Latitude: {Latitude}, Longitude: {Longitude} }} }}";
+ public override readonly string ToString() {
+ var sb = new StringBuilder("{ Values: [");
+ for (int i = 0; i < _current.Length; i++) {
+ if (i > 0) {
+ sb.Append(", ");
+ }
+
+ sb.Append(_current[i]);
+ }
+
+ sb.Append("], Deltas: [");
+ for (int i = 0; i < _deltas.Length; i++) {
+ if (i > 0) {
+ sb.Append(", ");
+ }
+
+ sb.Append(_deltas[i]);
+ }
+
+ sb.Append("] }");
+ return sb.ToString();
+ }
}
\ No newline at end of file
diff --git a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
index cc58c702..9a422a73 100644
--- a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
+++ b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
@@ -46,12 +46,11 @@ internal static partial class LogDebugExtensions {
internal static partial void LogOperationFinishedDebug(this ILogger logger, string operationName);
///
- /// Logs a debug message containing the decoded coordinate values and position.
+ /// Logs a debug message containing the number of decoded values and position.
///
/// The used to write the log entry.
- /// The decoded latitude value.
- /// The decoded longitude value.
- /// The position in the polyline buffer at which the coordinate was decoded.
- [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}.")]
- internal static partial void LogDecodedCoordinateDebug(this ILogger logger, double latitude, double longitude, int position);
+ /// The number of values that were decoded for this item.
+ /// The position in the polyline buffer at which the item was decoded.
+ [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded {count} values at position {position}.")]
+ internal static partial void LogDecodedValuesDebug(this ILogger logger, int count, int position);
}
diff --git a/src/PolylineAlgorithm/PolylineAlgorithm.csproj b/src/PolylineAlgorithm/PolylineAlgorithm.csproj
index 24504239..907a2a15 100644
--- a/src/PolylineAlgorithm/PolylineAlgorithm.csproj
+++ b/src/PolylineAlgorithm/PolylineAlgorithm.csproj
@@ -8,6 +8,13 @@
True
+
+
+ $(WarningsAsErrors);RS0017
+
+
true
diff --git a/src/PolylineAlgorithm/PolylineEncoding.cs b/src/PolylineAlgorithm/PolylineEncoding.cs
index 4b8d5312..3d6de5e7 100644
--- a/src/PolylineAlgorithm/PolylineEncoding.cs
+++ b/src/PolylineAlgorithm/PolylineEncoding.cs
@@ -1,4 +1,4 @@
-//
+//
// Copyright © Pete Sramek. All rights reserved.
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
//
@@ -76,10 +76,11 @@ public static int Normalize(double value, uint precision = 5) {
uint factor = Pow10.GetFactor(precision);
+ const double Epsilon = 1e-9;
+
checked {
- return (int)(Math.Truncate(value * 10 * factor) / 10);
+ return (int)Math.Truncate((value * factor) + (Epsilon * Math.Sign(value)));
}
-
}
///
diff --git a/src/PolylineAlgorithm/PublicAPI.Shipped.txt b/src/PolylineAlgorithm/PublicAPI.Shipped.txt
index 91b0e1a4..7dc5c581 100644
--- a/src/PolylineAlgorithm/PublicAPI.Shipped.txt
+++ b/src/PolylineAlgorithm/PublicAPI.Shipped.txt
@@ -1 +1 @@
-#nullable enable
\ No newline at end of file
+#nullable enable
diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
index 7dc5c581..4033ef24 100644
--- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
+++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
@@ -1 +1,9 @@
#nullable enable
+abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.CreateItem(System.ReadOnlyMemory values) -> TCoordinate
+abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory
+abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValuesPerItem.get -> int
+abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.GetValues(TCoordinate item, System.Span destination) -> void
+abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.ValuesPerItem.get -> int
+virtual PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValidateFormat(System.ReadOnlyMemory sequence, Microsoft.Extensions.Logging.ILogger? logger) -> void
+PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void
+PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void
diff --git a/src/PolylineAlgorithm/README.md b/src/PolylineAlgorithm/README.md
index d1bf97e0..97c4bb98 100644
--- a/src/PolylineAlgorithm/README.md
+++ b/src/PolylineAlgorithm/README.md
@@ -1,6 +1,8 @@
# PolylineAlgorithm for .NET
-A modern, fully compliant Google Encoded Polyline Algorithm library for .NET Standard 2.1+, supporting strong input validation, extensibility for custom coordinate types, and robust performance.
+[](https://www.nuget.org/packages/PolylineAlgorithm)
+
+Google's Encoded Polyline Algorithm compresses sequences of geographic coordinates into a compact ASCII string, widely used in mapping APIs. This library provides a fully compliant .NET implementation with extensible, type-safe encoding and decoding APIs.
## Features
@@ -59,6 +61,7 @@ var encoder = new MyPolylineEncoder();
string encoded = encoder.Encode(coordinates); // extension method for List
Console.WriteLine(encoded);
+// Output: "yseiHoc_MwacOjnwM"
```
### Implement a custom decoder
@@ -84,8 +87,22 @@ IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encode
## Advanced Usage
-- Pass a `PolylineEncodingOptions` (built via `PolylineEncodingOptionsBuilder`) to the encoder/decoder constructor for custom precision, stack-alloc limit, and logging.
-- Use static methods on `PolylineEncoding` for low-level normalization, validation, and bit-level read/write operations.
+Use `PolylineEncodingOptionsBuilder` to customize precision, buffer size, and logging, then pass the built options to the encoder or decoder constructor:
+
+```csharp
+using Microsoft.Extensions.Logging;
+
+PolylineEncodingOptions options = PolylineEncodingOptionsBuilder.Create()
+ .WithPrecision(6) // 6 decimal places instead of the default 5
+ .WithStackAllocLimit(1024) // increase stack-alloc buffer
+ .WithLoggerFactory(loggerFactory) // plug in your ILoggerFactory
+ .Build();
+
+var encoder = new MyPolylineEncoder(options);
+var decoder = new MyPolylineDecoder(options);
+```
+
+Use static methods on `PolylineEncoding` for low-level normalization, validation, and bit-level read/write operations.
> See [API Reference](https://petesramek.github.io/polyline-algorithm-csharp/) for full documentation.
@@ -93,6 +110,8 @@ IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encode
- **What coordinate ranges are valid?**
Latitude: -90..90, Longitude: -180..180 (throws `ArgumentOutOfRangeException` for invalid input)
+- **What happens if I pass malformed input to the decoder?**
+ The decoder throws `InvalidPolylineException` with a descriptive message. Wrap calls in a try/catch in your application.
- **What .NET versions are supported?**
Any environment supporting `netstandard2.1`
- **How do I customize encoder options?**
@@ -100,6 +119,11 @@ IEnumerable<(double Latitude, double Longitude)> decoded = decoder.Decode(encode
- **Where can I get help?**
[GitHub issues](https://github.com/petesramek/polyline-algorithm-csharp/issues)
+## Resources
+
+- [GitHub Repository](https://github.com/petesramek/polyline-algorithm-csharp) — source code, issues, changelog, and samples
+- [API Reference](https://petesramek.github.io/polyline-algorithm-csharp/) — full auto-generated documentation
+
## License
MIT License © Pete Sramek
diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
index c6734c6c..b5a64627 100644
--- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
@@ -16,16 +16,24 @@ namespace PolylineAlgorithm.Tests.Abstraction;
[TestClass]
public sealed class AbstractPolylineDecoderTests {
private sealed class TestStringDecoder : AbstractPolylineDecoder {
+ protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
+ }
}
private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder {
public TestStringDecoderWithOptions(PolylineEncodingOptions options)
: base(options) { }
+ protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
+ }
}
///
diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
index f537dda2..1500b0de 100644
--- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
@@ -21,9 +21,12 @@ public TestStringEncoder()
public TestStringEncoder(PolylineEncodingOptions options)
: base(options) { }
+ protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
- protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
+ protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
+ destination[0] = item.Latitude;
+ destination[1] = item.Longitude;
+ }
}
///
diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
index c44c914d..069c639f 100644
--- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
@@ -17,13 +17,21 @@ namespace PolylineAlgorithm.Tests.Extensions;
[TestClass]
public sealed class PolylineDecoderExtensionsTests {
private sealed class TestStringDecoder : AbstractPolylineDecoder {
+ protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
+ }
}
private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> {
+ protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline;
- protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
+ protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
+ ReadOnlySpan span = values.Span;
+ return (span[0], span[1]);
+ }
}
// ----- Decode(char[]) for IPolylineDecoder -----
diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
index da8a622e..874f168c 100644
--- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
@@ -17,9 +17,12 @@ namespace PolylineAlgorithm.Tests.Extensions;
[TestClass]
public sealed class PolylineEncoderExtensionsTests {
private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
+ protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
- protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
+ protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
+ destination[0] = item.Latitude;
+ destination[1] = item.Longitude;
+ }
}
// ----- Encode(List) -----
diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
index 1e915fe2..03ef5e66 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
@@ -6,7 +6,6 @@
namespace PolylineAlgorithm.Tests.Internal;
using PolylineAlgorithm.Internal;
-using System.Globalization;
///
/// Tests for .
@@ -14,20 +13,22 @@ namespace PolylineAlgorithm.Tests.Internal;
[TestClass]
public sealed class CoordinateDeltaTests {
///
- /// Tests that the default constructor initializes delta values to zero.
+ /// Tests that a newly constructed instance reports all-zero deltas.
///
[TestMethod]
- public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() {
+ public void Constructor_Default_Initializes_Deltas_To_Zero() {
// Act
- CoordinateDelta delta = new();
+ CoordinateDelta delta = new(2);
// Assert
- Assert.AreEqual(0, delta.Latitude);
- Assert.AreEqual(0, delta.Longitude);
+ ReadOnlySpan deltas = delta.Deltas;
+ Assert.AreEqual(2, deltas.Length);
+ Assert.AreEqual(0, deltas[0]);
+ Assert.AreEqual(0, deltas[1]);
}
///
- /// Tests that a single call to Next computes the correct delta from the initial zero state.
+ /// Tests that a single call to Next computes the correct delta from the initial zero state for 2 values.
///
[TestMethod]
[DataRow(10, 20, 10, 20)]
@@ -35,59 +36,94 @@ public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() {
[DataRow(0, 0, 0, 0)]
[DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)]
[DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)]
- public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int longitude, int expectedLatitude, int expectedLongitude) {
+ public void Next_Single_Call_From_Zero_Computes_Expected_Delta_For_Two_Values(int v0, int v1, int expectedD0, int expectedD1) {
// Arrange
- CoordinateDelta delta = new();
+ CoordinateDelta delta = new(2);
// Act
- delta.Next(latitude, longitude);
+ delta.Next([v0, v1]);
// Assert
- Assert.AreEqual(expectedLatitude, delta.Latitude);
- Assert.AreEqual(expectedLongitude, delta.Longitude);
+ ReadOnlySpan deltas = delta.Deltas;
+ Assert.AreEqual(expectedD0, deltas[0]);
+ Assert.AreEqual(expectedD1, deltas[1]);
}
///
- /// Tests that two consecutive calls to Next compute the delta relative to the previous value.
+ /// Tests that two consecutive calls to Next compute the delta relative to the previous value for 2 values.
///
[TestMethod]
[DataRow(10, 20, 15, 30, 5, 10)]
[DataRow(100, 200, 50, 150, -50, -50)]
[DataRow(42, 84, 42, 84, 0, 0)]
[DataRow(-50, 100, 25, -75, 75, -175)]
- public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value(
- int firstLatitude, int firstLongitude,
- int secondLatitude, int secondLongitude,
- int expectedLatitude, int expectedLongitude) {
+ public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value_For_Two_Values(
+ int first0, int first1,
+ int second0, int second1,
+ int expectedD0, int expectedD1) {
// Arrange
- CoordinateDelta delta = new();
- delta.Next(firstLatitude, firstLongitude);
+ CoordinateDelta delta = new(2);
+ delta.Next([first0, first1]);
// Act
- delta.Next(secondLatitude, secondLongitude);
+ delta.Next([second0, second1]);
// Assert
- Assert.AreEqual(expectedLatitude, delta.Latitude);
- Assert.AreEqual(expectedLongitude, delta.Longitude);
+ ReadOnlySpan deltas = delta.Deltas;
+ Assert.AreEqual(expectedD0, deltas[0]);
+ Assert.AreEqual(expectedD1, deltas[1]);
}
///
- /// Tests that ToString on a default instance returns a string containing expected structural keywords and a zero value.
+ /// Tests that Next works correctly for a single value dimension.
+ ///
+ [TestMethod]
+ public void Next_Single_Dimension_Computes_Correct_Delta() {
+ // Arrange
+ CoordinateDelta delta = new(1);
+ delta.Next([100]);
+
+ // Act
+ delta.Next([150]);
+
+ // Assert
+ Assert.AreEqual(50, delta.Deltas[0]);
+ }
+
+ ///
+ /// Tests that Next works correctly for three value dimensions.
+ ///
+ [TestMethod]
+ public void Next_Three_Dimensions_Computes_Correct_Deltas() {
+ // Arrange
+ CoordinateDelta delta = new(3);
+ delta.Next([10, 20, 30]);
+
+ // Act
+ delta.Next([15, 25, 25]);
+
+ // Assert
+ ReadOnlySpan deltas = delta.Deltas;
+ Assert.AreEqual(5, deltas[0]);
+ Assert.AreEqual(5, deltas[1]);
+ Assert.AreEqual(-5, deltas[2]);
+ }
+
+ ///
+ /// Tests that ToString on a default instance returns a non-null string containing structural keywords.
///
[TestMethod]
public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zeros() {
// Arrange
- CoordinateDelta delta = new();
+ CoordinateDelta delta = new(2);
// Act
string result = delta.ToString();
// Assert
Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains("Coordinate", StringComparison.Ordinal));
- Assert.IsTrue(result.Contains("Delta", StringComparison.Ordinal));
- Assert.IsTrue(result.Contains("Latitude", StringComparison.Ordinal));
- Assert.IsTrue(result.Contains("Longitude", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Values", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Deltas", StringComparison.Ordinal));
Assert.Contains('0', result);
}
@@ -97,20 +133,18 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero
[TestMethod]
[DataRow(42, 84)]
[DataRow(-100, -200)]
- [DataRow(int.MaxValue, int.MaxValue)]
- [DataRow(int.MinValue, int.MinValue)]
- public void ToString_After_Next_Contains_Expected_Values(int latitude, int longitude) {
+ public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) {
// Arrange
- CoordinateDelta delta = new();
- delta.Next(latitude, longitude);
+ CoordinateDelta delta = new(2);
+ delta.Next([v0, v1]);
// Act
string result = delta.ToString();
// Assert
Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains(latitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
- Assert.IsTrue(result.Contains(longitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains(v0.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains(v1.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal));
}
///
@@ -119,9 +153,9 @@ public void ToString_After_Next_Contains_Expected_Values(int latitude, int longi
[TestMethod]
public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() {
// Arrange
- CoordinateDelta delta = new();
- delta.Next(10, 20);
- delta.Next(30, 50);
+ CoordinateDelta delta = new(2);
+ delta.Next([10, 20]);
+ delta.Next([30, 50]);
// Act
string result = delta.ToString();
@@ -132,5 +166,5 @@ public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Lat
Assert.IsTrue(result.Contains("50", StringComparison.Ordinal));
Assert.IsTrue(result.Contains("20", StringComparison.Ordinal));
}
-
}
+
diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
index 0dff7193..c9daaa1f 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
@@ -80,20 +80,21 @@ public void LogOperationFinishedDebug_With_Operation_Name_Logs_Finished_Message(
}
///
- /// Tests that LogDecodedCoordinateDebug WithCoordinatesAndPosition LogsDecodedCoordinateMessage.
+ /// Tests that LogDecodedValuesDebug WithCountAndPosition LogsDecodedValuesMessage.
///
[TestMethod]
- public void LogDecodedCoordinateDebug_With_Coordinates_And_Position_Logs_Decoded_Coordinate_Message() {
+ public void LogDecodedValuesDebug_With_Count_And_Position_Logs_Decoded_Values_Message() {
var logger = new TestLogger();
- const double latitude = 38.5;
- const double longitude = -120.2;
+ const int count = 2;
const int position = 42;
- logger.LogDecodedCoordinateDebug(latitude, longitude, position);
+ logger.LogDecodedValuesDebug(count, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}."), logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains(position.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
}
///
@@ -142,37 +143,35 @@ public void LogOperationFinishedDebug_With_Null_Operation_Name_Logs_Message() {
}
///
- /// Tests that LogDecodedCoordinateDebug WithZeroCoordinates LogsMessage.
+ /// Tests that LogDecodedValuesDebug WithZeroCountAndPosition LogsMessage.
///
[TestMethod]
- public void LogDecodedCoordinateDebug_With_Zero_Coordinates_Logs_Message() {
+ public void LogDecodedValuesDebug_With_Zero_Count_Logs_Message() {
var logger = new TestLogger();
- const double latitude = 0.0;
- const double longitude = 0.0;
+ const int count = 0;
const int position = 0;
- logger.LogDecodedCoordinateDebug(latitude, longitude, position);
+ logger.LogDecodedValuesDebug(count, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains("Decoded coordinate", logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal);
}
///
- /// Tests that LogDecodedCoordinateDebug WithNegativeCoordinates LogsMessage.
+ /// Tests that LogDecodedValuesDebug WithLargeCount LogsMessage.
///
[TestMethod]
- public void LogDecodedCoordinateDebug_With_Negative_Coordinates_Logs_Message() {
+ public void LogDecodedValuesDebug_With_Large_Count_Logs_Message() {
var logger = new TestLogger();
- const double latitude = -90.0;
- const double longitude = -180.0;
+ const int count = 5;
const int position = 100;
- logger.LogDecodedCoordinateDebug(latitude, longitude, position);
+ logger.LogDecodedValuesDebug(count, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Latitude: {latitude}, Longitude: {longitude}"), logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
}
///
diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
index d3d83b9e..0ca40426 100644
--- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
+++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
@@ -105,16 +105,15 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat
private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
+ protected override int ValuesPerItem => 2;
+
protected override string CreatePolyline(ReadOnlyMemory polyline) {
return polyline.ToString();
}
- protected override double GetLatitude((double Latitude, double Longitude) current) {
- return current.Latitude;
- }
-
- protected override double GetLongitude((double Latitude, double Longitude) current) {
- return current.Longitude;
+ protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
+ destination[0] = item.Latitude;
+ destination[1] = item.Longitude;
}
}
}
\ No newline at end of file
From 9660b87c4167fa7eab103ca9cd6b613738e4ef44 Mon Sep 17 00:00:00 2001
From: Pete Sramek <2333452+petesramek@users.noreply.github.com>
Date: Mon, 6 Apr 2026 00:06:42 +0200
Subject: [PATCH 04/24] Revert "refactor: replace fixed lat/lon pair contract
with N-value GetValues/CreateItem/ValuesPerItem"
This reverts commit a94f7c7f194754782d429a469a8b75ec3c169d5d.
---
.../PolylineDecoderBenchmark.cs | 18 +--
.../PolylineEncoderBenchmark.cs | 7 +-
.../NetTopologyPolylineDecoder.cs | 17 +--
.../NetTopologyPolylineEncoder.cs | 35 +++---
.../Abstraction/AbstractPolylineDecoder.cs | 77 ++++--------
.../Abstraction/AbstractPolylineEncoder.cs | 98 ++++++---------
.../Internal/CoordinateDelta.cs | 88 ++++++--------
.../Diagnostics/LogDebugExtensions.cs | 11 +-
src/PolylineAlgorithm/PublicAPI.Unshipped.txt | 8 --
.../AbstractPolylineDecoderTests.cs | 12 +-
.../AbstractPolylineEncoderTests.cs | 7 +-
.../PolylineDecoderExtensionsTests.cs | 12 +-
.../PolylineEncoderExtensionsTests.cs | 7 +-
.../Internal/CoordinateDeltaTests.cs | 112 ++++++------------
.../Diagnostics/LogDebugExtensionsTests.cs | 35 +++---
.../RandomValueProvider.cs | 11 +-
16 files changed, 206 insertions(+), 349 deletions(-)
diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
index b6b54081..f28c8141 100644
--- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
+++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineDecoderBenchmark.cs
@@ -93,10 +93,8 @@ public void PolylineDecoder_Decode_Memory() {
}
private sealed class StringPolylineDecoder : AbstractPolylineDecoder {
- protected override int ValuesPerItem => 2;
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
+ return (latitude, longitude);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) {
@@ -105,10 +103,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) {
}
private sealed class CharArrayPolylineDecoder : AbstractPolylineDecoder {
- protected override int ValuesPerItem => 2;
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
+ return (latitude, longitude);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) {
@@ -117,10 +113,8 @@ protected override ReadOnlyMemory GetReadOnlyMemory(in char[] polyline) {
}
private sealed class MemoryCharPolylineDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> {
- protected override int ValuesPerItem => 2;
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) {
+ return (latitude, longitude);
}
protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) {
diff --git a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
index c4b9d5a8..e0b97c5c 100644
--- a/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
+++ b/benchmarks/PolylineAlgorithm.Benchmarks/PolylineEncoderBenchmark.cs
@@ -85,11 +85,8 @@ public void PolylineEncoder_Encode_List() {
}
private sealed class StringPolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
- protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
- destination[0] = item.Latitude;
- destination[1] = item.Longitude;
- }
+ protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
+ protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
}
}
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
index dd05ca88..d7dcb13e 100644
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineDecoder.cs
@@ -14,21 +14,14 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample;
///
internal sealed class NetTopologyPolylineDecoder : AbstractPolylineDecoder {
///
- /// Gets the number of encoded values per item: latitude (index 0) and longitude (index 1).
+ /// Creates a NetTopologySuite point from latitude and longitude.
///
- protected override int ValuesPerItem => 2;
-
- ///
- /// Creates a NetTopologySuite point from the decoded values.
- ///
- ///
- /// A memory region containing two values: index 0 is latitude, index 1 is longitude.
- ///
+ /// Latitude value.
+ /// Longitude value.
/// Point instance.
- protected override Point CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
+ protected override Point CreateCoordinate(double latitude, double longitude) {
// NetTopologySuite Point: x = longitude, y = latitude
- return new Point(span[1], span[0]);
+ return new Point(longitude, latitude);
}
///
diff --git a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
index 5a7b5529..c6719000 100644
--- a/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
+++ b/samples/PolylineAlgorithm.NetTopologySuite.Sample/NetTopologyPolylineEncoder.cs
@@ -7,17 +7,11 @@ namespace PolylineAlgorithm.NetTopologySuite.Sample;
using global::NetTopologySuite.Geometries;
using PolylineAlgorithm.Abstraction;
-using System;
///
/// Polyline encoder using NetTopologySuite's Point type.
///
internal sealed class NetTopologyPolylineEncoder : AbstractPolylineEncoder {
- ///
- /// Gets the number of values per item: latitude (index 0) and longitude (index 1).
- ///
- protected override int ValuesPerItem => 2;
-
///
/// Creates encoded polyline string from memory.
///
@@ -32,15 +26,26 @@ protected override string CreatePolyline(ReadOnlyMemory polyline) {
}
///
- /// Fills destination with latitude (index 0) and longitude (index 1) from the point.
+ /// Gets latitude from point.
///
- /// Point instance.
- /// Span of length 2 to fill.
- protected override void GetValues(Point item, Span destination) {
- ArgumentNullException.ThrowIfNull(item);
-
- // NetTopologySuite Point: Y = latitude, X = longitude
- destination[0] = item.Y;
- destination[1] = item.X;
+ /// Point instance.
+ /// Latitude value.
+ protected override double GetLatitude(Point current) {
+ ArgumentNullException.ThrowIfNull(current);
+
+ // NetTopologySuite Point: Y = latitude
+ return current.Y;
+ }
+
+ ///
+ /// Gets longitude from point.
+ ///
+ /// Point instance.
+ /// Longitude value.
+ protected override double GetLongitude(Point current) {
+ ArgumentNullException.ThrowIfNull(current);
+
+ // NetTopologySuite Point: X = longitude
+ return current.X;
}
}
\ No newline at end of file
diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
index ea087776..1059abb9 100644
--- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
+++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs
@@ -6,27 +6,19 @@
using Microsoft.Extensions.Logging;
using PolylineAlgorithm.Internal;
using PolylineAlgorithm.Internal.Diagnostics;
-using System.Buffers;
using System.Runtime.CompilerServices;
namespace PolylineAlgorithm.Abstraction;
///
-/// Provides a base implementation for decoding encoded polyline strings into sequences of items.
+/// Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
///
///
-/// Derive from this class to implement a decoder for a specific polyline type. Override
-/// , , and to provide
-/// type-specific behavior.
-///
-/// The polyline format encodes each item as a fixed-length run of delta-compressed
-/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS decoder
-/// sets to 2 (latitude, longitude), while a 3D GPS decoder sets it to 3
-/// (latitude, longitude, altitude).
-///
+/// Derive from this class to implement a decoder for a specific polyline type. Override
+/// and to provide type-specific behavior.
///
/// The type that represents the encoded polyline input.
-/// The type that represents a decoded item.
+/// The type that represents a decoded geographic coordinate.
public abstract class AbstractPolylineDecoder : IPolylineDecoder {
private readonly ILogger> _logger;
@@ -61,16 +53,6 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
///
public PolylineEncodingOptions Options { get; }
- ///
- /// Gets the number of encoded values that make up a single decoded item.
- ///
- ///
- /// Override this property to specify the arity of each item. For example, return 2 for
- /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count
- /// that matches the encoding scheme used to produce the polyline.
- ///
- protected abstract int ValuesPerItem { get; }
-
///
/// Decodes an encoded into a sequence of instances,
/// with support for cancellation.
@@ -82,7 +64,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
/// A that can be used to cancel the decoding operation.
///
///
- /// An of representing the decoded items.
+ /// An of representing the decoded latitude and longitude pairs.
///
///
/// Thrown when is .
@@ -108,45 +90,30 @@ public IEnumerable Decode(TPolyline polyline, CancellationToken can
ValidateSequence(sequence, _logger);
ValidateFormat(sequence, _logger);
- int valuesPerItem = ValuesPerItem;
int position = 0;
-
- int[]? runningRent = ArrayPool.Shared.Rent(valuesPerItem);
- // Zero-initialize so delta decoding starts from 0 for all dimensions.
- for (int j = 0; j < valuesPerItem; j++) {
- runningRent[j] = 0;
- }
+ int encodedLatitude = 0;
+ int encodedLongitude = 0;
try {
while (position < sequence.Length) {
cancellationToken.ThrowIfCancellationRequested();
- bool allRead = true;
- for (int j = 0; j < valuesPerItem; j++) {
- if (!PolylineEncoding.TryReadValue(ref runningRent[j], sequence, ref position)) {
- allRead = false;
- break;
- }
- }
-
- if (!allRead) {
+ if (!PolylineEncoding.TryReadValue(ref encodedLatitude, sequence, ref position)
+ || !PolylineEncoding.TryReadValue(ref encodedLongitude, sequence, ref position)) {
_logger?.LogOperationFailedDebug(OperationName);
_logger?.LogInvalidPolylineWarning(position);
ExceptionGuard.ThrowInvalidPolylineFormat(position);
}
- double[] decoded = new double[valuesPerItem];
- for (int j = 0; j < valuesPerItem; j++) {
- decoded[j] = PolylineEncoding.Denormalize(runningRent[j], Options.Precision);
- }
+ double decodedLatitude = PolylineEncoding.Denormalize(encodedLatitude, Options.Precision);
+ double decodedLongitude = PolylineEncoding.Denormalize(encodedLongitude, Options.Precision);
- _logger?.LogDecodedValuesDebug(valuesPerItem, position);
+ _logger?.LogDecodedCoordinateDebug(decodedLatitude, decodedLongitude, position);
- yield return CreateItem(decoded.AsMemory());
+ yield return CreateCoordinate(decodedLatitude, decodedLongitude);
}
} finally {
- ArrayPool.Shared.Return(runningRent!);
_logger?.LogOperationFinishedDebug(OperationName);
}
}
@@ -221,19 +188,17 @@ protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? lo
protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline);
///
- /// Creates a instance from the specified decoded values.
+ /// Creates a instance from the specified latitude and longitude values.
///
- ///
- /// A of containing exactly
- /// decoded values for this item, in the same order they were encoded.
+ ///
+ /// The latitude component of the coordinate, in degrees.
+ ///
+ ///
+ /// The longitude component of the coordinate, in degrees.
///
///
- /// A instance representing the decoded item.
+ /// A instance representing the specified geographic coordinate.
///
- ///
- /// Implementations should read all required values from and construct the
- /// immediately. The memory is valid only for the duration of this call.
- ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected abstract TCoordinate CreateItem(ReadOnlyMemory values);
+ protected abstract TCoordinate CreateCoordinate(double latitude, double longitude);
}
diff --git a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
index dff4eac3..1bcdb0ee 100644
--- a/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
+++ b/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs
@@ -16,19 +16,13 @@ namespace PolylineAlgorithm.Abstraction;
using System.Threading;
///
-/// Provides a base implementation for encoding sequences of items into encoded polyline strings.
+/// Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
///
///
-/// Derive from this class to implement an encoder for a specific item and polyline type. Override
-/// , , and to provide type-specific behavior.
-///
-/// The polyline format encodes each item as a fixed-length run of delta-compressed
-/// values. All items in a single polyline must have the same number of values. For example, a 2D GPS encoder
-/// sets to 2 (latitude, longitude), while a 3D GPS encoder sets it to 3
-/// (latitude, longitude, altitude).
-///
+/// Derive from this class to implement an encoder for a specific coordinate and polyline type. Override
+/// , , and to provide type-specific behavior.
///
-/// The type that represents an item to encode.
+/// The type that represents a geographic coordinate to encode.
/// The type that represents the encoded polyline output.
public abstract class AbstractPolylineEncoder : IPolylineEncoder {
private readonly ILogger> _logger;
@@ -62,16 +56,6 @@ protected AbstractPolylineEncoder(PolylineEncodingOptions options) {
///
public PolylineEncodingOptions Options { get; }
- ///
- /// Gets the number of values that make up a single encoded item.
- ///
- ///
- /// Override this property to specify the arity of each item. For example, return 2 for
- /// latitude/longitude pairs, 3 for latitude/longitude/altitude triples, or any other count
- /// that matches your encoding scheme.
- ///
- protected abstract int ValuesPerItem { get; }
-
///
/// Encodes a collection of instances into an encoded string.
///
@@ -104,12 +88,11 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
ValidateEmptyCoordinates(ref coordinates, _logger);
- int valuesPerItem = ValuesPerItem;
- CoordinateDelta delta = new(valuesPerItem);
+ CoordinateDelta delta = new();
int position = 0;
int consumed = 0;
- int length = GetMaxBufferLength(coordinates.Length, valuesPerItem);
+ int length = GetMaxBufferLength(coordinates.Length);
char[]? temp = length <= Options.StackAllocLimit
? null
@@ -117,37 +100,29 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
Span buffer = temp is null ? stackalloc char[length] : temp.AsSpan(0, length);
- int[]? normalizedRent = ArrayPool.Shared.Rent(valuesPerItem);
- Span normalized = normalizedRent.AsSpan(0, valuesPerItem);
-
- double[]? valuesRent = ArrayPool.Shared.Rent(valuesPerItem);
- Span values = valuesRent.AsSpan(0, valuesPerItem);
-
string encodedResult;
try {
for (var i = 0; i < coordinates.Length; i++) {
cancellationToken.ThrowIfCancellationRequested();
- GetValues(coordinates[i], values);
-
- for (int j = 0; j < valuesPerItem; j++) {
- normalized[j] = PolylineEncoding.Normalize(values[j], Options.Precision);
- }
+ delta
+ .Next(
+ PolylineEncoding.Normalize(GetLatitude(coordinates[i]), Options.Precision),
+ PolylineEncoding.Normalize(GetLongitude(coordinates[i]), Options.Precision)
+ );
- delta.Next(normalized);
+ if (!PolylineEncoding.TryWriteValue(delta.Latitude, buffer, ref position)
+ || !PolylineEncoding.TryWriteValue(delta.Longitude, buffer, ref position)
+ ) {
+ // This shouldn't happen, but if it does, log the error and throw an exception.
+ _logger
+ .LogOperationFailedDebug(OperationName);
+ _logger
+ .LogCannotWriteValueToBufferWarning(position, consumed);
- ReadOnlySpan deltas = delta.Deltas;
- for (int j = 0; j < deltas.Length; j++) {
- if (!PolylineEncoding.TryWriteValue(deltas[j], buffer, ref position)) {
- // This shouldn't happen, but if it does, log the error and throw an exception.
- _logger
- .LogOperationFailedDebug(OperationName);
- _logger
- .LogCannotWriteValueToBufferWarning(position, consumed);
+ ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer();
- ExceptionGuard.ThrowCouldNotWriteEncodedValueToBuffer();
- }
}
consumed++;
@@ -155,8 +130,6 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
encodedResult = buffer[..position].ToString();
} finally {
- ArrayPool.Shared.Return(valuesRent!);
- ArrayPool.Shared.Return(normalizedRent!);
if (temp is not null) {
ArrayPool.Shared.Return(temp);
}
@@ -168,10 +141,10 @@ public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken
return CreatePolyline(encodedResult.AsMemory());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- static int GetMaxBufferLength(int count, int perItem) {
+ static int GetMaxBufferLength(int count) {
Debug.Assert(count > 0, "Count must be greater than zero.");
- int requestedBufferLength = count * perItem * Defaults.Polyline.Block.Length.Max;
+ int requestedBufferLength = count * 2 * Defaults.Polyline.Block.Length.Max;
Debug.Assert(requestedBufferLength > 0, "Requested buffer length must be greater than zero.");
@@ -202,18 +175,23 @@ static void ValidateEmptyCoordinates(ref ReadOnlySpan coordinates,
protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline);
///
- /// Fills with the values to encode for the specified item.
+ /// Extracts the longitude value from the specified coordinate.
///
- /// The item from which to extract values.
- ///
- /// A of length to fill with the item's values,
- /// in the order they should be encoded.
- ///
- ///
- /// Implementations should write exactly values into .
- /// For example, a 2D GPS encoder writes destination[0] = latitude; destination[1] = longitude;.
- ///
+ /// The coordinate from which to extract the longitude.
+ ///
+ /// The longitude value as a .
+ ///
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ protected abstract double GetLongitude(TCoordinate current);
+
+ ///
+ /// Extracts the latitude value from the specified coordinate.
+ ///
+ /// The coordinate from which to extract the latitude.
+ ///
+ /// The latitude value as a .
+ ///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- protected abstract void GetValues(TCoordinate item, Span destination);
+ protected abstract double GetLatitude(TCoordinate current);
}
diff --git a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
index 70826216..ae217c57 100644
--- a/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
+++ b/src/PolylineAlgorithm/Internal/CoordinateDelta.cs
@@ -5,82 +5,68 @@
namespace PolylineAlgorithm.Internal;
-using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
-using System.Text;
///
-/// Represents the running delta state for an arbitrary number of encoded values between consecutive items.
+/// Represents the difference (delta) in latitude and longitude between consecutive geographic coordinates.
///
///
-/// This struct computes and stores the change in each value dimension as integer deltas between successive items.
-/// The number of dimensions is specified at construction time, enabling support for any number of encoded fields
-/// (e.g. latitude/longitude, latitude/longitude/altitude, or arbitrary sensor fields).
+/// This struct computes and stores the change in coordinate values as integer deltas between successive coordinates.
///
[DebuggerDisplay("{ToString(),nq}")]
[StructLayout(LayoutKind.Auto)]
internal struct CoordinateDelta {
- private readonly int[] _current;
- private readonly int[] _deltas;
+ private (int Latitude, int Longitude) _current;
///
- /// Initializes a new instance of the struct for the specified number of value dimensions.
+ /// Initializes a new instance of the struct with the default latitude and longitude deltas.
///
- /// The number of value dimensions to track. Must be greater than zero.
- public CoordinateDelta(int count) {
- Debug.Assert(count > 0, "Count must be greater than zero.");
-
- _current = new int[count];
- _deltas = new int[count];
+ public CoordinateDelta() {
+ _current = (default, default);
}
///
- /// Gets the current deltas computed by the most recent call to .
+ /// Gets the current delta in latitude between the most recent and previous coordinate.
+ ///
+ public int Latitude { get; private set; }
+
+ ///
+ /// Gets the current delta in longitude between the most recent and previous coordinate.
///
- public ReadOnlySpan Deltas => _deltas;
+ public int Longitude { get; private set; }
///
- /// Updates the delta values based on the next set of values, and sets them as the baseline for the next call.
+ /// Updates the delta values based on the next latitude and longitude, and sets the current coordinate as next delta baseline.
///
- ///
- /// The next normalized integer values. Must have the same length as the count passed to the constructor.
- ///
- public void Next(ReadOnlySpan values) {
- Debug.Assert(values.Length == _current.Length, "Values length must match the delta dimension count.");
+ /// The next latitude value.
+ /// The next longitude value.
+ public void Next(int latitude, int longitude) {
+ Latitude = Delta(_current.Latitude, latitude);
+ Longitude = Delta(_current.Longitude, longitude);
- for (int i = 0; i < values.Length; i++) {
- _deltas[i] = values[i] - _current[i];
- _current[i] = values[i];
- }
+ _current.Latitude = latitude;
+ _current.Longitude = longitude;
}
///
- /// Returns a string representation of the current values and deltas.
+ /// Calculates the delta between two coordinate values.
+ ///
+ ///
+ /// This method computes the difference between two integer coordinate values, handling cases where the values may be positive or negative.
+ ///
+ /// The previous coordinate value.
+ /// The next coordinate value.
+ /// The computed delta between and .
+ private static int Delta(int initial, int next) => next - initial;
+
+ ///
+ /// Returns a string representation of the current coordinate delta.
///
///
- /// A string in the format { Values: [v0, v1, ...], Deltas: [d0, d1, ...] }.
+ /// A string in the format { Coordinate: { Latitude: [int], Longitude: [int] }, Delta: { Latitude: [int], Longitude: [int] } } representing the current coordinate and deltas to previous coordinate.
///
- public override readonly string ToString() {
- var sb = new StringBuilder("{ Values: [");
- for (int i = 0; i < _current.Length; i++) {
- if (i > 0) {
- sb.Append(", ");
- }
-
- sb.Append(_current[i]);
- }
-
- sb.Append("], Deltas: [");
- for (int i = 0; i < _deltas.Length; i++) {
- if (i > 0) {
- sb.Append(", ");
- }
-
- sb.Append(_deltas[i]);
- }
-
- sb.Append("] }");
- return sb.ToString();
- }
+ public override readonly string ToString() =>
+ $"{{ Coordinate: {{ Latitude: {_current.Latitude}, Longitude: {_current.Longitude} }}, " +
+ $"Delta: {{ Latitude: {Latitude}, Longitude: {Longitude} }} }}";
}
\ No newline at end of file
diff --git a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
index 9a422a73..cc58c702 100644
--- a/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
+++ b/src/PolylineAlgorithm/Internal/Diagnostics/LogDebugExtensions.cs
@@ -46,11 +46,12 @@ internal static partial class LogDebugExtensions {
internal static partial void LogOperationFinishedDebug(this ILogger logger, string operationName);
///
- /// Logs a debug message containing the number of decoded values and position.
+ /// Logs a debug message containing the decoded coordinate values and position.
///
/// The used to write the log entry.
- /// The number of values that were decoded for this item.
- /// The position in the polyline buffer at which the item was decoded.
- [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded {count} values at position {position}.")]
- internal static partial void LogDecodedValuesDebug(this ILogger logger, int count, int position);
+ /// The decoded latitude value.
+ /// The decoded longitude value.
+ /// The position in the polyline buffer at which the coordinate was decoded.
+ [LoggerMessage(EVENT_ID_BASE + 4, LOG_LEVEL, "Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}.")]
+ internal static partial void LogDecodedCoordinateDebug(this ILogger logger, double latitude, double longitude, int position);
}
diff --git a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
index 4033ef24..7dc5c581 100644
--- a/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
+++ b/src/PolylineAlgorithm/PublicAPI.Unshipped.txt
@@ -1,9 +1 @@
#nullable enable
-abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.CreateItem(System.ReadOnlyMemory values) -> TCoordinate
-abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.GetReadOnlyMemory(in TPolyline polyline) -> System.ReadOnlyMemory
-abstract PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValuesPerItem.get -> int
-abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.GetValues(TCoordinate item, System.Span destination) -> void
-abstract PolylineAlgorithm.Abstraction.AbstractPolylineEncoder.ValuesPerItem.get -> int
-virtual PolylineAlgorithm.Abstraction.AbstractPolylineDecoder.ValidateFormat(System.ReadOnlyMemory sequence, Microsoft.Extensions.Logging.ILogger? logger) -> void
-PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException() -> void
-PolylineAlgorithm.InvalidPolylineException.InvalidPolylineException(string! message, System.Exception! innerException) -> void
diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
index b5a64627..c6734c6c 100644
--- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineDecoderTests.cs
@@ -16,24 +16,16 @@ namespace PolylineAlgorithm.Tests.Abstraction;
[TestClass]
public sealed class AbstractPolylineDecoderTests {
private sealed class TestStringDecoder : AbstractPolylineDecoder {
- protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
- }
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
}
private sealed class TestStringDecoderWithOptions : AbstractPolylineDecoder {
public TestStringDecoderWithOptions(PolylineEncodingOptions options)
: base(options) { }
- protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
- }
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
}
///
diff --git a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
index 1500b0de..f537dda2 100644
--- a/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Abstraction/AbstractPolylineEncoderTests.cs
@@ -21,12 +21,9 @@ public TestStringEncoder()
public TestStringEncoder(PolylineEncodingOptions options)
: base(options) { }
- protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
- destination[0] = item.Latitude;
- destination[1] = item.Longitude;
- }
+ protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
+ protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
}
///
diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
index 069c639f..c44c914d 100644
--- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineDecoderExtensionsTests.cs
@@ -17,21 +17,13 @@ namespace PolylineAlgorithm.Tests.Extensions;
[TestClass]
public sealed class PolylineDecoderExtensionsTests {
private sealed class TestStringDecoder : AbstractPolylineDecoder {
- protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in string polyline) => polyline.AsMemory();
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
- }
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
}
private sealed class TestMemoryDecoder : AbstractPolylineDecoder, (double Latitude, double Longitude)> {
- protected override int ValuesPerItem => 2;
protected override ReadOnlyMemory GetReadOnlyMemory(in ReadOnlyMemory polyline) => polyline;
- protected override (double Latitude, double Longitude) CreateItem(ReadOnlyMemory values) {
- ReadOnlySpan span = values.Span;
- return (span[0], span[1]);
- }
+ protected override (double Latitude, double Longitude) CreateCoordinate(double latitude, double longitude) => (latitude, longitude);
}
// ----- Decode(char[]) for IPolylineDecoder -----
diff --git a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
index 874f168c..da8a622e 100644
--- a/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Extensions/PolylineEncoderExtensionsTests.cs
@@ -17,12 +17,9 @@ namespace PolylineAlgorithm.Tests.Extensions;
[TestClass]
public sealed class PolylineEncoderExtensionsTests {
private sealed class TestStringEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
- protected override int ValuesPerItem => 2;
protected override string CreatePolyline(ReadOnlyMemory polyline) => polyline.ToString();
- protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
- destination[0] = item.Latitude;
- destination[1] = item.Longitude;
- }
+ protected override double GetLatitude((double Latitude, double Longitude) current) => current.Latitude;
+ protected override double GetLongitude((double Latitude, double Longitude) current) => current.Longitude;
}
// ----- Encode(List) -----
diff --git a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
index 03ef5e66..1e915fe2 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/CoordinateDeltaTests.cs
@@ -6,6 +6,7 @@
namespace PolylineAlgorithm.Tests.Internal;
using PolylineAlgorithm.Internal;
+using System.Globalization;
///
/// Tests for .
@@ -13,22 +14,20 @@ namespace PolylineAlgorithm.Tests.Internal;
[TestClass]
public sealed class CoordinateDeltaTests {
///
- /// Tests that a newly constructed instance reports all-zero deltas.
+ /// Tests that the default constructor initializes delta values to zero.
///
[TestMethod]
- public void Constructor_Default_Initializes_Deltas_To_Zero() {
+ public void Constructor_Default_Initializes_Latitude_And_Longitude_To_Zero() {
// Act
- CoordinateDelta delta = new(2);
+ CoordinateDelta delta = new();
// Assert
- ReadOnlySpan deltas = delta.Deltas;
- Assert.AreEqual(2, deltas.Length);
- Assert.AreEqual(0, deltas[0]);
- Assert.AreEqual(0, deltas[1]);
+ Assert.AreEqual(0, delta.Latitude);
+ Assert.AreEqual(0, delta.Longitude);
}
///
- /// Tests that a single call to Next computes the correct delta from the initial zero state for 2 values.
+ /// Tests that a single call to Next computes the correct delta from the initial zero state.
///
[TestMethod]
[DataRow(10, 20, 10, 20)]
@@ -36,94 +35,59 @@ public void Constructor_Default_Initializes_Deltas_To_Zero() {
[DataRow(0, 0, 0, 0)]
[DataRow(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)]
[DataRow(int.MinValue, int.MinValue, int.MinValue, int.MinValue)]
- public void Next_Single_Call_From_Zero_Computes_Expected_Delta_For_Two_Values(int v0, int v1, int expectedD0, int expectedD1) {
+ public void Next_Single_Call_From_Zero_Computes_Expected_Delta(int latitude, int longitude, int expectedLatitude, int expectedLongitude) {
// Arrange
- CoordinateDelta delta = new(2);
+ CoordinateDelta delta = new();
// Act
- delta.Next([v0, v1]);
+ delta.Next(latitude, longitude);
// Assert
- ReadOnlySpan deltas = delta.Deltas;
- Assert.AreEqual(expectedD0, deltas[0]);
- Assert.AreEqual(expectedD1, deltas[1]);
+ Assert.AreEqual(expectedLatitude, delta.Latitude);
+ Assert.AreEqual(expectedLongitude, delta.Longitude);
}
///
- /// Tests that two consecutive calls to Next compute the delta relative to the previous value for 2 values.
+ /// Tests that two consecutive calls to Next compute the delta relative to the previous value.
///
[TestMethod]
[DataRow(10, 20, 15, 30, 5, 10)]
[DataRow(100, 200, 50, 150, -50, -50)]
[DataRow(42, 84, 42, 84, 0, 0)]
[DataRow(-50, 100, 25, -75, 75, -175)]
- public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value_For_Two_Values(
- int first0, int first1,
- int second0, int second1,
- int expectedD0, int expectedD1) {
+ public void Next_Sequential_Calls_Compute_Delta_From_Previous_Value(
+ int firstLatitude, int firstLongitude,
+ int secondLatitude, int secondLongitude,
+ int expectedLatitude, int expectedLongitude) {
// Arrange
- CoordinateDelta delta = new(2);
- delta.Next([first0, first1]);
+ CoordinateDelta delta = new();
+ delta.Next(firstLatitude, firstLongitude);
// Act
- delta.Next([second0, second1]);
+ delta.Next(secondLatitude, secondLongitude);
// Assert
- ReadOnlySpan deltas = delta.Deltas;
- Assert.AreEqual(expectedD0, deltas[0]);
- Assert.AreEqual(expectedD1, deltas[1]);
+ Assert.AreEqual(expectedLatitude, delta.Latitude);
+ Assert.AreEqual(expectedLongitude, delta.Longitude);
}
///
- /// Tests that Next works correctly for a single value dimension.
- ///
- [TestMethod]
- public void Next_Single_Dimension_Computes_Correct_Delta() {
- // Arrange
- CoordinateDelta delta = new(1);
- delta.Next([100]);
-
- // Act
- delta.Next([150]);
-
- // Assert
- Assert.AreEqual(50, delta.Deltas[0]);
- }
-
- ///
- /// Tests that Next works correctly for three value dimensions.
- ///
- [TestMethod]
- public void Next_Three_Dimensions_Computes_Correct_Deltas() {
- // Arrange
- CoordinateDelta delta = new(3);
- delta.Next([10, 20, 30]);
-
- // Act
- delta.Next([15, 25, 25]);
-
- // Assert
- ReadOnlySpan deltas = delta.Deltas;
- Assert.AreEqual(5, deltas[0]);
- Assert.AreEqual(5, deltas[1]);
- Assert.AreEqual(-5, deltas[2]);
- }
-
- ///
- /// Tests that ToString on a default instance returns a non-null string containing structural keywords.
+ /// Tests that ToString on a default instance returns a string containing expected structural keywords and a zero value.
///
[TestMethod]
public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zeros() {
// Arrange
- CoordinateDelta delta = new(2);
+ CoordinateDelta delta = new();
// Act
string result = delta.ToString();
// Assert
Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains("Values", StringComparison.Ordinal));
- Assert.IsTrue(result.Contains("Deltas", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Coordinate", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Delta", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Latitude", StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains("Longitude", StringComparison.Ordinal));
Assert.Contains('0', result);
}
@@ -133,18 +97,20 @@ public void ToString_With_Default_Constructor_Returns_Formatted_String_With_Zero
[TestMethod]
[DataRow(42, 84)]
[DataRow(-100, -200)]
- public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) {
+ [DataRow(int.MaxValue, int.MaxValue)]
+ [DataRow(int.MinValue, int.MinValue)]
+ public void ToString_After_Next_Contains_Expected_Values(int latitude, int longitude) {
// Arrange
- CoordinateDelta delta = new(2);
- delta.Next([v0, v1]);
+ CoordinateDelta delta = new();
+ delta.Next(latitude, longitude);
// Act
string result = delta.ToString();
// Assert
Assert.IsNotNull(result);
- Assert.IsTrue(result.Contains(v0.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal));
- Assert.IsTrue(result.Contains(v1.ToString(System.Globalization.CultureInfo.InvariantCulture), StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains(latitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
+ Assert.IsTrue(result.Contains(longitude.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal));
}
///
@@ -153,9 +119,9 @@ public void ToString_After_Next_Contains_Expected_Values(int v0, int v1) {
[TestMethod]
public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Latest_Values() {
// Arrange
- CoordinateDelta delta = new(2);
- delta.Next([10, 20]);
- delta.Next([30, 50]);
+ CoordinateDelta delta = new();
+ delta.Next(10, 20);
+ delta.Next(30, 50);
// Act
string result = delta.ToString();
@@ -166,5 +132,5 @@ public void ToString_After_Multiple_Next_Calls_Returns_Formatted_String_With_Lat
Assert.IsTrue(result.Contains("50", StringComparison.Ordinal));
Assert.IsTrue(result.Contains("20", StringComparison.Ordinal));
}
-}
+}
diff --git a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
index c9daaa1f..0dff7193 100644
--- a/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
+++ b/tests/PolylineAlgorithm.Tests/Internal/Diagnostics/LogDebugExtensionsTests.cs
@@ -80,21 +80,20 @@ public void LogOperationFinishedDebug_With_Operation_Name_Logs_Finished_Message(
}
///
- /// Tests that LogDecodedValuesDebug WithCountAndPosition LogsDecodedValuesMessage.
+ /// Tests that LogDecodedCoordinateDebug WithCoordinatesAndPosition LogsDecodedCoordinateMessage.
///
[TestMethod]
- public void LogDecodedValuesDebug_With_Count_And_Position_Logs_Decoded_Values_Message() {
+ public void LogDecodedCoordinateDebug_With_Coordinates_And_Position_Logs_Decoded_Coordinate_Message() {
var logger = new TestLogger();
- const int count = 2;
+ const double latitude = 38.5;
+ const double longitude = -120.2;
const int position = 42;
- logger.LogDecodedValuesDebug(count, position);
+ logger.LogDecodedCoordinateDebug(latitude, longitude, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal);
- Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
- Assert.Contains(position.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Decoded coordinate: (Latitude: {latitude}, Longitude: {longitude}) at position {position}."), logger.Logs[0].Message, StringComparison.Ordinal);
}
///
@@ -143,35 +142,37 @@ public void LogOperationFinishedDebug_With_Null_Operation_Name_Logs_Message() {
}
///
- /// Tests that LogDecodedValuesDebug WithZeroCountAndPosition LogsMessage.
+ /// Tests that LogDecodedCoordinateDebug WithZeroCoordinates LogsMessage.
///
[TestMethod]
- public void LogDecodedValuesDebug_With_Zero_Count_Logs_Message() {
+ public void LogDecodedCoordinateDebug_With_Zero_Coordinates_Logs_Message() {
var logger = new TestLogger();
- const int count = 0;
+ const double latitude = 0.0;
+ const double longitude = 0.0;
const int position = 0;
- logger.LogDecodedValuesDebug(count, position);
+ logger.LogDecodedCoordinateDebug(latitude, longitude, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains("Decoded", logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains("Decoded coordinate", logger.Logs[0].Message, StringComparison.Ordinal);
}
///
- /// Tests that LogDecodedValuesDebug WithLargeCount LogsMessage.
+ /// Tests that LogDecodedCoordinateDebug WithNegativeCoordinates LogsMessage.
///
[TestMethod]
- public void LogDecodedValuesDebug_With_Large_Count_Logs_Message() {
+ public void LogDecodedCoordinateDebug_With_Negative_Coordinates_Logs_Message() {
var logger = new TestLogger();
- const int count = 5;
+ const double latitude = -90.0;
+ const double longitude = -180.0;
const int position = 100;
- logger.LogDecodedValuesDebug(count, position);
+ logger.LogDecodedCoordinateDebug(latitude, longitude, position);
Assert.HasCount(1, logger.Logs);
Assert.AreEqual(LogLevel.Debug, logger.Logs[0].Level);
- Assert.Contains(count.ToString(CultureInfo.InvariantCulture), logger.Logs[0].Message, StringComparison.Ordinal);
+ Assert.Contains(string.Create(CultureInfo.InvariantCulture, $"Latitude: {latitude}, Longitude: {longitude}"), logger.Logs[0].Message, StringComparison.Ordinal);
}
///
diff --git a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
index 0ca40426..d3d83b9e 100644
--- a/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
+++ b/utilities/PolylineAlgorithm.Utility/RandomValueProvider.cs
@@ -105,15 +105,16 @@ private readonly struct PolylineCoordinateCollectionPair(IEnumerable<(double Lat
private sealed class PolylineEncoder : AbstractPolylineEncoder<(double Latitude, double Longitude), string> {
- protected override int ValuesPerItem => 2;
-
protected override string CreatePolyline(ReadOnlyMemory polyline) {
return polyline.ToString();
}
- protected override void GetValues((double Latitude, double Longitude) item, Span destination) {
- destination[0] = item.Latitude;
- destination[1] = item.Longitude;
+ protected override double GetLatitude((double Latitude, double Longitude) current) {
+ return current.Latitude;
+ }
+
+ protected override double GetLongitude((double Latitude, double Longitude) current) {
+ return current.Longitude;
}
}
}
\ No newline at end of file
From 345637de98c3d689a2fa1aa822704a7f5ac46dcd Mon Sep 17 00:00:00 2001
From: Pete Sramek <2333452+petesramek@users.noreply.github.com>
Date: Mon, 6 Apr 2026 00:09:01 +0200
Subject: [PATCH 05/24] updated slnx
---
PolylineAlgorithm.slnx | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/PolylineAlgorithm.slnx b/PolylineAlgorithm.slnx
index 3c54b2a7..9f6748bf 100644
--- a/PolylineAlgorithm.slnx
+++ b/PolylineAlgorithm.slnx
@@ -7,7 +7,9 @@
-
+
+
+
From a86ac30be05525b21db4e945f0293f2545dbe50b Mon Sep 17 00:00:00 2001
From: Pete Sramek <2333452+petesramek@users.noreply.github.com>
Date: Sun, 5 Apr 2026 22:11:58 +0000
Subject: [PATCH 06/24] Updated docs for version 0.0
---
...m.Abstraction.AbstractPolylineDecoder-2.yml | 16 ++++++++--------
...m.Abstraction.AbstractPolylineEncoder-2.yml | 16 ++++++++--------
...lgorithm.Abstraction.IPolylineDecoder-2.yml | 4 ++--
...lgorithm.Abstraction.IPolylineEncoder-2.yml | 4 ++--
...hm.Extensions.PolylineDecoderExtensions.yml | 8 ++++----
...hm.Extensions.PolylineEncoderExtensions.yml | 6 +++---
...ylineAlgorithm.InvalidPolylineException.yml | 6 +++---
.../0.0/PolylineAlgorithm.PolylineEncoding.yml | 18 +++++++++---------
...lylineAlgorithm.PolylineEncodingOptions.yml | 8 ++++----
...lgorithm.PolylineEncodingOptionsBuilder.yml | 12 ++++++------
10 files changed, 49 insertions(+), 49 deletions(-)
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
index b5693066..56ef6af4 100644
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
+++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
@@ -3,7 +3,7 @@ title: Class AbstractPolylineDecoder
body:
- api1: Class AbstractPolylineDecoder
id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2
commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2
@@ -56,7 +56,7 @@ body:
- h2: Constructors
- api3: AbstractPolylineDecoder()
id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor
@@ -64,7 +64,7 @@ body:
- code: protected AbstractPolylineDecoder()
- api3: AbstractPolylineDecoder(PolylineEncodingOptions)
id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
@@ -86,7 +86,7 @@ body:
- h2: Properties
- api3: Options
id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Options
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options
commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options
@@ -100,7 +100,7 @@ body:
- h2: Methods
- api3: CreateCoordinate(double, double)
id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateCoordinate_System_Double_System_Double_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double)
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double)
@@ -125,7 +125,7 @@ body:
description: A TCoordinate instance representing the specified geographic coordinate.
- api3: Decode(TPolyline, CancellationToken)
id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
@@ -175,7 +175,7 @@ body:
description: Thrown when cancellationToken is canceled during decoding.
- api3: GetReadOnlyMemory(in TPolyline)
id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@)
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@)
@@ -199,7 +199,7 @@ body:
description: A of representing the encoded polyline characters.
- api3: ValidateFormat(ReadOnlyMemory, ILogger?)
id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger)
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger)
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
index 64e97b11..985138f8 100644
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
+++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
@@ -3,7 +3,7 @@ title: Class AbstractPolylineEncoder
body:
- api1: Class AbstractPolylineEncoder
id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2
commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2
@@ -62,7 +62,7 @@ body:
- h2: Constructors
- api3: AbstractPolylineEncoder()
id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor
@@ -70,7 +70,7 @@ body:
- code: protected AbstractPolylineEncoder()
- api3: AbstractPolylineEncoder(PolylineEncodingOptions)
id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
@@ -92,7 +92,7 @@ body:
- h2: Properties
- api3: Options
id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Options
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options
commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options
@@ -106,7 +106,7 @@ body:
- h2: Methods
- api3: CreatePolyline(ReadOnlyMemory)
id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char})
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char})
@@ -130,7 +130,7 @@ body:
description: An instance of TPolyline representing the encoded polyline.
- api3: Encode(ReadOnlySpan, CancellationToken)
id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
@@ -176,7 +176,7 @@ body:
description: Thrown when the internal encoding buffer cannot accommodate the encoded value.
- api3: GetLatitude(TCoordinate)
id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLatitude__0_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0)
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0)
@@ -196,7 +196,7 @@ body:
description: The latitude value as a .
- api3: GetLongitude(TCoordinate)
id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLongitude__0_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184
metadata:
uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0)
commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0)
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
index 733987cb..c3a0cc71 100644
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
+++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
@@ -3,7 +3,7 @@ title: Interface IPolylineDecoder
body:
- api1: Interface IPolylineDecoder
id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22
metadata:
uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2
commentId: T:PolylineAlgorithm.Abstraction.IPolylineDecoder`2
@@ -31,7 +31,7 @@ body:
- h2: Methods
- api3: Decode(TPolyline, CancellationToken)
id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48
metadata:
uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
commentId: M:PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
index 341a9de7..952d1a27 100644
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
+++ b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
@@ -3,7 +3,7 @@ title: Interface IPolylineEncoder
body:
- api1: Interface IPolylineEncoder
id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36
metadata:
uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2
commentId: T:PolylineAlgorithm.Abstraction.IPolylineEncoder`2
@@ -63,7 +63,7 @@ body:
- h2: Methods
- api3: Encode(ReadOnlySpan, CancellationToken)
id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76
metadata:
uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
commentId: M:PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
index 8356b63c..5b6e2da1 100644
--- a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
+++ b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
@@ -3,7 +3,7 @@ title: Class PolylineDecoderExtensions
body:
- api1: Class PolylineDecoderExtensions
id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L16
metadata:
uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions
commentId: T:PolylineAlgorithm.Extensions.PolylineDecoderExtensions
@@ -41,7 +41,7 @@ body:
- h2: Methods
- api3: Decode(IPolylineDecoder, char[])
id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_Char___
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L33
metadata:
uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[])
commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.Char[])
@@ -89,7 +89,7 @@ body:
description: Thrown when decoder or polyline is null.
- api3: Decode(IPolylineDecoder, ReadOnlyMemory)
id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_String___0__System_ReadOnlyMemory_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L61
metadata:
uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char})
commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.String,``0},System.ReadOnlyMemory{System.Char})
@@ -139,7 +139,7 @@ body:
description: Thrown when decoder is null.
- api3: Decode(IPolylineDecoder, TValue>, string)
id: PolylineAlgorithm_Extensions_PolylineDecoderExtensions_Decode__1_PolylineAlgorithm_Abstraction_IPolylineDecoder_System_ReadOnlyMemory_System_Char____0__System_String_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineDecoderExtensions.cs#L86
metadata:
uid: PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String)
commentId: M:PolylineAlgorithm.Extensions.PolylineDecoderExtensions.Decode``1(PolylineAlgorithm.Abstraction.IPolylineDecoder{System.ReadOnlyMemory{System.Char},``0},System.String)
diff --git a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
index e5296518..bd62ed13 100644
--- a/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
+++ b/api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
@@ -3,7 +3,7 @@ title: Class PolylineEncoderExtensions
body:
- api1: Class PolylineEncoderExtensions
id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L19
metadata:
uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions
commentId: T:PolylineAlgorithm.Extensions.PolylineEncoderExtensions
@@ -41,7 +41,7 @@ body:
- h2: Methods
- api3: Encode(IPolylineEncoder, List)
id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L37
metadata:
uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0})
commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},System.Collections.Generic.List{``0})
@@ -92,7 +92,7 @@ body:
description: Thrown when encoder or coordinates is null.
- api3: Encode(IPolylineEncoder, TCoordinate[])
id: PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Extensions/PolylineEncoderExtensions.cs#L73
metadata:
uid: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[])
commentId: M:PolylineAlgorithm.Extensions.PolylineEncoderExtensions.Encode``2(PolylineAlgorithm.Abstraction.IPolylineEncoder{``0,``1},``0[])
diff --git a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml
index 2c4e3cc1..8f6b6e76 100644
--- a/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml
+++ b/api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml
@@ -3,7 +3,7 @@ title: Class InvalidPolylineException
body:
- api1: Class InvalidPolylineException
id: PolylineAlgorithm_InvalidPolylineException
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L17
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L17
metadata:
uid: PolylineAlgorithm.InvalidPolylineException
commentId: T:PolylineAlgorithm.InvalidPolylineException
@@ -71,7 +71,7 @@ body:
- h2: Constructors
- api3: InvalidPolylineException()
id: PolylineAlgorithm_InvalidPolylineException__ctor
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L22
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L22
metadata:
uid: PolylineAlgorithm.InvalidPolylineException.#ctor
commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor
@@ -79,7 +79,7 @@ body:
- code: public InvalidPolylineException()
- api3: InvalidPolylineException(string, Exception)
id: PolylineAlgorithm_InvalidPolylineException__ctor_System_String_System_Exception_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/InvalidPolylineException.cs#L43
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/InvalidPolylineException.cs#L43
metadata:
uid: PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception)
commentId: M:PolylineAlgorithm.InvalidPolylineException.#ctor(System.String,System.Exception)
diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml
index 1add8147..56818e4c 100644
--- a/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml
+++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml
@@ -3,7 +3,7 @@ title: Class PolylineEncoding
body:
- api1: Class PolylineEncoding
id: PolylineAlgorithm_PolylineEncoding
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L23
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L23
metadata:
uid: PolylineAlgorithm.PolylineEncoding
commentId: T:PolylineAlgorithm.PolylineEncoding
@@ -50,7 +50,7 @@ body:
- h2: Methods
- api3: Denormalize(int, uint)
id: PolylineAlgorithm_PolylineEncoding_Denormalize_System_Int32_System_UInt32_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L122
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L122
metadata:
uid: PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32)
commentId: M:PolylineAlgorithm.PolylineEncoding.Denormalize(System.Int32,System.UInt32)
@@ -117,7 +117,7 @@ body:
description: Thrown if the arithmetic operation overflows during conversion.
- api3: GetRequiredBufferSize(int)
id: PolylineAlgorithm_PolylineEncoding_GetRequiredBufferSize_System_Int32_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L298
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L298
metadata:
uid: PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32)
commentId: M:PolylineAlgorithm.PolylineEncoding.GetRequiredBufferSize(System.Int32)
@@ -200,7 +200,7 @@ body:
- )
- api3: Normalize(double, uint)
id: PolylineAlgorithm_PolylineEncoding_Normalize_System_Double_System_UInt32_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L61
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L61
metadata:
uid: PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32)
commentId: M:PolylineAlgorithm.PolylineEncoding.Normalize(System.Double,System.UInt32)
@@ -268,7 +268,7 @@ body:
description: Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int.
- api3: TryReadValue(ref int, ReadOnlyMemory, ref int)
id: PolylineAlgorithm_PolylineEncoding_TryReadValue_System_Int32__System_ReadOnlyMemory_System_Char__System_Int32__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L169
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L169
metadata:
uid: PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@)
commentId: M:PolylineAlgorithm.PolylineEncoding.TryReadValue(System.Int32@,System.ReadOnlyMemory{System.Char},System.Int32@)
@@ -328,7 +328,7 @@ body:
- api3: TryWriteValue(int, Span, ref int)
id: PolylineAlgorithm_PolylineEncoding_TryWriteValue_System_Int32_System_Span_System_Char__System_Int32__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L237
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L237
metadata:
uid: PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@)
commentId: M:PolylineAlgorithm.PolylineEncoding.TryWriteValue(System.Int32,System.Span{System.Char},System.Int32@)
@@ -407,7 +407,7 @@ body:
- api3: ValidateBlockLength(ReadOnlySpan)
id: PolylineAlgorithm_PolylineEncoding_ValidateBlockLength_System_ReadOnlySpan_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L438
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L438
metadata:
uid: PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char})
commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateBlockLength(System.ReadOnlySpan{System.Char})
@@ -441,7 +441,7 @@ body:
description: Thrown when a block exceeds 7 characters or the polyline does not end with a valid block terminator.
- api3: ValidateCharRange(ReadOnlySpan)
id: PolylineAlgorithm_PolylineEncoding_ValidateCharRange_System_ReadOnlySpan_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L392
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L392
metadata:
uid: PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char})
commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateCharRange(System.ReadOnlySpan{System.Char})
@@ -479,7 +479,7 @@ body:
description: Thrown when an invalid character is found in the polyline segment.
- api3: ValidateFormat(ReadOnlySpan)
id: PolylineAlgorithm_PolylineEncoding_ValidateFormat_System_ReadOnlySpan_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncoding.cs#L370
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncoding.cs#L370
metadata:
uid: PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char})
commentId: M:PolylineAlgorithm.PolylineEncoding.ValidateFormat(System.ReadOnlySpan{System.Char})
diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml
index 1947eac1..90dc279b 100644
--- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml
+++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml
@@ -3,7 +3,7 @@ title: Class PolylineEncodingOptions
body:
- api1: Class PolylineEncodingOptions
id: PolylineAlgorithm_PolylineEncodingOptions
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L29
metadata:
uid: PolylineAlgorithm.PolylineEncodingOptions
commentId: T:PolylineAlgorithm.PolylineEncodingOptions
@@ -54,7 +54,7 @@ body:
- h2: Properties
- api3: LoggerFactory
id: PolylineAlgorithm_PolylineEncodingOptions_LoggerFactory
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L41
metadata:
uid: PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory
commentId: P:PolylineAlgorithm.PolylineEncodingOptions.LoggerFactory
@@ -72,7 +72,7 @@ body:
To enable logging, provide a custom implementation.
- api3: Precision
id: PolylineAlgorithm_PolylineEncodingOptions_Precision
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L60
metadata:
uid: PolylineAlgorithm.PolylineEncodingOptions.Precision
commentId: P:PolylineAlgorithm.PolylineEncodingOptions.Precision
@@ -104,7 +104,7 @@ body:
- api3: StackAllocLimit
id: PolylineAlgorithm_PolylineEncodingOptions_StackAllocLimit
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptions.cs#L73
metadata:
uid: PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit
commentId: P:PolylineAlgorithm.PolylineEncodingOptions.StackAllocLimit
diff --git a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
index 66ae63b8..2c959bdb 100644
--- a/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
+++ b/api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
@@ -3,7 +3,7 @@ title: Class PolylineEncodingOptionsBuilder
body:
- api1: Class PolylineEncodingOptionsBuilder
id: PolylineAlgorithm_PolylineEncodingOptionsBuilder
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L15
metadata:
uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder
commentId: T:PolylineAlgorithm.PolylineEncodingOptionsBuilder
@@ -39,7 +39,7 @@ body:
- h2: Methods
- api3: Build()
id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Build
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L38
metadata:
uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build
commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Build
@@ -53,7 +53,7 @@ body:
description: A configured instance.
- api3: Create()
id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_Create
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L28
metadata:
uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create
commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.Create
@@ -67,7 +67,7 @@ body:
description: An instance for configuring polyline encoding options.
- api3: WithLoggerFactory(ILoggerFactory)
id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithLoggerFactory_Microsoft_Extensions_Logging_ILoggerFactory_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L97
metadata:
uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory)
commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithLoggerFactory(Microsoft.Extensions.Logging.ILoggerFactory)
@@ -88,7 +88,7 @@ body:
description: The current instance for method chaining.
- api3: WithPrecision(uint)
id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithPrecision_System_UInt32_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L82
metadata:
uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32)
commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithPrecision(System.UInt32)
@@ -109,7 +109,7 @@ body:
description: The current instance for method chaining.
- api3: WithStackAllocLimit(int)
id: PolylineAlgorithm_PolylineEncodingOptionsBuilder_WithStackAllocLimit_System_Int32_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/review-github-templates/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61
+ src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/PolylineEncodingOptionsBuilder.cs#L61
metadata:
uid: PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32)
commentId: M:PolylineAlgorithm.PolylineEncodingOptionsBuilder.WithStackAllocLimit(System.Int32)
From 5641294ab9a856cb383f24d791de0a25abd7890e Mon Sep 17 00:00:00 2001
From: Pete Sramek <2333452+petesramek@users.noreply.github.com>
Date: Mon, 6 Apr 2026 00:12:44 +0200
Subject: [PATCH 07/24] fixed slnx
---
PolylineAlgorithm.slnx | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/PolylineAlgorithm.slnx b/PolylineAlgorithm.slnx
index 9f6748bf..2be9e3c1 100644
--- a/PolylineAlgorithm.slnx
+++ b/PolylineAlgorithm.slnx
@@ -7,10 +7,7 @@
-
-
-
-
+
From b48500306b8253efbb40230f9ab0f8636408923b Mon Sep 17 00:00:00 2001
From: Pete Sramek <2333452+petesramek@users.noreply.github.com>
Date: Mon, 6 Apr 2026 00:13:47 +0200
Subject: [PATCH 08/24] removed 0.0 api ref
---
....Abstraction.AbstractPolylineDecoder-2.yml | 233 --------
....Abstraction.AbstractPolylineEncoder-2.yml | 219 --------
...gorithm.Abstraction.IPolylineDecoder-2.yml | 90 ---
...gorithm.Abstraction.IPolylineEncoder-2.yml | 142 -----
.../0.0/PolylineAlgorithm.Abstraction.yml | 34 --
...m.Extensions.PolylineDecoderExtensions.yml | 195 -------
...m.Extensions.PolylineEncoderExtensions.yml | 139 -----
.../0.0/PolylineAlgorithm.Extensions.yml | 19 -
...lineAlgorithm.InvalidPolylineException.yml | 102 ----
.../PolylineAlgorithm.PolylineEncoding.yml | 529 ------------------
...ylineAlgorithm.PolylineEncodingOptions.yml | 127 -----
...gorithm.PolylineEncodingOptionsBuilder.yml | 141 -----
api-reference/0.0/PolylineAlgorithm.yml | 38 --
api-reference/0.0/toc.yml | 34 --
14 files changed, 2042 deletions(-)
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Abstraction.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineDecoderExtensions.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.PolylineEncoderExtensions.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.Extensions.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.InvalidPolylineException.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncoding.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptions.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.PolylineEncodingOptionsBuilder.yml
delete mode 100644 api-reference/0.0/PolylineAlgorithm.yml
delete mode 100644 api-reference/0.0/toc.yml
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
deleted file mode 100644
index 56ef6af4..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.yml
+++ /dev/null
@@ -1,233 +0,0 @@
-### YamlMime:ApiPage
-title: Class AbstractPolylineDecoder
-body:
-- api1: Class AbstractPolylineDecoder
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L22
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2
- commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm.Abstraction
- url: PolylineAlgorithm.Abstraction.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
-- code: 'public abstract class AbstractPolylineDecoder : IPolylineDecoder'
-- h4: Type Parameters
-- parameters:
- - name: TPolyline
- description: The type that represents the encoded polyline input.
- - name: TCoordinate
- description: The type that represents a decoded geographic coordinate.
-- h4: Inheritance
-- inheritance:
- - text: object
- url: https://learn.microsoft.com/dotnet/api/system.object
- - text: AbstractPolylineDecoder
- url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html
-- h4: Implements
-- list:
- - text: IPolylineDecoder
- url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
-- h4: Inherited Members
-- list:
- - text: object.Equals(object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
- - text: object.Equals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
- - text: object.GetHashCode()
- url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
- - text: object.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.object.gettype
- - text: object.MemberwiseClone()
- url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
- - text: object.ReferenceEquals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
- - text: object.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.object.tostring
-- h2: Remarks
-- markdown: >-
- Derive from this class to implement a decoder for a specific polyline type. Override
-
- and to provide type-specific behavior.
-- h2: Constructors
-- api3: AbstractPolylineDecoder()
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L28
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor
-- markdown: Initializes a new instance of the class with default encoding options.
-- code: protected AbstractPolylineDecoder()
-- api3: AbstractPolylineDecoder(PolylineEncodingOptions)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L40
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
-- markdown: Initializes a new instance of the class with the specified encoding options.
-- code: protected AbstractPolylineDecoder(PolylineEncodingOptions options)
-- h4: Parameters
-- parameters:
- - name: options
- type:
- - text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
- description: The to use for encoding operations.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when options is null.
-- h2: Properties
-- api3: Options
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Options
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L54
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options
- commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Options
-- markdown: Gets the encoding options used by this polyline decoder.
-- code: public PolylineEncodingOptions Options { get; }
-- h4: Property Value
-- parameters:
- - type:
- - text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
-- h2: Methods
-- api3: CreateCoordinate(double, double)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_CreateCoordinate_System_Double_System_Double_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L202
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.CreateCoordinate(System.Double,System.Double)
-- markdown: Creates a TCoordinate instance from the specified latitude and longitude values.
-- code: protected abstract TCoordinate CreateCoordinate(double latitude, double longitude)
-- h4: Parameters
-- parameters:
- - name: latitude
- type:
- - text: double
- url: https://learn.microsoft.com/dotnet/api/system.double
- description: The latitude component of the coordinate, in degrees.
- - name: longitude
- type:
- - text: double
- url: https://learn.microsoft.com/dotnet/api/system.double
- description: The longitude component of the coordinate, in degrees.
-- h4: Returns
-- parameters:
- - type:
- - TCoordinate
- description: A TCoordinate instance representing the specified geographic coordinate.
-- api3: Decode(TPolyline, CancellationToken)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L81
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
-- markdown: >-
- Decodes an encoded TPolyline into a sequence of TCoordinate instances,
-
- with support for cancellation.
-- code: public IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - TPolyline
- description: The TPolyline instance containing the encoded polyline string to decode.
- - name: cancellationToken
- type:
- - text: CancellationToken
- url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
- description: A that can be used to cancel the decoding operation.
- optional: true
-- h4: Returns
-- parameters:
- - type:
- - text: IEnumerable
- url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
- - <
- - TCoordinate
- - '>'
- description: An of TCoordinate representing the decoded latitude and longitude pairs.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when polyline is null.
- - type:
- - text: ArgumentException
- url: https://learn.microsoft.com/dotnet/api/system.argumentexception
- description: Thrown when polyline is empty.
- - type:
- - text: InvalidPolylineException
- url: PolylineAlgorithm.InvalidPolylineException.html
- description: Thrown when the polyline format is invalid or malformed at a specific position.
- - type:
- - text: OperationCanceledException
- url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception
- description: Thrown when cancellationToken is canceled during decoding.
-- api3: GetReadOnlyMemory(in TPolyline)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_GetReadOnlyMemory__0__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L187
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.GetReadOnlyMemory(`0@)
-- markdown: Extracts the underlying read-only memory region of characters from the specified polyline instance.
-- code: protected abstract ReadOnlyMemory GetReadOnlyMemory(in TPolyline polyline)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - TPolyline
- description: The TPolyline instance from which to extract the character sequence.
-- h4: Returns
-- parameters:
- - type:
- - text: ReadOnlyMemory
- url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: A of representing the encoded polyline characters.
-- api3: ValidateFormat(ReadOnlyMemory, ILogger?)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineDecoder_2_ValidateFormat_System_ReadOnlyMemory_System_Char__Microsoft_Extensions_Logging_ILogger_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs#L167
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineDecoder`2.ValidateFormat(System.ReadOnlyMemory{System.Char},Microsoft.Extensions.Logging.ILogger)
-- markdown: Validates the format of the polyline character sequence, ensuring all characters are within the allowed range.
-- code: protected virtual void ValidateFormat(ReadOnlyMemory sequence, ILogger? logger)
-- h4: Parameters
-- parameters:
- - name: sequence
- type:
- - text: ReadOnlyMemory
- url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: The read-only memory region of characters representing the polyline to validate.
- - name: logger
- type:
- - text: ILogger
- url: https://learn.microsoft.com/dotnet/api/microsoft.extensions.logging.ilogger
- - '?'
- description: An optional used to log a warning when format validation fails.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentException
- url: https://learn.microsoft.com/dotnet/api/system.argumentexception
- description: Thrown when the polyline contains characters outside the valid encoding range or has an invalid block structure.
-languageId: csharp
-metadata:
- description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
deleted file mode 100644
index 985138f8..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.yml
+++ /dev/null
@@ -1,219 +0,0 @@
-### YamlMime:ApiPage
-title: Class AbstractPolylineEncoder
-body:
-- api1: Class AbstractPolylineEncoder
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L27
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2
- commentId: T:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm.Abstraction
- url: PolylineAlgorithm.Abstraction.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
-- code: 'public abstract class AbstractPolylineEncoder : IPolylineEncoder'
-- h4: Type Parameters
-- parameters:
- - name: TCoordinate
- description: The type that represents a geographic coordinate to encode.
- - name: TPolyline
- description: The type that represents the encoded polyline output.
-- h4: Inheritance
-- inheritance:
- - text: object
- url: https://learn.microsoft.com/dotnet/api/system.object
- - text: AbstractPolylineEncoder
- url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html
-- h4: Implements
-- list:
- - text: IPolylineEncoder
- url: PolylineAlgorithm.Abstraction.IPolylineEncoder-2.html
-- h4: Inherited Members
-- list:
- - text: object.Equals(object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object)
- - text: object.Equals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.equals#system-object-equals(system-object-system-object)
- - text: object.GetHashCode()
- url: https://learn.microsoft.com/dotnet/api/system.object.gethashcode
- - text: object.GetType()
- url: https://learn.microsoft.com/dotnet/api/system.object.gettype
- - text: object.MemberwiseClone()
- url: https://learn.microsoft.com/dotnet/api/system.object.memberwiseclone
- - text: object.ReferenceEquals(object, object)
- url: https://learn.microsoft.com/dotnet/api/system.object.referenceequals
- - text: object.ToString()
- url: https://learn.microsoft.com/dotnet/api/system.object.tostring
-- h4: Extension Methods
-- list:
- - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List)
- url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__
- - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TCoordinate[])
- url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___
-- h2: Remarks
-- markdown: >-
- Derive from this class to implement an encoder for a specific coordinate and polyline type. Override
-
- , , and to provide type-specific behavior.
-- h2: Constructors
-- api3: AbstractPolylineEncoder()
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L33
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor
-- markdown: Initializes a new instance of the class with default encoding options.
-- code: protected AbstractPolylineEncoder()
-- api3: AbstractPolylineEncoder(PolylineEncodingOptions)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2__ctor_PolylineAlgorithm_PolylineEncodingOptions_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L43
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.#ctor(PolylineAlgorithm.PolylineEncodingOptions)
-- markdown: Initializes a new instance of the class with the specified encoding options.
-- code: protected AbstractPolylineEncoder(PolylineEncodingOptions options)
-- h4: Parameters
-- parameters:
- - name: options
- type:
- - text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
- description: The to use for encoding operations.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when options is null
-- h2: Properties
-- api3: Options
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Options
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L57
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options
- commentId: P:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Options
-- markdown: Gets the encoding options used by this polyline encoder.
-- code: public PolylineEncodingOptions Options { get; }
-- h4: Property Value
-- parameters:
- - type:
- - text: PolylineEncodingOptions
- url: PolylineAlgorithm.PolylineEncodingOptions.html
-- h2: Methods
-- api3: CreatePolyline(ReadOnlyMemory)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_CreatePolyline_System_ReadOnlyMemory_System_Char__
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L174
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char})
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.CreatePolyline(System.ReadOnlyMemory{System.Char})
-- markdown: Creates a polyline instance from the provided read-only sequence of characters.
-- code: protected abstract TPolyline CreatePolyline(ReadOnlyMemory polyline)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - text: ReadOnlyMemory
- url: https://learn.microsoft.com/dotnet/api/system.readonlymemory-1
- - <
- - text: char
- url: https://learn.microsoft.com/dotnet/api/system.char
- - '>'
- description: A containing the encoded polyline characters.
-- h4: Returns
-- parameters:
- - type:
- - TPolyline
- description: An instance of TPolyline representing the encoded polyline.
-- api3: Encode(ReadOnlySpan, CancellationToken)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L80
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
-- markdown: Encodes a collection of TCoordinate instances into an encoded TPolyline string.
-- code: >-
- [SuppressMessage("Design", "MA0051:Method is too long", Justification = "Method contains local methods. Actual method only 55 lines.")]
-
- public TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default)
-- h4: Parameters
-- parameters:
- - name: coordinates
- type:
- - text: ReadOnlySpan
- url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
- - <
- - TCoordinate
- - '>'
- description: The collection of TCoordinate objects to encode.
- - name: cancellationToken
- type:
- - text: CancellationToken
- url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
- description: A that can be used to cancel the encoding operation.
- optional: true
-- h4: Returns
-- parameters:
- - type:
- - TPolyline
- description: An instance of TPolyline representing the encoded coordinates.
-- h4: Exceptions
-- parameters:
- - type:
- - text: ArgumentNullException
- url: https://learn.microsoft.com/dotnet/api/system.argumentnullexception
- description: Thrown when coordinates is null.
- - type:
- - text: ArgumentException
- url: https://learn.microsoft.com/dotnet/api/system.argumentexception
- description: Thrown when coordinates is an empty enumeration.
- - type:
- - text: InvalidOperationException
- url: https://learn.microsoft.com/dotnet/api/system.invalidoperationexception
- description: Thrown when the internal encoding buffer cannot accommodate the encoded value.
-- api3: GetLatitude(TCoordinate)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLatitude__0_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L194
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLatitude(`0)
-- markdown: Extracts the latitude value from the specified coordinate.
-- code: protected abstract double GetLatitude(TCoordinate current)
-- h4: Parameters
-- parameters:
- - name: current
- type:
- - TCoordinate
- description: The coordinate from which to extract the latitude.
-- h4: Returns
-- parameters:
- - type:
- - text: double
- url: https://learn.microsoft.com/dotnet/api/system.double
- description: The latitude value as a .
-- api3: GetLongitude(TCoordinate)
- id: PolylineAlgorithm_Abstraction_AbstractPolylineEncoder_2_GetLongitude__0_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/AbstractPolylineEncoder.cs#L184
- metadata:
- uid: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0)
- commentId: M:PolylineAlgorithm.Abstraction.AbstractPolylineEncoder`2.GetLongitude(`0)
-- markdown: Extracts the longitude value from the specified coordinate.
-- code: protected abstract double GetLongitude(TCoordinate current)
-- h4: Parameters
-- parameters:
- - name: current
- type:
- - TCoordinate
- description: The coordinate from which to extract the longitude.
-- h4: Returns
-- parameters:
- - type:
- - text: double
- url: https://learn.microsoft.com/dotnet/api/system.double
- description: The longitude value as a .
-languageId: csharp
-metadata:
- description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
deleted file mode 100644
index c3a0cc71..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineDecoder-2.yml
+++ /dev/null
@@ -1,90 +0,0 @@
-### YamlMime:ApiPage
-title: Interface IPolylineDecoder
-body:
-- api1: Interface IPolylineDecoder
- id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L22
- metadata:
- uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2
- commentId: T:PolylineAlgorithm.Abstraction.IPolylineDecoder`2
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm.Abstraction
- url: PolylineAlgorithm.Abstraction.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates.
-- code: public interface IPolylineDecoder
-- h4: Type Parameters
-- parameters:
- - name: TPolyline
- description: >-
- The type that represents the encoded polyline input. Common implementations use ,
-
- but custom wrapper types are allowed to carry additional metadata.
- - name: TValue
- description: >-
- The coordinate type returned by the decoder. Typical implementations return a struct or class that
-
- contains latitude and longitude (for example a LatLng type or a ValueTuple<double,double>).
-- h2: Methods
-- api3: Decode(TPolyline, CancellationToken)
- id: PolylineAlgorithm_Abstraction_IPolylineDecoder_2_Decode__0_System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineDecoder.cs#L48
- metadata:
- uid: PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
- commentId: M:PolylineAlgorithm.Abstraction.IPolylineDecoder`2.Decode(`0,System.Threading.CancellationToken)
-- markdown: >-
- Decodes the specified encoded polyline into an ordered sequence of geographic coordinates.
-
- The sequence preserves the original vertex order encoded by the polyline.
-- code: IEnumerable Decode(TPolyline polyline, CancellationToken cancellationToken = default)
-- h4: Parameters
-- parameters:
- - name: polyline
- type:
- - TPolyline
- description: >-
- The TPolyline instance containing the encoded polyline to decode.
-
- Implementations SHOULD validate the input and may throw
-
- or for invalid formats.
- - name: cancellationToken
- type:
- - text: CancellationToken
- url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
- description: >-
- A to observe while decoding. If cancellation is requested,
-
- implementations SHOULD stop work and throw an .
- optional: true
-- h4: Returns
-- parameters:
- - type:
- - text: IEnumerable
- url: https://learn.microsoft.com/dotnet/api/system.collections.generic.ienumerable-1
- - <
- - TValue
- - '>'
- description: >-
- An of TValue representing the decoded
-
- latitude/longitude pairs (or equivalent coordinates) in the same order they were encoded.
-- h4: Remarks
-- markdown: >-
- Implementations commonly follow the Google Encoded Polyline Algorithm Format, but this interface
-
- does not mandate a specific encoding. Consumers should rely on a concrete decoder's documentation
-
- to understand the exact encoding supported.
-- h4: Exceptions
-- parameters:
- - type:
- - text: OperationCanceledException
- url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception
- description: Thrown when the provided cancellationToken requests cancellation.
-languageId: csharp
-metadata:
- description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
deleted file mode 100644
index 952d1a27..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.IPolylineEncoder-2.yml
+++ /dev/null
@@ -1,142 +0,0 @@
-### YamlMime:ApiPage
-title: Interface IPolylineEncoder
-body:
-- api1: Interface IPolylineEncoder
- id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L36
- metadata:
- uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2
- commentId: T:PolylineAlgorithm.Abstraction.IPolylineEncoder`2
-- facts:
- - name: Namespace
- value:
- text: PolylineAlgorithm.Abstraction
- url: PolylineAlgorithm.Abstraction.html
- - name: Assembly
- value: PolylineAlgorithm.dll
-- markdown: >-
- Contract for encoding a sequence of geographic coordinates into an encoded polyline representation.
-
- Implementations interpret the generic TValue type and produce an encoded
-
- representation of those coordinates as TPolyline.
-- code: public interface IPolylineEncoder
-- h4: Type Parameters
-- parameters:
- - name: TValue
- description: >-
- The concrete coordinate representation used by the encoder (for example a struct or class containing
-
- Latitude and Longitude values). Implementations must document the expected shape,
-
- units (typically decimal degrees), and any required fields for TValue.
-
- Common shapes:
-
- - A struct or class with two double properties named Latitude and Longitude.
-
- - A tuple-like type (for example ValueTuple<double,double>) where the encoder documents
- which element represents latitude and longitude.
- - name: TPolyline
- description: >-
- The encoded polyline representation returned by the encoder (for example string,
-
- ReadOnlyMemory<char>, or a custom wrapper type). Concrete implementations should document
-
- the chosen representation and any memory / ownership expectations.
-- h4: Extension Methods
-- list:
- - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, List)
- url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1__System_Collections_Generic_List___0__
- - text: PolylineEncoderExtensions.Encode(IPolylineEncoder, TValue[])
- url: PolylineAlgorithm.Extensions.PolylineEncoderExtensions.html#PolylineAlgorithm_Extensions_PolylineEncoderExtensions_Encode__2_PolylineAlgorithm_Abstraction_IPolylineEncoder___0___1____0___
-- h2: Remarks
-- markdown: >-
- - This interface is intentionally minimal to allow different encoding strategies (Google encoded polyline,
- precision/scale variants, or custom compressed formats) to be expressed behind a common contract.
- - Implementations should document:
- - Coordinate precision and rounding rules (for example 1e-5 for 5-decimal precision).
- - Coordinate ordering and whether altitude or additional dimensions are supported.
- - Thread-safety guarantees: whether instances are safe to reuse concurrently or must be instantiated per-call.
- - Implementations are encouraged to be memory-efficient; the API accepts a
- to avoid forced allocations when callers already have contiguous memory.
-- h2: Methods
-- api3: Encode(ReadOnlySpan, CancellationToken)
- id: PolylineAlgorithm_Abstraction_IPolylineEncoder_2_Encode_System_ReadOnlySpan__0__System_Threading_CancellationToken_
- src: https://github.com/petesramek/polyline-algorithm-csharp/blob/copilot/assess-repository-state/src/PolylineAlgorithm/Abstraction/IPolylineEncoder.cs#L76
- metadata:
- uid: PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
- commentId: M:PolylineAlgorithm.Abstraction.IPolylineEncoder`2.Encode(System.ReadOnlySpan{`0},System.Threading.CancellationToken)
-- markdown: >-
- Encodes a sequence of geographic coordinates into an encoded polyline representation.
-
- The order of coordinates in coordinates is preserved in the encoded result.
-- code: TPolyline Encode(ReadOnlySpan coordinates, CancellationToken cancellationToken = default)
-- h4: Parameters
-- parameters:
- - name: coordinates
- type:
- - text: ReadOnlySpan
- url: https://learn.microsoft.com/dotnet/api/system.readonlyspan-1
- - <
- - TValue
- - '>'
- description: >-
- The collection of TValue instances to encode into a polyline.
-
- The span may be empty; implementations should return an appropriate empty encoded representation
-
- (for example an empty string or an empty memory slice) rather than null.
- - name: cancellationToken
- type:
- - text: CancellationToken
- url: https://learn.microsoft.com/dotnet/api/system.threading.cancellationtoken
- description: >-
- A that can be used to cancel the encoding operation.
-
- Implementations should observe this token and throw
-
- when cancellation is requested. For fast, in-memory encoders cancellation may be best-effort.
- optional: true
-- h4: Returns
-- parameters:
- - type:
- - TPolyline
- description: >-
- A TPolyline containing the encoded polyline that represents the input coordinates.
-
- The exact format and any delimiting/terminating characters are implementation-specific and must be
-
- documented by concrete encoder types.
-- h4: Examples
-- markdown: >-
- // Example pseudocode for typical usage with a string-based encoder:
-
- var coords = new[] {
- new Coordinate { Latitude = 47.6219, Longitude = -122.3503 },
- new Coordinate { Latitude = 47.6220, Longitude = -122.3504 }
- };
-
- IPolylineEncoder<Coordinate,string> encoder = new GoogleEncodedPolylineEncoder();
-
- string encoded = encoder.Encode(coords, CancellationToken.None);
-- h4: Remarks
-- markdown: >-
- - Implementations should validate input as appropriate and document any preconditions (for example
- if coordinates must be within [-90,90] latitude and [-180,180] longitude).
- - For large input sequences, implementations may provide streaming or incremental encoders; those
- variants can still implement this interface by materializing the final encoded result.
-- h4: Exceptions
-- parameters:
- - type:
- - text: OperationCanceledException
- url: https://learn.microsoft.com/dotnet/api/system.operationcanceledexception
- description: Thrown if the operation is canceled via cancellationToken.
-languageId: csharp
-metadata:
- description: >-
- Contract for encoding a sequence of geographic coordinates into an encoded polyline representation.
-
- Implementations interpret the generic TValue type and produce an encoded
-
- representation of those coordinates as TPolyline.
diff --git a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml b/api-reference/0.0/PolylineAlgorithm.Abstraction.yml
deleted file mode 100644
index e9de48f7..00000000
--- a/api-reference/0.0/PolylineAlgorithm.Abstraction.yml
+++ /dev/null
@@ -1,34 +0,0 @@
-### YamlMime:ApiPage
-title: Namespace PolylineAlgorithm.Abstraction
-body:
-- api1: Namespace PolylineAlgorithm.Abstraction
- id: PolylineAlgorithm_Abstraction
- metadata:
- uid: PolylineAlgorithm.Abstraction
- commentId: N:PolylineAlgorithm.Abstraction
-- h3: Classes
-- parameters:
- - type:
- text: AbstractPolylineDecoder
- url: PolylineAlgorithm.Abstraction.AbstractPolylineDecoder-2.html
- description: Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates.
- - type:
- text: AbstractPolylineEncoder
- url: PolylineAlgorithm.Abstraction.AbstractPolylineEncoder-2.html
- description: Provides a base implementation for encoding sequences of geographic coordinates into encoded polyline strings.
-- h3: Interfaces
-- parameters:
- - type:
- text: IPolylineDecoder
- url: PolylineAlgorithm.Abstraction.IPolylineDecoder-2.html
- description: Defines a contract for decoding an encoded polyline into a sequence of geographic coordinates.
- - type:
- text: IPolylineEncoder