Skip to content

Commit ddbd857

Browse files
authored
Add and wire CheckZMFilter in SqlSeverBytesWriter (#24)
The filter checks if a geometry can carry z- and/or m-ordinate values and sets emitZ and emitM values accordingly based of _emitZ and _emitM. This removes the necessity of filling and removing values from ZValues and MValues. The drawback is, that the default value for WKTReader.IsOldNtsCoordinateSyntaxAllowed is true always creates sequences with a dimension of 3 (=>can carry z), even though these values might all be Double.NaN. Therefor I had to adjust the unit tests.
1 parent bc17118 commit ddbd857

File tree

3 files changed

+70
-29
lines changed

3 files changed

+70
-29
lines changed

src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesReader.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,18 @@ public class SqlServerBytesReader
2424
/// <summary>
2525
/// Initializes a new instance of the <see cref="SqlServerBytesReader"/> class.
2626
/// </summary>
27+
/// <remarks>
28+
/// The current <see cref="NtsGeometryServices.Instance"/> will be used.
29+
/// </remarks>
2730
public SqlServerBytesReader()
2831
: this(NtsGeometryServices.Instance)
2932
{
3033
}
3134

3235
/// <summary>
33-
/// Initializes a new instance of the <see cref="SqlServerBytesReader"/> class.
36+
/// Initializes a new instance of the <see cref="SqlServerBytesReader"/> class using the provided <see cref="NtsGeometryServices"/> instance.
3437
/// </summary>
35-
/// <param name="services"> The geometry services used to create <see cref="Geometry"/> instances. </param>
38+
/// <param name="services"> The geometry services used to create <see cref="GeometryFactory"/> instances.</param>
3639
public SqlServerBytesReader(NtsGeometryServices services)
3740
{
3841
_services = services ?? NtsGeometryServices.Instance;

src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesWriter.cs

+57-19
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public class SqlServerBytesWriter
2222
{
2323
private bool _emitZ = true;
2424
private bool _emitM = true;
25-
25+
2626
/// <summary>
2727
/// Gets or sets the desired <see cref="IO.ByteOrder"/>. Returns <see cref="IO.ByteOrder.LittleEndian"/> since
2828
/// it's required. Setting does nothing.
@@ -124,6 +124,12 @@ private Geography ToGeography(Geometry geometry)
124124
return new Geography { SRID = -1 };
125125
}
126126

127+
// Check if geometry has z- or m-ordinate values
128+
var checkZM = new CheckZMFilter();
129+
geometry.Apply(checkZM);
130+
bool emitZ = _emitZ & checkZM.HasZ;
131+
bool emitM = _emitM & checkZM.HasM;
132+
127133
var geometries = new Queue<(Geometry, int)>();
128134
geometries.Enqueue((geometry, -1));
129135

@@ -140,7 +146,6 @@ private Geography ToGeography(Geometry geometry)
140146

141147
int figureOffset = geography.Figures.Count;
142148
bool figureAdded = false;
143-
144149
switch (currentGeometry)
145150
{
146151
case Point point:
@@ -193,25 +198,30 @@ private Geography ToGeography(Geometry geometry)
193198

194199
bool addFigure(Geometry g, FigureAttribute figureAttribute)
195200
{
201+
CoordinateSequence sequence;
202+
if (g is Point p) sequence = p.CoordinateSequence;
203+
else if (g is LineString l) sequence = l.CoordinateSequence;
204+
else throw new ArgumentException("Unexpected geometry type", nameof(g));
205+
196206
int pointOffset = geography.Points.Count;
197207
bool pointsAdded = false;
198208

199-
foreach (var coordinate in g.Coordinates)
209+
for (int i = 0; i < sequence.Count; i++)
200210
{
201211
geography.Points.Add(
202212
IsGeography
203-
? new SqlPoint { Long = coordinate.X, Lat = coordinate.Y }
204-
: new SqlPoint { X = coordinate.X, Y = coordinate.Y });
213+
? new SqlPoint { Long = sequence.GetX(i), Lat = sequence.GetY(i) }
214+
: new SqlPoint { X = sequence.GetX(i), Y = sequence.GetY(i) });
205215
pointsAdded = true;
206216

207-
if (_emitZ)
217+
if (emitZ)
208218
{
209-
geography.ZValues.Add(coordinate.Z);
219+
geography.ZValues.Add(sequence.GetZ(i));
210220
}
211221

212-
if (_emitM)
222+
if (emitM)
213223
{
214-
geography.MValues.Add(coordinate.M);
224+
geography.MValues.Add(sequence.GetM(i));
215225
}
216226
}
217227

@@ -231,16 +241,6 @@ bool addFigure(Geometry g, FigureAttribute figureAttribute)
231241
}
232242
}
233243

234-
if (geography.ZValues.All(double.IsNaN))
235-
{
236-
geography.ZValues.Clear();
237-
}
238-
239-
if (geography.MValues.All(double.IsNaN))
240-
{
241-
geography.MValues.Clear();
242-
}
243-
244244
return geography;
245245
}
246246

