这是我的设置。我定义了一个多边形和一个靠近该多边形中间的点。使用 STWithin 或 STIntersects 不会返回任何内容。
create table #gtest ([Lat] [float], [Lng] [float], [GeoPoint] AS ([geography]::Point([Lat],[Lng],(4326))))
insert #gtest(Lat, Lng) values (36.3893, -102.796)
declare @swLng float, @swLat floa, @neLng float, @neLat float
declare @g geography, @poly varchar(max)
select @swLng=-147.45514585847684, @swLat=28.841195680455485, @neLng=-59.86599816500535, @neLat=56.14838208179307
set @poly = 'POLYGON((' + cast(@swLng as varchar) + ' ' + cast(@swLat as varchar) + ',' + cast(@neLng as varchar) + ' ' + cast(@swLat as varchar) + ',' + cast(@neLng as varchar) + ' ' + cast(@neLat as varchar) + ',' + cast(@swLng as varchar) + ' ' + cast(@neLat as varchar) + ',' + cast(@swLng as varchar) + ' ' + cast(@swLat as varchar) + '))'
set @g = geography::STGeomFromText(@poly, 4326);
select * from #gtest where GeoPoint.STWithin(@g) = 1 -- no results
select * from #gtest where GeoPoint.STIntersects(@g) = 1 -- no results either
但是如果我减小多边形大小,从sql server的角度来看,该点开始适合它。
select @swLng=-134.35054327724572, @swLat=31.64106010841097, @neLng=-71.77427705012154, @neLat=51.66708602548192
UPD:从评论中我可以看到多边形是球体的一部分,这是有道理的,但是我如何处理墨卡托投影? 我正在使用 Mapbox 绘制一些点,这就是我使用 Mapbox 的边界得到的结果:
如果您希望边界遵循纬度线或以其他方式遵循墨卡托投影上的直线,我相信您需要通过在每对线段或现有线段之间添加中间点来用一系列线段来近似它(达到可接受的公差)顶点。
对于本次讨论,我将使用
(x, y)
坐标符号而不是 (Longitude, Latitude)
。下面的方法也是一种近似,假设要纠正的误差相当于欧几里得空间中的弧和弦之间的差。
如果边缘起点和终点坐标定义为
{(xs,ys),(xe,ye)}
,则可以将欧几里得中点定义为 (xm,ym)
,其中 xm = (xs+xe)/2
和 xm = (xs+xe)/2
。然后,您可以使用 STDistance
计算该点与端点定义的线之间的距离 h
。
对于给定的弧,弦高
h
等于 R(1-cos(θ/2)),其中 θ 是弧的角度。对于小弧,该高度大致与角度平方成正比,因此要实现公差 t
(以米为单位),您可以计算 N ≈ SQRT(h/t)
。因为这是一个近似值,您可能需要添加一个模糊因子并计算类似 N = CEIL(1.1 * h / t)
的值。
从那里您可以计算
(xi,yi)
的中点 i in 1..N-1
,其中 xi = ((N-i) * xs + i * xe) / N
和 yi = ((N-i) * ys + i * ye) / N
。您可以将这些点插入到我们原来的起点和终点之间。
对于向北/向南延伸(恒定经度)的边界线段以及其他原始
h
小于容差 t
的边界线段,您可能会发现计算出的 N
为 0
或 1
,其中如果您不需要插入任何中间点。
我上面写的所有内容目前都未经测试,但我正在编写一些示例代码......