Skip to content

Commit ac2eee0

Browse files
Provide a custom way to validate the geometry when written to SQL. (#25)
This allows to override the default IsValid of the NTS Geometry and provide an own strategy. This way you can use the IsValidOp with the option SelfTouchingRingFormingHoleValid flagged. Or just make them all valid following the NTS way. Either way the developer will have more control, and if we would manage to provide a IsValidSqlServerOp, it could be passed this way. relates to #12
1 parent ddbd857 commit ac2eee0

File tree

2 files changed

+98
-8
lines changed

2 files changed

+98
-8
lines changed

src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesWriter.cs

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
using System;
1+
using NetTopologySuite.Geometries;
2+
using NetTopologySuite.IO.Properties;
3+
using System;
24
using System.Collections.Generic;
35
using System.IO;
4-
using System.Linq;
5-
using NetTopologySuite.Geometries;
6-
using NetTopologySuite.IO.Properties;
7-
86
using Figure = NetTopologySuite.IO.Serialization.Figure;
97
using FigureAttribute = NetTopologySuite.IO.Serialization.FigureAttribute;
108
using Geography = NetTopologySuite.IO.Serialization.Geography;
@@ -22,7 +20,9 @@ public class SqlServerBytesWriter
2220
{
2321
private bool _emitZ = true;
2422
private bool _emitM = true;
25-
23+
private Func<Geometry, bool> _geometryValidationFn;
24+
private static readonly Func<Geometry, bool> DefaultGeometryValidationFn = (g) => g.IsValid;
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.
@@ -87,6 +87,15 @@ public virtual Ordinates HandleOrdinates
8787
/// </summary>
8888
public virtual bool IsGeography { get; set; }
8989

90+
/// <summary>
91+
/// Gets or sets a validator for a geometry. The result of this validator will be used to set the Valid flag of the Geography in SQL Server
92+
/// </summary>
93+
public Func<Geometry, bool> GeometryValidator
94+
{
95+
get => _geometryValidationFn ?? DefaultGeometryValidationFn;
96+
set => _geometryValidationFn = value;
97+
}
98+
9099
/// <summary>
91100
/// Writes a binary representation of a given geometry.
92101
/// </summary>
@@ -137,7 +146,7 @@ private Geography ToGeography(Geometry geometry)
137146
var geography = new Geography
138147
{
139148
SRID = Math.Max(0, geometry.SRID),
140-
IsValid = geometry.IsValid
149+
IsValid = GeometryValidator(geometry)
141150
};
142151

143152
while (geometries.Count > 0)

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

+82-1
Original file line numberDiff line numberDiff line change
@@ -209,17 +209,98 @@ public void Types_still_unknown(string wkt)
209209
() => reader.Read(wkt));
210210
}
211211

