cesium绘制路线,实现三维漫游

这篇具有很好参考价值的文章主要介绍了cesium绘制路线,实现三维漫游。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1.鼠标点击添加点和线

handler.setInputAction(function (event) {
        //返回地球表面上的点坐标
        const earthPosition = positionUtil.cartesian2ToCartesian3(event.position)
        if (Cesium.defined(earthPosition)) {
            const ellipsoid = viewer.scene.globe.ellipsoid;
            const cartographic = ellipsoid.cartesianToCartographic(earthPosition);
            const lon = Cesium.Math.toDegrees(cartographic.longitude);
            const lat = Cesium.Math.toDegrees(cartographic.latitude);
            const alt = cartographic.height + 20 // 高度加20
            AddPoint({
                lon,
                lat,
                alt,
                color: Cesium.Color.YELLOW
            }, viewer);
            positions.push(Cesium.Cartesian3.fromDegrees(lon, lat, alt))
            positons2.push({x:lon,y:lat,z:alt})
            if (positions.length >=2) {
              if (!polyline)
                polyline = AddPolyline(viewer)
            }
        }
    }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    // 添加点
const AddPoint = (params, viewer) => {
  const entity:any = new Cesium.Entity({
      id:`${params.lon}`,
      name: '点',
      show: true,
      position: Cesium.Cartesian3.fromDegrees(params.lon, params.lat, params.alt),
      point: new Cesium.PointGraphics({
          show: true, //是否展示
          pixelSize: 10, //点大小
          color: params.color
      })
  });
  //收集Id
  viewer.entities.add(entity);
  return entity;
}
 // 添加线
 const AddPolyline = (viewer) => {
  const entity = new Cesium.Entity({
      id:`${new Date().getTime()}线`,
      name: '线',
      polyline: new Cesium.PolylineGraphics({
          show: true,
          clampToGround: false,
          positions: new Cesium.CallbackProperty(function () {
            return positions;
          }, false),//params.positions,
          width: 10,
          material: new Cesium.PolylineGlowMaterialProperty({
              glowPower: 0.2,
              color: Cesium.Color.BLUE
          })
      })
  } as any);
  viewer.entities.add(entity);
  return entity;
}

2.右键结束绘制时,计算折线中心点和绘制方向;折线中心点可以替换为模型中心点,这样就会看着这个点飞行;计算方向主要是判断绘制的顺序是顺时针绘制的还是逆时针绘制的

handler.setInputAction(function (event) {
      // 计算折线中心点
      centerPos = caclPolyCenter(viewer)
      isRight = _judgeDirection(positions)
      // console.log(isRight, '逆时针');
      if (handler) {
        handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
        handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
      }
    }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)
    const caclPolyCenter = (viewer) => {
  const entity = new Cesium.Entity({
    name: "Red polygon on surface",
    polygon:{
      hierarchy: new Cesium.PolygonHierarchy(positions),
      material: Cesium.Color.RED.withAlpha(0.5),
    },
  });
  const polyPositions = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions;
  let polyCenter = Cesium.BoundingSphere.fromPoints(polyPositions).center;//中心点
  polyCenter = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(polyCenter);
  const cartographic = Cesium.Cartographic.fromCartesian(polyCenter, viewer.scene.globe.ellipsoid, new Cesium.Cartographic());
  const lat = Cesium.Math.toDegrees(cartographic.latitude);
  const lng = Cesium.Math.toDegrees(cartographic.longitude);
  const height = cartographic.height;
  return {x: lng, y: lat, z: height}
}
/**
   * 判断点的顺序是顺时针还是逆时针
   * @param {Cesium.Cartesian3[]} points
   */
const _judgeDirection = (points) => {
  const lonlat1 = Cesium.Cartographic.fromCartesian(points[0])
  const lonlat2 = Cesium.Cartographic.fromCartesian(points[1])
  const lonlat3 = Cesium.Cartographic.fromCartesian(points[2])
  const x1 = lonlat1.longitude,
    y1 = lonlat1.latitude,
    x2 = lonlat2.longitude,
    y2 = lonlat2.latitude,
    x3 = lonlat3.longitude,
    y3 = lonlat3.latitude,
    dirRes = (x2 - x1) * (y3 - y2) - (y2 - y1) * (x3 - x2)

  const isR = dirRes > 0
  return isR
}

3.点击飞行
pitch默认为-5
setExtentTime: 在viewer的clock中设置时间间隔,flytime默认为15,也可以根据线段的长度来定义每一段的飞行时间
TimeExecution: 添加clock.onTick事件监听,每一帧调用,根据时间动态计算下一个点的坐标,然后更新相机位置.关于viewer.clock.onTick可查看api深入学习
changeCameraHeading: 如果当前的时间=设定的停止时间,移除监听并开始转向,当前时间=设定的停止时间时,开始下一段线的飞行marksIndex+1

const flyExtent = (viewer) => {
  // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
  const pitch = Cesium.Math.toRadians(pitchValue); //  默认-5
  // 时间间隔15秒钟
  setExtentTime(flytime, viewer);
  Exection = function TimeExecution() {
    let preIndex = marksIndex - 1;
    if (marksIndex === 0) {
      preIndex = positons2.length - 1;
    }
    //计算俯仰角

    // 当前已经过去的时间,单位s
    const delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime);
    const originLat = marksIndex == 0 ? positons2[positons2.length - 1].y : positons2[marksIndex - 1].y;
    const originLng = marksIndex == 0 ? positons2[positons2.length - 1].x : positons2[marksIndex - 1].x;
    const endPosition = Cesium.Cartesian3.fromDegrees(
      (originLng + (positons2[marksIndex].x - originLng) / flytime * delTime),
      (originLat + (positons2[marksIndex].y - originLat) / flytime * delTime),
      positons2[marksIndex].z
    );
    let heading = bearing(originLat,originLng, centerPos.y, centerPos.x);
    // let heading = bearing(centerPos.y, centerPos.x, originLat,originLng);
    heading = Cesium.Math.toRadians(heading);
    viewer.scene.camera.setView({
      destination: endPosition,
      orientation: {
        heading: heading,
        pitch: pitch,
      }
    });
    if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) {
      viewer.clock.onTick.removeEventListener(Exection);
      //有个转向的功能
      changeCameraHeading(viewer);
    }
  };
  viewer.clock.onTick.addEventListener(Exection);
}
// 相机原地定点转向
const changeCameraHeading = (viewer) => {
  // 计算两点之间的方向
  let nextIndex = marksIndex + 1;
  if (marksIndex == positons2.length - 1) {
    nextIndex = 0;
  }
  const heading = bearing(positons2[marksIndex].y, positons2[marksIndex].x,centerPos.y, centerPos.x );
  console.log(heading, Cesium.Math.toDegrees(viewer.camera.heading));

  // 相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
  const pitch = Cesium.Math.toRadians(pitchValue);
  // 给定飞行一周所需时间,比如10s, 那么每秒转动度数
  // 相机是始终往角度小的方向转, 先确定绘制的线路是顺时针还是逆时针_judgeDirection
  // 判断当前camera.heading > 两点的heading
  // 如果大于,则360 - camera.heading + heading, eg: 360-340+20
  //这部分主要解决的是相机朝哪个方向转的问题,顺时针绘制的线和逆时针绘制的线转向不同,所以有了下面这些判断,或许还有更好的办法处理
  let angle = 0
  if (!isRight) { // 顺时针
    if (Cesium.Math.toDegrees(viewer.camera.heading) > heading) {
      angle = ((Cesium.Math.toDegrees(Cesium.Math.TWO_PI - viewer.camera.heading) + heading) / changeCameraTime);
    } else {
      angle = ((heading - Cesium.Math.toDegrees(viewer.camera.heading)) / changeCameraTime);
    }
  } else {
    if (Cesium.Math.toDegrees(viewer.camera.heading) < heading) {
      angle = ((Cesium.Math.toDegrees(Cesium.Math.toRadians(heading) - Cesium.Math.TWO_PI) - Cesium.Math.toDegrees(viewer.camera.heading)) / changeCameraTime);
    } else {
      angle = ((heading - Cesium.Math.toDegrees(viewer.camera.heading)) / changeCameraTime);
    }
    // angle = ((heading - Cesium.Math.toDegrees(viewer.camera.heading)) / changeCameraTime);
  }
  // const angle = ((heading - Cesium.Math.toDegrees(viewer.camera.heading)) / changeCameraTime);
  console.log(angle, 'angle');
  // 时间间隔2秒钟
  setExtentTime(changeCameraTime, viewer);
  // 相机的当前heading
  const initialHeading = viewer.camera.heading;
  Exection = function TimeExecution() {
    // 当前已经过去的时间,单位s
    const delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime);
    // console.log(Cesium.Math.toRadians(delTime * angle), '1s转动的角度');

    const heading = Cesium.Math.toRadians(delTime * angle) + initialHeading;
    viewer.scene.camera.setView({
      orientation: {
        heading: heading,
        pitch: pitch
      }
    });
    if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) {
      viewer.clock.onTick.removeEventListener(Exection);
      marksIndex = ++marksIndex >= positons2.length ? 0 : marksIndex;
      if (marksIndex != 0) {
        console.log(marksIndex, 'marksIndex');
        flyExtent(viewer);
      }
    }
  };
  viewer.clock.onTick.addEventListener(Exection);
}
//计算俯仰角
const bearing = (startLat, startLng, destLat, destLng) => {
  startLat = toRadians(startLat);
  startLng = toRadians(startLng);
  destLat = toRadians(destLat);
  destLng = toRadians(destLng);

  const y = Math.sin(destLng - startLng) * Math.cos(destLat);
  const x = Math.cos(startLat) * Math.sin(destLat) - Math.sin(startLat) * Math.cos(destLat) * Math.cos(destLng - startLng);
  const brng = Math.atan2(y, x);
  const brngDgr = toDegrees(brng);

  return (brngDgr + 360) % 360;
}
// 角度转弧度
const toRadians = (degrees) => {
  return degrees * Math.PI / 180;
}
// 弧度转角度
const toDegrees = (radians) => {
  return radians * 180 / Math.PI;
}

