M-значения C# NetTopologySuite

Я использую NetTopologySuite в качестве замены ядра .net для SqlGeometries. Кажется, что он не поддерживает значения M в точках или координатах, хотя у него есть свойства M. Например, этот простой код:

using NetTopologySuite.Geometries;
using System.Diagnostics;

namespace PlaygroundCore
{
    class Program
    {
        static void Main(string[] args)
        {
            var p3 = new Point(1, 2, 3);
            p3.Y = 8;
            p3.M = 1;
            var m = p3.M;

            Debug.WriteLine(p3);
            Debug.WriteLine(p3.M);
            Debug.WriteLine(m);
        }
    }
}

Выходы

POINT (1 8 3)
NaN
NaN

Значение M кажется полностью отвергнутым. Это ошибка в реализации? Есть ли способ создать Points/Coordinates/LineStrings с M-значениями?


person Johan    schedule 13.12.2018    source источник


Ответы (2)


Последовательность координат по умолчанию — CoordinateArraySequence, которая в настоящее время не поддерживает значения M, но похоже, что DotSpatialAffineCoordinateSequence поддерживает значения M. Чтобы заставить значения M работать, мне пришлось сделать следующее

using NetTopologySuite.Geometries;
using NetTopologySuite.Geometries.Implementation;
using System.Diagnostics;

namespace NetTopologyTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //This sequence has to be initialized with ordinates XYZM. If you construct it
            //with just XYZ values, then you can't add M values to it later.
            var coordinateSequence = new DotSpatialAffineCoordinateSequence(new[] { 1.0, 2.0 }, new[] { 3.0 }, new[] { 4.0 });
            var sequenceFactory = new DotSpatialAffineCoordinateSequenceFactory(GeoAPI.Geometries.Ordinates.XYZM);
            var geometryFactory = new GeometryFactory(sequenceFactory);
            var p3 = new Point(coordinateSequence, geometryFactory);
            p3.Y = 8;
            p3.M = 1;
            var m = p3.M;

            Debug.WriteLine(p3);
            Debug.WriteLine(p3.M);
            Debug.WriteLine(m);
        }
    }
}
person TJ Rockefeller    schedule 13.12.2018
comment
Это не ошибка, это зависит от того, что может обрабатывать последовательность координат (фабрика). Фабрика CooedinateSequence и irs (по умолчанию) может обрабатывать три банкомата, третий — Z. - person FObermaier; 14.12.2018
comment
Спасибо TJ за альтернативное решение. @FObermaier При реализации интерфейса (в данном случае IPoint) я бы посчитал, если не ошибкой, то, по крайней мере, плохим / нежелательным дизайном иметь вызываемый установщик, но не получатель для одного из свойств интерфейса. Неважно, что находится под капотом, поскольку это то, что публично видно пользователю. - person Johan; 17.12.2018
comment
@ Йохан, ты предпочитаешь NotSupportedException? Я видел множество общедоступных интерфейсов, которые были реализованы лишь частично. - person FObermaier; 17.12.2018
comment
@FObermaier Я бы предпочел правильную реализацию. И когда это официальный пакет Microsoft .NET nuget (Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite), я ожидаю, что он будет работать, как задумано. - person Johan; 17.12.2018

Да, это функция ошибка, которая отсутствует в стандартной реализации ICoordinateSequence. Похоже, что они начали вносить изменения для поддержки значений M, но эти изменения были внесены не везде. Ниже приведена по крайней мере одна область, где значения M не поддерживаются в коде, который в конечном итоге вызывает проблему, которую вы видите.

При обращении к p3.M он использует эти методы получения и установки.

    public double M
    {
        get
        {
            if (CoordinateSequence == null)
                throw new ArgumentOutOfRangeException("M called on empty Point");
            return CoordinateSequence.GetOrdinate(0, Ordinate.M);
        }
        set => CoordinateSequence.SetOrdinate(0, Ordinate.M, value);
    }

Который затем, в свою очередь, вызывает GetOrdinate и SetOrdinate в CoordinateArraySequence

    /// <summary>
    /// Returns the ordinate of a coordinate in this sequence.
    /// Ordinate indices 0 and 1 are assumed to be X and Y.
    /// Ordinate indices greater than 1 have user-defined semantics
    /// (for instance, they may contain other dimensions or measure values).
    /// </summary>
    /// <param name="index">The coordinate index in the sequence.</param>
    /// <param name="ordinate">The ordinate index in the coordinate (in range [0, dimension-1]).</param>
    /// <returns></returns>
    public double GetOrdinate(int index, Ordinate ordinate)
    {
        switch (ordinate)
        {
            case Ordinate.X:
                return Coordinates[index].X;
            case Ordinate.Y:
                return Coordinates[index].Y;
            case Ordinate.Z:
                return Coordinates[index].Z;
            default:
                return double.NaN;
        }
    }

    /// <summary>
    /// Sets the value for a given ordinate of a coordinate in this sequence.
    /// </summary>
    /// <param name="index">The coordinate index in the sequence.</param>
    /// <param name="ordinate">The ordinate index in the coordinate (in range [0, dimension-1]).</param>
    /// <param name="value">The new ordinate value.</param>
    public void SetOrdinate(int index, Ordinate ordinate, double value)
    {
        switch (ordinate)
        {
            case Ordinate.X:
                Coordinates[index].X = value;
                break;
            case Ordinate.Y:
                Coordinates[index].Y = value;
                break;
            case Ordinate.Z:
                Coordinates[index].Z = value;
                break;
            //default:
            //    //throw new ArgumentException("invalid ordinate index: " + ordinate);
        }
    }

Который, как вы можете видеть, когда вы вызываете SetOrdinate с Ordinate.M, ничего не устанавливается, а при вызове GetOrdinate с Ordinate.M он всегда возвращает NaN.

Если вы действительно хотите использовать NetTopologySuite, вы можете разветвить репозиторий отсюда https://github.com/NetTopologySuite/NetTopologySuite и внести обновления, необходимые для поддержки значений M по умолчанию, но я полагаю, что есть много вещей, которые необходимо изменить. Если вы обновите его, я уверен, что ребята, поддерживающие репозиторий NetTopologySuite GitHub, будут признательны за запрос на внесение любых изменений.

person TJ Rockefeller    schedule 13.12.2018
comment
Ладно, это все объясняет. Я могу ошибаться, но разве NetTopologySuite не единственный способ заставить его работать с Entity Framework Core (т.е. иметь возможность извлекать и сохранять геометрию из/в базу данных)? - person Johan; 17.12.2018