C#网络拓扑套件M-值



我使用NetTopologySuite作为SqlGeometry的.net核心替代品。它似乎不支持点或坐标中的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值似乎被完全拒绝了。这是实现中的错误吗?是否有任何方法可以创建具有M值的点/坐标/字符串?

默认坐标序列是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);
}
}
}

是的,这是ICoordinateSequence的默认实现中缺少的bug功能。看起来他们已经开始进行更改以支持M值,但这些更改并没有在任何地方进行。以下是代码中至少有一个不支持M值的区域,它最终导致了您所看到的问题。

当引用p3.M时,它使用的是这些get和set方法。

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);
}

然后依次调用CoordinateArraySequence中的GetOrdinateSetOrdinate

/// <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);
}
}

正如你所看到的,当你用Ordinate.M调用SetOrdinate时,什么都没有设置,而当用Ordinate.M调用GetOrdinate时,它总是会返回NaN。

如果你真的想使用NetTopologySuite,你可以从这里分叉回购https://github.com/NetTopologySuite/NetTopologySuite并进行默认情况下支持M值所需的更新,但我认为有很多事情需要更改。如果你真的更新了它,我相信维护NetTopologySuite GitHub repo的人会很感激任何更改的pull请求。

最新更新