我的政府提供的地图数据存储在我们的数据库中,带有投影EPSG4326。由于所有数据都存储为经度和纬度,因此即使传单本身默认为投影EPSG3857,也可以成功正确地加载和显示传单。这样做是可以的,因为没有地方将传单转换到EPSG4326,因为没有地图提供商提供为EPSG4326投影的地图图块,我不想自己生成它们。
有很多数据,所以我只想检索可见视口内的数据。 Leaflet为我提供了getBounds()方法来检索可见视口的经度和纬度。不幸的是,它提供给我的坐标是EPSG3857坐标,这意味着检索到的数据在边界周围扭曲 - 4326和3857之间的差异意味着曲线是错误的。
在下图中,我将边界框的经度和纬度传递给数据库,并将其与数据相交。我绘制了绿线,以显示使用传单提供给我的EPSG3857坐标的问题。如果坐标是EPSG4326,那么它会给我更宽的坐标,这些坐标将检索绿线上方和视口内的数据。
我目前有一个黑客,我在边界框的经度和纬度上加了几度,但我希望有一个更好的解决方案。有没有更好的方法来实现这一目标?我可以以某种方式将边界框转换为EPSG4326而无需将整个过程切换到EPSG4326,从而丢失地图图块吗?
更新
以下是我在后端SQL Server中使用的代码:
CREATE PROC [core].[GetGeoData]
@Zoom int,
@BoundingBox_N decimal(18,14),
@BoundingBox_S decimal(18,14),
@BoundingBox_E decimal(18,14),
@BoundingBox_W decimal(18,14)
AS
BEGIN
DECLARE @BoundingBox varchar(200)
DECLARE @BoundingBoxGeo geography
SET @BoundingBox = 'POLYGON((' + CAST(@BoundingBox_E as varchar(20)) + ' ' + CAST(@BoundingBox_S as varchar(20)) + ',' + CAST(@BoundingBox_E as varchar(20)) + ' ' + CAST(@BoundingBox_N as varchar(20)) + ',' + CAST(@BoundingBox_W as varchar(20)) + ' ' + CAST(@BoundingBox_N as varchar(20)) + ',' + CAST(@BoundingBox_W as varchar(20)) + ' ' + CAST(@BoundingBox_S as varchar(20)) + ',' + CAST(@BoundingBox_E as varchar(20)) + ' ' + CAST(@BoundingBox_S as varchar(20)) + '))'
SET @BoundingBoxGeo = geography::STGeomFromText(@BoundingBox, 4326)
SELECT PostalCode, geo.STIntersection(@BoundingBoxGeo) AS geo
FROM [geo].[AustralianGeoData]
WHERE zoom=@Zoom AND geo.STIntersects(@BoundingBoxGeo)=1
END
在前端,我正在调用我的代码:
const mapBounds = map.getBounds();
const zoom = this.map.getZoom();
const boundingBoxN = mapBounds.getNorth();
const boundingBoxS = mapBounds.getSouth();
const boundingBoxE = mapBounds.getEast();
const boundingBoxW = mapBounds.getWest();
this.mapService.getGeoData(zoom, boundingBoxN, boundingBoxS, boundingBoxE, boundingBoxW)
.subscribe(
response => {
const geoJson = JSON.parse(row.geoJson);
this.layers.push(geoJson);
});
将边界框直接传递给后端。 map是一个L.map实例。
答案 0 :(得分:0)
好的,我在执行交集时已将查询更改为使用几何类型而不是地理类型。这将检索到正确的数据 - 当我移动地图时,我可以看到数据仅在视口中加载,因为在检索卸载区域和渲染新图层时会有一个小延迟。
我的存储过程现在看起来像这样:
ALTER PROC [core].[GetGeoData]
@Zoom int,
@BoundingBox_N decimal(18,14),
@BoundingBox_S decimal(18,14),
@BoundingBox_E decimal(18,14),
@BoundingBox_W decimal(18,14)
AS
BEGIN
DECLARE @BoundingBox varchar(200)
DECLARE @BoundingBoxGeo geometry
SET @BoundingBox = 'POLYGON((' + CAST(@BoundingBox_E as varchar(20)) + ' ' + CAST(@BoundingBox_S as varchar(20)) + ',' + CAST(@BoundingBox_E as varchar(20)) + ' ' + CAST(@BoundingBox_N as varchar(20)) + ',' + CAST(@BoundingBox_W as varchar(20)) + ' ' + CAST(@BoundingBox_N as varchar(20)) + ',' + CAST(@BoundingBox_W as varchar(20)) + ' ' + CAST(@BoundingBox_S as varchar(20)) + ',' + CAST(@BoundingBox_E as varchar(20)) + ' ' + CAST(@BoundingBox_S as varchar(20)) + '))'
SET @BoundingBoxGeo = geometry::STGeomFromText(@BoundingBox, 4326)
SELECT PostalCode, geography::STGeomFromText(geometry::STGeomFromText(geo.AsTextZM(),4326).STIntersection(@BoundingBoxGeo).AsTextZM(),4326) AS geo
FROM [geo].[AustralianGeoData]
WHERE zoom=@Zoom AND geometry::STGeomFromText(geo.AsTextZM(),4326).STIntersects(@BoundingBoxGeo)=1
AND geo.STGeometryType() IN ('Polygon','MultiPolygon','GeometryCollection')
END