Skip to content

Commit e32edcb

Browse files
committed
fixes
1 parent 3ca7776 commit e32edcb

5 files changed

Lines changed: 99 additions & 71 deletions

File tree

src/PolylineAlgorithm/Abstraction/AbstractPolylineDecoder.cs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,8 @@ namespace PolylineAlgorithm.Abstraction;
99
using PolylineAlgorithm;
1010
using PolylineAlgorithm.Internal;
1111
using PolylineAlgorithm.Internal.Logging;
12-
using PolylineAlgorithm.Properties;
1312
using System;
14-
using System.Globalization;
1513
using System.Runtime.CompilerServices;
16-
#if NET8_0_OR_GREATER
17-
using System.Text;
18-
#endif
1914

2015
/// <summary>
2116
/// Decodes encoded polyline strings into sequences of geographic coordinates.
@@ -25,13 +20,6 @@ namespace PolylineAlgorithm.Abstraction;
2520
/// This abstract class provides a base implementation for decoding polylines, allowing subclasses to define how to handle specific polyline formats.
2621
/// </remarks>
2722
public abstract class AbstractPolylineDecoder<TPolyline, TCoordinate> : IPolylineDecoder<TPolyline, TCoordinate> {
28-
#if NET8_0_OR_GREATER
29-
private static readonly CompositeFormat _polylineCannotBeShorterThanExceptionMessage = CompositeFormat.Parse(ExceptionMessageResource.PolylineCannotBeShorterThanExceptionMessage);
30-
#else
31-
private static readonly string _polylineCannotBeShorterThanExceptionMessage = ExceptionMessageResource.PolylineCannotBeShorterThanExceptionMessage;
32-
#endif
33-
34-
3523
private readonly ILogger<AbstractPolylineDecoder<TPolyline, TCoordinate>> _logger;
3624
/// <summary>
3725
/// Initializes a new instance of the <see cref="AbstractPolylineDecoder{TPolyline, TCoordinate}"/> class with default encoding options.
@@ -131,7 +119,7 @@ static void ValidateEmptySequence(ReadOnlyMemory<char> polyline, ILogger logger)
131119
logger
132120
.LogPolylineCannotBeShorterThanWarning(nameof(polyline), polyline.Length, Defaults.Polyline.Block.Length.Min);
133121

134-
throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, _polylineCannotBeShorterThanExceptionMessage, polyline.Length, Defaults.Polyline.Block.Length.Min), nameof(polyline));
122+
throw new ArgumentException(ExceptionMessages.GetPolylineCannotBeShorterThanExceptionMessage(polyline.Length, Defaults.Polyline.Block.Length.Min), nameof(polyline));
135123
}
136124
}
137125
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
namespace PolylineAlgorithm.Internal;
2+
3+
using PolylineAlgorithm.Properties;
4+
using System.Globalization;
5+
6+
#if NET8_0_OR_GREATER
7+
using System.Text;
8+
#endif
9+
10+
11+
[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Naming Styles", Justification = "Usage and readability.")]
12+
internal static class ExceptionMessages {
13+
#if NET8_0_OR_GREATER
14+
private static CompositeFormat PolylineCannotBeShorterThanExceptionMessage = CompositeFormat.Parse(ExceptionMessageResource.PolylineCannotBeShorterThanExceptionMessage);
15+
#else
16+
private static readonly string PolylineCannotBeShorterThanExceptionMessage = ExceptionMessageResource.PolylineCannotBeShorterThanExceptionMessage;
17+
#endif
18+
19+
internal static string GetPolylineCannotBeShorterThanExceptionMessage(int length, int minLength) {
20+
return string.Format(CultureInfo.InvariantCulture, PolylineCannotBeShorterThanExceptionMessage, length, minLength);
21+
}
22+
}

src/PolylineAlgorithm/PolylineEncoding.cs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,26 @@ public static class PolylineEncoding {
5959
/// <exception cref="OverflowException">
6060
/// Thrown when the normalized result exceeds the range of a 32-bit signed integer during the conversion from double to int.
6161
/// </exception>
62-
public static int Normalize(double value, uint precision = 5, MidpointRounding rounding = MidpointRounding.AwayFromZero) {
62+
public static int Normalize(double value, uint precision = 5) {
63+
// Fast return if the value is zero, return 0 as the normalized value.
64+
if (value.Equals(default)) {
65+
return 0;
66+
}
67+
6368
// Validate that the value is finite and not NaN or Infinity.
6469
if (!double.IsFinite(value)) {
6570
throw new ArgumentOutOfRangeException(nameof(value), ExceptionMessageResource.ArgumentValueMustBeFiniteNumber);
6671
}
6772

68-
// Fast return if the value is zero, return 0 as the normalized value.
69-
if (value.Equals(default)) {
70-
return 0;
73+
// Fast return if precision is zero, return current value converted to Int32.
74+
if (precision == 0) {
75+
return Convert.ToInt32(value);
7176
}
7277

7378
uint factor = Pow10.GetFactor(precision);
7479

7580
checked {
76-
return (int)Math.Round(precision == 0 ? value : value * factor, rounding);
81+
return (int)Math.Round(value * factor, MidpointRounding.AwayFromZero);
7782
}
7883
}
7984

@@ -82,12 +87,13 @@ public static int Normalize(double value, uint precision = 5, MidpointRounding r
8287
/// </summary>
8388
/// <remarks>
8489
/// <para>
85-
/// This method reverses the normalization process performed by <see cref="Normalize"/>. It takes an integer value and converts it
86-
/// to a double by dividing it by 10 raised to the power of the specified precision. If the precision is 0, the value is returned as a double
87-
/// without division.
90+
/// This method reverses the normalization performed by <see cref="Normalize"/>. It takes an integer value and converts it
91+
/// to a double by dividing by 10 raised to the power of the specified precision. If <paramref name="precision"/> is 0,
92+
/// the value is returned as a double without division.
8893
/// </para>
8994
/// <para>
90-
/// The calculation is performed inside a <see langword="checked"/> block to ensure that any arithmetic overflow is detected and an <see cref="OverflowException"/> is thrown.
95+
/// The calculation is performed inside a <see langword="checked"/> block to ensure that any arithmetic overflow is detected
96+
/// and an <see cref="OverflowException"/> is thrown.
9197
/// </para>
9298
/// <para>
9399
/// For example, with a precision of 5:
@@ -106,21 +112,30 @@ public static int Normalize(double value, uint precision = 5, MidpointRounding r
106112
/// <param name="precision">
107113
/// The number of decimal places used during normalization. Default is 5, matching standard polyline encoding precision.
108114
/// </param>
115+
/// <param name="rounding">
116+
/// The rounding strategy to use when converting the result to a double. Default is <see cref="MidpointRounding.AwayFromZero"/>.
117+
/// </param>
109118
/// <returns>
110119
/// The denormalized floating-point coordinate value.
111120
/// </returns>
112121
/// <exception cref="OverflowException">
113122
/// Thrown if the arithmetic operation overflows during conversion.
114123
/// </exception>
115124
public static double Denormalize(int value, uint precision = 5) {
116-
if (value == 0) {
117-
return 0.0;
125+
if (value.Equals(default)) {
126+
return default;
127+
}
128+
129+
// Fast return if precision is zero, return current value converted to Int32.
130+
if (precision == 0) {
131+
return Convert.ToDouble(value);
118132
}
119133

120134
uint factor = Pow10.GetFactor(precision);
121135

122136
checked {
123-
return precision == 0 ? value : (double)value / factor;
137+
138+
return value / (double)factor;
124139
}
125140
}
126141

src/PolylineAlgorithm/Pow10.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public static class Pow10 {
1313
/// <summary>
1414
/// Pre-computed powers of 10 from 10^0 to 10^9.
1515
/// </summary>
16-
private static readonly uint[] _pow10 = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
16+
private static readonly uint[] _pow10 = {/* 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000*/ };
1717

1818
/// <summary>
1919
/// Gets the multiplication factor for a given precision level.

tests/PolylineAlgorithm.Tests/PolylineEncodingTest.cs

Lines changed: 48 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -36,49 +36,52 @@ public class PolylineEncodingTest {
3636
(-16777215,"|~~~^"),
3737
];
3838

39-
public static IEnumerable<(double denormalized, int normalized, uint precision)> DenormalizedNormalizedPairs => [
40-
(0, 0, 5),
39+
public static IEnumerable<(int normalized, double expected, uint precision)> NormalizedValues => [
40+
(0, 0.0, 0),
41+
(123456, 123456.0, 0),
42+
(-123456, -123456.0, 0),
43+
(90, 90.0, 0),
44+
(-90, -90.0, 0),
45+
( 0, 0.00,2),
46+
(123456, 1234.56, 2),
47+
(-123456, -1234.56, 2),
48+
(9000, 90.00, 2),
49+
(-9000, -90.00, 2),
50+
(0, 0.0, 5),
51+
(123456789, 1234.56789, 5),
52+
(-123456789, -1234.56789, 5),
53+
(900000000, 9000, 5),
54+
(-900000000,-9000, 5),
55+
];
56+
57+
public static IEnumerable<(double denormalized, int expected, uint precision)> DenormalizedValues => [
58+
(0, 0, 0),
59+
(1.23456, 1, 0),
60+
(-1.23456789, -1, 0),
61+
(90, 90, 0),
62+
(-90, -90, 0),
63+
(0, 0, 2),
64+
(1.23456, 123, 2),
65+
(-1.23456789, -123, 2),
66+
(90, 9000, 2),
67+
(-90, -9000, 2),
4168
(0, 0, 5),
42-
(1.23456, 123456, 5),
69+
(1.23456789, 123456, 5),
4370
(-1.23456789, -123456, 5),
44-
(1.23456789, 12, 2),
45-
(-1.23456789, -12, 2),
71+
(1.23456789, 123456, 5),
4672
(90, 9000000, 5),
47-
(-90, -900000, 5),
48-
(90, 900, 2),
49-
(-90, -900, 2),
73+
(-90, -9000000, 5),
5074
];
5175

52-
public static IEnumerable<(double denormalized, CoordinateValueType)> DenormalizedOutOfRangeValues => [
53-
(90.00001,CoordinateValueType.Latitude),
54-
(-90.00001,CoordinateValueType.Latitude),
55-
(180.00001,CoordinateValueType.Longitude),
56-
(-180.00001,CoordinateValueType.Longitude),
57-
(double.NaN,CoordinateValueType.Latitude),
58-
(double.NaN,CoordinateValueType.Longitude),
59-
(double.MinValue,CoordinateValueType.Latitude),
60-
(double.MaxValue,CoordinateValueType.Latitude),
61-
(double.MinValue,CoordinateValueType.Longitude),
62-
(double.MaxValue,CoordinateValueType.Longitude),
63-
(double.NegativeInfinity,CoordinateValueType.Latitude),
64-
(double.PositiveInfinity,CoordinateValueType.Latitude),
65-
(double.NegativeInfinity,CoordinateValueType.Longitude),
66-
(double.PositiveInfinity,CoordinateValueType.Longitude),
67-
(0, CoordinateValueType.Unspecified),
68-
(0, CoordinateValueType.Unspecified),
76+
public static IEnumerable<object[]> DoubleNotFiniteValues => [
77+
[double.NaN],
78+
[double.NegativeInfinity],
79+
[double.PositiveInfinity],
6980
];
7081

71-
public static IEnumerable<(int normalized, CoordinateValueType)> NormalizedOutOfRangeValues => [
72-
(9000001,CoordinateValueType.Latitude),
73-
(-9000001,CoordinateValueType.Latitude),
74-
(18000001,CoordinateValueType.Longitude),
75-
(-18000001,CoordinateValueType.Longitude),
76-
(int.MinValue,CoordinateValueType.Latitude),
77-
(int.MaxValue,CoordinateValueType.Latitude),
78-
(int.MinValue,CoordinateValueType.Longitude),
79-
(int.MaxValue,CoordinateValueType.Longitude),
80-
(0, CoordinateValueType.Unspecified),
81-
(0, CoordinateValueType.Unspecified),
82+
public static IEnumerable<object[]> DoubleMinMaxValues => [
83+
[double.MinValue],
84+
[double.MaxValue],
8285
];
8386

8487
public static IEnumerable<(int delta, int bufferSize)> DeltaBufferSizePairs => [
@@ -110,7 +113,7 @@ public class PolylineEncodingTest {
110113
#endregion
111114

112115
[TestMethod]
113-
[DynamicData(nameof(DenormalizedNormalizedPairs))]
116+
[DynamicData(nameof(DenormalizedValues))]
114117
public void Normalize_Equals_Expected(double denormalized, int expected, uint precision) {
115118
// Arrange & Act
116119
int result = PolylineEncoding.Normalize(denormalized, precision);
@@ -121,8 +124,8 @@ public void Normalize_Equals_Expected(double denormalized, int expected, uint pr
121124

122125

123126
[TestMethod]
124-
[DynamicData(nameof(DenormalizedNormalizedPairs))]
125-
public void Denormalize_Equals_Expected(double expected, int normalized, uint precision) {
127+
[DynamicData(nameof(NormalizedValues))]
128+
public void Denormalize_Equals_Expected(int normalized, double expected, uint precision) {
126129
// Arrange & Act
127130
double result = PolylineEncoding.Denormalize(normalized, precision);
128131

@@ -230,7 +233,7 @@ public void TryReadValue_MalformedBuffer_Returns_False() {
230233
}
231234

232235
[TestMethod]
233-
[DynamicData(nameof(DenormalizedOutOfRangeValues))]
236+
[DynamicData(nameof(DoubleNotFiniteValues))]
234237
public void Normalize_Throws_ArgumentOutOfRangeException(double value) {
235238
// Arrange
236239
static int Normalize(double value) => PolylineEncoding.Normalize(value);
@@ -243,21 +246,21 @@ public void Normalize_Throws_ArgumentOutOfRangeException(double value) {
243246
}
244247

245248
[TestMethod]
246-
[DynamicData(nameof(NormalizedOutOfRangeValues))]
247-
public void Denormalize_Throws_ArgumentOutOfRangeException(int value) {
249+
[DynamicData(nameof(DoubleMinMaxValues))]
250+
public void Normalize_Throws_OverflowException(double value) {
248251
// Arrange
249-
static double Denormalize(int value) => PolylineEncoding.Denormalize(value);
252+
static int Normalize(double value) => PolylineEncoding.Normalize(value);
250253

251254
// Act
252-
var exception = Assert.ThrowsExactly<ArgumentOutOfRangeException>(() => Denormalize(value));
255+
var exception = Assert.ThrowsExactly<OverflowException>(() => Normalize(value));
253256

254257
// Assert
255258
Assert.IsFalse(string.IsNullOrWhiteSpace(exception.Message));
256259
}
257260

258261
[TestMethod]
259262
[DynamicData(nameof(DeltaBufferSizePairs))]
260-
public void GetCharCount_Equals_Expected(int delta, int expected) {
263+
public void GetRequiredBufferSize_Equals_Expected(int delta, int expected) {
261264
// Arrange & Act
262265
var bufferSize = PolylineEncoding.GetRequiredBufferSize(delta);
263266

0 commit comments

Comments
 (0)