Skip to content

Commit

Permalink
Added STMaximumInscribedCircle function support with result type mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
apdevelop committed Jul 29, 2023
1 parent 554eb8b commit ed9425f
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 35 deletions.
40 changes: 40 additions & 0 deletions LinqToDBPostGisNetTopologySuite.Tests/GeometryProcessingTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class GeometryProcessingTests : TestsBase
[SetUp]
public void Setup()
{
////PostGisTypesMapper.RegisterPostGisMappingsGlobally();
using (var db = new PostGisTestDataConnection(TestDatabaseConnectionString))
{
db.TestGeometries.Delete();
Expand Down Expand Up @@ -206,6 +207,45 @@ public void TestSTGeometricMedian()
}
}

[Test]
public void TestSTMaximumInscribedCircle()
{
using (var db = new PostGisTestDataConnection(TestDatabaseConnectionString))
{
if (base.CurrentVersion >= base.Version310)
{
db.RegisterPostGisMappings();

const int InputId = 1;
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))";

db.TestGeometries
.Value(g => g.Id, InputId)
.Value(g => g.Geometry, () => GeometryInput.STGeomFromText(InputWkt))
.Insert();

var maxInscribedCircle = db.TestGeometries
.Where(g => g.Id == InputId)
.Select(g => g.Geometry.STMaximumInscribedCircle())
.Single();

Assert.AreEqual("Point", maxInscribedCircle.Center.GeometryType);
Assert.AreEqual(96.953125, maxInscribedCircle.Center.Coordinate.X, 1.0E-6);
Assert.AreEqual(76.328125, maxInscribedCircle.Center.Coordinate.Y, 1.0E-6);

Assert.AreEqual("Point", maxInscribedCircle.Nearest.GeometryType);
Assert.AreEqual(140, maxInscribedCircle.Nearest.Coordinate.X, 1.0E-6);
Assert.AreEqual(90, maxInscribedCircle.Nearest.Coordinate.Y, 1.0E-6);

Assert.AreEqual(45.16584565, maxInscribedCircle.Radius, 1.0E-8);

Assert.AreEqual(
"POINT (140 90)",
db.Select(() => GeometryProcessing.STMaximumInscribedCircle(InputWkt)).Nearest.AsText());
}
}
}

[Test]
public void TestSTMakeValid()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System;
using System.Linq;
using System.Linq;

using LinqToDB;
using NUnit.Framework;
Expand All @@ -14,6 +13,7 @@ class GeometryValidationTests : TestsBase
[SetUp]
public void Setup()
{
////PostGisTypesMapper.RegisterPostGisMappingsGlobally();
using (var db = new PostGisTestDataConnection(TestDatabaseConnectionString))
{
db.TestGeometries.Delete();
Expand Down Expand Up @@ -64,8 +64,7 @@ public void TestSTIsValidDetail()
const string ExpectedGeomType = "Point";
using (var db = new PostGisTestDataConnection(TestDatabaseConnectionString))
{
db.Connection.RegisterPostGisCompositeTypes();
// or PostGisCompositeTypeMapper.RegisterPostGisCompositeTypesGlobally();
db.RegisterPostGisMappings();

var expectedReason = base.CurrentVersion >= base.Version320
? "Ring Self-intersection"
Expand Down
47 changes: 46 additions & 1 deletion LinqToDBPostGisNetTopologySuite/GeometryProcessing.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;

using LinqToDB;

using NpgsqlTypes;
using NTSG = NetTopologySuite.Geometries.Geometry;

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

// TODO: geometry ST_LineMerge(geometry amultilinestring);

/// <summary>
/// Finds the largest circle that is contained within input (multi)polygon <paramref name="geometry"/>, or which does not overlap any lines and points.
/// </summary>
/// <param name="geometry">Input geometry.</param>
/// <returns>Record with center, nearest and radius fields.</returns>
[Sql.Function("ST_MaximumInscribedCircle", ServerSideOnly = true)]
public static MaximumInscribedCircleResult STMaximumInscribedCircle(this NTSG geometry) => throw new InvalidOperationException();

/// <summary>
/// Finds the largest circle that is contained within input (multi)polygon <paramref name="geometry"/>, or which does not overlap any lines and points.
/// </summary>
/// <param name="geometry">Input geometry.</param>
/// <returns>Record with center, nearest and radius fields.</returns>
[Sql.Function("ST_MaximumInscribedCircle", ServerSideOnly = true)]
public static MaximumInscribedCircleResult STMaximumInscribedCircle(string geometry) => throw new InvalidOperationException();

/// <summary>
/// Mapping for ST_MaximumInscribedCircle result.
/// </summary>
/// <remarks>
/// See https://postgis.net/docs/ST_MaximumInscribedCircle.html
/// </remarks>
public class MaximumInscribedCircleResult
{
/// <summary>
/// Center point of the circle.
/// </summary>
[PgName("center")]
public NTSG Center { get; set; }

/// <summary>
/// Point on the geometry nearest to the center.
/// </summary>
[PgName("nearest")]
public NTSG Nearest { get; set; }

/// <summary>
/// Radius of the circle.
/// </summary>
[PgName("radius")]
public double Radius { get; set; }
}

/// <summary>
/// Returns smallest circle polygon that can fully contain input geometry.
/// </summary>
Expand Down
30 changes: 0 additions & 30 deletions LinqToDBPostGisNetTopologySuite/PostGisCompositeTypeMapper.cs

This file was deleted.

44 changes: 44 additions & 0 deletions LinqToDBPostGisNetTopologySuite/PostGisTypesMapper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using LinqToDB.Data;
using LinqToDB.Mapping;
using Npgsql;

using NTSG = NetTopologySuite.Geometries.Geometry;

namespace LinqToDBPostGisNetTopologySuite
{
/// <summary>
/// Utility class with methods for registering PostGIS types mappings.
/// </summary>
public static class PostGisTypesMapper
{
/// <summary>
/// Registers PostGIS types mappings for given <paramref name="dataConnection"/>.
/// </summary>
/// <param name="dataConnection">Database connection.</param>
public static void RegisterPostGisMappings(this DataConnection dataConnection)
{
var typeMapper = (dataConnection.Connection as NpgsqlConnection).TypeMapper;
typeMapper.MapComposite<ValidDetail>(ValidDetail.CompositeTypeName);

dataConnection.MappingSchema.SetConverter<object[], GeometryProcessing.MaximumInscribedCircleResult>(objs => CreateMaximumInscribedCircleResult(objs));
}

/// <summary>
/// Registers PostGIS types mappings globally for all database connections.
/// </summary>
public static void RegisterPostGisMappingsGlobally()
{
NpgsqlConnection.GlobalTypeMapper.MapComposite<ValidDetail>(ValidDetail.CompositeTypeName);

MappingSchema.Default.SetConverter<object[], GeometryProcessing.MaximumInscribedCircleResult>(objs => CreateMaximumInscribedCircleResult(objs));
}

private static GeometryProcessing.MaximumInscribedCircleResult CreateMaximumInscribedCircleResult(object[] objs) =>
new GeometryProcessing.MaximumInscribedCircleResult
{
Center = objs[0] as NTSG,
Nearest = objs[1] as NTSG,
Radius = (double)objs[2],
};
}
}

0 comments on commit ed9425f

Please sign in to comment.