Как ускорить преобразование lat-long в SqlGeometry?
У меня есть этот код, он принимает геометрию стран, а также набор точек, а затем он возвращает только точки внутри этих стран:
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 точек, с двойными значениями lat/long, преобразование из этого в 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)
может быть уменьшено для ускорения вещей, однако я не могу это контролировать. Что мне нужно, так это способ ускорить преобразование из широты / долготы в точку 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;
}
}