Skip to content

Commit 63c141f

Browse files
author
Petr Sramek
committed
temp commit
1 parent e846892 commit 63c141f

19 files changed

+417
-68
lines changed
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// Copyright (c) Pete Sramek. All rights reserved.
3+
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace PolylineAlgorithm;
7+
8+
using System;
9+
using System.Collections.Generic;
10+
11+
/// <summary>
12+
/// Defines method to decode a polyline.
13+
/// </summary>
14+
public interface IPolylineDecoder {
15+
/// <summary>
16+
/// Converts an encoded polyline to a set of coordinates.
17+
/// </summary>
18+
/// <param name="polyline">An encoded polyline to decode.</param>
19+
/// <returns>A set of coordinates.</returns>
20+
IEnumerable<Coordinate> Decode(ref readonly ReadOnlySpan<char> polyline);
21+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//
2+
// Copyright (c) Pete Sramek. All rights reserved.
3+
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace PolylineAlgorithm;
7+
8+
using System;
9+
using System.Collections.Generic;
10+
11+
/// <summary>
12+
/// Defines method to encode a set of coordinates.
13+
/// </summary>
14+
public interface IPolylineEncoder {
15+
/// <summary>
16+
/// Converts a set of coordinates to an encoded polyline.
17+
/// </summary>
18+
/// <param name="coordinates">A set of coordinates to encode.</param>
19+
/// <returns>An encoded polyline.</returns>
20+
ReadOnlySpan<char> Encode(IEnumerable<Coordinate> coordinates);
21+
}

src/PolylineAlgorithm/Internal/Constants.cs

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -38,29 +38,29 @@ internal static class ASCII {
3838
public const int UnitSeparator = 31;
3939
}
4040

41-
///// <summary>
42-
///// Defines coordinates constant values
43-
///// </summary>
44-
//internal static class Coordinate {
45-
// /// <summary>
46-
// /// Defines the maximum value for latitude
47-
// /// </summary>
48-
// public const int MaxLatitude = 90;
41+
/// <summary>
42+
/// Defines coordinates constant values
43+
/// </summary>
44+
internal static class Coordinate {
45+
/// <summary>
46+
/// Defines the maximum value for latitude
47+
/// </summary>
48+
public const int MaxLatitude = 90;
4949

50-
// /// <summary>
51-
// /// Defines the maximum value for longitude
52-
// /// </summary>
53-
// public const int MaxLongitude = 180;
50+
/// <summary>
51+
/// Defines the maximum value for longitude
52+
/// </summary>
53+
public const int MaxLongitude = 180;
5454

55-
// /// <summary>
56-
// /// Defines the maximum value for latitude
57-
// /// </summary>
58-
// public const int MinLatitude = -MaxLatitude;
55+
/// <summary>
56+
/// Defines the maximum value for latitude
57+
/// </summary>
58+
public const int MinLatitude = -MaxLatitude;
5959

60-
// /// <summary>
61-
// /// Defines the maximum value for longitude
62-
// /// </summary>
63-
// public const int MinLongitude = -MaxLongitude;
64-
//}
60+
/// <summary>
61+
/// Defines the maximum value for longitude
62+
/// </summary>
63+
public const int MinLongitude = -MaxLongitude;
64+
}
6565
}
6666
}

