Skip to content

Commit ed9425f

Browse files
committed
Added STMaximumInscribedCircle function support with result type mapping
1 parent 554eb8b commit ed9425f

File tree

5 files changed

+133
-35
lines changed

5 files changed

+133
-35
lines changed

LinqToDBPostGisNetTopologySuite.Tests/GeometryProcessingTests.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ class GeometryProcessingTests : TestsBase
1515
[SetUp]
1616
public void Setup()
1717
{
18+
////PostGisTypesMapper.RegisterPostGisMappingsGlobally();
1819
using (var db = new PostGisTestDataConnection(TestDatabaseConnectionString))
1920
{
2021
db.TestGeometries.Delete();
@@ -206,6 +207,45 @@ public void TestSTGeometricMedian()
206207
}
207208
}
208209

210+
[Test]
211+
public void TestSTMaximumInscribedCircle()
212+
{
213+
using (var db = new PostGisTestDataConnection(TestDatabaseConnectionString))
214+
{
215+
if (base.CurrentVersion >= base.Version310)
216+
{
217+
db.RegisterPostGisMappings();
218+
219+
const int InputId = 1;
220+
const string InputWkt = "POLYGON ((40 180, 110 160, 180 180, 180 120, 140 90, 160 40, 80 10, 70 40, 20 50, 40 180), (60 140, 50 90, 90 140, 60 140))";
221+
222+
db.TestGeometries
223+
.Value(g => g.Id, InputId)
224+
.Value(g => g.Geometry, () => GeometryInput.STGeomFromText(InputWkt))
225+
.Insert();
226+
227+
var maxInscribedCircle = db.TestGeometries
228+
.Where(g => g.Id == InputId)
229+
.Select(g => g.Geometry.STMaximumInscribedCircle())
230+
.Single();
231+
232+
Assert.AreEqual("Point", maxInscribedCircle.Center.GeometryType);
233+
Assert.AreEqual(96.953125, maxInscribedCircle.Center.Coordinate.X, 1.0E-6);
234+
Assert.AreEqual(76.328125, maxInscribedCircle.Center.Coordinate.Y, 1.0E-6);
235+
236+
Assert.AreEqual("Point", maxInscribedCircle.Nearest.GeometryType);
237+
Assert.AreEqual(140, maxInscribedCircle.Nearest.Coordinate.X, 1.0E-6);
238+
Assert.AreEqual(90, maxInscribedCircle.Nearest.Coordinate.Y, 1.0E-6);
239+
240+
Assert.AreEqual(45.16584565, maxInscribedCircle.Radius, 1.0E-8);
241+
242+
Assert.AreEqual(
243+
"POINT (140 90)",
244+
db.Select(() => GeometryProcessing.STMaximumInscribedCircle(InputWkt)).Nearest.AsText());
245+
}
246+
}
247+
}
248+
209249
[Test]
210250
public void TestSTMakeValid()
211251
{

LinqToDBPostGisNetTopologySuite.Tests/GeometryValidationTests.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System;
2-
using System.Linq;
1+
using System.Linq;
32

43
using LinqToDB;
54
using NUnit.Framework;
@@ -14,6 +13,7 @@ class GeometryValidationTests : TestsBase
1413
[SetUp]
1514
public void Setup()
1615
{
16+
////PostGisTypesMapper.RegisterPostGisMappingsGlobally();
1717
using (var db = new PostGisTestDataConnection(TestDatabaseConnectionString))
1818
{
1919
db.TestGeometries.Delete();
@@ -64,8 +64,7 @@ public void TestSTIsValidDetail()
6464
const string ExpectedGeomType = "Point";
6565
using (var db = new PostGisTestDataConnection(TestDatabaseConnectionString))
6666
{
67-
db.Connection.RegisterPostGisCompositeTypes();
68-
// or PostGisCompositeTypeMapper.RegisterPostGisCompositeTypesGlobally();
67+
db.RegisterPostGisMappings();
6968

7069
var expectedReason = base.CurrentVersion >= base.Version320
7170
? "Ring Self-intersection"

LinqToDBPostGisNetTopologySuite/GeometryProcessing.cs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using System;
22

33
using LinqToDB;
4-
4+
using NpgsqlTypes;
55
using NTSG = NetTopologySuite.Geometries.Geometry;
66

77
namespace LinqToDBPostGisNetTopologySuite
@@ -187,6 +187,51 @@ public static class GeometryProcessing
187187
[Sql.Function("ST_GeometricMedian", ServerSideOnly = true)]
188188
public static NTSG STGeometricMedian(this NTSG geometry) => throw new InvalidOperationException();
189189

190+
// TODO: geometry ST_LineMerge(geometry amultilinestring);
191+
192+
/// <summary>
193+
/// Finds the largest circle that is contained within input (multi)polygon <paramref name="geometry"/>, or which does not overlap any lines and points.
194+
/// </summary>
195+
/// <param name="geometry">Input geometry.</param>
196+
/// <returns>Record with center, nearest and radius fields.</returns>
197+
[Sql.Function("ST_MaximumInscribedCircle", ServerSideOnly = true)]
198+
public static MaximumInscribedCircleResult STMaximumInscribedCircle(this NTSG geometry) => throw new InvalidOperationException();
199+
200+
/// <summary>
201+
/// Finds the largest circle that is contained within input (multi)polygon <paramref name="geometry"/>, or which does not overlap any lines and points.
202+
/// </summary>
203+
/// <param name="geometry">Input geometry.</param>
204+
/// <returns>Record with center, nearest and radius fields.</returns>
205+
[Sql.Function("ST_MaximumInscribedCircle", ServerSideOnly = true)]
206+
public static MaximumInscribedCircleResult STMaximumInscribedCircle(string geometry) => throw new InvalidOperationException();
207+
208+
/// <summary>
209+
/// Mapping for ST_MaximumInscribedCircle result.
210+
/// </summary>
211+
/// <remarks>
212+
/// See https://postgis.net/docs/ST_MaximumInscribedCircle.html
213+
/// </remarks>
214+
public class MaximumInscribedCircleResult
215+
{
216+
/// <summary>
217+
/// Center point of the circle.
218+
/// </summary>
219+
[PgName("center")]
220+
public NTSG Center { get; set; }
221+
222+
/// <summary>
223+
/// Point on the geometry nearest to the center.
224+
/// </summary>
225+
[PgName("nearest")]
226+
public NTSG Nearest { get; set; }
227+
228+
/// <summary>
229+
/// Radius of the circle.
230+
/// </summary>
231+
[PgName("radius")]
232+
public double Radius { get; set; }
233+
}
234+
190235
/// <summary>
191236
/// Returns smallest circle polygon that can fully contain input geometry.
192237
/// </summary>

LinqToDBPostGisNetTopologySuite/PostGisCompositeTypeMapper.cs

Lines changed: 0 additions & 30 deletions
This file was deleted.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
using LinqToDB.Data;
2+
using LinqToDB.Mapping;
3+
using Npgsql;
4+
5+
using NTSG = NetTopologySuite.Geometries.Geometry;
6+
7+
namespace LinqToDBPostGisNetTopologySuite
8+
{
9+
/// <summary>
10+
/// Utility class with methods for registering PostGIS types mappings.
11+
/// </summary>
12+
public static class PostGisTypesMapper
13+
{
14+
/// <summary>
15+
/// Registers PostGIS types mappings for given <paramref name="dataConnection"/>.
16+
/// </summary>
17+
/// <param name="dataConnection">Database connection.</param>
18+
public static void RegisterPostGisMappings(this DataConnection dataConnection)
19+
{
20+
var typeMapper = (dataConnection.Connection as NpgsqlConnection).TypeMapper;
21+
typeMapper.MapComposite<ValidDetail>(ValidDetail.CompositeTypeName);
22+
23+
dataConnection.MappingSchema.SetConverter<object[], GeometryProcessing.MaximumInscribedCircleResult>(objs => CreateMaximumInscribedCircleResult(objs));
24+
}
25+
26+
/// <summary>
27+
/// Registers PostGIS types mappings globally for all database connections.
28+
/// </summary>
29+
public static void RegisterPostGisMappingsGlobally()
30+
{
31+
NpgsqlConnection.GlobalTypeMapper.MapComposite<ValidDetail>(ValidDetail.CompositeTypeName);
32+
33+
MappingSchema.Default.SetConverter<object[], GeometryProcessing.MaximumInscribedCircleResult>(objs => CreateMaximumInscribedCircleResult(objs));
34+
}
35+
36+
private static GeometryProcessing.MaximumInscribedCircleResult CreateMaximumInscribedCircleResult(object[] objs) =>
37+
new GeometryProcessing.MaximumInscribedCircleResult
38+
{
39+
Center = objs[0] as NTSG,
40+
Nearest = objs[1] as NTSG,
41+
Radius = (double)objs[2],
42+
};
43+
}
44+
}

0 commit comments

Comments
 (0)