Skip to content

Commit 101b813

Browse files
committed
Respect the PrecisionModel grid when serializing coordinates. (NetTopologySuite#135)
1 parent 0393f41 commit 101b813

File tree

5 files changed

+78
-16
lines changed

5 files changed

+78
-16
lines changed

src/NetTopologySuite.IO.GeoJSON4STJ/Converters/GeoJsonConverterFactory.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializer
202202
if (GeometryTypes.Contains(typeToConvert))
203203
return new StjGeometryConverter(_factory, _writeGeometryBBox, _ringOrientationOption);
204204
if (typeToConvert == typeof(Envelope))
205-
return new StjEnvelopeConverter();
205+
return new StjEnvelopeConverter(_factory.PrecisionModel);
206206
if (typeToConvert == typeof(FeatureCollection))
207207
return new StjFeatureCollectionConverter(_writeGeometryBBox);
208208
if (typeof(IFeature).IsAssignableFrom(typeToConvert))

src/NetTopologySuite.IO.GeoJSON4STJ/Converters/StjEnvelopeConverter.cs

+16-11
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
using NetTopologySuite.Geometries;
22
using System;
3-
using System.Collections.Generic;
4-
using System.Text;
53
using System.Text.Json;
64
using System.Text.Json.Serialization;
75

86
namespace NetTopologySuite.IO.Converters
97
{
108
internal class StjEnvelopeConverter : JsonConverter<Envelope>
119
{
10+
private readonly PrecisionModel _precisionModel;
11+
12+
public StjEnvelopeConverter(PrecisionModel precisionModel)
13+
{
14+
_precisionModel = precisionModel;
15+
}
16+
1217
public override Envelope Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
1318
{
1419
Envelope res = null;
@@ -22,19 +27,19 @@ public override Envelope Read(ref Utf8JsonReader reader, Type typeToConvert, Jso
2227
{
2328
reader.ReadToken(JsonTokenType.StartArray);
2429

25-
double minX = reader.GetDouble();
30+
double minX = reader.GetDouble(_precisionModel);
2631
reader.Read();
27-
double minY = reader.GetDouble();
32+
double minY = reader.GetDouble(_precisionModel);
2833
reader.Read();
29-
double maxX = reader.GetDouble();
34+
double maxX = reader.GetDouble(_precisionModel);
3035
reader.Read();
31-
double maxY = reader.GetDouble();
36+
double maxY = reader.GetDouble(_precisionModel);
3237
reader.Read();
3338

3439
if (reader.TokenType == JsonTokenType.Number)
3540
{
3641
maxX = maxY;
37-
maxY = reader.GetDouble();
42+
maxY = reader.GetDouble(_precisionModel);
3843
reader.Read();
3944
reader.Read();
4045
}
@@ -59,10 +64,10 @@ public override void Write(Utf8JsonWriter writer, Envelope value, JsonSerializer
5964
}
6065

6166
writer.WriteStartArray();
62-
writer.WriteNumberValue(value.MinX);
63-
writer.WriteNumberValue(value.MinY);
64-
writer.WriteNumberValue(value.MaxX);
65-
writer.WriteNumberValue(value.MaxY);
67+
writer.WriteNumberValue(value.MinX, _precisionModel);
68+
writer.WriteNumberValue(value.MinY, _precisionModel);
69+
writer.WriteNumberValue(value.MaxX, _precisionModel);
70+
writer.WriteNumberValue(value.MaxY, _precisionModel);
6671
writer.WriteEndArray();
6772
}
6873
}

src/NetTopologySuite.IO.GeoJSON4STJ/Converters/StjGeometryConverter.Coordinates.cs

+5-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ internal partial class StjGeometryConverter
88
{
99
private void WriteCoordinateSequence(Utf8JsonWriter writer, CoordinateSequence sequence, JsonSerializerOptions options, bool multiple = true, OrientationIndex orientation = OrientationIndex.None)
1010
{
11-
//writer.WritePropertyName("coordinates");
1211
if (sequence == null)
1312
{
1413
writer.WriteNullValue();
@@ -29,15 +28,17 @@ private void WriteCoordinateSequence(Utf8JsonWriter writer, CoordinateSequence s
2928
for (int i = 0; i < sequence.Count; i++)
3029
{
3130
writer.WriteStartArray();
32-
writer.WriteNumberValue(sequence.GetX(i));
33-
writer.WriteNumberValue(sequence.GetY(i));
31+
32+
writer.WriteNumberValue(sequence.GetX(i), _geometryFactory.PrecisionModel);
33+
writer.WriteNumberValue(sequence.GetY(i), _geometryFactory.PrecisionModel);
3434

3535
if (hasZ)
3636
{
3737
double z = sequence.GetZ(i);
3838
if (!double.IsNaN(z))
39-
writer.WriteNumberValue(sequence.GetZ(i));
39+
writer.WriteNumberValue(z, _geometryFactory.PrecisionModel);
4040
}
41+
4142
writer.WriteEndArray();
4243

4344
if (!multiple) break;

src/NetTopologySuite.IO.GeoJSON4STJ/Converters/Utility.cs

+19
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Text.Json.Nodes;
66
using System.Text.Json.Serialization;
77
using NetTopologySuite.Features;
8+
using NetTopologySuite.Geometries;
89
using NetTopologySuite.IO.Properties;
910

1011
namespace NetTopologySuite.IO.Converters
@@ -94,5 +95,23 @@ private static void ThrowForUnexpectedEndOfStream()
9495
[MethodImpl(MethodImplOptions.NoInlining)]
9596
private static void ThrowForUnexpectedToken(JsonTokenType requiredNextTokenType, ref Utf8JsonReader reader)
9697
=> throw new JsonException(string.Format(Resources.EX_UnexpectedToken, requiredNextTokenType, reader.TokenType, reader.GetString()));
98+
99+
/// <summary>
100+
/// Parses the current JSON token value from the source as a <see cref="double"/>. Rounds a value to the <see cref="PrecisionModel"/> grid.
101+
/// </summary>
102+
/// <param name="reader">The reader.</param>
103+
/// <param name="precisionModel">The precision model to round to.</param>
104+
/// <returns>The rounded value</returns>
105+
internal static double GetDouble(this Utf8JsonReader reader, PrecisionModel precisionModel)
106+
=> precisionModel.MakePrecise(reader.GetDouble());
107+
108+
/// <summary>
109+
/// Rounds a <see cref="double"/> value to the <see cref="PrecisionModel"/> grid. Writes the rounded value (as a JSON number) as an element of a JSON array.
110+
/// </summary>
111+
/// <param name="writer">The writer.</param>
112+
/// <param name="value">The value to write.</param>
113+
/// <param name="precisionModel">The precision model to round to.</param>
114+
internal static void WriteNumberValue(this Utf8JsonWriter writer, double value, PrecisionModel precisionModel)
115+
=> writer.WriteNumberValue(precisionModel.MakePrecise(value));
97116
}
98117
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
using NetTopologySuite.Geometries;
2+
using NetTopologySuite.IO.Converters;
3+
using NetTopologySuite.IO.GeoJSON4STJ.Test.Converters;
4+
using NUnit.Framework;
5+
using System.Text.Json;
6+
7+
namespace NetTopologySuite.IO.GeoJSON4STJ.Test.Issues
8+
{
9+
internal class Issue135 : SandDTest<Geometry>
10+
{
11+
[Test, GeoJsonIssueNumber(135)]
12+
public void TestOutputPrecision()
13+
{
14+
var coords = new[]
15+
{
16+
new Coordinate(0.001, 0.001),
17+
new Coordinate(10.1, 0.002),
18+
new Coordinate(10, 10.1),
19+
new Coordinate(0.05, 9.999),
20+
new Coordinate(0.001, 0.001)
21+
};
22+
var factory = new GeometryFactory(new PrecisionModel(10), 4326);
23+
var polygon = factory.CreatePolygon(coords);
24+
25+
string json = JsonSerializer.Serialize(polygon, new JsonSerializerOptions
26+
{
27+
ReadCommentHandling = JsonCommentHandling.Skip,
28+
Converters =
29+
{
30+
new GeoJsonConverterFactory(factory)
31+
}
32+
});
33+
34+
Assert.That(json, Is.EqualTo("{\"type\":\"Polygon\",\"coordinates\":[[[0,0],[10.1,0],[10,10.1],[0.1,10],[0,0]]]}"));
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)