【问题标题】:How to speed up conversion of lat-long to a SqlGeometry?如何加快 lat-long 到 SqlGeometry 的转换?
【发布时间】:2014-11-28 09:26:17
【问题描述】:

我有这个代码,它需要国家的几何形状和一组点,然后它只返回这些国家内的点:

public static IEnumerable<Point> RemovePointsOutsideBorders(IEnumerable<Point> points, IEnumerable<Country> countries)
{
    var cc = new List<Point>();

    var SPAT_REF_ID = 4326;
    foreach (var p in points)
    {
            var validText = new SqlChars(new SqlString(string.Format("POINT({0} {1})", p.Longitude, p.Latitude)));
            var geoPoint = SqlGeometry.STPointFromText(validText, SPAT_REF_ID);

        foreach (var c in countries)
        {
            if(c.Polygon.STIntersects(geoPoint))
            {
                cc.Add(p);
                break;
            }
        }
    }

    return cc;
}

目前它很慢,大约有 4000 个点,具有双纬度/经度值,从它到 SqlGeometry 的转换很慢(大约需要 25 秒——我需要这可能降低到一两秒) :

var s = new SqlChars(new SqlString(string.Format("POINT({0} {1})", p.Longitude, p.Latitude)));
var pGeo = SqlGeometry.STPointFromText(s, SPAT_REF_ID);

这样做只是因为 SqlGeometry.Point 采用 x,y 而不是 lat,long ...关于如何加快速度的任何提示?

我已经知道可以减少 SqlGeometry (c.Polygon) 以加快速度,但是我无法控制它。我所追求的是一种加快从 lat/long 到 SqlGeometry 点的转换的方法。

【问题讨论】:

  • 您确定要与SqlGeometry 而不是SqlGeorgaphy 打交道吗?这两者在一些关键方面有很大的不同,尤其是在处理很远的点时(比如两个国家可能)。
  • @MatthewHaugen 我仅限于几何,因为这是我们在数据库中拥有的,任何将其转换为 C# 中的 SqlGeography 的操作都将进一步降低 IMO 的速度。
  • @Muhammad 将 DB 转换为 SqlGeography。任何其他解决方案只会推迟不可避免的事情,数据库是错误的,需要更改。
  • 积分从何而来?如果它们来自数据库表,则在此处进行转换。即使它们不存在,也请考虑将它们全部放入临时表中并集体进行转换。此外,一旦它们在那里,也将 STIntersects() 部分作为一组进行。 SQL 擅长基于集合的解决方案,而现在您正在执行 RBAR(“逐行逐行”)解决方案。
  • @BenThul 点是在代码中生成的。在边界框之间均匀分布,其中一部分不在一个国家/地区(即在海中),因此检查

标签: c# sql-server latitude-longitude sqlgeometry


【解决方案1】:

这是我最终想出的解决方案,它在半秒内完成了整个事情:

public static IEnumerable<Point> RemovePointsOutsideBorders(IEnumerable<Point> points, IEnumerable<Country> countries)
{
    // join all the country polygons into one (make a stamp)
    var allCountryPolygon = countries.Select(x => x.Polygon).UnionAll();

    // make a single geometry shape from our evenly spaced extent points (cookie dough)
    var pointsGeo = PointsToGeometry(points);

    // do an intersect (stamp country shape over extent based geometry)
    var cookieOfPoints = pointsGeo.STIntersection(allCountryPolygon);

    // how many points left inside? pick them all back out
    for (int n = 1; n <= cookieOfPoints.STNumPoints(); n++)
    {
        var insidePoint = cookieOfPoints.STPointN(n);
        yield return new Point
        {
            Longitude = insidePoint.STX.Value,
            Latitude = insidePoint.STY.Value
        };
    }
}

public static SqlGeometry PointsToGeometry(IEnumerable<Point> points)
{
    var bld = new SqlGeometryBuilder();
    bld.SetSrid(4326);
    bld.BeginGeometry(OpenGisGeometryType.MultiPoint);

    foreach (var p in points)
    {
        bld.BeginGeometry(OpenGisGeometryType.Point);
        bld.BeginFigure(p.Longitude, p.Latitude);
        bld.EndFigure();
        bld.EndGeometry();
    }

    bld.EndGeometry();
    return bld.ConstructedGeometry;
}

public static class ExtensionMethods
{
    /// <summary>
    /// Joins many geometries into one
    /// </summary>
    /// <param name="geometries">geometries to join</param>
    /// <returns>composite geometry</returns>
    public static SqlGeometry UnionAll(this IEnumerable<SqlGeometry> geometries)
    {
        var compositeGeometry = geometries.First();
        foreach (var g in geometries.Skip(1))
        {
            compositeGeometry = compositeGeometry.STUnion(g);
        }
        return compositeGeometry;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多