66using Microsoft . Extensions . Logging ;
77using PolylineAlgorithm . Internal ;
88using PolylineAlgorithm . Internal . Diagnostics ;
9- using System . Buffers ;
109using System . Runtime . CompilerServices ;
1110
1211namespace PolylineAlgorithm . Abstraction ;
1312
1413/// <summary>
15- /// Provides a base implementation for decoding encoded polyline strings into sequences of items .
14+ /// Provides a base implementation for decoding encoded polyline strings into sequences of geographic coordinates .
1615/// </summary>
1716/// <remarks>
18- /// Derive from this class to implement a decoder for a specific polyline type. Override
19- /// <see cref="ValuesPerItem"/>, <see cref="GetReadOnlyMemory"/>, and <see cref="CreateItem"/> to provide
20- /// type-specific behavior.
21- /// <para>
22- /// The polyline format encodes each item as a fixed-length run of <see cref="ValuesPerItem"/> delta-compressed
23- /// values. All items in a single polyline must have the same number of values. For example, a 2D GPS decoder
24- /// sets <see cref="ValuesPerItem"/> to 2 (latitude, longitude), while a 3D GPS decoder sets it to 3
25- /// (latitude, longitude, altitude).
26- /// </para>
17+ /// Derive from this class to implement a decoder for a specific polyline type. Override <see cref="GetReadOnlyMemory"/>
18+ /// and <see cref="CreateCoordinate"/> to provide type-specific behavior.
2719/// </remarks>
2820/// <typeparam name="TPolyline">The type that represents the encoded polyline input.</typeparam>
29- /// <typeparam name="TCoordinate">The type that represents a decoded item .</typeparam>
21+ /// <typeparam name="TCoordinate">The type that represents a decoded geographic coordinate .</typeparam>
3022public abstract class AbstractPolylineDecoder < TPolyline , TCoordinate > : IPolylineDecoder < TPolyline , TCoordinate > {
3123 private readonly ILogger < AbstractPolylineDecoder < TPolyline , TCoordinate > > _logger ;
3224
@@ -61,16 +53,6 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
6153 /// </summary>
6254 public PolylineEncodingOptions Options { get ; }
6355
64- /// <summary>
65- /// Gets the number of encoded values that make up a single decoded item.
66- /// </summary>
67- /// <remarks>
68- /// Override this property to specify the arity of each item. For example, return <c>2</c> for
69- /// latitude/longitude pairs, <c>3</c> for latitude/longitude/altitude triples, or any other count
70- /// that matches the encoding scheme used to produce the polyline.
71- /// </remarks>
72- protected abstract int ValuesPerItem { get ; }
73-
7456 /// <summary>
7557 /// Decodes an encoded <typeparamref name="TPolyline"/> into a sequence of <typeparamref name="TCoordinate"/> instances,
7658 /// with support for cancellation.
@@ -82,7 +64,7 @@ protected AbstractPolylineDecoder(PolylineEncodingOptions options) {
8264 /// A <see cref="CancellationToken"/> that can be used to cancel the decoding operation.
8365 /// </param>
8466 /// <returns>
85- /// An <see cref="IEnumerable{T}"/> of <typeparamref name="TCoordinate"/> representing the decoded items .
67+ /// An <see cref="IEnumerable{T}"/> of <typeparamref name="TCoordinate"/> representing the decoded latitude and longitude pairs .
8668 /// </returns>
8769 /// <exception cref="ArgumentNullException">
8870 /// Thrown when <paramref name="polyline"/> is <see langword="null"/>.
@@ -108,45 +90,30 @@ public IEnumerable<TCoordinate> Decode(TPolyline polyline, CancellationToken can
10890 ValidateSequence ( sequence , _logger ) ;
10991 ValidateFormat ( sequence , _logger ) ;
11092
111- int valuesPerItem = ValuesPerItem ;
11293 int position = 0 ;
113-
114- int [ ] ? runningRent = ArrayPool < int > . Shared . Rent ( valuesPerItem ) ;
115- // Zero-initialize so delta decoding starts from 0 for all dimensions.
116- for ( int j = 0 ; j < valuesPerItem ; j ++ ) {
117- runningRent [ j ] = 0 ;
118- }
94+ int encodedLatitude = 0 ;
95+ int encodedLongitude = 0 ;
11996
12097 try {
12198 while ( position < sequence . Length ) {
12299 cancellationToken . ThrowIfCancellationRequested ( ) ;
123100
124- bool allRead = true ;
125- for ( int j = 0 ; j < valuesPerItem ; j ++ ) {
126- if ( ! PolylineEncoding . TryReadValue ( ref runningRent [ j ] , sequence , ref position ) ) {
127- allRead = false ;
128- break ;
129- }
130- }
131-
132- if ( ! allRead ) {
101+ if ( ! PolylineEncoding . TryReadValue ( ref encodedLatitude , sequence , ref position )
102+ || ! PolylineEncoding . TryReadValue ( ref encodedLongitude , sequence , ref position ) ) {
133103 _logger ? . LogOperationFailedDebug ( OperationName ) ;
134104 _logger ? . LogInvalidPolylineWarning ( position ) ;
135105
136106 ExceptionGuard . ThrowInvalidPolylineFormat ( position ) ;
137107 }
138108
139- double [ ] decoded = new double [ valuesPerItem ] ;
140- for ( int j = 0 ; j < valuesPerItem ; j ++ ) {
141- decoded [ j ] = PolylineEncoding . Denormalize ( runningRent [ j ] , Options . Precision ) ;
142- }
109+ double decodedLatitude = PolylineEncoding . Denormalize ( encodedLatitude , Options . Precision ) ;
110+ double decodedLongitude = PolylineEncoding . Denormalize ( encodedLongitude , Options . Precision ) ;
143111
144- _logger ? . LogDecodedValuesDebug ( valuesPerItem , position ) ;
112+ _logger ? . LogDecodedCoordinateDebug ( decodedLatitude , decodedLongitude , position ) ;
145113
146- yield return CreateItem ( decoded . AsMemory ( ) ) ;
114+ yield return CreateCoordinate ( decodedLatitude , decodedLongitude ) ;
147115 }
148116 } finally {
149- ArrayPool < int > . Shared . Return ( runningRent ! ) ;
150117 _logger ? . LogOperationFinishedDebug ( OperationName ) ;
151118 }
152119 }
@@ -221,19 +188,17 @@ protected virtual void ValidateFormat(ReadOnlyMemory<char> sequence, ILogger? lo
221188 protected abstract ReadOnlyMemory < char > GetReadOnlyMemory ( in TPolyline polyline ) ;
222189
223190 /// <summary>
224- /// Creates a <typeparamref name="TCoordinate"/> instance from the specified decoded values.
191+ /// Creates a <typeparamref name="TCoordinate"/> instance from the specified latitude and longitude values.
225192 /// </summary>
226- /// <param name="values">
227- /// A <see cref="ReadOnlyMemory{T}"/> of <see cref="double"/> containing exactly <see cref="ValuesPerItem"/>
228- /// decoded values for this item, in the same order they were encoded.
193+ /// <param name="latitude">
194+ /// The latitude component of the coordinate, in degrees.
195+ /// </param>
196+ /// <param name="longitude">
197+ /// The longitude component of the coordinate, in degrees.
229198 /// </param>
230199 /// <returns>
231- /// A <typeparamref name="TCoordinate"/> instance representing the decoded item .
200+ /// A <typeparamref name="TCoordinate"/> instance representing the specified geographic coordinate .
232201 /// </returns>
233- /// <remarks>
234- /// Implementations should read all required values from <paramref name="values"/> and construct the
235- /// <typeparamref name="TCoordinate"/> immediately. The memory is valid only for the duration of this call.
236- /// </remarks>
237202 [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
238- protected abstract TCoordinate CreateItem ( ReadOnlyMemory < double > values ) ;
203+ protected abstract TCoordinate CreateCoordinate ( double latitude , double longitude ) ;
239204}
0 commit comments