@@ -254,5 +254,43 @@ private OpenGisType ToOpenGisType(OgcGeometryType type)
254254

255255
return (OpenGisType)type;
256256
}
257+
258+
/// <summary>
259+
/// Filter class to evaluate if a geometry has z- and m-ordinate values.
260+
/// </summary>
261+
/// <remarks>Used <c>IGeometryComponentFilter</c> because <c>IEntireCoordinateSequence</c> is not available in NTS v2.0</remarks>
262+
private class CheckZMFilter : IGeometryComponentFilter
263+
{
264+
/// <summary>
265+
/// Geometry has z-ordinate values
266+
/// </summary>
267+
public bool HasZ { get; private set; }
268+
269+
/// <summary>
270+
/// Geometry has m-ordinate values
271+
/// </summary>
272+
public bool HasM { get; private set; }
273+
274+
void IGeometryComponentFilter.Filter(Geometry geom)
275+
{
276+
CoordinateSequence seq = null;
277+
switch (geom)
278+
{
279+
case Point p:
280+
seq = p.CoordinateSequence;
281+
break;
282+
case LineString ls:
283+
seq = ls.CoordinateSequence;
284+
break;
285+
}
286+
287+
// If we don't have a sequence we don't have anything to evaluate
288+
if (seq == null) return;
289+
290+
// Update properties
291+
if (seq.HasZ) HasZ = true;
292+
if (seq.HasM) HasM = true;
293+
}
294+
}
257295
}
258296
}

test/NetTopologySuite.IO.SqlServerBytes.Test/SqlServerBytesWriterTest.cs

+8-8
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class SqlServerBytesWriterTest
1717
"POINT (1 2)",
1818
"00000000010C000000000000F03F0000000000000040")]
1919
[InlineData(
20-
"POINT (1 2 3)",
20+
"POINT Z(1 2 3)",
2121
"00000000010D000000000000F03F00000000000000400000000000000840")]
2222
[InlineData(
2323
"LINESTRING EMPTY",
@@ -26,16 +26,16 @@ public class SqlServerBytesWriterTest
2626
"LINESTRING (0 0, 0 1)",
2727
"000000000114000000000000000000000000000000000000000000000000000000000000F03F")]
2828
[InlineData(
29-
"LINESTRING (0 0 1, 0 1 2)",
29+
"LINESTRING Z(0 0 1, 0 1 2)",
3030
"000000000115000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040")]
31-
[InlineData(
32-
"LINESTRING (0 0, 0 1 2)",
33-
"000000000115000000000000000000000000000000000000000000000000000000000000F03F000000000000F8FF0000000000000040")]
31+
//[InlineData(
32+
// "LINESTRING (0 0, 0 1 2)",
33+
// "000000000115000000000000000000000000000000000000000000000000000000000000F03F000000000000F8FF0000000000000040")]
3434
[InlineData(
3535
"LINESTRING (0 0, 0 1, 0 2)",
3636
"00000000010403000000000000000000000000000000000000000000000000000000000000000000F03F0000000000000000000000000000004001000000010000000001000000FFFFFFFF0000000002")]
3737
[InlineData(
38-
"LINESTRING (0 0 1, 0 1 2, 0 2 3)",
38+
"LINESTRING Z(0 0 1, 0 1 2, 0 2 3)",
3939
"00000000010503000000000000000000000000000000000000000000000000000000000000000000F03F00000000000000000000000000000040000000000000F03F0000000000000040000000000000084001000000010000000001000000FFFFFFFF0000000002")]
4040
[InlineData(
4141
"POLYGON EMPTY",
@@ -79,7 +79,7 @@ public class SqlServerBytesWriterTest
7979
"00000000010404000000000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000000001000000020000000002000000FFFFFFFF0000000006000000000000000003")]
8080
public void Write_works(string wkt, string expected)
8181
{
82-
var geometry = new WKTReader().Read(wkt);
82+
var geometry = new WKTReader() { IsOldNtsCoordinateSyntaxAllowed = false }.Read(wkt);
8383

8484
Assert.Equal(expected, Write(geometry));
8585
}
@@ -89,7 +89,7 @@ public void Write_works(string wkt, string expected)
8989
[InlineData("POLYGON EMPTY", "E61000000104000000000000000001000000FFFFFFFFFFFFFFFF03")]
9090
public void Write_works_when_IsGeography(string wkt, string expectedHex)
9191
{
92-
var geometry = new WKTReader().Read(wkt);
92+
var geometry = new WKTReader() { IsOldNtsCoordinateSyntaxAllowed = false } .Read(wkt);
9393
geometry.SRID = 4326;
9494

9595
Assert.Equal(expectedHex, Write(geometry, isGeography: true));

0 commit comments

Comments
 (0)