212+
[Theory]
213+
[InlineData(
214+
"POINT EMPTY",
215+
"000000000100000000000000000001000000FFFFFFFFFFFFFFFF01")]
216+
[InlineData(
217+
"POINT (1 2)",
218+
"000000000108000000000000F03F0000000000000040")]
219+
[InlineData(
220+
"POINT Z(1 2 3)",
221+
"000000000109000000000000F03F00000000000000400000000000000840")]
222+
[InlineData(
223+
"LINESTRING EMPTY",
224+
"000000000100000000000000000001000000FFFFFFFFFFFFFFFF02")]
225+
[InlineData(
226+
"LINESTRING (0 0, 0 1)",
227+
"000000000110000000000000000000000000000000000000000000000000000000000000F03F")]
228+
[InlineData(
229+
"LINESTRING Z(0 0 1, 0 1 2)",
230+
"000000000111000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040")]
231+
//[InlineData(
232+
// "LINESTRING (0 0, 0 1 2)",
233+
// "000000000115000000000000000000000000000000000000000000000000000000000000F03F000000000000F8FF0000000000000040")]
234+
[InlineData(
235+
"LINESTRING (0 0, 0 1, 0 2)",
236+
"00000000010003000000000000000000000000000000000000000000000000000000000000000000F03F0000000000000000000000000000004001000000010000000001000000FFFFFFFF0000000002")]
237+
[InlineData(
238+
"LINESTRING Z(0 0 1, 0 1 2, 0 2 3)",
239+
"00000000010103000000000000000000000000000000000000000000000000000000000000000000F03F00000000000000000000000000000040000000000000F03F0000000000000040000000000000084001000000010000000001000000FFFFFFFF0000000002")]
240+
[InlineData(
241+
"POLYGON EMPTY",
242+
"000000000100000000000000000001000000FFFFFFFFFFFFFFFF03")]
243+
// 0xE61000000104000000000000000001000000FFFFFFFFFFFFFFFF03
244+
[InlineData(
245+
"POLYGON ((0 0, 0 1, 1 1, 0 0))",
246+
"00000000010004000000000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000000001000000020000000001000000FFFFFFFF0000000003")]
247+
[InlineData(
248+
"POLYGON ((0 0, 0 3, 3 3, 3 0, 0 0), (1 1, 1 2, 2 2, 2 1, 1 1))",
249+
"0000000001000A0000000000000000000000000000000000000000000000000000000000000000000840000000000000084000000000000008400000000000000840000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F0000000000000040000000000000004000000000000000400000000000000040000000000000F03F000000000000F03F000000000000F03F020000000200000000000500000001000000FFFFFFFF0000000003")]
250+
[InlineData(
251+
"POLYGON ((0 0, 0 3, 3 3, 3 0, 0 0), (0 0, 0 2, 2 2, 2 0, 0 0))",
252+
"0000000001000A00000000000000000000000000000000000000000000000000000000000000000008400000000000000840000000000000084000000000000008400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000004000000000000000400000000000000040000000000000000000000000000000000000000000000000020000000200000000000500000001000000FFFFFFFF0000000003")]
253+
[InlineData(
254+
"GEOMETRYCOLLECTION EMPTY",
255+
"000000000100000000000000000001000000FFFFFFFFFFFFFFFF07")]
256+
[InlineData(
257+
"GEOMETRYCOLLECTION (POINT (0 0))",
258+
"000000000100010000000000000000000000000000000000000001000000010000000002000000FFFFFFFF0000000007000000000000000001")]
259+
[InlineData(
260+
"GEOMETRYCOLLECTION (POINT (0 0), POINT (0 1))",
261+
"00000000010002000000000000000000000000000000000000000000000000000000000000000000F03F020000000100000000010100000003000000FFFFFFFF0000000007000000000000000001000000000100000001")]
262+
[InlineData(
263+
"GEOMETRYCOLLECTION (POINT (0 0), POINT EMPTY, POINT (0 1))",
264+
"00000000010002000000000000000000000000000000000000000000000000000000000000000000F03F020000000100000000010100000004000000FFFFFFFF000000000700000000000000000100000000FFFFFFFF01000000000100000001")]
265+
[InlineData(
266+
"GEOMETRYCOLLECTION (GEOMETRYCOLLECTION (POINT (0 1)))",
267+
"000000000100010000000000000000000000000000000000F03F01000000010000000003000000FFFFFFFF0000000007000000000000000007010000000000000001")]
268+
[InlineData(
269+
"GEOMETRYCOLLECTION (POINT (0 0), GEOMETRYCOLLECTION (POINT (0 1)))",
270+
"00000000010002000000000000000000000000000000000000000000000000000000000000000000F03F020000000100000000010100000004000000FFFFFFFF0000000007000000000000000001000000000100000007020000000100000001")]
271+
[InlineData(
272+
"MULTIPOINT ((0 0))",
273+
"000000000100010000000000000000000000000000000000000001000000010000000002000000FFFFFFFF0000000004000000000000000001")]
274+
[InlineData(
275+
"MULTILINESTRING ((0 0, 0 1))",
276+
"00000000010002000000000000000000000000000000000000000000000000000000000000000000F03F01000000010000000002000000FFFFFFFF0000000005000000000000000002")]
277+
[InlineData(
278+
"MULTIPOLYGON (((0 0, 0 1, 1 1, 0 0)))",
279+
"00000000010004000000000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000000001000000020000000002000000FFFFFFFF0000000006000000000000000003")]
280+
public void Write_AllInvalid(string wkt, string expected)
281+
{
282+
var geometry = new WKTReader() { IsOldNtsCoordinateSyntaxAllowed = false }.Read(wkt);
283+
284+
Assert.Equal(expected, Write(geometry, geometryValidator: _ => false));
285+
}
286+
212287
private string Write(
213288
Geometry geometry,
214289
Ordinates handleOrdinates = Ordinates.XYZM,
215-
bool isGeography = false)
290+
bool isGeography = false,
291+
Func<Geometry, bool> geometryValidator = default)
216292
{
217293
var writer = new SqlServerBytesWriter
218294
{
219295
HandleOrdinates = handleOrdinates,
220296
IsGeography = isGeography
221297
};
222298

299+
if (geometryValidator != default)
300+
{
301+
writer.GeometryValidator = geometryValidator;
302+
}
303+
223304
return string.Concat(writer.Write(geometry).Select(b => b.ToString("X2")));
224305
}
225306
}

0 commit comments

Comments
 (0)