Skip to content

二维点贴合三维场景

将只有经纬度的设备、监控点或业务点位,批量贴合到地球、3D Tiles 或 其他场景几何表面,并返回可回写数据库的经纬高结果。

能力定位

CoordinateUtils.clampGeographicPointsToScene 面向从二维 GIS 迁移到三维场景的批处理需求:

  • 输入是经纬度(可选初始高度),无需调用方先构造 Cartesian3
  • 默认异步查询 3D Tiles 的最高可用精度,也可只查询当前已渲染场景;
  • 返回数组与输入等长、同顺序,可按 index 稳定回写原业务记录;
  • 未命中和运行环境不支持会返回明确原因,不会静默丢失数据;
  • 只计算坐标,不创建 Entity、Primitive 或装备。

API

ts
static clampGeographicPointsToScene(
  viewer: Cesium.Viewer,
  points: readonly GeographicCoordinate[],
  options?: ClampGeographicPointsOptions,
): Promise<ClampGeographicPointResult[]>

选项

ts
interface ClampGeographicPointsOptions {
  mode?: 'current' | 'most-detailed'
  objectsToExclude?: readonly object[]
  width?: number
}
字段默认值说明
mode'most-detailed'最高精度异步查询;current 只查询当前已渲染的地球瓦片 / 3D Tiles
objectsToExcludeundefined不参与贴合的 Primitive、Entity 或 3D Tiles Feature
widthCesium 默认值沿椭球法线查询的交叉体宽度(米),显式传入时必须大于 0

结果

ts
interface ClampGeographicPointResult {
  index: number
  source: GeographicCoordinate
  success: boolean
  position?: Cesium.Cartesian3
  coordinate?: LngLatAlt
  reason?: 'unsupported' | 'not-found'
}
  • position 是 ECEF 世界坐标,coordinate 是角度制经纬度 + 米制高度;
  • 两者只在 success === true 时存在;
  • sourceposition 都是独立副本,Cesium 的原地更新不会改写调用方数据;
  • unsupported 表示当前浏览器 / 渲染环境不支持 Scene clamp,not-found 表示该位置没有可命中几何。

基础用法

ts
import { CesiumViewer, CoordinateUtils } from '@nexa/gis-cesium'

const nexaGis = new CesiumViewer('container')
const viewer = nexaGis.viewer

const sourcePoints = [
  { longitude: 116.391, latitude: 39.906 },
  { longitude: 116.392, latitude: 39.907 },
]

const results = await CoordinateUtils.clampGeographicPointsToScene(
  viewer,
  sourcePoints
)

for (const result of results) {
  if (!result.success) {
    console.warn(`第 ${result.index} 个点转换失败:${result.reason}`)
    continue
  }
  console.log(result.coordinate)
}

当前场景与最高精度

ts
// 快速:只使用当前已渲染的地球瓦片 / 3D Tiles
const current = await CoordinateUtils.clampGeographicPointsToScene(
  viewer,
  points,
  { mode: 'current' }
)

// 批处理优先:请求 3D Tiles 最高可用精度后再返回
const detailed = await CoordinateUtils.clampGeographicPointsToScene(
  viewer,
  points,
  { mode: 'most-detailed' }
)

most-detailed 是默认值,适合数据回写、批量入库等对高度稳定性要求较高的场景。 current 适合用户正在浏览的局部区域或对响应时间更敏感的交互。

与装备系统组合

API 只返回坐标。在 nexa 中,有业务身份的监控点、传感器或装备应继续 通过 viewer.createEntity 创建:

ts
import { viewerEntityMixin } from '@nexa/gis-cesium'

nexaGis.extend(viewerEntityMixin)

for (const result of results) {
  if (!result.coordinate) continue
  const { longitude, latitude, height } = result.coordinate

  viewer.createEntity({
    id: `converted-${result.index}`,
    name: `三维监控点 ${result.index}`,
    entityType: 'other',
    components: [
      { id: 'position', type: 'PositionComponent', lon: longitude, lat: latitude, alt: height },
      { id: 'billboard', type: 'BillboardComponent', url: markerUrl, scale: 0.6 },
    ],
    modules: [],
  })
}

objectsToExclude 可用于排除原始设备自身的 Entity,避免查询射线命中待转换标记:

ts
const objectsToExclude = sourceEquipment.map(item => item.entity)
await CoordinateUtils.clampGeographicPointsToScene(viewer, points, {
  objectsToExclude,
})

输入验证

以下输入会抛出明确错误:

  • 经度不在 [-180, 180]
  • 纬度不在 [-90, 90]
  • 经度、纬度、高度或 widthNaN / Infinity
  • width <= 0
  • 未知 mode

空数组是合法输入,会直接返回空数组且不调用 Scene。

资源与版本说明

  • 工具方法不创建 Entity、Primitive、DOM、事件或定时器,无需单独销毁;
  • 只使用 Cesium 1.133.1 公共 clampToHeightSupportedclampToHeightclampToHeightMostDetailedCartesian3Cartographic API;
  • 场景必须已包含待贴合几何。current 模式下,相关地球瓦片 / 3D Tiles 还必须已渲染;
  • 源案例依赖的 HTTP 3D Tiles、高德底图与 PNG 标记均不属于转换能力, 目标案例使用本地程序化几何与内联 SVG,无外部资产依赖。