src/PolylineAlgorithm/Internal/PolylineReader.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public Coordinate Read() {
2626
Coordinate coordinate = new(Precise(ref latitude), Precise(ref longitude));
2727

2828
if (!coordinate.IsValid) {
29-
throw new InvalidOperationException();
29+
throw new InvalidCoordinateException(coordinate);
3030
}
3131

3232
return coordinate;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// Copyright (c) Pete Sramek. All rights reserved.
3+
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace PolylineAlgorithm;
7+
8+
using PolylineAlgorithm.Internal;
9+
using System.Diagnostics.CodeAnalysis;
10+
11+
/// <summary>
12+
/// Represents error that is caused by invalid coordinate.
13+
/// </summary>
14+
[SuppressMessage("Design", "CA1032:Implement standard exception constructors", Justification = "Main purpose is to report coordinate that is invalid, thus we have to have only one construtor.")]
15+
public sealed class InvalidCoordinateException : Exception {
16+
public InvalidCoordinateException(Coordinate coordinate, Exception? innerException = null)
17+
: base(string.Format(ExceptionMessageResource.CoordinateValidationExceptionCoordinateIsOutOfRangeErrorMessageFormat, coordinate.Latitude, coordinate.Longitude),
18+
innerException)
19+
{
20+
Coordinate = coordinate;
21+
}
22+
23+
/// <summary>
24+
/// Coordinate that caused the exception.
25+
/// </summary>
26+
public Coordinate Coordinate { get; }
27+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
//
2+
// Copyright (c) Pete Sramek. All rights reserved.
3+
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace PolylineAlgorithm;
7+
8+
using PolylineAlgorithm.Internal;
9+
using System;
10+
using System.Diagnostics.CodeAnalysis;
11+
12+
/// <summary>
13+
/// Represents error that occurs during polyline encoding.
14+
/// </summary>
15+
[SuppressMessage("Design", "CA1032:Implement standard exception constructors", Justification = "Main purpose is to report position in which failure occurs, thus we have to have only one construtor.")]
16+
public sealed class MalformedPolylineException : Exception {
17+
/// <summary>
18+
/// Initializes an instance
19+
/// </summary>
20+
/// <param name="position"></param>
21+
/// <param name="innerException"></param>
22+
public MalformedPolylineException(int position, Exception? innerException = null)
23+
: base(string.Format(ExceptionMessageResource.PolylineStringIsMalformed, position),
24+
innerException)
25+
{
26+
Position = position;
27+
}
28+
29+
/// <summary>
30+
/// Position in polyline string at which error occurs.
31+
/// </summary>
32+
public int Position { get; }
33+
}

src/PolylineAlgorithm/PolylineEncoder.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,16 @@ public ReadOnlySpan<char> Encode(IEnumerable<Coordinate> coordinates) {
3333
}
3434

3535
// Initializing local variables
36-
int capacity = count * 11;
36+
int capacity = count * 12;
3737
Span<char> buffer = new char[capacity];
3838
PolylineWriter writer = new(in buffer);
3939

4040
// Looping over coordinates and building encoded result
4141
foreach (var coordinate in coordinates) {
42+
if(!coordinate.IsValid) {
43+
throw new InvalidCoordinateException(coordinate);
44+
}
45+
4246
writer.Write(in coordinate);
4347
}
4448

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//
2+
// Copyright (c) Pete Sramek. All rights reserved.
3+
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace PolylineAlgorithm.Validation;
7+
8+
using PolylineAlgorithm.Internal;
9+
using System;
10+
using System.Diagnostics;
11+
using System.Runtime.InteropServices;
12+
13+
/// <summary>
14+
/// Represents a range within coordinate value, latitude or longitude, is considered valid.
15+
/// </summary>
16+
[DebuggerDisplay(@"{ Min: {Min}, Max: {Max} }")]
17+
[StructLayout(LayoutKind.Sequential, Pack = 8, Size = 16)]
18+
public readonly struct CoordinateRange : IEquatable<CoordinateRange> {
19+
public CoordinateRange(double min, double max) {
20+
if (min >= max) {
21+
throw new ArgumentException(string.Format("", min.ToString(), max.ToString()), paramName: nameof(min));
22+
}
23+
24+
Min = min;
25+
Max = max;
26+
}
27+
28+
/// <summary>
29+
/// Represents inclusive minimal value of the range.
30+
/// </summary>
31+
public readonly double Min { get; }
32+
33+
/// <summary>
34+
/// Represents inclusive maximal value of the range.
35+
/// </summary>
36+
public readonly double Max { get; }
37+
38+
/// <summary>
39+
/// Indicates whether the <paramref name="value"/> is within the range.
40+
/// </summary>
41+
/// <param name="value">A value to be validated is in range.</param>
42+
/// <returns><see langword="true" /> if <paramref name="value"/> is within the range; otherwise, <see langword="false"/>.</returns>
43+
public bool IsInRange(double value) => value >= Min && value <= Max;
44+
45+
/// <summary>
46+
/// Returns the formatted string respresentation of this instance.
47+
/// </summary>
48+
/// <returns>The formatted string respresentation of this instance.</returns>
49+
/// <remarks>{ Min: [double], Max: [double] }</remarks>
50+
public override string ToString() {
51+
return $"{{ {nameof(Min)}: {Min}, {nameof(Max)}: {Max} }}";
52+
}
53+
54+
/// <inheritdoc />
55+
public override bool Equals(object? obj) {
56+
return obj is CoordinateRange range && Equals(range);
57+
}
58+
59+
/// <inheritdoc />
60+
public bool Equals(CoordinateRange other) {
61+
return Min == other.Min &&
62+
Max == other.Max;
63+
}
64+
65+
/// <inheritdoc />
66+
public override int GetHashCode() {
67+
return HashCode.Combine(Min, Max);
68+
}
69+
70+
public static bool operator ==(CoordinateRange left, CoordinateRange right) {
71+
return left.Equals(right);
72+
}
73+
74+
public static bool operator !=(CoordinateRange left, CoordinateRange right) {
75+
return !(left == right);
76+
}
77+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
//
2+
// Copyright (c) Pete Sramek. All rights reserved.
3+
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
4+
//
5+
6+
namespace PolylineAlgorithm.Validation;
7+
8+
using PolylineAlgorithm.Internal;
9+
using System.Diagnostics.CodeAnalysis;
10+
11+
/// <summary>
12+
///
13+
/// </summary>
14+
public sealed class CoordinateValidator {
15+
/// <summary>
16+
/// Represents default coordinate validator. This field is read-only.
17+
/// </summary>
18+
/// <remarks>Validates latitude between -90 and 90; longitude between -180 and 180.</remarks>
19+
[SuppressMessage("Usage", "CA2211:Non-constant fields should not be visible", Justification = "We just want to deal with it this way.")]
20+
public static readonly CoordinateValidator Default = new(new CoordinateRange(Constants.Coordinate.MinLatitude, Constants.Coordinate.MaxLatitude), new CoordinateRange(Constants.Coordinate.MinLongitude, Constants.Coordinate.MaxLongitude));
21+
22+
/// <summary>
23+
/// Initializes an instance of coordinate validator.
24+
/// </summary>
25+
/// <param name="latitudeRange">A latitude range.</param>
26+
/// <param name="longitudeRange">A longitude range.</param>
27+
public CoordinateValidator(CoordinateRange latitudeRange, CoordinateRange longitudeRange) {
28+
Latitude = latitudeRange;
29+
Longitude = longitudeRange;
30+
}
31+
32+
/// <summary>
33+
/// A latitude validation range.
34+
/// </summary>
35+
public CoordinateRange Latitude { get; }
36+
37+
/// <summary>
38+
/// A longitude validation range.
39+
/// </summary>
40+
public CoordinateRange Longitude { get; }
41+
}

tests/PolylineAlgorithm.Tests/GlobalSuppressions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@
55

66
using System.Diagnostics.CodeAnalysis;
77

8-
[assembly: SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Applies only to production code. Test assemblies are not production code.")]
8+
[assembly: SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "Ignore in test asemblies.")]

tests/PolylineAlgorithm.Tests/GlobalUsings.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,4 @@
33
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
44
//
55

6-
global using Microsoft.VisualStudio.TestTools.UnitTesting;
7-
global using System;
8-
global using System.Collections.Generic;
9-
global using System.Linq;
6+
global using Microsoft.VisualStudio.TestTools.UnitTesting;
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
namespace PolylineAlgorithm.Tests.Internal;
2+
internal static class Category {
3+
public const string Unit = nameof(Unit);
4+
}

tests/PolylineAlgorithm.Tests/Defaults.cs renamed to tests/PolylineAlgorithm.Tests/Internal/Defaults.cs

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
44
//
55

6-
namespace PolylineAlgorithm.Tests;
6+
namespace PolylineAlgorithm.Tests.Internal;
77

8-
using System;
98
using System.Collections.Generic;
109

1110
/// <summary>
1211
/// Defines default values and objects used for testing purposes
1312
/// </summary>
14-
public static class Defaults {
13+
internal static class Defaults {
14+
internal static readonly Random R = new(DateTime.Now.Millisecond);
15+
1516
/// <summary>
1617
/// Defines default decoded values and objects udśed for testing purposes
1718
/// </summary>
@@ -24,12 +25,12 @@ public static class Coordinates {
2425
/// <summary>
2526
/// Defines range of invalid coordinates. Equals to decoded <seealso cref="Polyline.Invalid"/>
2627
/// </summary>
27-
//public static readonly IEnumerable<Coordinate> Invalid = [
28-
// new(149.47383, 259.06250),
29-
// new(-158.37407, 225.31250),
30-
// new(152.99363, -220.93750),
31-
// new(-144.49024, -274.37500)
32-
//];
28+
public static readonly IEnumerable<Coordinate> Invalid = [
29+
new(149.47383, 259.06250),
30+
new(-158.37407, 225.31250),
31+
new(152.99363, -220.93750),
32+
new(-144.49024, -274.37500)
33+
];
3334

3435
/// <summary>
3536
/// Defines range of valid coordinates. Equals to decoded <seealso cref="Polyline.Valid"/>
@@ -61,4 +62,12 @@ public static class Polyline {
6162
/// </summary>
6263
public static readonly string Valid = "mz}lHssngJj`gqSnx~lEcovfTnms{Zdy~qQj_deI";
6364
}
65+
66+
public static class MalformedPolylineException {
67+
public static readonly int Position = R.Next();
68+
}
69+
70+
public static class InvalidCoordinateException {
71+
public static readonly Coordinate Coordinate = new(R.NextDouble(), R.NextDouble());
72+
}
6473
}

0 commit comments

Comments
 (0)