当前位置: 首页 > article >正文

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

作者:gaogy

1、背景

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

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

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

2、无人机飞行效果演示

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

3、实现过程

3.1、初始化 viewer 场景

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 如下:

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 如下:

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

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、向场景添加移动光源

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 移动

window.viewer.clock.onTick.addEventListener(() => {
  light.position = flyEntity.position.getValue(viewer.clock.currentTime)
})

http://www.kler.cn/a/444360.html

相关文章:

  • gpu硬件架构
  • python web app开发
  • (五)FT2232HL高速调试器之--三步实现STM32的VSCODE在线仿真工程搭建
  • 使用Python从阿里云物联网平台获取STM32温度数据
  • 36.在 Vue 3 中使用 OpenLayers 上传包含 SHP 的 ZIP 文件并显示图形
  • WEB开发: 全栈工程师起步 - Python Flask +SQLite的管理系统实现
  • neo4j 图表数据导入到 TuGraph
  • 使用Docker启用MySQL8.0.11
  • HTMLCSS:这个动态删除按钮打几分?
  • 基于JavaScript的DBUtils增删改查操作实验
  • 算法编程题-不相交的线 联通网络的操作次数 销售价值减少的颜色球
  • git废弃指定文件的修改
  • Java设计模式 —— 【结构型模式】适配器模式(类的适配器、对象适配器、接口适配器)详解
  • 可视化平台FineReport的安装及简单使用
  • Windows 配置 Tomcat环境
  • 专业125+总分400+南京理工大学818考研经验南理工电子信息与通信工程,真题,大纲,参考书。
  • Python中map函数返回值类型用法介绍
  • arcgisPro将面要素转成CAD多段线
  • K8s HPA的常用功能介绍
  • 利用系统自带的存储感知功能清理系统中的升级补丁
  • Linux 定时任务操作详解及python简单的任务管理器
  • 设计模式-读书笔记2
  • Docker+Redis单机和集群部署【非常详细】
  • Android 获取屏幕物理尺寸
  • 建站技术 | HUGO + GitHub 创建博客页面
  • 若依前端挂Nginx、打包部署运行!!!!