iClent3D for Cesium 实现无人机巡检飞行效果

作者:gaogy

1、背景

随着地理信息技术的发展,三维地球技术逐渐成为了许多领域中的核心工具,尤其是在城市规划、环境监测、航空航天以及军事领域。三维地图和场景的应用正在帮助人们更加直观地理解空间数据,提供更高效的决策支持。

iClient3D for Cesium 是由 SuperMap 提供的一款开发工具,旨在将三维地理信息系统 (3D GIS) 技术应用于大规模的地理信息可视化与分析,帮助开发者通过 Web 平台展示三维地图,还提供了强大的数据分析功能,包括对建筑物、地形、设施等的空间分析。

本文将利用 iClient3D for Cesium 实现三维场景下的无人机巡检飞行效果,模拟无人机的飞行,并能将无人机拍摄范围以光源形式实时展示于三维场景之中,为低空经济与发展提供有效的无人机可视化飞行效果。

2、无人机飞行效果演示

iClent3D for Cesium 实现无人机巡检飞行效

3、实现过程

3.1、初始化 viewer 场景

js 复制代码
function initViewer(viewerContainer) {
  window.viewer = new Cesium.Viewer(viewerContainer, {
    shouldAnimate: true,
    useDefaultRenderLoop: true,
    infoBox: false,
    contextOptions: {
      webgl: {
        alpha: false,
        antialias: true,
        preserveDrawingBuffer: true,
        failIfMajorPerformanceCaveat: false,
        depth: true,
        stencil: false,
        anialias: false
      }
    }
  })
  viewer.imageryLayers.addImageryProvider(
    new Cesium.BingMapsImageryProvider({
      url: 'https://dev.virtualearth.net',
      mapStyle: Cesium.BingMapsStyle.AERIAL,
      key: 'AiCyZH6DplpqBK5CViec7lYcLq941OtnIAvlcVojsyxBfZwUDvp0CsHzZr--U2KY'
    })
  )
  viewer.scene.open('http://www.supermapol.com/realspace/services/3D-CBD/rest/realspace')
}

3.2、自定义 Cesium 飞行 Entity 的 vue hook 如下:

js 复制代码
import { onMounted } from 'vue'

function getDirection(tagPosition, position) {
  return Cesium.Cartesian3.normalize(
    Cesium.Cartesian3.subtract(tagPosition, position, new Cesium.Cartesian3()),
    new Cesium.Cartesian3()
  )
}

function getModelGraphics(options) {
  if (options) {
    return new Cesium.ModelGraphics({
      uri: options.m_url,
      scale: options.m_scale || 28,
      minimumPixelSize: options.m_minimumPixelSize || 30,
      color: options.m_color || Cesium.Color.WHITE
    })
  }
}

function getLabelGraphics(options) {
  if (options && options.l_text) {
    return new Cesium.LabelGraphics({
      text: options.l_text,
      font: options.l_font || '14px sans-serif',
      fillColor: options.l_fillColor || Cesium.Color.GOLD,
      style: options.l_style || Cesium.LabelStyle.FILL_AND_OUTLINE,
      outlineWidth: options.l_outlineWidth || 2,
      outlineColor: options.l_outlineColor || undefined,
      showBackground: options.l_showBackground || false,
      backgroundColor: options.l_backgroundColor || new Cesium.Color(0.165, 0.165, 0.165, 0.8),
      verticalOrigin: options.l_verticalOrigin || Cesium.VerticalOrigin.BOTTOM,
      pixelOffset: options.l_pixelOffset || new Cesium.Cartesian2(0, -30)
      //heightReference:Cesium.HeightReference.RELATIVE_TO_GROUND
    })
  }
}

function getBillboardGraphics(options) {
  if (options && options.b_img) {
    return new Cesium.BillboardGraphics({
      image: options.b_img,
      width: options.b_width || 35,
      height: options.b_height || 35,
      clampToGround: options.b_clampToGround || true,
      scale: options.b_scale || 1,
      // eyeOffset :new Cesium.Cartesian2(0, -20),
      pixelOffset: options.b_pixelOffset || new Cesium.Cartesian2(0, -20),
      scaleByDistance: options.b_scaleByDistance || undefined
      // heightReference:Cesium.HeightReference.RELATIVE_TO_GROUND
    })
  }
}

