【问题标题】:Apply d3 geo projection to an image将 d3 地理投影应用于图像
【发布时间】:2016-09-11 16:30:04
【问题描述】:

我有一张图像,我知道墨卡托投影的左下角和右上角坐标(纬度/经度)。

我将其作为 google.maps.GroundOverlay 添加到 Google 地图中,这给了我正确的结果

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

这一切都很好,除了我想使用 topojson 从 Google Maps 转移到 d3,因为 d3 更轻量级并且不需要 Google Map 的功能。

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

如果我覆盖两个窗口(包含 Google Maps 地图的浏览器和包含 d3 地图的浏览器),那么我可以让国家边界和角点非常精确地重叠。

这是一个动画 gif,其 d3-map 浏览器优于 Google Maps 地图浏览器,并且 d3-map 浏览器窗口的透明度正在借助工具进行更改。它从完全不透明变为完全透明,然后再次变为完全不透明。显示国家名称的图像是谷歌地图。

如您所见,这些点和国家边界对齐得非常好,但雷达图像却没有。将 d3 图像向下移动一点可以缓解问题,但不是正确的解决方案。我知道谷歌地图显示的是那个。

我在做什么:在 d3 地图中我正在创建投影

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

然后为所提供的图像 latlong 角创建一个边界框。

bb = {
  east:  16.0,
  west:   4.0,
  north: 56.0,
  south: 46.0,
}

并将它们从 latlong-space 投影到画布 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; })

当我画圆圈时,位置与谷歌地图上的位置非常精确。这意味着投影正在工作。

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);

问题来了:我正在以一种非常“便宜”的方式应用图像。我将左上角的 latlong 投影到画布 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 位置视为纬度/经度位置,然后通过墨卡托投影将每个像素投影到地图上。

但我不知道该怎么做。有任何想法吗? d3.geo 有没有类似于google.maps.GroundOverlay 的简单叠加插件?

【问题讨论】:

  • 如果 D3 有更多的地理插件当然会很好,看起来像谷歌地图 GroundOverlay 这样的东西是一个很常见的要求

标签: image google-maps d3.js map-projections d3.geo


【解决方案1】:

Google 地图使用 WEB MERCATOR 投影,与真正的墨卡托投影(由 D3 使用)相比略有不同。 (来自Wikipedia:Web Mercator 是主要用于基于 Web 的制图程序中的 Mercator 投影的一个轻微变体。它使用与用于小比例尺地图的标准 Mercator 相同的公式。但是,Web Mercator在所有比例尺上都使用球面公式,而大比例尺墨卡托地图通常使用投影的椭球体形式。这种差异在全球范围内是难以察觉的,但会导致局部区域的地图与相同比例尺的真实椭球墨卡托图略有偏差。这离赤道越远偏差越明显,在地面上可达35公里。

虽然 Web 墨卡托的公式适用于墨卡托的球形,但地理坐标必须位于 WGS 84 椭球基准面中。这种差异会导致投影略微不一致。

有一个S.O. 讨论,其中询问了为什么当包含带有 D3 的光栅图像时缩放会发生变化。这又是由于 D3 和墨卡托之间的差异。如果您的光栅图像在谷歌地图中完美对齐......由于网络墨卡托和墨卡托之间的细微差异,它不应该在 d3 中对齐,并且为了使其正常工作,我认为必须(重新投影)光栅图像,并且这就是您在 d3 与谷歌地图上看到它未对齐的原因。 (编辑注意我用错了词。没有缩放,而是重新投影....)

希望这会有所帮助。

实际上,可以在here:(GDAL 项目的一部分)中找到一些不错的重新投影软件,它也是开源的。 (希望对你有所帮助。)

【讨论】:

  • 谢谢,这是有趣的信息。如果我应该回去修复我的代码,我会考虑到这一点。所以,显然有两个问题。 1 是每像素映射,另一个是投影类型。但是我想知道为什么角落匹配得这么好,好像投影还可以。
  • 端点起作用了...它是所有奇怪的中间...。一个不错的(免费)程序从 equilinier 重新投影在这里giss.nasa.gov/tools/gprojector
  • (一些kool的例子来自不同投影的nasa页面.....
  • 错过了不同投影的链接...giss.nasa.gov/tools/gprojector/help/projections.html
猜你喜欢
  • 2012-08-14
  • 1970-01-01
  • 1970-01-01
  • 2017-07-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多