From 44366de9845f222f84850db0cd3037ea85bab56e Mon Sep 17 00:00:00 2001 From: Xavier Fischer Date: Mon, 4 Nov 2024 23:49:31 +0100 Subject: [PATCH 1/5] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2667bd2..cfeb781 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Build and Test](https://github.com/GeoJSON-Net/GeoJSON.Text/actions/workflows/ci-build.yml/badge.svg?branch=main)](https://github.com/GeoJSON-Net/GeoJSON.Text/actions/workflows/ci-build.yml) [![codecov](https://codecov.io/gh/GeoJSON-Net/GeoJSON.Text/branch/main/graph/badge.svg?token=SE9XY1T8XO)](https://codecov.io/gh/GeoJSON-Net/GeoJSON.Text) +[![NuGet Version](http://img.shields.io/nuget/v/GeoJSON.Text.svg?style=flat)](https://www.nuget.org/packages/GeoJSON.Text/) [![Build and Test](https://github.com/GeoJSON-Net/GeoJSON.Text/actions/workflows/ci-build.yml/badge.svg?branch=main)](https://github.com/GeoJSON-Net/GeoJSON.Text/actions/workflows/ci-build.yml) [![codecov](https://codecov.io/gh/GeoJSON-Net/GeoJSON.Text/branch/main/graph/badge.svg?token=SE9XY1T8XO)](https://codecov.io/gh/GeoJSON-Net/GeoJSON.Text) # GeoJSON.Text GeoJSON.Text is a .NET library for the [RFC 7946 The GeoJSON Format](https://tools.ietf.org/html/rfc7946) and it uses and provides [System.Text.Json](https://docs.microsoft.com/en-us/dotnet/api/system.text.json?view=net-6.0) converters for serialization and deserialization of GeoJSON data. From aa13a7534acc3117e398526384b04cbb9c396c13 Mon Sep 17 00:00:00 2001 From: Captainpast Date: Wed, 19 Feb 2025 18:01:15 +0100 Subject: [PATCH 2/5] using generic JsonStringEnumConverter for net8.0 --- src/GeoJSON.Text/Feature/Feature.cs | 1 - src/GeoJSON.Text/Feature/FeatureCollection.cs | 2 -- src/GeoJSON.Text/GeoJSONObject.cs | 1 - src/GeoJSON.Text/GeoJSONObjectType.cs | 6 ++++++ src/GeoJSON.Text/Geometry/GeometryCollection.cs | 1 - src/GeoJSON.Text/Geometry/IGeometryObject.cs | 1 - src/GeoJSON.Text/Geometry/LineString.cs | 1 - src/GeoJSON.Text/Geometry/MultiLineString.cs | 1 - src/GeoJSON.Text/Geometry/MultiPoint.cs | 1 - src/GeoJSON.Text/Geometry/MultiPolygon.cs | 1 - src/GeoJSON.Text/Geometry/Point.cs | 1 - src/GeoJSON.Text/Geometry/Polygon.cs | 1 - 12 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/GeoJSON.Text/Feature/Feature.cs b/src/GeoJSON.Text/Feature/Feature.cs index 5568519..ba4d2bd 100644 --- a/src/GeoJSON.Text/Feature/Feature.cs +++ b/src/GeoJSON.Text/Feature/Feature.cs @@ -49,7 +49,6 @@ public Feature(IGeometryObject geometry, TProps properties, string id = null) [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public override GeoJSONObjectType Type => GeoJSONObjectType.Feature; [JsonPropertyName( "id")] diff --git a/src/GeoJSON.Text/Feature/FeatureCollection.cs b/src/GeoJSON.Text/Feature/FeatureCollection.cs index 8caeefc..2e1243e 100644 --- a/src/GeoJSON.Text/Feature/FeatureCollection.cs +++ b/src/GeoJSON.Text/Feature/FeatureCollection.cs @@ -37,7 +37,6 @@ public FeatureCollection(List features) [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public override GeoJSONObjectType Type => GeoJSONObjectType.FeatureCollection; /// @@ -156,7 +155,6 @@ public FeatureCollection(List> features) [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public override GeoJSONObjectType Type => GeoJSONObjectType.FeatureCollection; /// diff --git a/src/GeoJSON.Text/GeoJSONObject.cs b/src/GeoJSON.Text/GeoJSONObject.cs index 2e69d81..8adf906 100644 --- a/src/GeoJSON.Text/GeoJSONObject.cs +++ b/src/GeoJSON.Text/GeoJSONObject.cs @@ -55,7 +55,6 @@ public abstract class GeoJSONObject : IGeoJSONObject, IEqualityComparer [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public abstract GeoJSONObjectType Type { get; } diff --git a/src/GeoJSON.Text/GeoJSONObjectType.cs b/src/GeoJSON.Text/GeoJSONObjectType.cs index ed3ae0e..b8d8582 100644 --- a/src/GeoJSON.Text/GeoJSONObjectType.cs +++ b/src/GeoJSON.Text/GeoJSONObjectType.cs @@ -1,12 +1,18 @@ // Copyright © Joerg Battermann 2014, Matt Hunt 2017 using System.Runtime.Serialization; +using System.Text.Json.Serialization; namespace GeoJSON.Text { /// /// Defines the GeoJSON Objects types. /// +#if NET8_0_OR_GREATER + [JsonConverter(typeof(JsonStringEnumConverter))] +#else + [JsonConverter(typeof(JsonStringEnumConverter))] +#endif public enum GeoJSONObjectType { /// diff --git a/src/GeoJSON.Text/Geometry/GeometryCollection.cs b/src/GeoJSON.Text/Geometry/GeometryCollection.cs index ee32cbb..3381eff 100644 --- a/src/GeoJSON.Text/Geometry/GeometryCollection.cs +++ b/src/GeoJSON.Text/Geometry/GeometryCollection.cs @@ -36,7 +36,6 @@ public GeometryCollection(IEnumerable geometries) [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public override GeoJSONObjectType Type => GeoJSONObjectType.GeometryCollection; /// diff --git a/src/GeoJSON.Text/Geometry/IGeometryObject.cs b/src/GeoJSON.Text/Geometry/IGeometryObject.cs index 9fe7592..c757537 100644 --- a/src/GeoJSON.Text/Geometry/IGeometryObject.cs +++ b/src/GeoJSON.Text/Geometry/IGeometryObject.cs @@ -23,7 +23,6 @@ public interface IGeometryObject /// The type of the object. /// [JsonPropertyName("type")] - [JsonConverter(typeof(JsonStringEnumConverter))] GeoJSONObjectType Type { get; } } } diff --git a/src/GeoJSON.Text/Geometry/LineString.cs b/src/GeoJSON.Text/Geometry/LineString.cs index 1b17959..797b7ff 100644 --- a/src/GeoJSON.Text/Geometry/LineString.cs +++ b/src/GeoJSON.Text/Geometry/LineString.cs @@ -52,7 +52,6 @@ public LineString(IEnumerable coordinates) [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public override GeoJSONObjectType Type => GeoJSONObjectType.LineString; /// diff --git a/src/GeoJSON.Text/Geometry/MultiLineString.cs b/src/GeoJSON.Text/Geometry/MultiLineString.cs index c33f99e..9b349a4 100644 --- a/src/GeoJSON.Text/Geometry/MultiLineString.cs +++ b/src/GeoJSON.Text/Geometry/MultiLineString.cs @@ -46,7 +46,6 @@ public MultiLineString(IEnumerable>> coordinates [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public override GeoJSONObjectType Type => GeoJSONObjectType.MultiLineString; /// diff --git a/src/GeoJSON.Text/Geometry/MultiPoint.cs b/src/GeoJSON.Text/Geometry/MultiPoint.cs index cb97fe7..307fc04 100644 --- a/src/GeoJSON.Text/Geometry/MultiPoint.cs +++ b/src/GeoJSON.Text/Geometry/MultiPoint.cs @@ -40,7 +40,6 @@ public MultiPoint(IEnumerable> coordinates) [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public override GeoJSONObjectType Type => GeoJSONObjectType.MultiPoint; /// diff --git a/src/GeoJSON.Text/Geometry/MultiPolygon.cs b/src/GeoJSON.Text/Geometry/MultiPolygon.cs index 3c9b261..66342a9 100644 --- a/src/GeoJSON.Text/Geometry/MultiPolygon.cs +++ b/src/GeoJSON.Text/Geometry/MultiPolygon.cs @@ -42,7 +42,6 @@ public MultiPolygon(IEnumerable>>> c [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public override GeoJSONObjectType Type => GeoJSONObjectType.MultiPolygon; /// diff --git a/src/GeoJSON.Text/Geometry/Point.cs b/src/GeoJSON.Text/Geometry/Point.cs index 19724a0..7db90f9 100644 --- a/src/GeoJSON.Text/Geometry/Point.cs +++ b/src/GeoJSON.Text/Geometry/Point.cs @@ -31,7 +31,6 @@ public Point(IPosition coordinates) [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public override GeoJSONObjectType Type => GeoJSONObjectType.Point; /// diff --git a/src/GeoJSON.Text/Geometry/Polygon.cs b/src/GeoJSON.Text/Geometry/Polygon.cs index 6c78a53..aa55cbc 100644 --- a/src/GeoJSON.Text/Geometry/Polygon.cs +++ b/src/GeoJSON.Text/Geometry/Polygon.cs @@ -57,7 +57,6 @@ public Polygon(IEnumerable>> coordinates) [JsonPropertyName("type")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] - [JsonConverter(typeof(JsonStringEnumConverter))] public override GeoJSONObjectType Type => GeoJSONObjectType.Polygon; /// From a5e6693e9c0e6d5483a4dad35f8860e019bf1684 Mon Sep 17 00:00:00 2001 From: Captainpast Date: Wed, 19 Feb 2025 18:02:35 +0100 Subject: [PATCH 3/5] Define the type of CrsConverter --- src/GeoJSON.Text/Converters/CrsConverter.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/GeoJSON.Text/Converters/CrsConverter.cs b/src/GeoJSON.Text/Converters/CrsConverter.cs index 5fadd87..d4d8674 100644 --- a/src/GeoJSON.Text/Converters/CrsConverter.cs +++ b/src/GeoJSON.Text/Converters/CrsConverter.cs @@ -10,7 +10,7 @@ namespace GeoJSON.Text.Converters /// /// Converts types to and from JSON. /// - public class CrsConverter : JsonConverter + public class CrsConverter : JsonConverter { public override bool HandleNull => true; @@ -41,7 +41,7 @@ public override bool CanConvert(Type objectType) /// or /// CRS must have a "type" property /// - public override object Read( + public override ICRSObject Read( ref Utf8JsonReader reader, Type type, JsonSerializerOptions options) @@ -106,7 +106,8 @@ public override object Read( } } - return new NotSupportedException(string.Format("Type {0} unexpected.", crsType)); + //return new NotSupportedException(string.Format("Type {0} unexpected.", crsType)); + return null; } /// @@ -118,7 +119,7 @@ public override object Read( /// public override void Write( Utf8JsonWriter writer, - object crsValue, + ICRSObject crsValue, JsonSerializerOptions options) { var value = (ICRSObject)crsValue; From 0ec813bb517d8c2e19faa084b296181db769cfea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Grafstr=C3=B6m?= Date: Fri, 28 Feb 2025 11:23:01 +0100 Subject: [PATCH 4/5] Handle null altitudes when reading positions --- .../GeoJSON.Text.Test.Unit.csproj | 4 + .../Geometry/LineStringTests.cs | 25 ++++++ ...ngTests_Can_Deserialize_With_Altitude.json | 9 ++ .../Converters/PositionConverter.cs | 85 +++++++++++++++++-- 4 files changed, 114 insertions(+), 9 deletions(-) create mode 100644 src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_With_Altitude.json diff --git a/src/GeoJSON.Text.Test.Unit/GeoJSON.Text.Test.Unit.csproj b/src/GeoJSON.Text.Test.Unit/GeoJSON.Text.Test.Unit.csproj index 8b52673..4be94e0 100644 --- a/src/GeoJSON.Text.Test.Unit/GeoJSON.Text.Test.Unit.csproj +++ b/src/GeoJSON.Text.Test.Unit/GeoJSON.Text.Test.Unit.csproj @@ -22,6 +22,7 @@ + @@ -76,6 +77,9 @@ + + + Always diff --git a/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs index 0f77d8a..2855a2c 100644 --- a/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs +++ b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs @@ -83,6 +83,31 @@ public void Can_Deserialize() Assert.AreEqual(expectedLineString.Coordinates[0].Longitude, actualLineString.Coordinates[0].Longitude); } + [Test] + public void Can_Deserialize_With_Altitude() + { + var coordinates = new List + { + new Position(52.370725881211314, 4.889259338378906, 10.0), + new Position(52.3711451105601, 4.895267486572266, 10.5), + new Position(52.36931095278263, 4.892091751098633, null), + new Position(52.370725881211314, 4.889259338378906, 10.2) + }; + + var expectedLineString = new LineString(coordinates); + + var json = GetExpectedJson(); + var actualLineString = JsonSerializer.Deserialize(json); + + Assert.AreEqual(expectedLineString, actualLineString); + + Assert.AreEqual(4, actualLineString.Coordinates.Count); + Assert.AreEqual(expectedLineString.Coordinates[0].Latitude, actualLineString.Coordinates[0].Latitude); + Assert.AreEqual(expectedLineString.Coordinates[0].Longitude, actualLineString.Coordinates[0].Longitude); + Assert.AreEqual(expectedLineString.Coordinates[0].Altitude, actualLineString.Coordinates[0].Altitude); + Assert.AreEqual(expectedLineString.Coordinates[2].Altitude, actualLineString.Coordinates[2].Altitude); + } + [Test] public void Constructor_No_Coordinates_Throws_Exception() { diff --git a/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_With_Altitude.json b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_With_Altitude.json new file mode 100644 index 0000000..f0ed4f0 --- /dev/null +++ b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_With_Altitude.json @@ -0,0 +1,9 @@ +{ + "coordinates": [ + [4.8892593383789062, 52.370725881211314, 10.0], + [4.8952674865722656, 52.3711451105601, 10.5], + [4.8920917510986328, 52.369310952782627, null], + [4.8892593383789062, 52.370725881211314, 10.2] + ], + "type": "LineString" +} \ No newline at end of file diff --git a/src/GeoJSON.Text/Converters/PositionConverter.cs b/src/GeoJSON.Text/Converters/PositionConverter.cs index 58abb40..0ab9947 100644 --- a/src/GeoJSON.Text/Converters/PositionConverter.cs +++ b/src/GeoJSON.Text/Converters/PositionConverter.cs @@ -2,6 +2,7 @@ using GeoJSON.Text.Geometry; using System; +using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; @@ -28,10 +29,9 @@ public override bool CanConvert(Type objectType) /// /// Reads the JSON representation of the object. /// - /// The to read from. - /// Type of the object. - /// The existing value of object being read. - /// The calling serializer. + /// The to read from. + /// Type of the object. + /// Serializer options. /// /// The object value. /// @@ -40,17 +40,84 @@ public override IPosition Read( Type type, JsonSerializerOptions options) { - double[] coordinates; - try - { - coordinates = JsonSerializer.Deserialize(ref reader, options); + { + if (reader.TokenType != JsonTokenType.StartArray) + { + throw new ArgumentException("Expected start of array"); + } + + double lng, lat; + double? alt; + + // Read longitude + if (!reader.Read()) + { + throw new ArgumentException("Expected number, but got end of data"); + } + if (reader.TokenType == JsonTokenType.EndArray) + { + throw new ArgumentException("Expected 2 or 3 coordinates but got 0"); + } + if (reader.TokenType != JsonTokenType.Number) + { + throw new ArgumentException("Expected number but got other type"); + } + lng = reader.GetDouble(); + + // Read latitude + if (!reader.Read()) + { + throw new ArgumentException("Expected number, but got end of data"); + } + if (reader.TokenType == JsonTokenType.EndArray) + { + throw new ArgumentException("Expected 2 or 3 coordinates but got 1"); + } + if (reader.TokenType != JsonTokenType.Number) + { + throw new ArgumentException("Expected number but got other type"); + } + lat = reader.GetDouble(); + + // Read altitude, or return if end of array is found + if (!reader.Read()) + { + throw new ArgumentException("Unexpected end of data"); + } + if (reader.TokenType == JsonTokenType.EndArray) + { + return new Position(lat, lng); + } + else if (reader.TokenType == JsonTokenType.Null) + { + alt = null; + } + else if (reader.TokenType == JsonTokenType.Number) + { + alt = reader.GetDouble(); + } + else + { + throw new ArgumentException("Expected number but got other type"); + } + + // Check what comes next. Expects end of array. + if (!reader.Read()) + { + throw new ArgumentException("Expected end of array, but got end of data"); + } + if (reader.TokenType != JsonTokenType.EndArray) + { + throw new ArgumentException("Expected 2 or 3 coordinates but got >= 4"); + } + + return new Position(lat, lng, alt); } catch (Exception e) { throw new JsonException("Error parsing coordinates", e); } - return coordinates?.ToPosition() ?? throw new JsonException("Coordinates cannot be null"); } /// From e51f9b56e94b28d2db304b07f4606955934c4491 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Grafstr=C3=B6m?= Date: Fri, 28 Feb 2025 13:41:59 +0100 Subject: [PATCH 5/5] Restore support for serializer options when reading positions --- .../GeoJSON.Text.Test.Unit.csproj | 4 ++ .../Geometry/LineStringTests.cs | 52 +++++++++++++++++++ ...Tests_Can_Deserialize_String_Literals.json | 9 ++++ ...neStringTests_Can_Deserialize_Strings.json | 9 ++++ .../Converters/PositionConverter.cs | 30 +++++++++-- .../DoubleTenDecimalPlaceComparer.cs | 5 +- 6 files changed, 104 insertions(+), 5 deletions(-) create mode 100644 src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_String_Literals.json create mode 100644 src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_Strings.json diff --git a/src/GeoJSON.Text.Test.Unit/GeoJSON.Text.Test.Unit.csproj b/src/GeoJSON.Text.Test.Unit/GeoJSON.Text.Test.Unit.csproj index 4be94e0..af09af1 100644 --- a/src/GeoJSON.Text.Test.Unit/GeoJSON.Text.Test.Unit.csproj +++ b/src/GeoJSON.Text.Test.Unit/GeoJSON.Text.Test.Unit.csproj @@ -22,6 +22,8 @@ + + @@ -49,6 +51,8 @@ + + diff --git a/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs index 2855a2c..63d9b56 100644 --- a/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs +++ b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs @@ -83,6 +83,30 @@ public void Can_Deserialize() Assert.AreEqual(expectedLineString.Coordinates[0].Longitude, actualLineString.Coordinates[0].Longitude); } + [Test] + public void Can_Deserialize_Strings() + { + var coordinates = new List + { + new Position(52.370725881211314, 4.889259338378906), + new Position(52.3711451105601, 4.895267486572266), + new Position(52.36931095278263, 4.892091751098633), + new Position(52.370725881211314, 4.889259338378906) + }; + + var expectedLineString = new LineString(coordinates); + + var json = GetExpectedJson(); + var options = new JsonSerializerOptions { NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowReadingFromString }; + var actualLineString = JsonSerializer.Deserialize(json, options); + + Assert.AreEqual(expectedLineString, actualLineString); + + Assert.AreEqual(4, actualLineString.Coordinates.Count); + Assert.AreEqual(expectedLineString.Coordinates[0].Latitude, actualLineString.Coordinates[0].Latitude); + Assert.AreEqual(expectedLineString.Coordinates[0].Longitude, actualLineString.Coordinates[0].Longitude); + } + [Test] public void Can_Deserialize_With_Altitude() { @@ -108,6 +132,34 @@ public void Can_Deserialize_With_Altitude() Assert.AreEqual(expectedLineString.Coordinates[2].Altitude, actualLineString.Coordinates[2].Altitude); } + [Test] + public void Can_Deserialize_String_Literals() + { + var coordinates = new List + { + new Position(52.370725881211314, 4.889259338378906, double.NegativeInfinity), + new Position(52.3711451105601, 4.895267486572266, double.PositiveInfinity), + new Position(52.36931095278263, 4.892091751098633, double.NaN), + new Position(52.370725881211314, 4.889259338378906, double.NegativeInfinity) + }; + + var expectedLineString = new LineString(coordinates); + + var json = GetExpectedJson(); + var options = new JsonSerializerOptions { NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals }; + var actualLineString = JsonSerializer.Deserialize(json, options); + + bool b = expectedLineString.Coordinates[0].Equals(actualLineString.Coordinates[0]); + Assert.AreEqual(expectedLineString, actualLineString); + + Assert.AreEqual(4, actualLineString.Coordinates.Count); + Assert.AreEqual(expectedLineString.Coordinates[0].Latitude, actualLineString.Coordinates[0].Latitude); + Assert.AreEqual(expectedLineString.Coordinates[0].Longitude, actualLineString.Coordinates[0].Longitude); + Assert.AreEqual(expectedLineString.Coordinates[0].Altitude, actualLineString.Coordinates[0].Altitude); + Assert.AreEqual(expectedLineString.Coordinates[1].Altitude, actualLineString.Coordinates[1].Altitude); + Assert.AreEqual(expectedLineString.Coordinates[2].Altitude, actualLineString.Coordinates[2].Altitude); + } + [Test] public void Constructor_No_Coordinates_Throws_Exception() { diff --git a/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_String_Literals.json b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_String_Literals.json new file mode 100644 index 0000000..594d58f --- /dev/null +++ b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_String_Literals.json @@ -0,0 +1,9 @@ +{ + "coordinates": [ + [4.8892593383789062, 52.370725881211314, "-Infinity"], + [4.8952674865722656, 52.3711451105601, "Infinity"], + [4.8920917510986328, 52.369310952782627, "NaN"], + [4.8892593383789062, 52.370725881211314, "-Infinity"] + ], + "type": "LineString" +} \ No newline at end of file diff --git a/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_Strings.json b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_Strings.json new file mode 100644 index 0000000..7c5a502 --- /dev/null +++ b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests_Can_Deserialize_Strings.json @@ -0,0 +1,9 @@ +{ + "coordinates": [ + ["4.8892593383789062", "52.370725881211314"], + ["4.8952674865722656", "52.3711451105601"], + ["4.8920917510986328", "52.369310952782627"], + ["4.8892593383789062", "52.370725881211314"] + ], + "type": "LineString" +} \ No newline at end of file diff --git a/src/GeoJSON.Text/Converters/PositionConverter.cs b/src/GeoJSON.Text/Converters/PositionConverter.cs index 0ab9947..995b8b9 100644 --- a/src/GeoJSON.Text/Converters/PositionConverter.cs +++ b/src/GeoJSON.Text/Converters/PositionConverter.cs @@ -55,30 +55,48 @@ public override IPosition Read( { throw new ArgumentException("Expected number, but got end of data"); } + if (reader.TokenType == JsonTokenType.EndArray) { throw new ArgumentException("Expected 2 or 3 coordinates but got 0"); } - if (reader.TokenType != JsonTokenType.Number) + + if (reader.TokenType == JsonTokenType.Number) + { + lng = reader.GetDouble(); + } + else if (reader.TokenType == JsonTokenType.String) + { + lng = JsonSerializer.Deserialize(ref reader, options); + } + else { throw new ArgumentException("Expected number but got other type"); } - lng = reader.GetDouble(); // Read latitude if (!reader.Read()) { throw new ArgumentException("Expected number, but got end of data"); } + if (reader.TokenType == JsonTokenType.EndArray) { throw new ArgumentException("Expected 2 or 3 coordinates but got 1"); } - if (reader.TokenType != JsonTokenType.Number) + + if (reader.TokenType == JsonTokenType.Number) + { + lat = reader.GetDouble(); + } + else if (reader.TokenType == JsonTokenType.String) + { + lat = JsonSerializer.Deserialize(ref reader, options); + } + else { throw new ArgumentException("Expected number but got other type"); } - lat = reader.GetDouble(); // Read altitude, or return if end of array is found if (!reader.Read()) @@ -97,6 +115,10 @@ public override IPosition Read( { alt = reader.GetDouble(); } + else if (reader.TokenType == JsonTokenType.String) + { + alt = JsonSerializer.Deserialize(ref reader, options); + } else { throw new ArgumentException("Expected number but got other type"); diff --git a/src/GeoJSON.Text/DoubleTenDecimalPlaceComparer.cs b/src/GeoJSON.Text/DoubleTenDecimalPlaceComparer.cs index dbe75c5..da7aec0 100644 --- a/src/GeoJSON.Text/DoubleTenDecimalPlaceComparer.cs +++ b/src/GeoJSON.Text/DoubleTenDecimalPlaceComparer.cs @@ -15,7 +15,10 @@ public class DoubleTenDecimalPlaceComparer : IEqualityComparer { public bool Equals(double x, double y) { - return Math.Abs(x - y) < 0.0000000001; + return (double.IsNaN(x) && double.IsNaN(y)) || + (double.IsInfinity(x) && double.IsInfinity(y)) || + (double.IsNegativeInfinity(x) && double.IsNegativeInfinity(y)) || + Math.Abs(x - y) < 0.0000000001; } public int GetHashCode(double obj)