如何使用 three.js 可视化 GPS 轨迹? 棘手的部分是获得正确的投影,以便 GPS 轨迹与我的 Jotunheimen 地形图对齐。 在 D3.js 的帮助下,我能够做我想做的事。
推荐:用 NSDT设计器 快速搭建可编程3D场景。
我将使用我之前在 Leaflet 中使用的相同 GPS 轨迹。 我的计划是将这条轨迹转换为 GeoJSON,但我尝试过的所有工具都不包括我的轨迹的高程值。 我没有构建自己的转换器,而是决定直接在 JavaScript 中解析 GPX 文件。 GPX是一种XML格式,D3.js支持通过d3.xml方法读取XML文件:
d3.xml('jotunheimen-track.gpx', 'application/xml', gpxParser);
gpxParser 函数(如下所示)在加载 GPX 文件时调用,传入 XML 文档的根元素。 可以使用 JavaScript XML/DOM 访问工具解析此文档。
我的 GPS 轨迹是地理坐标(纬度和经度),我需要投影这些点才能在我的 Jotunheimen 地图上显示轨迹。 Three.js 不支持不同的地图投影,但我们可以使用 D3.js 强大的投影支持。 我的地图在 UTM 32 投影中,我之前在 D3.js 中尝试过 UTM。
Universal Transverse Mercator (UTM) 投影基于 D3.js 支持的圆柱形横向墨卡托投影。 下面就是我定义投影的方式:
var terrainSize = 60; // 60 x 60 km
var projection = d3.geo.transverseMercator()
.translate([terrainSize / 2, terrainSize / 2])
.scale(terrainSize * 106.4)
.rotate([-9, 0, 0])
.center([-0.714, 61.512]);
terrainSize 可以是任意大小,但我使用 60,因为我绘制的 Jotunheimen 区域是 60 x 60 公里。 我花了一些时间才找到投影配置方法中使用的值:
- translate:投影中心的像素坐标。
- scale:比例因子与投影点之间的距离线性对应。 对于我的示例,我发现这是 t- errainSize 乘以 106.4,但我不知道为什么恰好是 106.4…
- rotate:我将投影旋转负 9 度经度,对应于 UTM 32 区域的中央子午线。
- center:投影中心的经度和纬度。 这与我的地图中心 (8.286, 61.512) 相同,只是经度位置是相对于 UTM 32 的中央子午线 (8.286 - 9 = -0.714)。
对这些数字进行排序后,我的 GPS 轨迹就在我的地图上正确排列了。 但是如何在 three.js 中渲染GPS轨迹呢? 我将每个轨迹点的顶点添加到 THREE.Geometry 对象。 这是我的 GPX 解析器的代码:
function gpxParser(gpx) {
var tracks = gpx.getElementsByTagName('trk'),
geometry = new THREE.Geometry();
for (i = 0; i < tracks.length; i++) {
var points = tracks[i].getElementsByTagName('trkpt')
for (x = 0; x < points.length; x++) {
var point = points[x],
ele = parseInt(point.getElementsByTagName('ele')[0].firstChild.nodeValue),
lat = parseFloat(point.getAttribute('lat')),
lng = parseFloat(point.getAttribute('lon')),
coord = translate(projection([lng, lat]));
geometry.vertices.push(new THREE.Vector3(coord[0], coord[1], (ele / 2470 * heightFactor) + (0.01 * heightFactor)));
}
}
var material = new THREE.LineBasicMaterial({
color: 0xffffff,
linewidth: 2
});
var line = new THREE.Line(geometry, material);
scene.add(line);
}
function translate(point) {
return [point[0] - (terrainSize / 2), (terrainSize / 2) - point[1]];
}
此函数从 GPX 轨迹中提取海拔、纬度和经度值,并为每个点创建一个顶点。 坐标使用我们的 D3 投影对象进行投影,并转换到 three.js 的坐标空间,就像这篇文章中所述:
在 Three.js 中,坐标系的工作方式如下。 点 (0,0,0) 是世界的中心。 当你查看屏幕时,正 x 值向右移动,负 x 值向左移动。 正 y 值向上移动,负 y 值向下移动。 正 z 值向您移动,负 z 值远离您。
高程值也乘以高度因子,这与我用于地形的高度因子相同。 此外,我添加了一个小的偏移量,因此轨迹渲染得略高于地面。
我正在使用 THREE.LineBasicMaterial 创建线型,并使用 THREE.Line 在将线几何体和材质添加到场景之前将其放在一起。 可以看到地图上的白线:
可以从 Github 下载本教程的代码。 另一种方法是跳过 GPS 轨道中的高程值,而是将轨道固定到地形上,但我还没有找到使用 three.js 执行此操作的简单方法。
原文链接:Three.js显示GPS轨迹 — BimAnt