Three.js教程
cesium
绘制箭头、符号标记

Cesium 绘制箭头、符号等标记

Cesium 是一个用于 3D 地理可视化的开源引擎,可以在浏览器里展示地球、卫星影像、三维地形等。

很多 GIS 项目都需要在 3D 场景中绘制各种标记、符号、箭头等,来表达地理标注或态势信息,比如用于军事标绘中的部队前进、攻击方向等。

Cesium 本身就可以实现这些效果,最直接的方式就是手动绘制。接下来我们先来看一个最基础的示例:通过写死点位来绘制一个红色箭头

手动绘制一个红色箭头

这里的核心思路是:

  1. 把箭头的轮廓坐标(经纬度)一一枚举出来;
  2. 转换为 Cesium 的笛卡尔坐标;
  3. 新建一个 polygon 实体并设置外边框、颜色、透明度等;

下面是一个简单的实现:

const viewer = new Cesium.Viewer(container);
 
// 定义一个“写死”的箭头多边形 - 直接列出顶点经纬度
const arrowShape = Cesium.Cartesian3.fromDegreesArray([
  115.8,
  39.91, // 箭身左下角
  115.8,
  39.89, // 箭身右下角
  115.9,
  39.89, // 箭头底部右
  115.9,
  39.88, // 箭头右侧
  116.0,
  39.9, // 箭头尖端
  115.9,
  39.92, // 箭头左侧
  115.9,
  39.91, // 箭头底部左
]);
 
// 4. 创建一个实体(Entity),并用 polygon 绘制箭头
const arrowEntity = viewer.entities.add({
  name: "红色箭头",
  polygon: {
    // 轮廓点
    hierarchy: new Cesium.PolygonHierarchy(arrowShape),
    // 填充材质:带点透明度的红色
    material: Cesium.Color.RED.withAlpha(0.8),
    // 加边框
    outline: true,
    outlineWidth: 2,
    // 高程设置(可选)
    height: 0,
    extrudedHeight: 1000, // 如果想让箭头“拔高”成一个立体多边形,可设置 extrudedHeight
  },
});

这种方式确实简单直接,适合绘制一些固定形状的箭头或标记。但问题也很明显:

  • 所有顶点坐标都得自己手动写或计算
  • 如果箭头带有弧度、曲线、钩子等复杂几何,就非常难手动算清楚;
  • 更不用说如果要支持用户自己在地图上画,这种方法就完全不适用了。

用 cesium-plot-js 进行符号绘制

为了解决上述问题,我们可以使用社区的开源库 —— cesium-plot-js (opens in a new tab)

这是一个基于 Cesium 封装的轻量级绘图工具,支持鼠标交互式绘制各种军事符号和地图图形。

cesium-plot-js 是什么?

cesium-plot-js 支持在 Cesium 地图上交互式绘制各种态势标注、箭头、多边形等。

它的特点是:

  • 支持 19 种常见符号,包括:自由箭头、进攻箭头、钳形箭头、双箭头、曲线等;
  • 允许用户通过 鼠标点击、拖动 在地图上交互式生成复杂图形;
  • 支持编辑图形、获取点位数据、加载已有图形等功能;
  • 支持绘制和只读展示两种模式。

地址: https://github.com/ethan-zf/cesium-plot-js?tab=readme-ov-file (opens in a new tab)

依赖安装

npm i cesium-plot-js

引入

import CesiumPlot from "cesium-plot-js";

绘制进攻箭头

比如,我们要创建一个进攻箭头的效果

const geometry = new CesiumPlot.AttackArrow(Cesium, viewer, {
  material: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
  outlineMaterial: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
  outlineWidth: 3,
});

AttackArrow 就是对应上图的攻击箭头的类名,现在我们在地图上进行点击就可以绘制出想要的箭头了,并且能够指定方向。

同时它有五个事件,便于开发者控制流程:

  • drawStart:绘制开始
  • drawUpdate:绘制过程中点位更新,回调事件返回更新的 Cartesian3 点位
  • drawEnd:绘制结束,回调事件返回图形的关键点位```
  • editStart:编辑开始
  • editEnd:编辑结束,回调事件返回图形的关键点位

例如,我们监听绘制完成事件以获取图形数据:

geometry.on("drawEnd", (data) => {
  console.log(data);
});

当双击结束绘制后,控制台将输出箭头的关键点坐标: 绘制完成后,可通过点击图形来拖动整体,或调整各个顶点位置:

若想绘制双箭头,只需将 AttackArrow 替换为 DoubleArrow

const geometry2 = new CesiumPlot.DoubleArrow(Cesium, viewer, {
  material: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
  outlineMaterial: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
  outlineWidth: 3,
});

对应效果如下:

根据已有坐标数据创建图形

我们也可以不使用鼠标绘制,而是基于已有点位数据直接生成图形。例如,以下是一组笛卡尔坐标点:

const cartesianPoints = [
  {
    x: -2133835.4252435253,
    y: 4417894.642531558,
    z: 4061821.4828650053,
  },
  {
    x: -2137181.2256785277,
    y: 4417579.261006469,
    z: 4060414.659839411,
  },
  {
    x: -2139410.4770342503,
    y: 4412744.708073081,
    z: 4064468.266519916,
  },
];

基于这些数据创建进攻箭头图形:

const geometry3 = CesiumPlot.createGeometryFromData(Cesium, viewer, {
  type: "AttackArrow",
  cartesianPoints: cartesianPoints,
  style: {
    material: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
    outlineMaterial: Cesium.Color.fromCssColorString("rgba(255, 0, 0, 1)"),
  },
});

效果如下所示:

优势总结

使用 cesium-plot-js 进行符号绘制,有以下优势:

  • 无需手动计算复杂图形的顶点;
  • 多种常见符号可直接绘制,支持箭头、圆弧、钩状标记等;
  • 交互友好、代码简洁、功能丰富;
  • 支持数据导出与还原,便于集成与持久化。

代码

文章中的案例代码,可以访问 https://github.com/calmound/cesium-demo/tree/main/src/demos/arrow-symbol (opens in a new tab)