Skip to content

HedronPlotEditor 体对象标绘

在 Editor 自有 CustomDataSource 中绘制、选择和编辑多边体、半球体与圆柱体,并以 GeoJSON 保存控制点。对齐源案例 LabelPlotting/HedronPlot

职责边界

  • 体对象是地图标绘注记,不是 ScenarioEntity 业务装备;Editor 不调用 viewer.createEntity()
  • 标绘实体、绘制预览和编辑控制柄全部归 Editor 的 CustomDataSource 所有。
  • 若需要判断飞机等装备是否进入体域,装备必须先由 viewer.createEntity() 创建,再传给 updateTarget();Editor 只读取装备位置,不创建、更新或删除装备。
  • 不复制源案例的远程底图、3D Tiles、JSON 或来源不明图片;模板使用内联自生成种子。

基础用法

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

const editor = new HedronPlotEditor({ viewer })

editor.addPlot({
  id: 'restricted-zone',
  type: 'cylinder',
  name: '圆柱禁飞区',
  controlPoints: [[106.445, 29.52, 100]],
  style: { radius: 650, extrudedHeight: 1100 },
})

editor.startDraw('polyhedron') // 左键加点,至少 3 点后右键完成

公共 API

ts
new HedronPlotEditor(options: HedronPlotEditorOptions)

readonly dataSource: CustomDataSource
readonly plots: readonly HedronPlotRecord[]
readonly selectedId?: string
readonly isDrawing: boolean

addPlot(definition: HedronPlotDefinition): HedronPlotRecord
updatePlot(id: string, patch: HedronPlotUpdatePatch): HedronPlotRecord
removePlot(id: string): boolean
clear(): void
select(id?: string): HedronPlotRecord | undefined

startDraw(type: HedronPlotType, draft?): void
cancelDraw(): void

contains(id: string, target: Cartesian3): boolean
updateTarget(target: CombatEntityLike, time?: JulianDate): readonly string[]
clearTarget(targetId: string): void

exportGeoJson(): HedronPlotGeoJsonFeatureCollection
importGeoJson(collection, options?): HedronPlotRecord[]

enable(): void
disable(): void
destroy(): void

类型与点数

类型控制点样式
polyhedron至少 3 个;右键完成extrudedHeight
hemisphere固定 1 个radius
cylinder固定 1 个radiusextrudedHeight

控制点统一使用 [longitude, latitude, height],角度为度、高度为椭球高米。radiusextrudedHeight 必须是有限正数。

交互

  • 单击体对象选中并高亮;单击空白取消选择。
  • 半球体和圆柱体拖动中心控制柄以移动位置。
  • 多边体拖动蓝色控制柄编辑顶点。
  • 拖动期间只暂时禁用相机 rotate / translate / tilt,结束、取消、禁用或销毁时精确恢复进入前状态与光标。
  • 取点只使用公开 API,并按 scene.pickPositionglobe.pickcamera.pickEllipsoid 回退。

动态装备进入/离开

ts
viewer.extend(viewerEntityMixin)

const fighter = viewer.createEntity({
  id: 'fighter-01',
  name: '目标机',
  entityType: 'fighter',
  components: [
    { id: 'position', type: 'PositionComponent', lon: 106.44, lat: 29.51, alt: 500 },
    { id: 'model', type: 'ModelComponent', url: '/static/J16.glb', scale: 1 },
  ],
  modules: [],
})

const editor = new HedronPlotEditor({
  viewer,
  onTargetEnter: ({ target, plot }) => console.log(target.name, '进入', plot.name),
  onTargetLeave: ({ target, plot }) => console.log(target.name, '离开', plot.name),
})

const removeTick = viewer.clock.onTick.addEventListener(clock => {
  editor.updateTarget(fighter, clock.currentTime)
})

// cleanup
removeTick()
editor.destroy()

updateTarget() 以装备 id 保存上一帧命中集合,只在状态跨越时触发一次 enter / leave,不会每帧重复通知。clearTarget() 会补发当前命中体域的离开事件并清理状态。

空间数学

包含判断统一在第一个控制点的局部 ENU 坐标系中完成:

  • 半球:z >= 0 且三维距离不超过半径;修复源实现用完整球距离判断、下半球也会命中的问题。
  • 圆柱:水平距离不超过半径,且局部高度位于 [0, extrudedHeight]
  • 多边体:局部 XY 点在多边形内,且局部高度位于拉伸范围内。
  • 边界使用毫米级 epsilon 视为内部,减少动态目标贴边时的进入/离开抖动。

GeoJSON

Point 保存半球/圆柱中心,Polygon 保存多边体控制点;属性兼容源案例的 plotCodeplotBase: "HedronPlot"plotTypeplotNamestyle。导入先完整校验全部 Feature,clearExisting: true 下非法输入也不会清空已有标绘。

生命周期与源缺陷修复

  • 一个公开 ScreenSpaceEventHandler 负责全部交互,disable() / destroy() 完整销毁。
  • 不使用源案例的 viewer._element_cesiumWidget 或 React _reactInternals
  • 不调用 viewer.entities.removeAll();清理只影响 Editor 自有 DataSource。
  • 处理 DataSourceCollection.add() 异步完成与立即 destroy() 的竞态。
  • 源实现创建的选择 handler、点/面编辑 handler 未完整销毁,且拖动仅把相机旋转强制恢复为 true;本实现按所有权和进入前状态恢复。