OpenLayers:通过跳过投影并允许自定义特征格式来优化无 GPU 平台上的渲染?

问题描述 投票:0回答:1

我有一系列轨迹。每个轨迹代表一辆移动的车辆,并且是一个由唯一 ID 和一组坐标组成的对象,这些坐标是车辆随时间变化的位置的等间隔样本。例如,

[
  {
    id: 1,
    p: [[100, 200], [300, 400]] // Array<[x, y]>
  },
  {
    id: 2,
    p: [[300, 400], [500, 600], [700, 800]] // Array<[x, y]>
  }
]

例如,这些轨迹可能代表这样的运动(2 辆车)。 (该图像与上面的数据无关,而只是另一个(视觉)示例)。

enter image description here

这里的困难部分是可能有多达 15000 个轨迹,我需要同时为所有这些移动车辆设置动画。

目前,如果我采用 15000 个点的 GeoJSON(坐标为 LonLat 对)并尝试将它们投影到地图上(使用 WebMercator 投影),整个操作大约需要 350 毫秒。鉴于我的目标是流畅的 60fps 动画,我知道理想情况下整个计算部分不会超过 16.7 毫秒。此外,绘画也是由CPU执行的(在我的例子中没有硬件加速),所以这16.7ms对于数据准备和绘画来说应该足够了。同样,目前这一切大约需要 350ms,所以我需要优化算法的某些部分。

最关键的优化是轨迹点的坐标已经计算为画布范围。也就是说,如果有坐标

[100, 200]
,则意味着该点需要在 canvas
x = 100 and y = 200
处渲染,而不是 Lon 100 和 Lat 200(或 WebMercator 坐标
100 and 200
)。这应该会跳过投影步骤,从而释放一些 CPU 时间。

但是,我仍然希望能够受益于 OpenLayers 为矢量图层和源提供的所有内置功能。即,造型。此外,还有其他功能,例如交互和选择。这意味着我不能盲目地获取 Canvas 的 2D 渲染上下文并在那里绘制一些

arc

据我了解,我仍然需要创建

Feature

// Create features with screen coordinates
const points = trajectory.p.map(([x, y]) => {
  const geometry = new Point([x, y]);
  return new Feature(geometry);
});

但是在这种情况下,坐标被视为 WebMercator 坐标(要素被投影到地图上)。

问题是,如何让要素在渲染时跳过这一部分,将自身投影到地图上,而是处理它们的坐标和相对于渲染地图的画布的绝对坐标?


一个额外问题。

将这些坐标转换为

Feature
对象也是一个相当昂贵的操作。我想知道是否有办法跳过它,但仍然受益于 OL 为其功能提供的所有样式和交互可能性?

我虽然想基于

VectorSource
创建自定义源,但这仍然涉及转换为
Features
。如果我扩展基本
Source
,则不可能将其他源类型与
VectorLayer
一起使用,因为它们仅适用于
VectorSource
。如果我使用自定义
Layer
扩展基础
CustomLayer
以与
CustomSource
一起使用并给它一个
CanvasCustomLayerRenderer
,那么我将失去所有默认矢量图层的样式可能性。

在我的情况下,我能做的最好的事情是什么,以保留 OpenLayers 开箱即用提供的所有功能,但同时通过删除我不感兴趣的步骤来提高性能?

javascript gis openlayers
1个回答
0
投票

OpenLayers 样式示例,像素坐标,无特征

  <html>
<head>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/ol.css">
  <style>
    html, body, .map {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
    }
  </style>
  <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/ol.js"></script>
</head>
<body>
  <div id="map" class="map"></div>
  <script>

    const style = new ol.style.Style({
      image: new ol.style.Circle({
        radius: 10,
        fill: new ol.style.Fill({
          color: 'blue',
        }),
      }),
    });

    const base = new ol.layer.Tile({
      source:  new ol.source.OSM(),
    });

    base.on('postrender', e => {
      const vectorContext = ol.render.toContext(e.context);
      vectorContext.setStyle(style);
      vectorContext.drawGeometry(
        new ol.geom.Point([200, 100])
      );
    });

    const map = new ol.Map({
      target: 'map',
      pixelRatio: 1,
      layers: [base],
      view: new ol.View({
        center: [0, 0],
        zoom: 5,
      }),
    });

  </script>
</body>
  </html>

© www.soinside.com 2019 - 2024. All rights reserved.