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..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,9 @@
+
+
+
@@ -48,6 +51,8 @@
+
+
@@ -76,6 +81,9 @@
+
+
+
Always
diff --git a/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs
index 0f77d8a..63d9b56 100644
--- a/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs
+++ b/src/GeoJSON.Text.Test.Unit/Geometry/LineStringTests.cs
@@ -83,6 +83,83 @@ 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()
+ {
+ 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 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.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..995b8b9 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,106 @@ 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)
+ {
+ 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");
+ }
+
+ // 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)
+ {
+ 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");
+ }
+
+ // 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 if (reader.TokenType == JsonTokenType.String)
+ {
+ alt = JsonSerializer.Deserialize(ref reader, options);
+ }
+ 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");
}
///
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)