将d3地理投影应用于图像

时间:2016-05-15 22:48:37

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

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

image of current weather conditions in Germany

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

enter image description here

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

这很好,除了我想通过topojson从谷歌地图转移到d3,因为d3更轻巧,并且不需要谷歌地图的功能。

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

enter image description here

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

这是一个动画gif,它在Google Maps地图浏览器上有d3-map浏览器,d3-map浏览器窗口的透明度正在借助工具进行更改。它从完全透明变为完全透明,然后再变为完全不透明。显示国家/地区名称的图片是Google地图名称。

enter image description here

正如您所看到的,点和国家边界对齐非常好,但雷达图像并不是很好。将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; })

当我绘制圆圈时,位置非常精确地匹配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);

问题就出现了:我正在以非常好的方式应用该图像"办法。我将左上角的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

1 个答案:

答案 0 :(得分:2)

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

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

有一个S.O.讨论问题被问到为什么当包含D3的光栅图像时缩放会发生变化。再次,这是由于D3和墨卡托之间的差异。如果你的光栅图像在谷歌地图中完美对齐......由于web mercator和mercator之间的微妙变化,它应该永远不会在d3中对齐,并且为了工作我会认为光栅图像必须(重新投影),并且这就是你在d3和谷歌地图上看到它不对齐的原因。 (编辑注意我使用了错误的单词。没有缩放,而是重新复制....)

希望这有点帮助。

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