From bddad86a605179f5f0d70b62cdffba6bfe50d461 Mon Sep 17 00:00:00 2001 From: Brice Lambson Date: Sat, 29 May 2021 12:05:01 -0700 Subject: [PATCH] WIP: Integrate with NetTopologySuite.Curved --- .gitmodules | 3 ++ NetTopologySuite.Curved | 1 + .../NetTopologySuite.IO.SqlServerBytes.csproj | 2 +- .../SqlServerBytesReader.cs | 14 ++++++- .../SqlServerBytesWriter.cs | 2 + .../SqlServerBytesReaderTest.cs | 38 ++++++------------- .../SqlServerBytesWriterTest.cs | 31 +++++++-------- 7 files changed, 44 insertions(+), 47 deletions(-) create mode 100644 .gitmodules create mode 160000 NetTopologySuite.Curved diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..012413a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "NetTopologySuite.Curved"] + path = NetTopologySuite.Curved + url = https://github.com/NetTopologySuite/NetTopologySuite.Curved.git diff --git a/NetTopologySuite.Curved b/NetTopologySuite.Curved new file mode 160000 index 0000000..5e8ca25 --- /dev/null +++ b/NetTopologySuite.Curved @@ -0,0 +1 @@ +Subproject commit 5e8ca258ff4363ddb20793e97186e139f66b3c60 diff --git a/src/NetTopologySuite.IO.SqlServerBytes/NetTopologySuite.IO.SqlServerBytes.csproj b/src/NetTopologySuite.IO.SqlServerBytes/NetTopologySuite.IO.SqlServerBytes.csproj index 7750838..a883c3d 100644 --- a/src/NetTopologySuite.IO.SqlServerBytes/NetTopologySuite.IO.SqlServerBytes.csproj +++ b/src/NetTopologySuite.IO.SqlServerBytes/NetTopologySuite.IO.SqlServerBytes.csproj @@ -22,7 +22,7 @@ - + diff --git a/src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesReader.cs b/src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesReader.cs index 478c6ef..9774883 100644 --- a/src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesReader.cs +++ b/src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesReader.cs @@ -129,7 +129,10 @@ private Geometry ToGeometry(Geography geography) bool handleZ = _handleOrdinates.HasFlag(Ordinates.Z) && geography.ZValues.Count > 0; bool handleM = _handleOrdinates.HasFlag(Ordinates.M) && geography.MValues.Count > 0; - var factory = _services.CreateGeometryFactory(geography.SRID); + // TODO: Cache factories by SRID? + // TODO: Shouldn't this accept _services? + // TODO: Is arcSegmentLength the same as SQL Server's tolerance? Is this a good default? + var factory = new CurvedGeometryFactory(_services.DefaultPrecisionModel, geography.SRID, _services.DefaultCoordinateSequenceFactory, arcSegmentLength: 0.001); var geometries = new Dictionary>(); int lastFigureIndex = geography.Figures.Count - 1; int lastPointIndex = geography.Points.Count - 1; @@ -144,6 +147,7 @@ private Geometry ToGeometry(Geography geography) for (int figureIndex = lastFigureIndex; figureIndex >= shape.FigureOffset; figureIndex--) { var figure = geography.Figures[figureIndex]; + // TODO: Handle Segments when FigureAttribute = Curve int pointCount = figure.PointOffset != -1 ? lastPointIndex + 1 - figure.PointOffset : 0; @@ -238,6 +242,14 @@ private Geometry ToGeometry(Geography geography) geometries.Remove(shapeIndex); break; + case OpenGisType.CircularString: + // TODO: Assert it's an Arc? + geometry = factory.CreateCircularString(figures.SingleOrDefault()); + Debug.Assert(!geometries.ContainsKey(shapeIndex)); + break; + + // TODO: Handle CompoundCurve & CurvePolygon + default: throw new ParseException(string.Format(Resources.UnexpectedGeographyType, shape.Type)); } diff --git a/src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesWriter.cs b/src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesWriter.cs index bb20c5c..de58505 100644 --- a/src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesWriter.cs +++ b/src/NetTopologySuite.IO.SqlServerBytes/SqlServerBytesWriter.cs @@ -178,6 +178,8 @@ private Geography ToGeography(Geometry geometry) } break; + // TODO: Handle CircularString, CompoundCurve & CurvePolygon + default: throw new InvalidOperationException( string.Format(Resources.UnexpectedGeometryType, geometry.GetType())); diff --git a/test/NetTopologySuite.IO.SqlServerBytes.Test/SqlServerBytesReaderTest.cs b/test/NetTopologySuite.IO.SqlServerBytes.Test/SqlServerBytesReaderTest.cs index 421d809..8743430 100644 --- a/test/NetTopologySuite.IO.SqlServerBytes.Test/SqlServerBytesReaderTest.cs +++ b/test/NetTopologySuite.IO.SqlServerBytes.Test/SqlServerBytesReaderTest.cs @@ -70,6 +70,17 @@ public class SqlServerBytesReaderTest [InlineData( "MULTIPOLYGON (((0 0, 0 1, 1 1, 0 0)))", "00000000010404000000000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000000001000000020000000002000000FFFFFFFF0000000006000000000000000003")] + [InlineData( + "CIRCULARSTRING (0 0, 1 1, 2 0)", + "0000000002040300000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000000001000000020000000001000000FFFFFFFF0000000008")] + // TODO: Test CompoundCurve with consecutive lines/arcs + [InlineData( + "COMPOUNDCURVE ((0 0, 1 0), CIRCULARSTRING (1 0, 2 1, 3 0))", + "0000000002040400000000000000000000000000000000000000000000000000F03F00000000000000000000000000000040000000000000F03F0000000000000840000000000000000001000000030000000001000000FFFFFFFF0000000009020000000203")] + // TODO: Test CurvePolygon with interior rings + [InlineData( + "CURVEPOLYGON (CIRCULARSTRING (2 1, 1 2, 0 1, 1 0, 2 1))", + "000000000204050000000000000000000040000000000000F03F000000000000F03F00000000000000400000000000000000000000000000F03F000000000000F03F00000000000000000000000000000040000000000000F03F01000000020000000001000000FFFFFFFF000000000A")] public void Read_works(string expected, string bytes) { Assert.Equal(expected, Read(bytes).AsText()); @@ -161,33 +172,6 @@ public void HandleOrdinates_works() Assert.Equal("POINT (1 2)", new WKTWriter(4).Write(point)); } - [Fact] - public void Read_throws_when_circular_string() - { - var ex = Assert.Throws( - () => Read("0000000002040300000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000000001000000020000000001000000FFFFFFFF0000000008")); - - Assert.Equal(string.Format(Resources.UnexpectedGeographyType, "CircularString"), ex.Message); - } - - [Fact] - public void Read_throws_when_compound_curve() - { - var ex = Assert.Throws( - () => Read("0000000002040400000000000000000000000000000000000000000000000000F03F00000000000000000000000000000040000000000000F03F0000000000000840000000000000000001000000030000000001000000FFFFFFFF0000000009020000000203")); - - Assert.Equal(string.Format(Resources.UnexpectedGeographyType, "CompoundCurve"), ex.Message); - } - - [Fact] - public void Read_throws_when_curve_polygon() - { - var ex = Assert.Throws( - () => Read("000000000204050000000000000000000040000000000000F03F000000000000F03F00000000000000400000000000000000000000000000F03F000000000000F03F00000000000000000000000000000040000000000000F03F01000000020000000001000000FFFFFFFF000000000A")); - - Assert.Equal(string.Format(Resources.UnexpectedGeographyType, "CurvePolygon"), ex.Message); - } - [Fact] public void Read_throws_when_full_globe() { diff --git a/test/NetTopologySuite.IO.SqlServerBytes.Test/SqlServerBytesWriterTest.cs b/test/NetTopologySuite.IO.SqlServerBytes.Test/SqlServerBytesWriterTest.cs index 8f6b670..b003ae0 100644 --- a/test/NetTopologySuite.IO.SqlServerBytes.Test/SqlServerBytesWriterTest.cs +++ b/test/NetTopologySuite.IO.SqlServerBytes.Test/SqlServerBytesWriterTest.cs @@ -77,9 +77,18 @@ public class SqlServerBytesWriterTest [InlineData( "MULTIPOLYGON (((0 0, 0 1, 1 1, 0 0)))", "00000000010404000000000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000000001000000020000000002000000FFFFFFFF0000000006000000000000000003")] + [InlineData( + "CIRCULARSTRING (0 0, 1 1, 2 0)", + "0000000002040300000000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000000001000000020000000001000000FFFFFFFF0000000008")] + [InlineData( + "COMPOUNDCURVE ((0 0, 1 0), CIRCULARSTRING (1 0, 2 1, 3 0))", + "0000000002040400000000000000000000000000000000000000000000000000F03F00000000000000000000000000000040000000000000F03F0000000000000840000000000000000001000000030000000001000000FFFFFFFF0000000009020000000203")] + [InlineData( + "CURVEPOLYGON (CIRCULARSTRING (2 1, 1 2, 0 1, 1 0, 2 1))", + "000000000204050000000000000000000040000000000000F03F000000000000F03F00000000000000400000000000000000000000000000F03F000000000000F03F00000000000000000000000000000040000000000000F03F01000000020000000001000000FFFFFFFF000000000A")] public void Write_works(string wkt, string expected) { - var geometry = new WKTReader().Read(wkt); + var geometry = new WKTReaderEx().Read(wkt); Assert.Equal(expected, Write(geometry)); } @@ -89,7 +98,7 @@ public void Write_works(string wkt, string expected) [InlineData("POLYGON EMPTY", "E61000000104000000000000000001000000FFFFFFFFFFFFFFFF03")] public void Write_works_when_IsGeography(string wkt, string expectedHex) { - var geometry = new WKTReader().Read(wkt); + var geometry = new WKTReaderEx().Read(wkt); geometry.SRID = 4326; Assert.Equal(expectedHex, Write(geometry, isGeography: true)); @@ -98,7 +107,7 @@ public void Write_works_when_IsGeography(string wkt, string expectedHex) [Fact] public void Write_throws_when_IsGeography_and_shell_oriented_clockwise() { - var geometry = new WKTReader().Read("POLYGON ((0 0, 0 1, 1 1, 0 0))"); + var geometry = new WKTReaderEx().Read("POLYGON ((0 0, 0 1, 1 1, 0 0))"); geometry.SRID = 4326; var ex = Assert.Throws( @@ -110,7 +119,7 @@ public void Write_throws_when_IsGeography_and_shell_oriented_clockwise() [Fact] public void Write_throws_when_IsGeography_and_hole_oriented_counter_clockwise() { - var geometry = new WKTReader().Read("POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0), (1 1, 2 1, 2 2, 1 2, 1 1))"); + var geometry = new WKTReaderEx().Read("POLYGON ((0 0, 3 0, 3 3, 0 3, 0 0), (1 1, 2 1, 2 2, 1 2, 1 1))"); geometry.SRID = 4326; var ex = Assert.Throws( @@ -195,20 +204,6 @@ public void HandleOrdinates_works() Write(point, Ordinates.XY)); } - [Theory] - [InlineData("CIRCULARSTRING (0 0, 1 1, 2 0)")] - [InlineData("COMPOUNDCURVE ((0 0, 1 0), CIRCULARSTRING (1 0, 2 1, 3 0))")] - [InlineData("CURVEPOLYGON (CIRCULARSTRING (2 1, 1 2, 0 1, 1 0, 2 1))")] - [InlineData("FULLGLOBE")] - public void Types_still_unknown(string wkt) - { - var reader = new WKTReader(); - - // NB: If this doesn't throw, we're unblocked and can add support - Assert.Throws( - () => reader.Read(wkt)); - } - private string Write( Geometry geometry, Ordinates handleOrdinates = Ordinates.XYZM,