经纬志
首页 / Cesium / 教程

空间分析:测距、剖面与可视域

先看结论

Cesium 不提供现成的分析工具箱,只提供几何与地形采样两类基础能力。 测距、剖面、通视判断都要自己组合这几块积木,组合方式决定了结果是否可信。

最后验证 2026-11-03 · CesiumJS 1.121 · 难度:进阶 · 核验 2026-10-29 · 引用本文

先分清三种距离

距离算法结果典型用途
椭球面距离Cesium.EllipsoidGeodesic沿椭球面的测地线长度,米地图量距、航线里程
空间直线距离Cesium.Cartesian3.distance两点在 ECEF 中的直线长度,米通视、遮挡、三维间距
屏幕像素距离SceneTransforms画布上的像素数交互判定、标注避让
var start = Cesium.Cartographic.fromDegrees(116.30, 39.90);
var end   = Cesium.Cartographic.fromDegrees(116.46, 39.92);

var geodesic = new Cesium.EllipsoidGeodesic(start, end);
console.log('地表距离', geodesic.surfaceDistance.toFixed(1), '米');
console.log('方位角', Cesium.Math.toDegrees(geodesic.startHeading).toFixed(1), '度');

var a = Cesium.Cartesian3.fromDegrees(116.30, 39.90, 40);
var b = Cesium.Cartesian3.fromDegrees(116.46, 39.92, 120);
console.log('直线距离', Cesium.Cartesian3.distance(a, b).toFixed(1), '米');

两者在几十公里范围内差别不大,但在地形起伏明显的山区, 直线距离会因为高差而明显短于地表距离。报表里写「里程」应当用测地线, 写「视线长度」才用直线距离。

沿线段采样地形,得到剖面

Cesium.sampleTerrainMostDetailed 接收一个 Cartographic 数组,返回带 height 的新数组。 它内部会请求对应层级的地形瓦片,返回是异步的,点数越多耗时越长。

function sampleLine(start, end, count) {
  var out = [];
  for (var i = 0; i <= count; i++) {
    var t = i / count;
    out.push(new Cesium.Cartographic(
      start.longitude + (end.longitude - start.longitude) * t,
      start.latitude + (end.latitude - start.latitude) * t
    ));
  }
  return out;
}

async function buildProfile(start, end, count) {
  var samples = sampleLine(start, end, count || 120);
  await Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, samples);

  return samples.map(function (c) {
    return {
      lng: Cesium.Math.toDegrees(c.longitude),
      lat: Cesium.Math.toDegrees(c.latitude),
      height: c.height
    };
  });
}

var profile = await buildProfile(
  Cesium.Cartographic.fromDegrees(116.30, 39.90),
  Cesium.Cartographic.fromDegrees(116.46, 39.92),
  120
);
var maxHeight = Math.max.apply(null, profile.map(function (p) { return p.height; }));

viewer.terrainProvider 为 EllipsoidTerrainProvider 时, 所有采样点的高程都是 0。剖面是一条直线,不代表算法错了,只代表场景没有加载地形。

采样密度看用途。画一张示意图,60 个点足够;做坡度统计或工程断面, 要按地形瓦片分辨率反推点数,通常每 5 到 10 米一个采样点,否则细窄的沟壑会被跨过去。

两点通视判断

观察点与目标点之间逐点比较「视线高度」和「地面高度」,任意一个采样点地面高出视线, 两点即不可见。这是最常用的近似可视域算法,代价是一次地形采样请求。

async function isVisible(observer, target, steps) {
  var n = steps || 100;
  var samples = sampleLine(observer, target, n);
  await Cesium.sampleTerrainMostDetailed(viewer.terrainProvider, samples);

  for (var i = 1; i < n; i++) {
    var t = i / n;
    var sightHeight = observer.height + (target.height - observer.height) * t;
    if (samples[i].height > sightHeight + 0.3) {
      return { visible: false, blockedAt: samples[i] };
    }
  }
  return { visible: true, blockedAt: null };
}

var observer = Cesium.Cartographic.fromDegrees(116.391, 39.907, 28);
var target   = Cesium.Cartographic.fromDegrees(116.412, 39.921, 60);
var result = await isVisible(observer, target, 100);

observer.height 在 Cartographic 里是米,不是弧度, 这一点与经纬度不同,容易在拷贝代码时改错。0.3 米的余量用来抵消地形采样误差。

把结果画回场景

分析结果最终要落到地图上:测量线、剖面采样点、遮挡位置。用实体绘制, 并把临时结果放在单独的数据源里,方便一次清空。

var analysisSource = new Cesium.CustomDataSource('analysis');
viewer.dataSources.add(analysisSource);

function drawMeasureLine(positions, labelText) {
  analysisSource.entities.add({
    polyline: {
      positions: positions,
      width: 2,
      material: Cesium.Color.fromCssColorString('#4d9bff'),
      clampToGround: false
    },
    label: {
      text: labelText,
      font: '500 13px sans-serif',
      fillColor: Cesium.Color.WHITE,
      showBackground: true,
      backgroundColor: Cesium.Color.fromCssColorString('rgba(14, 17, 22, 0.85)'),
      pixelOffset: new Cesium.Cartesian2(0, -18),
      disableDepthTestDistance: Number.POSITIVE_INFINITY
    },
    position: positions[positions.length - 1]
  });
}

function clearAnalysis() {
  analysisSource.entities.removeAll();
}

注意事项

  • sampleTerrainMostDetailed 会等待整块地形瓦片下载完成,首屏调用可能耗时数秒;界面上要有加载状态。
  • 相机移动后再做一次分析,必须重新采样,不能复用上一次的结果。
  • 可视域是「点对点」判断,不是「面」判断。要得到可视范围,需要从观察点向四周发射多条视线。
  • 实体数量多时用 viewer.entities.suspendEvents() 与 resumeEvents() 包住批量增删。
  • 剖面数据只用于展示,不要直接当工程量算;地形瓦片本身有简化,高程存在米级误差。

性能底线:一次通视判断采样 100 个点,交互中连续触发就会堆积请求。 用计数器限制并发,或者把结果按「起终点网格」缓存,避免同一区域重复采样。

引用本文

经纬志(2026)。《空间分析:测距、剖面与可视域》。https://www.jingweizhi.com/cesium/tutorial/spatial-analysis.html(访问日期 2026-11-03)。