export default function useCustomEntity(options) {
  if (window.viewer && options && options.paths) {
    const _paths = options.paths
    const _positionProperty = new Cesium.SampledPositionProperty()
    const _rEntity = new Cesium.Entity()
    const _directionProperty = new Cesium.SampledPositionProperty()
    const _startTime = new Cesium.JulianDate()
    let _direction = null
    let _stopTime = null
    let _increment = null
    let _time = null
    if (options.times) {
      let _times = options.times - (options.times % (_paths.length - 1))
      ;(_stopTime = Cesium.JulianDate.addSeconds(_startTime, _times, new Cesium.JulianDate())),
        (_increment = _times / (_paths.length - 1))
    } else {
      _stopTime = Cesium.JulianDate.addSeconds(
        _startTime,
        (_paths.length - 1) * (options.step || 120),
        new Cesium.JulianDate()
      )
    }
    const startTime = options.startTime || _startTime
    const stopTime = options.stopTime || _stopTime
    window.viewer.clock.startTime = startTime.clone()
    window.viewer.clock.currentTime = startTime.clone()
    window.viewer.clock.stopTime = stopTime.clone()
    window.viewer.clock.multiplier = options.multiplier || 10
    window.viewer.clock.clockRange = options.clockRange || Cesium.ClockRange.LOOP_STOP
    for (let i = 0; i < _paths.length; i++) {
      const cartesian = Cesium.Cartesian3.fromDegrees(_paths[i].lon, _paths[i].lat, _paths[i].alt)
      if (options.times) _time = Cesium.JulianDate.addSeconds(startTime, i * _increment, new Cesium.JulianDate())
      else _time = Cesium.JulianDate.addSeconds(startTime, _paths[i].time, new Cesium.JulianDate())
      _positionProperty.addSample(_time, cartesian)
      let directionCartesian = null
      if (i === _paths.length - 1) {
        _directionProperty.addSample(_time, _direction)
        continue
      } else {
        directionCartesian = Cesium.Cartesian3.fromDegrees(_paths[i + 1].lon, _paths[i + 1].lat, _paths[i + 1].alt)
      }
      _direction = getDirection(directionCartesian, cartesian)
      _directionProperty.addSample(_time, _direction)
    }
    _rEntity.name = options.name || '漫游Entity'
    _rEntity.availability = new Cesium.TimeIntervalCollection([
      new Cesium.TimeInterval({ start: startTime, stop: stopTime })
    ])
    _rEntity.position = _positionProperty
    _rEntity.orientation = new Cesium.VelocityOrientationProperty(_positionProperty)
    _rEntity.direction = _directionProperty
    if (options.model) _rEntity.model = getModelGraphics(options)
    if (options.label) _rEntity.label = getLabelGraphics(options)
    if (options.billboard) _rEntity.billboard = getBillboardGraphics(options)
    onMounted(() => window.viewer.entities.add(_rEntity))
    return { _rEntity }
  }
}

3.3、自定义 Cesium 的移动光源的 vue hook 如下:

js 复制代码
import { onMounted } from 'vue'

export default function useCustomLight(position, options) {
  if (window.viewer && position) {
    const DEF_OPTS = {
      color: options.color || new Cesium.Color(1, 1, 2, 0.8),
      cutoffDistance: options.cutoffDistance || 1000,
      decay: options.decay || 0.5,
      intensity: options.intensity || 1
    }
    const _options = options || DEF_OPTS
    const customLight = new Cesium.PointLight(position, _options)
    onMounted(() => window.viewer.scene.addLightSource(customLight))
    return { customLight }
  }
}

3.4、向场景添加飞行无人机 Entity

js 复制代码
const { _rEntity: flyEntity } = useCustomEntity({
  paths: [
    { lon: 116.44596605973072, lat: 39.90275976224633, alt: 400, time: 0 },
    { lon: 116.470769862146, lat: 39.90961660773017, alt: 400, time: 120 },
    { lon: 116.44621270736882, lat: 39.912427615595874, alt: 400, time: 240 },
    { lon: 116.45867843557505, lat: 39.92072065356812, alt: 400, time: 360 },
    { lon: 116.469697344222, lat: 39.91736853889283, alt: 400, time: 480 },
    { lon: 116.46625570699818, lat: 39.91100981903596, alt: 400, time: 600 }
  ],
  model: true,
  m_url: '/model/CesiumDrone.gltf',
  label: true,
  l_text: '无人机一号',
  l_outlineWidth: 3,
  l_fillColor: Cesium.Color.CYAN
})

3.5、向场景添加移动光源

js 复制代码
const { customLight: light } = useCustomLight(flyEntity.position.getValue(viewer.clock.currentTime), {
  color: new Cesium.Color(0, 140, 140, 0.8),
  cutoffDistance: 500,
  decay: 2,
  intensity: 5
})

3.6、设置光源跟随无人机 Entity 移动

js 复制代码
window.viewer.clock.onTick.addEventListener(() => {
  light.position = flyEntity.position.getValue(viewer.clock.currentTime)
})
相关推荐
曲折3 小时前
Cesium-气象要素PNG色斑图叠加
前端·cesium
十启树5 天前
QGis开发环境部署
开发语言·gis·qgis
rainstop_313 天前
为 Claude Code 开发自定义 Skill:解决中国地图坐标系转换痛点
gis·ai编程·claude
GIS开发特训营14 天前
Cesium Shader 实战:三维 GIS 可视化进阶教程
gis·cesium·gis开发·webgis
GIS好难学19 天前
【分享】120套开源数据可视化大屏H5模板
信息可视化·webgis
GDAL20 天前
viewer.camera.flyTo 全面教程
cesium·camera·flyto
深紫色的三北六号20 天前
射线法判断一个坐标点(经纬度)是否在一个多边形区域内部
java·算法·gis
GIS学姐嘉欣20 天前
Cesium进阶教程(2)线性高度雾
javascript·cesium·gis开发·webgis
牛老师讲GIS20 天前
终于,Leaflet WIKI发布上线了
leaflet·webgis
图扑可视化20 天前
WebGIS 智慧交通——路网运行态势 BI 可视化大屏
gis·数字孪生·智慧交通·智慧高速