desktop 2023-04-03 11-55-18

参考大佬文章: https://blog.csdn.net/CFXXXL/article/details/125365952文章来源地址https://www.toymoban.com/news/detail-752772.html

到了这里,关于cesium绘制路线,实现三维漫游的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Cesium实现动态绘制轨迹线

    需求就是一个飞机动画,飞机飞到哪里,轨迹线就画到哪里。 我的轨迹线非常长,从我国出发一直到欧洲那边,光是经过的点就有7000多个。 刚开始的时候想要使用的是entity的画线方法进行轨迹线的绘制,如果数据量不大,应该是可以实现的。 整体思路就是:先创建一个Po

    2024年02月11日
    浏览(22)
  • uniapp实现路线规划

    UniApp是一个基于Vue.js框架开发的跨平台应用开发框架,可以同时构建iOS、Android、H5等多个平台的应用。它使用了基于前端技术栈的Web开发方式,通过编写一套代码,即可在不同平台上运行和发布应用。 UniApp具有以下特点: 跨平台开发:UniApp支持将一套代码同时转换为iOS、A

    2024年02月06日
    浏览(65)
  • 微信小程序实现地图路线规划

    1、获取用户地理位置: 使用 wx.getLocation API 获取用户当前的经纬度坐标。 2、 选择终点位置: 选择你要显示路线的终点经纬度坐标。 3、 使用地图组件: 在小程序页面中使用 map 组件,设置 markers 属性显示起点和终点。 4、 显示路线: 通过 polyline 属性可以显示路线。在上述

    2024年04月11日
    浏览(27)
  • Three.js指定路径漫游(站走切换、路径动画、展示路线、开始、暂停、继续、退出、镜头跟随)

    (由点生成曲线,npc沿曲线移动,相机跟随方式1)参考大佬: https://blog.csdn.net/weixin_40856652/article/details/125302355 (相机跟随方式2)参考大佬: https://lequ7.com/guan-yu-threejsthreejs-xi-lie-xie-yi-ge-di-yi-san-ren-cheng-shi-jiao-xiao-you-xi.html (模型站走切换)参考大佬: https://zhuanlan.zhihu.com/p

    2024年02月05日
    浏览(27)
  • VR步进式漫游,轻松构建三维模型,带来展示新形式!

    引言: 虚拟现实(Virtual Reality,简称VR)已经成为当今科技领域的一项创新力量,它正在逐渐渗透到不同的领域,其中步进式漫游是VR技术的一项重要应用,它能在各个行业的宣传中发挥重要作用。 一.什么是VR步进式漫游? VR步进式漫游是一种虚拟现实体验,它允许用户通

    2024年02月08日
    浏览(31)
  • 微信小程序实现路线规划demo

    本文旨在以mpvue框架为基础,探讨地图类小程序的开发思路。 原作者利用mpvue + 腾讯地图的能力做了一个地铁路线规划的小程序,主要提供全球主要城市的地铁线网图及旅游介绍,其中国内城市支持查看地图和路线规划。 目前腾讯位置服务也推出了路线规划插件、地铁图插件

    2024年02月08日
    浏览(34)
  • 数学建模--三维图像绘制的Python实现

    目录 1.绘制三维坐标轴的方法 2.绘制三维函数的样例1  3.绘制三维函数的样例2 4.绘制三维函数的样例3  5.绘制三维函数的样例4  6.绘制三维函数的样例5           

    2024年02月09日
    浏览(35)
  • 微信小程序 + 腾讯位置服务SDK 实现路线规划

    本文旨在以mpvue框架为基础,探讨地图类小程序的开发思路。 原作者利用mpvue + 腾讯地图的能力做了一个地铁路线规划的小程序,主要提供全球主要城市的地铁线网图及旅游介绍,其中国内城市支持查看地图和路线规划。 目前腾讯位置服务也推出了路线规划插件、地铁图插件

    2024年02月08日
    浏览(33)
  • uniapp 开发安卓App实现高德地图路线规划导航

    描述这个技术是做什么的/什么情况下会使用到这个技术,学习该技术的原因,技术的难点在哪里。控制在50-100字内。 uniapp的map组件中导航路线的展示。是uniapp开发app时引入地图导航的实现方式。技术难点在于实现map组件时对于属性以及函数的细节使用很容易出现一些奇怪的

    2024年02月01日
    浏览(36)
  • 【JavaScript 漫游】【053】Reflect

    文章简介 本篇文章为【JavaScript 漫游】专栏的第 053 篇文章,记录了 ES6 规范中关于 Reflect 的知识点。 概述 Reflect 对象与 Proxy 对象一样,也是 ES6 为了操作对象而提供的新 API。 Reflect 对象的设计目的有这样几个。 (1)将 Object 对象的一些明显属于语言内部的方法(比如 Obje

    2024年04月08日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包