Lea*_*ple 5 gis projection d3.js extent
鉴于EPSG预测(例如,这个阿拉巴马州的预测:[ http://spatialreference.org/ref/epsg/26729/] [1 ])
如何以可以在D3.js投影中使用它们的方式获取给定的WGS84投影边界.
例如,您如何知道用于显示地图的投影,旋转度或边界框?
And*_*eid 17
这是一个相当复杂的问题.答案将根据您正在查看的空间参考(SRS或坐标参考系统(CRS))系统以及您的最终目标而有所不同.
我在这个答案中使用d3.js v4
例如,您如何知道用于显示地图的投影,旋转度或边界框?
没有硬性和快速的规则包含所有预测.查看投影参数通常可以为您提供足够的信息来快速创建投影 - 假设投影在d3中开箱即用.
我可以给出的关于设置参数的最佳建议,如何时旋转或何时居中,使用的平行等,是在精炼投影时缩小输出方式,以便您可以看到每个参数正在做什么以及您在哪里查看.然后进行缩放或范围拟合.那个并使用geojson验证器作为你的边界框,就像这个.
最后,您可以始终使用投影数据并完全删除d3.geoProjection(此问题),如果您的所有数据都已投影在同一投影中,则尝试定义投影是一个有争议的问题.
我会很快注意到,如果你看一下基准面之间的差异,这个问题可能会更复杂.例如,您引用的SRS使用了NAD27数据.基准面是地球形状的数学表示,NAD27将与NAD83或WGS84不同,尽管所有都是以度为单位测量的,因为基准面代表地球的三维表面.如果您正在混合使用冲突基准的数据,则可能会出现一些精度问题,例如,根据您的需要,NAD27和NAD83之间的基准平移并非无关紧要(维基百科截图,无法链接到图像):
如果由于使用多个基准而导致的位置变化是一个问题,那么您需要的不仅仅是d3才能将它们转换为一个标准基准.D3假设您将使用WGS84,这是GPS系统使用的数据.如果这些转变不是问题,那么忽略这部分答案.
那么,让我们来看看你的预测,EPSG:26729:
PROJCS["NAD27 / Alabama East",
GEOGCS["NAD27",
DATUM["North_American_Datum_1927",
SPHEROID["Clarke 1866",6378206.4,294.9786982138982,
AUTHORITY["EPSG","7008"]],
AUTHORITY["EPSG","6267"]],
PRIMEM["Greenwich",0,
AUTHORITY["EPSG","8901"]],
UNIT["degree",0.01745329251994328,
AUTHORITY["EPSG","9122"]],
AUTHORITY["EPSG","4267"]],
UNIT["US survey foot",0.3048006096012192,
AUTHORITY["EPSG","9003"]],
PROJECTION["Transverse_Mercator"],
PARAMETER["latitude_of_origin",30.5],
PARAMETER["central_meridian",-85.83333333333333],
PARAMETER["scale_factor",0.99996],
PARAMETER["false_easting",500000],
PARAMETER["false_northing",0],
AUTHORITY["EPSG","26729"],
AXIS["X",EAST],
AXIS["Y",NORTH]]
Run Code Online (Sandbox Code Playgroud)
这是投影的非常标准的描述.每种类型的投影都有特定于它的参数,因此这些参数并不总是相同的.
本说明中最重要的部分是:
NAD27 / Alabama East
投影名称,不需要,但是一个很好的参考,因为它比EPSG编号更容易记住,并且参考/工具可能只使用通用名称而不是EPSG编号.
PROJECTION["Transverse_Mercator"]
我们正在处理的投影类型.这定义了表示地球表面上的点的3d坐标如何转换为笛卡尔平面上的2d坐标.如果您在此处看到未在受支持投影的d3列表(v3 - v4)中列出的投影,那么您在定义自定义投影时需要做一些工作.但是,通常情况下,您会找到与此匹配的投影.无论地图是在每个轴上旋转还是居中,投影类型都会发生变化.
PARAMETER["latitude_of_origin",30.5],
PARAMETER["central_meridian",-85.83333333333333],
Run Code Online (Sandbox Code Playgroud)
这两个参数设置了投影的中心.对于横向墨卡托,只有中央子午线很重要.请参阅此演示,了解在横向墨卡托上选择中央子午线的效果.
原点的纬度主要用于设置northnigs的参考点.中央子午线也为东方做这个,但如上所述,设置中心子午线,其中失真从极到极最小化(它相当于常规墨卡托上的赤道).如果你真的需要有适当的北向和东向,以便你可以比较纸质地图和共享相同投影的网络地图中的x,y位置,那么d3可能不是最好的工具.如果您不关心测量笛卡尔坐标空间中的坐标,这些参数无关紧要:D3不会复制投影的坐标系(以英尺为单位测量假东/北),而是在SVG坐标中复制相同的形状空间.
因此,基于投影描述中的相关参数,以此投影原点为中心的d3.geoProjection将如下所示:
d3.geoTransverseMercator()
.rotate([85.8333,0])
.center([0,30.5])
Run Code Online (Sandbox Code Playgroud)
为什么我旋转大约86度?这就是横向墨卡托的构建方式.在横向墨卡托的演示中,地图沿x轴旋转.以x轴为中心将简单地左右平移地图,而不是改变投影的性质.在演示中很明显,投影正在经历一个与平移不同的变化,这就是应用的旋转.当我在投影下转动地球时,我使用的旋转是负的.所以这个投影集中在-85.833度或西85.8333度.
因为在横轴墨卡托上,沿着子午线的失真是一致的,我们可以向下平移而不需要旋转.这就是为什么我在y轴上使用中心(在这种情况下,在其他情况下,你也可以在y轴上旋转,负y,因为这将旋转地图下方的圆柱投影,得到与平移相同的结果) .
如果我们缩小了一点,这就是投影的样子:
它可能看起来很扭曲,但它只是为了显示阿拉巴马州内和附近的区域.放大它开始看起来更正常:
接下来的问题很自然:规模怎么样?那么这将根据您的视口大小和您想要显示的区域而有所不同.并且,您的投影未指定任何边界.如果你想显示地图投影的范围,我会在答案的最后触及边界.即使投影具有边界,它们也可能与您想要显示的区域(通常是整个投影边界的子集)对齐.
在其他地方居中怎么样?假设您只想展示一个不会出现在投影中心的城镇?好吧,我们可以使用中心.因为我们在x轴上旋转地球,所以任何居中都相对于中央子午线.以[1,30.5]为中心,将地图居中于中央子午线以东1度(西面85.8333度).因此x分量将相对于旋转,y分量将相对于赤道 - 其纬度.
如果坚持投影是很重要的,那么需要这种奇怪的居中行为,如果没有,可能更容易简单地修改x旋转,以便你有一个看起来像这样的投影:
d3.geoTransverseMercator()
.center([0,y])
.rotate([-x,0])
...
Run Code Online (Sandbox Code Playgroud)
这将定制横向墨卡托以针对您的特定区域进行优化,但代价是偏离您的起始预测.
不同的投影可能有不同的参数.例如,圆锥投影可以具有一条(切线)或两条(正割)线,这些线表示投影与地球相交的点(因此失真最小化的点).这些投影(例如Albers或Lambert Conformal)使用类似的方法进行居中(旋转-x,中心y),但具有附加参数以指定表示切线或正割线的平行线:
d3.geoAlbers()
.rotate([-x,0])
.center([0,y])
.parallels([a,b])
Run Code Online (Sandbox Code Playgroud)
请参阅此答案,了解如何旋转/居中Albers(对于此刻想到的所有圆锥投影,这基本相同).
平面/方位角投影(我没有检查过)可能只是居中.但是,每个地图投影在"居中"时可能会略有不同(通常是.rotate和.center的组合).
关于如何设置不同的投影类型/系列,有很多例子和SO问题,这些应该有助于大多数具体的预测.
但是,您可能有一个指定边界的投影.或者更可能的是,带有边界和投影的图像.在这种情况下,您需要指定这些边界.使用以下.fitExtent
方法使用geojson功能可以轻松完成此操作d3.geoProjection()
:
projection.fitExtent(extent,object):
设置投影的比例并进行平移以适合给定范围中心的指定GeoJSON对象.范围指定为数组[[x 0,y 0],[x 1,y 1]],其中x 0是边界框的左边,y 0是顶部,x 1是右边,y 1是底部.返回投影.
(另见这个问题/答案)
我将在此处的问题中使用示例来演示使用边界框来帮助定义投影.目标是使用以下知识投影下面的地图:它的投影和它的边界框(我把它放在手边,找不到一个定义好的边界框的好例子):
然而,在我们到达边界框坐标之前,让我们看一下投影.在这种情况下,它是这样的:
PROJCS["ETRS89 / Austria Lambert",
GEOGCS["ETRS89",
DATUM["European_Terrestrial_Reference_System_1989",
SPHEROID["GRS 1980",6378137,298.257222101,
AUTHORITY["EPSG","7019"]],
AUTHORITY["EPSG","6258"]],
PRIMEM["Greenwich",0,
AUTHORITY["EPSG","8901"]],
UNIT["degree",0.01745329251994328,
AUTHORITY["EPSG","9122"]],
AUTHORITY["EPSG","4258"]],
UNIT["metre",1,
AUTHORITY["EPSG","9001"]],
PROJECTION["Lambert_Conformal_Conic_2SP"],
PARAMETER["standard_parallel_1",49],
PARAMETER["standard_parallel_2",46],
PARAMETER["latitude_of_origin",47.5],
PARAMETER["central_meridian",13.33333333333333],
PARAMETER["false_easting",400000],
PARAMETER["false_northing",400000],
AUTHORITY["EPSG","3416"],
AXIS["Y",EAST],
AXIS["X",NORTH]]
Run Code Online (Sandbox Code Playgroud)
我们将让d3根据边界框选择比例和中心点,我们只关心几个参数:
PARAMETER["standard_parallel_1",49],
PARAMETER["standard_parallel_2",46],
Run Code Online (Sandbox Code Playgroud)
这些是两条割线,地图投影拦截地球表面.
PARAMETER["central_meridian",13.33333333333333],
Run Code Online (Sandbox Code Playgroud)
这是中央子午线,我们将用于沿x轴旋转投影的数字(就像人们会想到的所有圆锥投影一样).
最重要的是:
PROJECTION["Lambert_Conformal_Conic_2SP"],
Run Code Online (Sandbox Code Playgroud)
这条线给了我们投影系列/类型.
总而言之,这给了我们类似的东西:
d3.geoConicConformal()
.rotate([-13.33333,0]
.parallels([46,49])
Run Code Online (Sandbox Code Playgroud)
现在,边界框由这些限制定义:
的.fitExtent
(和.fitSize
)方法采取以GeoJSON对象,并适当地转换和调整的投影. 我将.fitSize
在这里使用它,因为它在边界周围跳过边距(fitExtent
允许提供边距,这是唯一的区别).所以我们需要用这些边界创建一个geojson对象:
var bbox = {
"type": "Polygon",
"coordinates": [
[
[9.3, 49.2], [17.2, 49.2], [17.2, 46], [9.3, 46], [9.3,49.2]
]
]
}
Run Code Online (Sandbox Code Playgroud)
记住使用右手规则,并使你的终点与你的起点相同(否则无休止的悲伤).
现在我们所要做的就是调用这个方法,我们将进行预测.由于我使用图像来验证我的投影参数,我知道我想要的宽高比.如果您不知道纵横比,则可能会有一些多余的宽度或高度.这给了我类似的东西:
var projection = d3.geoConicConformal()
.parallels([46,49])
.rotate([-13.333,0])
.fitSize([width,height],bbox)
Run Code Online (Sandbox Code Playgroud)
一个看起来很开心的最终产品(记住一个严重下采样的世界topojson):