【问题标题】:Parsing UTM coordinates to DBGeography in C#在 C# 中将 UTM 坐标解析为 DBGeography
【发布时间】:2018-07-27 20:43:59
【问题描述】:

我正在用 C# 编写一个 WinForms 应用程序。我需要确保我的Datatable 中没有两个Datarows 相距超过100 公里。每行在单独的DataColumns 中都有一个 UTM 区域、东向和北向。所有坐标都使用相同的数据,但有些坐标有不同的区域(否则,我只会使用 pythag 数学,因为 UTM 以米为单位)。到目前为止,我正在使用以下代码来执行此操作,但我的 DbGeography.PointFromText 方法似乎不太正常(请参阅代码中的 *),因为当代码到达带有 ' 的代码行时**' 在它的开头,我收到一条错误消息“24201:纬度值必须在 -90 到 90 度之间”。我也试过:

dtTrap.Rows[i]["TrapGeog"] = DbGeography.PointFromText(pointWellKnownText: "POINT M(" + dtTrap.Rows[i][intEastingIndex].ToString() + " " + dtTrap.Rows[i][intNorthingIndex].ToString() + " " + dtTrap.Rows[i][Zone].ToString() + ")", coordinateSystemId: SRID);

只是让它抱怨“没有第 17 列”(17 是我的 UTM 区域)。

我发现使用这些东西的文档非常少……据我所知,我的 SRID 是正确的(我从 this site 中提取了它们)。我以前用 Lat+Longs 做过这种事情,效果很好。我只是找不到适合 UTM 的语法。

using System.Data.Entity.Spatial;
...
DataColumn dcGeog = new DataColumn("TrapGeog", typeof(DbGeography));
dtTrap.Columns.Add(dcGeog);
byte Zone;
Int16 SRID;
for (int i = 0; i < dtTrap.Rows.Count; ++i)
{
    if (dtTrap.Rows[i][intZoneIndex] != null
    && dtTrap.Rows[i][intNorthingIndex] != null
    && dtTrap.Rows[i][intEastingIndex] != null
    && byte.TryParse(dtTrap.Rows[i][intZoneIndex].ToString(), out Zone) == true)
    {
        if (Zone == 15) { SRID = 26915; }
        else if (Zone == 16) { SRID = 26916; }
        else if (Zone == 17) { SRID = 26917; }
        else { SRID = 26918; }
        // shove it in:
        try
        {
            *dtTrap.Rows[i]["TrapGeog"] = DbGeography.PointFromText(pointWellKnownText: "POINT(" + dtTrap.Rows[i][intEastingIndex].ToString() + " " + dtTrap.Rows[i][intNorthingIndex].ToString() + ")", coordinateSystemId: SRID);
        }
        catch (Exception ex)
        {
            if (ex.InnerException != null)
            {
                **MessageBox.Show(ex.InnerException.Message);
            }
            else
            {
                MessageBox.Show(ex.Message);
            }
        }

    }
}
for (int i = 0; i < dtTrap.Rows.Count - 1; ++i)
{
    for (int k = i + 1; k < dtTrap.Rows.Count; ++i)
    {
        DbGeography iTrap = (DbGeography)dtTrap.Rows[i]["TrapGeog"];
        DbGeography kTrap = (DbGeography)dtTrap.Rows[k]["TrapGeog"];
        if (iTrap.Distance(kTrap) > 100000)
        {
            sbErrorsAndWarningsLog.Append(@"Warning:  Line number " + (i + 2).ToString() + " on the Trap spreadsheet has coordinates that are at least 100 km away from row " + (k + 2).ToString() + "'s point.  Please check that these coordinates are correct.").AppendLine();
            boolWarningsFound = true;
            break;
        }
    }
}

【问题讨论】:

    标签: c# spatial


    【解决方案1】:

    为了解决这个问题,我在姐妹网站here 上偶然发现了这篇帖子。我认为DbGeography 是基于 SQL Server 的地理数据类型,DbGeometry 同样是几何数据类型。

    一些相关的花絮:

    地理数据类型 EPSG:4326 以度为单位,这就是您的 POINT(257306 142708) 失败的原因,因为它超出了 (-180,180)、(-90,90) 范围。

    ...

    解决方案...改为使用几何数据类型,即投影,而不是地理。

    所以我将代码更改为:

    DataColumn dcGeom = new DataColumn("TrapGeom", typeof(DbGeometry));
    ...
    dtTrap.Rows[i]["TrapGeom"] = DbGeometry.PointFromText(pointWellKnownText: stPoint, coordinateSystemId: SRID);
    

    而且它似乎解析得很好。不过,帖子的最后一部分让我担心:

    SQL Server 坚持存在一个 SRID,即使您实际上不能用它做任何有用的事情,例如将一个坐标系转换为另一个坐标系。如果您不小心将几何图形与不同的 SRID 混合在一起,可能会变得非常混乱,因为您根本不会得到任何结果(没有警告,但这是一个旁白)。

    因此,当我最终执行if (Trap1.Distance(Trap2) &gt; 100000) ... 时,我有一半的预期是当我在不同的 SRID 中有两个不同的点时它会发生故障。我会测试我的发现并写评论。

    【讨论】:

    • 更新:我的担心是有道理的。在计算 Trap1 到 Trap2 (double? d = Trap1.Distance(Trap2)) 的距离时,当它们具有不同的 SRID(由于 UTM 区域的差异)时,Visual Studio 会引发错误“数据为 Null。无法对 Null 值调用此方法或属性。” - 尽管两个点都不为空。
    【解决方案2】:

    为了更好地调试此错误,我建议首先检查您的输入数据。

    string point = "";
    try
    {
        string point = "POINT(" + dtTrap.Rows[i][intEastingIndex].ToString() + " " + dtTrap.Rows[i][intNorthingIndex].ToString() + ")";
    
        dtTrap.Rows[i]["TrapGeog"] = DbGeography.PointFromText(pointWellKnownText: point, coordinateSystemId: SRID);
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine("correct point? " + point);
        if (ex.InnerException != null)
        {
            MessageBox.Show(ex.InnerException.Message + " at " + point);
        }
        else
        {
            MessageBox.Show(ex.Message);
        }
    }
    

    我的猜测是,你的字符串中有一些逗号而不是点一些空格

    【讨论】:

    • 感谢您的想法。这种情况下的字符串是 POINT(312338 5346686)。我很喜欢将 UTM 东向和北向解析为这种数据类型的替代语法......
    • 我也尝试过翻转东向和北向(例如,POINT(5346686 312338),错误消息没有变化。
    • 我不是空间数据方面的专家,但它不应该在 0 到 359.999 之间吗?所以你的数据缺少小数点 POINT(534.46686 31.2338) ?
    • 我的理解是,对于这个 SRID,测量单位是米而不是弧度,所以我的东移和北移值是完全合适的。
    • 到目前为止我没有帮助。我应该删除我的答案,以便吸引更多专家吗?
    猜你喜欢
    • 2023-04-03
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 2016-11-09
    • 2021-07-18
    • 2021-06-23
    • 1970-01-01
    • 2019-12-04
    相关资源
    最近更新 更多