zoukankan      html  css  js  c++  java
  • ArcGIS api for JS 实现三维飞行漫游功能

    说明

    基于arcgis api for js 4.17

    在arcgis api for js中实现三维飞行,同时视角要跟随飞行方向变化。实现此功能,主要使用Camera对象和goTo方法。

    Camera对象主要包含四个属性:fov(视角场,默认55度);heading;tilt和position。其中heading代表偏北角或方位角,当视角朝向正北时为0度,顺时针旋转增加,在0°~360°之间。tilt代表俯仰角,为90度时平行于水平面,0度时垂直俯视,180度时垂直仰视。position代表位置,有三个属性,一般为经度、纬度、高度。其中,要实现视角的变化,需要根据起点和终点的坐标来计算heading和tilt。

    View对象的goTo()方法返回一个Promise对象,一个goTo执行一个动作,在前一个动作成功完成后,在.then()中再调用goTo()执行下一个动作。通过这种Promise链式调用的方式实现连续的运动。

    代码

    代码如下:

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <title></title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <link rel="stylesheet" href="https://js.arcgis.com/4.17/esri/themes/light/main.css"/>
        <style>
          html, body {
             100%;
            height: 100%;
            padding: 0;
            margin: 0;
          }
          #viewDiv {
             100%;
            height: 100%;
          }
        </style>
      </head>
      <body>
        <div id="viewDiv"></div>
        <script src="https://js.arcgis.com/4.17/"></script>
        <script>
          require(["esri/Map",
            "esri/views/MapView",
            "esri/views/SceneView",
            "esri/Camera",
            "esri/Graphic",
            "esri/layers/GraphicsLayer"], function (Map, MapView, SceneView, Camera, Graphic, GraphicsLayer) {
              
              let map = new Map({
                basemap: "hybrid",
                ground: "world-elevation"
              })
              // const paths = [
              //   [-0.3, 51.4879, 3000],
              //   [-0.4, 50.4879, 10000],
              //   [-0.178, 49.4879, 1000],
              //   [-0.5, 51.4879, 1000],
              //   [-0.078, 51.4879, 8000],
              //   [-0.178, 52.4879, 5000]
              // ]
    
              const paths = [
                [120, 31, 3000],
                [119, 31, 13000],
                [119, 31, 40000],
                [119, 32, 10000],
                [121, 32, 1000],
                [119, 33, 8000]
              ]
    
              let view = new SceneView({
                map: map,
                container: "viewDiv",
                viewingMode: 'global',  // local, global
                camera: {
                  position: {
                    x: paths[0][0],
                    y: paths[0][1],
                    z: paths[0][2],
                    spatialReference: { wkid: 4326 }
                  }
                }
              })
    
              let gLayer = new GraphicsLayer()
              map.add(gLayer)
    
              // 创建图形
              function createGeometry(paths) {
                let polyline = {
                  type: 'polyline',
                  paths: paths
                }
                let polylineGraphic = new Graphic({
                  geometry: polyline,
                  symbol: {
                    type: 'simple-line',
                    color: [226, 119, 40],
                     4
                  }
                })
                gLayer.add(polylineGraphic)
                paths.forEach(item => {
                  let point = {
                    type: 'point',
                    x: item[0],
                    y: item[1],
                    z: item[2]
                  }
                  let pointGraphic = new Graphic({
                    geometry: point,
                    symbol: {
                      type: "simple-marker",
                      color: "blue",
                      size: 12,
                      outline: {
                         1,
                        color: "white"
                      }
                    }
                  })
                  gLayer.add(pointGraphic)
                })
              }
    
              // 递归函数, 实现连续飞行方法
              // 每次执行两次view.goTo()方法,第一次会将视角转向,第二次转向后会前进到指定位置
              function fly(i){
                if(i+1 == paths.length) {
                  return
                }
    
                let startPoint = paths[i]
                let endPoint = paths[i+1]
                let heading = calcHeading(startPoint[0], startPoint[1], endPoint[0], endPoint[1])
                let tilt = calcTilt(startPoint[0], startPoint[1], startPoint[2], endPoint[0], endPoint[1], endPoint[2])
                console.log('拐弯', i)
                console.log(startPoint, endPoint)
                console.log(heading, tilt)
                let cam = view.camera.clone()
                cam.heading = heading
                cam.tilt = tilt
                cam.position = {
                  longitude: startPoint[0],
                  latitude: startPoint[1],
                  z: startPoint[2],
                  spatialReference: { wkid: 4326 }
                }
    
                view.goTo(cam, {
                  speedFactor: 1,
                  easing: 'linear'
                })
                .then(() => {
                  console.log('前进', i)
                  cam.position = {
                    longitude: endPoint[0],
                    latitude: endPoint[1],
                    z: endPoint[2],
                    spatialReference: { wkid: 4326 }
                  }
                  return view.goTo(cam, {
                    speedFactor: 0.2,
                    easing: "linear"
                  })
                })
                .then(() => {
                  setTimeout(() => {
                    i++
                    fly(i)
                  }, 1000)
                })
              }
    
              view.when(() => {
                createGeometry(paths)
                view.watch('camera', e => {
                  // console.log(e.tilt, e.heading, e.position.z)
                })
                fly(0)
              })
    
              // 计算距离
              function calcDistance(lon1, lat1, lon2, lat2) {
                let radlat1 = lat1 * Math.PI / 180.0
                let radlat2 = lat2 * Math.PI / 180.0
                let a = radlat1 - radlat2
                let b = lon1 * Math.PI / 180.0 - lon2 * Math.PI / 180.0
                let distance = 2 * 6378137.0 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radlat2) * Math.cos(radlat2) * Math.pow(Math.sin(b / 2), 2)))
                return distance
              }
    
              // 计算偏北角,0指向正北,90指向正东,顺时针旋转
              function calcHeading(lon1, lat1, lon2, lat2) {
                let radlat1 = lat1 * Math.PI / 180.0
                let radlat2 = lat2 * Math.PI / 180.0
                let radlon1 = lon1 * Math.PI / 180.0
                let radlon2 = lon2 * Math.PI / 180.0
                let y = Math.sin(radlon2 - radlon1) * Math.cos(radlat2)
                let x = Math.cos(radlat1) * Math.sin(radlat2) - Math.sin(radlat1) * Math.cos(radlat2) * Math.cos(radlon2 - radlon1)
                let bearing = Math.atan2(y, x) * 180.0 / Math.PI
                return bearing < 0 ? bearing + 360.0 : bearing
              }
    
              // 计算俯仰角, 90度时平行于水平面,0度时自上向下垂直俯视, 180度时自下向上仰视
              function calcTilt(lon1, lat1, alt1, lon2, lat2, alt2) {
                let distance = calcDistance(lon1, lat1, lon2, lat2)
                let angle = Math.atan2((alt2 -alt1), distance) * 180.0 / Math.PI
                let tilt = angle + 90
                return tilt
              }
          })
        </script>
      </body>
    </html>
    
  • 相关阅读:
    一张图片入门Python
    4.1. 如何在Windows环境下开发Python
    你必须知道的EF知识和经验
    XUnit的使用
    如何使用NUnit
    Entity Framework 不支持DefaultValue
    Have You Ever Wondered About the Difference Between NOT NULL and DEFAULT?
    Validation failed for one or more entities. See 'EntityValidationErrors' property for more details
    Entity Framework 与多线程
    sqlite中的自增主键
  • 原文地址:https://www.cnblogs.com/ingen42/p/13794187.html
Copyright © 2011-2022 走看看