我尝试使用this example之后的 Map 的光栅重投影 . 如果我通过Azimuthal Equidistant投影更改示例 kavrayskiy7
投影,
var projection = d3.geo.azimuthalEquidistant()
.scale(90)
.translate([width / 2, height / 2])
.clipAngle(180 - 1e-3)
.precision(.1);
它应该将地球投射到光盘上(投影图的图像) . 然而,光栅重投影超出了该光盘并用扩展图像填充整个画布(反投影函数不是单射的, Map 上的几个x / y点对应于单个lon / lat坐标) . 在原始示例中,应该使用该行避免这种情况
if (λ > 180 || λ < -180 || φ > 90 || φ < -90) { i += 4; continue; }
但是这个例子不起作用 . 我发现其他故障,例如当使用Mollweide投影(两条线出现在两极)时,由于相同的效果 .
要解决这个问题,一种方法是修正反向投影,使它们在x / y输入超出范围时返回错误或无 . 我的尝试是使用整个球体的前向投影来检查点是否在范围内,以获得具有 Map 边界的SVG路径,如下面的代码所示:
var path = d3.geo.path()
.projection(projection);
var bdry = svg.append("defs").append("path")
.datum({type: "Sphere"})
.attr("id", "sphere")
.attr("d", path);
(参见例如this example) . 但是,我找不到简单的方法来检查点 [x,y]
是否在SVG闭合路径内 .
所以我的问题是:
-
逆投影是否有错误,或者我没有正确使用它们?
-
我怎么能找到
[x,y]
点是否在svg路径内,假设这是最好的方法? -
由于好奇心,d3
path
函数的算法代码在哪里获取 Map 的边界轮廓?我在github回购中找不到它 .
谢谢 .
编辑:我经历了this example中的所有44个投影,我发现以下25个故障:
Albers,Bromley,Collignon,Eckert II,Eckert IV,Eckert VI,Hammer,Hill,Goode Homolosine,Lambert圆柱形等面积,Larrivée,Laskowski,McBryde-Thomas平极抛物线,McBryde-Thomas平极四分之一,McBryde- Thomas Flat-Polar Sinusoidal,Mollweide,Natural Earth,Nell-Hammer,Polyconic,Sinu-Mollweide,van der Grinten,van der Grinten IV,Wagner IV,Wagner VII,Winkel Tripel .
2 回答
我只是使用第二个答案,因为这是针对同一问题的不同方法 . 同样,这个答案是一种替代方法,试图避免多边形解决方案中使用投影范围的svg轮廓的点 .
这个替代方案应该(我试图定义投影区域以确定是否应该渲染像素,但是使用d3.projection本身 .
由于多个点可以使用projection.invert返回相同的值,我们可以运行前向投影来验证是否应该绘制像素 .
如果
projection(projection.invert(point)) == point
则该点在我们的预测范围内 .当然,这可能存在一些精度/舍入误差,因此可以指定一定程度的容差 .
此检查符合for循环:
和其他答案一样,我构建了一个块here .
我没有检查这个答案的性能,看起来很奇怪需要这种检查,但它可能是你问题中提出的svg方法的一种合适的替代方法 .
虽然我很确定你正确使用projection.inverse函数,依赖于:
剪切投影将始终失败,因为投影 . 反转似乎始终返回东/西180度内的角度 . 虽然可能有一种方法可以修改投影本身以返回大于180度的值,但它可能比其他方法更难(而且老实说,这远远超出我能给出的任何答案) .
同样,使用SVG路径来表示世界轮廓,然后使用它作为确定是否应绘制点的基础可能使问题复杂化 .
相反,假设一个圆盘,您可以轻松计算光盘的半径,并从那里确定是否应绘制一个像素:
使用光盘的半径,我们可以计算像素是否落在光盘上或在for循环中超出光盘:
这些一起给了我:
为了美观效果,可能值得将半径缩小一定百分比 . 当然,对于不同的预测,这种方法可能是困难的或不可能的 .
我已将代码放入bl.ock here(我在此过程中将其移至d3 v4,部分是为了查看projection.inverse的行为是否相同) .
对于问题的第三部分,您可以尝试使用d3的经纬网(graticule.outline)函数来获取有关d3如何获得投影的边界轮廓的一些信息 .