将D3地理投影应用于图像

4

我有一张图片,我知道它在墨卡托投影中的左下角和右上角的经纬度坐标。

image of current weather conditions in Germany

我将其添加到Google Maps作为google.maps.GroundOverlay,这使我得到了正确的结果。

enter image description here

我在图像的左上角(绿色)、右上角(红色)、右下角(青色)和左下角(红色)添加了一些颜色标记。

这一切都很好,但是我想从Google Maps转移到d3和topojson,因为d3更加轻量级,而且不需要Google Map的功能。

我已经创建了基于d3的地图,包括图像角落的标记,这就是结果:

enter image description here

如果我将两个窗口叠加在一起(一个浏览器包含谷歌地图,另一个浏览器包含d3地图),那么我可以非常准确地重叠国家边界和角点。
这是一个动画GIF,其中d3-map浏览器位于谷歌地图浏览器上方,并且使用工具更改d3-map浏览器窗口的透明度。它从完全不透明变为完全透明,然后再次变为完全不透明。显示国家名称的图像是谷歌地图的图像。

enter image description here

正如您所看到的,点和国界非常对齐,但雷达图像却没有。将d3图像向下移动一点可以缓解问题,但这不是正确的解决方案。我知道Google Maps显示的解决方案是正确的。

我的做法:在创建d3地图时,我正在创建投影。

projection = d3.geo.mercator().scale(scale).translate([width / 2, width / 2]).center(center);

然后,根据提供的图像经纬度角落创建一个边界框。
bb = {
  east:  16.0,
  west:   4.0,
  north: 56.0,
  south: 46.0,
}

将它们从经纬度空间投影到画布的 x、y 坐标中。

p_ur = projection([bb.east, bb.north]).map(function(x) { return x; })
p_ll = projection([bb.west, bb.south]).map(function(x) { return x; })
p_ul = projection([bb.west, bb.north]).map(function(x) { return x; })
p_lr = projection([bb.east, bb.south]).map(function(x) { return x; })

当我绘制圆圈时,位置非常精确地与Google地图上的位置匹配。这意味着投影正在工作。
circle = svg.append("svg:circle").attr('cx',p_ll[0]).attr('cy',p_ll[1]).attr('r', 2).attr("class", "ll")
circle = svg.append("svg:circle").attr('cx',p_ur[0]).attr('cy',p_ur[1]).attr('r', 2).attr("class", "ur")
circle = svg.append("svg:circle").attr('cx',p_ul[0]).attr('cy',p_ul[1]).attr('r', 2).attr("class", "ul")
circle = svg.append("svg:circle").attr('cx',p_lr[0]).attr('cy',p_lr[1]).attr('r', 2).attr("class", "lr")

在绘制圆之前,我会先绘制topojson国家边界。
path = d3.geo.path().projection(projection);
countries = svg.append("g");
// ...fetching the data from the web...
countries.selectAll('.country')
         .data(topojson.feature(data, data.objects.europe).features)
         .enter()
         .append('path')
         .attr('class', 'country')
         .attr('d', path);
问题来了:我正在以一种非常“廉价”的方式应用图像。我将左上角的经纬度投影到画布的x、y空间中,并将其用作svg:image的x、y原点。这些点已经被计算出来用于上面的颜色圆圈,所以我在这里重新使用它们。
image = svg.append("svg:image")
         .attr('x', p_ul[0])
         .attr('y', p_ul[1])
         .attr('width',  (p_lr[0] - p_ul[0]))
         .attr('height', (p_lr[1] - p_ul[1]))
         .attr('preserveAspectRatio', 'none')
         .attr("xlink:href","http://.../current.png")

一些如何跳过使用角落将图像固定在地图上的投影变换的像素数据。 我认为应该将图像的每个x,y位置视为纬度/经度位置,然后通过墨卡托投影将每个像素投影到地图上。 但我不知道如何做。 有什么想法吗? 是否有类似于google.maps.GroundOverlay的简单d3.geo叠加插件?

1
希望D3能有更多的地理插件,似乎像谷歌地图的GroundOverlay这样的东西是一个相当普遍的需求。 - chrismarx
1个回答

2
Google Maps使用WEB MERCATOR投影,与真正的Mercator投影(由D3使用)略有不同。(摘自维基百科:Web Mercator是Mercator投影的一个轻微变体,主要用于基于Web的地图程序。它使用与小比例尺地图中使用的标准Mercator相同的公式。但是,Web Mercator在所有比例尺上都使用球面公式,而大比例尺Mercator地图通常使用投影的椭球形式。在全球范围内,这种差异是无法察觉的,但在相同比例尺下,本地区域的地图与真实的椭球形Mercator地图略有偏差。这种偏差在赤道以外的地方更加明显,在地面上可以高达35公里。

虽然Web Mercator的公式适用于Mercator的球面形式,但需要将地理坐标放在WGS 84椭球面基准上。这种差异导致投影略微不符合规范。

有一个S.O.的讨论,提出了一个问题:为什么当包含D3栅格图像时,缩放会发生变化。这再次归因于D3和墨卡托之间的差异。如果你的栅格图像在Google地图上对齐得很完美...它永远不应该在D3中对齐,因为Web墨卡托和墨卡托之间存在微小的差异,为了使其工作,我认为必须(重新投影)栅格图像,这就是你看到它在D3上与Google地图错位的原因。(编辑说明我用错了单词。不是缩放,而是重新投影...)
希望这能有所帮助。
实际上,一些不错的开源重新投影软件可以在此处找到(属于GDAL项目)。 (希望这能对你有所帮助。)

谢谢,这是有趣的信息。如果我回去修复我的代码,我会考虑这个问题。所以,显然有两个问题。一个是每像素映射,另一个是投影类型。但我想知道为什么角落匹配得如此完美,就好像投影是正确的一样。 - Daniel F
终点工作正常...问题出在中间....这里有一个不错的(免费)程序,可以从等距投影进行重投影,链接为http://www.giss.nasa.gov/tools/gprojector/。 - e3495026
(一些很酷的例子来自不同投影的NASA页面......) - e3495026
错过了不同投影的链接... http://www.giss.nasa.gov/tools/gprojector/help/projections.html - e3495026

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接