NSDT工具推荐Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包

如何使用 three.js 可视化 GPS 轨迹? 棘手的部分是获得正确的投影,以便 GPS 轨迹与我的 Jotunheimen 地形图对齐。 在 D3.js 的帮助下,我能够做我想做的事。

我将使用我之前在 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:比例因子与投影点之间的距离线性对应。 对于我的示例,我发现这是 terrainSize 乘以 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 执行此操作的简单方法。


原文链接:Showing GPS tracks in 3D with three.js and d3.js

BimAnt翻译整理,转载请标明出处