NetTopologySuite сказал, что геометрия недопустима, но Sql Server сказал, что она допустима

#c# #nettopologysuite

Вопрос:

У меня есть многоугольник:

 polygon((0 0, 1 0.1, 1 1, 0.5 1, 0.5 1.5, 1 1, 1.5 1.5, 1.5 1, 1 1, 1.5 0.5, 1 0.1, 2 0, 2 2,0 2, 0 0))
 

введите описание изображения здесь

Конечно, это выглядит ненормально, но Sql Server 2017 сказал, что это действительно так.
Но когда я попытался прочитать его с помощью NTE, он сказал, что он недействителен. Вот простой код:

 var wkt = @"polygon((0 0, 1 0.1, 1 1, 0.5 1, 0.5 1.5, 1 1, 1.5 1.5, 1.5 1, 1 1, 1.5 0.5, 1 0.1, 2 0, 2 2,0 2, 0 0))";
var wktReader2 = new WKTReader();
var initialGeometry = wktReader2.Read(wkt);
var t = initialGeometry.IsValid;
 

Я попытался «поиграть» с точными моделями, но безрезультатно. Есть какие-нибудь советы?

Ответ №1:

Вам нужно использовать IsValidOp явно и установить SelfTouchingRingFormingHoleValid = true :

 var ivo = new NetTopologySuite.Operation.Valid.IsValidOp(initialGeometry);
ivo.SelfTouchingRingFormingHoleValid = true;
bool t = ivo.IsValid;
 

Ваш многоугольник имеет только одно кольцо, определяющее оболочку и отверстия, а не отдельные. Чтобы он был действителен в NTS, WKT полигона будет

 POLYGON ((0 0, 0 2, 2 2, 2 0, 1 0.1, 0 0), (1 0.1, 1.5 0.5, 1 1, 1 0.1), 
         (1 1, 1.5 1, 1.5 1.5, 1 1), (1 1, 0.5 1.5, 0.5 1, 1 1))
 

Ответ №2:

Вы пробовали взломать «Buffer0», согласно https://github.com/NetTopologySuite/NetTopologySuite/wiki/GettingStarted. Сегодня вечером я столкнулся с аналогичной проблемой и нашел этот вопрос так же, как я решил его для своего случая.

Примечание: Иногда вы встретите недопустимые геометрии (Геометрия.isValid == ложь). Это вызовет проблемы при их дальнейшей обработке. В большинстве случаев вы сможете исправить это с помощью трюка Buffer0:

geom = geom.Buffer(0);

 var wkt = @"polygon((0 0, 1 0.1, 1 1, 0.5 1, 0.5 1.5, 1 1, 1.5 1.5, 1.5 1, 1 1, 1.5 0.5, 1 0.1, 2 0, 2 2,0 2, 0 0))";
var wktReader2 = new NetTopologySuite.IO.WKTReader();
var initialGeometry = wktReader2.Read(wkt);
var t = initialGeometry.IsValid;
_logger.LogInformation(t.ToString());        // False

var t2 = initialGeometry.Buffer(0).IsValid;
_logger.LogInformation(t2.ToString());       // True
 

Комментарии:

1. В настоящее время вы должны использовать NetTopologySuite.Geometries.Utilities.GeometryFixer.Fix(invalidGeometry) для исправления недопустимых геометрий.