Skip to content

FenceEffect 电子围栏效果

在指定闭合折线区域上生成双层墙体纵向扫描的电子围栏,对齐源案例 SpecialEffects/Fence。 底层是静态全高渐变墙(栅栏本体),上层是墙高从地面涨到 height 再回落到地面循环的 扫描带,直观表达「警戒 / 禁飞 / 缓冲区边界」。动画由时间驱动duration 为一次完整 扫描周期),修复源实现按帧累加 fenceHeight * 0.004 的帧率依赖问题。


能力定位

FenceEffect 适合:

  • 电子围栏 / 警戒区:在重要目标、营区、禁飞区外围画一圈动态扫描边界;
  • 边界高亮:用纵向扫描带强调某块区域的范围,配合 setPositions 在运行时动态改形;
  • 多围栏叠加:不同 color / height / duration 的围栏可并行使用,互不共享状态。

动态立体墙(材质流动)的区别:FenceEffect 的动画作用于墙高maximumHeights 锯齿扫描),而非上层材质流动;底层全高墙提供稳定的栅栏本体,扫描带 沿墙高方向从地面向上爬升后回落。

构造函数

ts
constructor(options: FenceEffectOptions)
ts
interface FenceEffectOptions {
  positions: Cartesian3[]; // 围栏顶点(世界坐标),至少 3 个点,必填
  height?: number;         // 围栏墙高(米),默认 30
  color?: Color;           // 围栏颜色,默认 Color.RED
  duration?: number;       // 一次完整扫描周期(毫秒),默认 3000
}
参数类型默认值描述
positionsCartesian3[]围栏顶点,少于 3 个点构造抛错;墙会沿折线闭合
heightnumber30围栏墙高(米),maximumHeights = 贴地高度 + height
colorColorColor.RED围栏颜色,同时作用于底层渐变墙与扫描墙
durationnumber3000扫描周期(毫秒):墙高从地面涨到 height 后回落,一次 duration 完成

生命周期

ts
on(viewer: Viewer): void       // 启用效果:创建底层全高墙与扫描墙两个实体,记录扫描起点(幂等)
off(viewer: Viewer): void      // 停用效果:移除本效果创建的两个实体(幂等)
destroy(viewer: Viewer): void  // 销毁效果,委托 off 释放全部自有资源(可重复调用)
setPositions(positions: Cartesian3[]): void // 运行时更新围栏顶点并重算贴地高度(启用状态下同样生效)
方法参数说明
onviewer重复调用为 no-op,不会重复创建实体
offviewer未启用时调用为 no-op
destroyviewer委托 off,重复调用安全
setPositionspositions少于 3 个点抛错;顶点与高度经 CallbackProperty 跟随最新状态,无需重建实体

基础示例

ts
import { FenceEffect } from '@nexa/gis-cesium'
import { Cartesian3, Color } from 'cesium'

// 扫描动画由时钟时间驱动:必须让时钟推进(shouldAnimate 或手动 tick),
// 否则 CallbackProperty 的 time 不变化,扫描墙会停在贴地高度看不到。
viewer.clock.shouldAnimate = true

const effect = new FenceEffect({
  positions: [
    Cartesian3.fromDegrees(106.455901, 29.505694),
    Cartesian3.fromDegrees(106.457311, 29.506953),
    Cartesian3.fromDegrees(106.458057, 29.506492),
    Cartesian3.fromDegrees(106.456782, 29.504892),
    Cartesian3.fromDegrees(106.455901, 29.505710),
  ],
  height: 30,
  color: Color.RED,
  duration: 3000,
})

effect.on(viewer)

// 页面或场景退出时由创建方负责清理
effect.destroy(viewer)

进阶示例

多围栏并行 + setPositions 运行时改形:

ts
import { FenceEffect } from '@nexa/gis-cesium'
import { Cartesian3, Color } from 'cesium'

// 红色 30 米高,慢速扫描
const redFence = new FenceEffect({
  positions: redPositions, // 同基础示例
  height: 30,
  color: Color.RED,
  duration: 3000,
})
redFence.on(viewer)

// 青色 20 米高,快速扫描(对齐源案例 addGreenFence)
const greenFence = new FenceEffect({
  positions: greenPositions,
  height: 20,
  color: Color.fromCssColorString('#0BFF0D'),
  duration: 1500,
})
greenFence.on(viewer)

// 8 秒后把红色围栏改造成矩形围界
setTimeout(() => {
  redFence.setPositions([
    Cartesian3.fromDegrees(106.4530, 29.5055),
    Cartesian3.fromDegrees(106.4590, 29.5055),
    Cartesian3.fromDegrees(106.4590, 29.5078),
    Cartesian3.fromDegrees(106.4530, 29.5078),
  ])
}, 8000)

// 场景退出时统一清理
redFence.destroy(viewer)
greenFence.destroy(viewer)

实现与性能说明

  • 复用现有材质:底层墙使用 WallGradientsMaterialProperty,扫描墙使用 WallTrailVerticalMaterialProperty,均为 SDK 既有材质,无新增 GLSL;
  • 动画依赖时钟推进:扫描墙高度回调的参数 time 来自 viewer.clock.currentTime,只有 时钟前进相位才会变化。SDK 的 CesiumViewer 默认不透传 shouldAnimate(时钟静止), 启用前需 viewer.clock.shouldAnimate = true,或自行驱动时钟(如 viewer.clock.tick()),对齐源案例 shouldAnimate: true
  • 时间驱动扫描:扫描墙 maximumHeightsCallbackProperty(isConstant=false)JulianDate.secondsDifference(now, startTime) 取模计算锯齿相位: 相位 0 → 贴地高度相位 0.5 → 贴地高度 + height相位 1 → 回落贴地高度。帧率无关, 修复源实现按帧累加 fenceHeight * 0.004 的帧率依赖(不同设备扫描速度不一致);
  • 顶点跟随positions / 贴地高度 / 全高均经 CallbackProperty 返回当前引用, setPositions 运行时重设后实体自动跟随,长度保持一致(回归:曾因 ConstantProperty 捕获旧数组引用导致 positionsmaximumHeights 长度失配);
  • 高度来源:贴地高度由 Cartographic.fromCartesian(position).height 计算,墙默认随 地形/地物高度贴底;minimumHeightsmaximumHeights 长度始终与顶点数一致;
  • 性能:每帧求值 positions/minimumHeights/maximumHeights 三次回调(数组引用返回, 无拷贝),适合少量围栏;扫描墙高度随帧变化会触发墙几何更新(源实现同样行为)。

Cesium 版本限制

  • 依赖 CallbackProperty / Cartographic / WallGraphics,为 Cesium 长期稳定 API;
  • 已验证目标版本:Cesium 1.133.1;
  • CallbackProperty 回调签名以目标版本为准(time: JulianDate | undefined),按源码 JSDoc @example 使用即可。

清理责任

  • on() 创建的底层墙与扫描墙两个实体统一由 destroy(viewer)(或 off(viewer))释放;
  • 不调用 destroy 会导致两个 wall 实体残留,务必在页面或场景退出时清理;
  • destroy 可重复调用,幂等安全;off 后可再次 on 重新启用。

与原生 Cesium API 的组合方式

  • positions 可直接复用 viewer.entities.add() 或绘制工具产出的 Cartesian3[]
  • 可与 viewer.camera.flyTo(viewer.entities) 组合,让相机自动框住全部围栏;
  • 需要显示围栏名称时,叠加一个 label/point 实体即可,FenceEffect 不占用命名空间。