    import {
      Zondy,
      defaultValue,
      BaseView,
      ShadowMode,
      Point,
      Extent,
      LayerType,
      showLayerByScale,
      Config,
      isNull,
      ViewEventType,
      SceneMode,
      IGSSceneLayer,
      IGSSceneSubLayer
    } from '@mapgis/webclient-common'
    import { SceneViewUtil } from './utils'
    import { getLayerView } from '../document'

    /**
     * 视图类
     * @class SceneView
     * @extends Evented
     * @moduleEX ViewModule
     * @fires BaseView#鼠标点击事件
     * @fires BaseView#鼠标双击事件
     * @fires BaseView#鼠标按下事件
     * @fires BaseView#鼠标抬起事件
     * @fires BaseView#鼠标右键点击事件
     * @fires BaseView#鼠标移动事件
     * @fires BaseView#地图视图改变事件
     * @param {Object} options 构造参数
     * @param {Map}  [options.Map]  图层管理器
     * @param {String} [options.viewId] 图层容器ID
     * @param {Boolean} [options.enableAnimation = true] 视点跳转或漫游时，是否启用动画
     * @param {Boolean | Cesium.SkyBox} [options.skyBox] 天空盒设置，可传入天空盒对象或者布尔值，当该值为false时，不显示天空盒
     * @param {Boolean | Cesium.SkyAtmosphere} [options.skyAtmosphere] 大气设置，可传入大气设置对象或者布尔值，当该值为false时，不显示大气层
     * @param {SceneMode} [options.sceneMode = SceneMode.scene3D] 场景模式
     * @param {Boolean} [options.enableShadows = false] 是否启用阴影效果
     * @param {ShadowMode} [options.terrainShadowMode = ShadowMode.receive] 地形阴影模式
     * @param {Boolean} [options.enableGeocoderWidget = false] 启用地理编码器控件
     * @param {Boolean} [options.enableHomeButtonWidget = false] 启用Home按钮控件
     * @param {Boolean} [options.enableSceneModePickerWidget = false] 启用场景控制器控件
     * @param {Boolean} [options.enableBaseLayerPickerWidget = false] 启用基础图层选择器控件
     * @param {Boolean} [options.enableNavigationHelpButtonWidget = false] 启用导航帮助按钮控件
     * @param {Boolean} [options.enableAnimationWidget = false] 启用动画控件
     * @param {Boolean} [options.enableTimeLineWidget = false] 启用时间轴控件
     * @param {Boolean} [options.enableFullScreenButtonWidget = false] 启用全屏按钮控件
     * @param {Boolean} [options.enableVRButtonWidget = false] 启用VR按钮控件
     * @param {Boolean} [options.enableFPSWidget = false] 启用FPS控件
     * @param {Point} [options.center = new Point({coordinates:[0,0]})] 地图视图中心点
     * @param {Number} [options.scale = undefined] 地图视图比例尺
     * @param {Number} [options.zoom = undefined] 地图视图层级
     * @param {Number} [options.minZoom = 0] 最小层级
     * @param {Number} [options.maxZoom = 19] 最大层级
     *
     * @summary <h5>支持如下方法：</h5>
     * <a href='#flyTo'>[1、视点跳转]</a><br/>
     * <a href='#toJSON'>[2、导出场景视图的配置文件]</a><br/>
     * <a href='#fromJSON'>[3、通过一个配置生成一个场景视图对象]</a><br/>
     * <a href='#toMap'>[4、屏幕像素坐标点转地理坐标点]</a><br/>
     * <a href='#toScreen'>[5、地理坐标点转屏幕像素坐标点]</a><br/>
     * <a href='#getSize'>[6、获取当前视图容器的宽高]</a><br/>
     * <a href='#getCenter'>[7、获取当前视图中心点]</a><br/>
     * <a href='#getExtent'>[8、获取当前视图的地理范围]</a><br/>
     * <a href='#getZoom'>[9、获取当前层级]</a><br/>
     * <a href='#getScale'>[10、获取当前比例尺]</a><br/>
     * <a href='#getZoomByScale'>[11、地图比例尺对应的层级]</a><br/>
     * <a href='#getScaleByZoom'>[12、地图层级对应的比例尺]</a><br/>
     * [13、注册事件]{@link Evented#on}<br/>
     * [14、移除事件]{@link Evented#off}<br/>
     * <a href='#getInnerLayer'>[15、获取实际的M3DSet对象]</a><br/>
     *
     * @example <caption><h7>初始化三维视图对象</h7></caption>
     * // ES5引入方式
     * const { Map, SceneView } = Zondy
     * // ES6引入方式
     * import { Map, SceneView } from "@mapgis/webclient-cesium-plugin"
     * // 初始化图层管理容器
     * const map = new Map();
     * // 初始化地图视图对象
     * const sceneView = new SceneView({
     *   // 视图id
     *   viewId: "mapgis-3d-viewer",
     *   // 图层管理容器
     *   map: map
     * });
     */
    class SceneView extends BaseView {
      constructor(options) {
        super(options)
        // eslint-disable-next-line no-param-reassign
        options = defaultValue(options, {})
        /**
         * 视点跳转或漫游时，是否启用动画
         * @readonly
         * @member {Boolean} SceneView.prototype.enableAnimation
         */
        this.enableAnimation = defaultValue(options.enableAnimation, true)
        /**
         * 天空盒设置，可传入天空盒对象或者布尔值，当该值为false时，不显示天空盒
         * @readonly
         * @member {Boolean | Cesium.SkyBox} SceneView.prototype.skyBox
         */
        this.skyBox = defaultValue(options.skyBox, true)
        /**
         * 大气设置，可传入大气设置对象或者布尔值，当该值为false时，不显示大气层
         * @readonly
         * @member {Boolean | Cesium.SkyAtmosphere} SceneView.prototype.skyAtmosphere
         */
        this.skyAtmosphere = defaultValue(options.skyAtmosphere, true)
        /**
         * 场景模式
         * @readonly
         * @member {SceneMode} SceneView.prototype.sceneMode
         */
        this.sceneMode = defaultValue(options.sceneMode, SceneMode.scene3d)
        /**
         * 是否启用阴影效果
         * @readonly
         * @member {Boolean} SceneView.prototype.enableShadows
         */
        this.enableShadows = defaultValue(options.enableShadows, false)
        /**
         * 地形阴影模式
         * @readonly
         * @member {ShadowMode} SceneView.prototype.terrainShadowMode
         */
        this.terrainShadowMode = defaultValue(
          options.terrainShadowMode,
          ShadowMode.receive
        )
        /**
         * 启用地理编码器控件
         * @member {Boolean} SceneView.prototype.enableGeocoderWidget
         */
        this._enableGeocoderWidget = defaultValue(
          options.enableGeocoderWidget,
          false
        )
        /**
         * 启用Home按钮控件
         * @member {Boolean} SceneView.prototype.enableHomeButtonWidget
         */
        this._enableHomeButtonWidget = defaultValue(
          options.enableHomeButtonWidget,
          false
        )
        /**
         * 启用场景控制器控件
         * @member {Boolean} SceneView.prototype.enableSceneModePickerWidget
         */
        this._enableSceneModePickerWidget = defaultValue(
          options.enableSceneModePickerWidget,
          false
        )
        /**
         * 启用基础图层选择器控件
         * @member {Boolean} SceneView.prototype.enableBaseLayerPickerWidget
         */
        this._enableBaseLayerPickerWidget = defaultValue(
          options.enableBaseLayerPickerWidget,
          false
        )
        /**
         * 启用导航帮助按钮控件
         * @member {Boolean} SceneView.prototype.enableNavigationHelpButtonWidget
         */
        this._enableNavigationHelpButtonWidget = defaultValue(
          options.enableNavigationHelpButtonWidget,
          false
        )
        /**
         * 启用动画控件
         * @member {Boolean} SceneView.prototype.enableAnimationWidget
         */
        this._enableAnimationWidget = defaultValue(
          options.enableAnimationWidget,
          false
        )
        /**
         * 启用时间轴控件
         * @member {Boolean} SceneView.prototype.enableTimeLineWidget
         */
        this._enableTimeLineWidget = defaultValue(
          options.enableTimeLineWidget,
          false
        )
        /**
         * 启用全屏按钮控件
         * @member {Boolean} SceneView.prototype.enableFullScreenButtonWidget
         */
        this._enableFullScreenButtonWidget = defaultValue(
          options.enableFullScreenButtonWidget,
          false
        )
        /**
         * 启用VR按钮控件
         * @member {Boolean} SceneView.prototype.enableVRButtonWidget
         */
        this._enableVRButtonWidget = defaultValue(
          options.enableVRButtonWidget,
          false
        )
        /**
         * 启用FPS控件
         * @member {Boolean} SceneView.prototype.enableFPSWidget
         */
        this._enableFPSWidget = defaultValue(options.enableFPSWidget, false)
        /**
         * 地图视图中心点
         * @member {Number} MapView.prototype.center
         */
        // 统一center的类型
        this._center = defaultValue(
          options.center,
          new Point({ coordinates: [0, 0] })
        )
        if (
          this._center &&
          Array.isArray(this._center) &&
          this._center.length > 1
        ) {
          this._center = new Point({
            coordinates: [this._center[0], this._center[1], this._center[2]]
          })
        }
        /**
         * 地图视图比例尺
         * @member {Number} MapView.prototype.scale
         */
        this._scale = defaultValue(options.scale, undefined)
        /**
         * 地图视图层级
         * @member {Number} MapView.prototype.zoom
         */
        this._zoom = defaultValue(options.zoom, undefined)
        /**
         * 地图视图层级
         * @member {Number} MapView.prototype.minZoom
         */
        this.minZoom = defaultValue(options.minZoom, undefined)
        /**
         * 地图视图层级
         * @member {Number} MapView.prototype.maxZoom
         */
        this.maxZoom = defaultValue(options.maxZoom, undefined)
        /**
         * 地图视图宽度
         * @readonly
         * @member {Number} MapView.prototype.width
         */
        this.width = undefined
        /**
         * 地图视图高度
         * @readonly
         * @member {Number} MapView.prototype.height
         */
        this.height = undefined
        // 初始化地图引擎
        const viewOptions = {
          shouldAnimate: this.enableAnimation,
          sceneMode: this.sceneMode,
          shadows: this.enableShadows,
          terrainShadows: this.terrainShadowMode,
          geocoder: this._enableGeocoderWidget,
          homeButton: this._enableHomeButtonWidget,
          sceneModePicker: this._enableSceneModePickerWidget,
          baseLayerPicker: this._enableBaseLayerPickerWidget,
          navigationHelpButton: this._enableNavigationHelpButtonWidget,
          animation: this._enableAnimationWidget,
          timeline: this._enableTimeLineWidget,
          fullscreenButton: this._enableFullScreenButtonWidget,
          vrButton: this._enableVRButtonWidget
        }
        if (this.skyBox instanceof Object) {
          viewOptions.skyBox = this.skyBox
        }
        if (this.skyAtmosphere instanceof Object) {
          viewOptions.skyAtmosphere = this.skyAtmosphere
        }
        this._innerView = new Cesium.Viewer(this._viewId, viewOptions)
        if (this._enableFPSWidget) {
          this._innerView.scene.debugShowFramesPerSecond = true
        }
        this._layersMap = new Cesium.HashMap()
        Cesium.Config(Config)
        // 初始化比例尺
        this._initScale()
        // 获取视图大小
        this._initSize()
        // 获取视图层级
        this._initZoom()
        // 初始化地图事件
        this._initViewEvent()
        // map上是否绑定Cesium
        this._map._initCesiumView = true
      }

      _initViewEvent() {
        const self = this
        // 注册左键点击事件
        this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
          // 发送点击事件
          self.fire(ViewEventType.click, SceneViewUtil.getMouseEvent(event, self))
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK)

        // 注册左键按下事件
        this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
          // 发送左键按下事件
          self.fire(
            ViewEventType.mouseDown,
            SceneViewUtil.getMouseEvent(event, self)
          )
        }, Cesium.ScreenSpaceEventType.LEFT_DOWN)

        // 注册左键抬起事件
        this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
          // 发送左键抬起事件
          self.fire(ViewEventType.mouseUp, SceneViewUtil.getMouseEvent(event, self))
        }, Cesium.ScreenSpaceEventType.LEFT_UP)

        // 注册左键双击事件
        this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
          // 发送左键双击事件
          self.fire(
            ViewEventType.doubleClick,
            SceneViewUtil.getMouseEvent(event, self)
          )
        }, Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK)

        // 注册右键点击事件
        this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
          // 发送点击事件
          self.fire(ViewEventType.click, SceneViewUtil.getMouseEvent(event, self))
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK)

        // 注册右键按下事件
        this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
          // 发送按下事件
          self.fire(
            ViewEventType.mouseDown,
            SceneViewUtil.getMouseEvent(event, self)
          )
          // 发送右键点击事件
          self.fire(
            ViewEventType.rightClickDown,
            SceneViewUtil.getMouseEvent(event, self)
          )
        }, Cesium.ScreenSpaceEventType.RIGHT_DOWN)

        // 注册右键抬起事件
        this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
          // 发送抬起事件
          self.fire(ViewEventType.mouseUp, SceneViewUtil.getMouseEvent(event, self))
        }, Cesium.ScreenSpaceEventType.RIGHT_UP)

        // 注册鼠标移动事件
        this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
          // 发送鼠标移动事件
          self.fire(
            ViewEventType.mouseMove,
            SceneViewUtil.getMouseMoveEvent(event, self)
          )
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE)

        // 注册鼠标滚轮事件
        this._innerView.screenSpaceEventHandler.setInputAction(function (event) {
          self._map.layers.forEach(function (layer) {
            switch (layer.type) {
              case LayerType.igsFeature:
              case LayerType.graphics:
                showLayerByScale(self, layer)
                break
              default:
                break
            }
          })
          // 发送鼠标滚轮事件
          self.fire(ViewEventType.wheel, {})
        }, Cesium.ScreenSpaceEventType.WHEEL)

        // 注册监控地图视野改变事件
        this._innerView.camera.changed.addEventListener(function (event) {
          self._mouseMoveHandler()
          self.fire(
            ViewEventType.viewChange,
            SceneViewUtil.getViewChangeEvent(event, self)
          )
        })
      }

      /**
       * <a id='flyTo'></a>
       * @description 视点跳转
       * @param options 跳转参数
       * @param {Array}  [options.center]  相机要跳转的中心点，单位度，[精度，纬度，高程]
       * @param {Number}  [options.duration = 2]  相机飞行到终点时的持续时间，单位秒
       * @param {Extent}  [options.extent]  相机要飞行的某个范围
       * @param {Object}  [options.orientation]  相机飞行到终点时的视角朝向，包含偏航角、俯仰角和翻滚角
       * @param {Function}  [options.complete]  相机飞行到终点时触发的函数
       * @param {Function}  [options.cancel]  相机取消飞行时触发的函数
       * @param {Object}  [options.endTransform]  相机飞行到终点时的矩阵
       * @param {Number}  [options.maximumHeight]  相机飞行的最大高度
       * @param {Number}  [options.pitchAdjustHeight]  如果相机的飞行高度高于该值，则调整飞行过程中的俯仰角使相机视角向下看，并将地球保持在相机视窗中
       * @param {Number}  [options.flyOverLongitude]  强制让相机绕着地球飞行指定经度，直到到达终点位置
       * @param {Number}  [options.flyOverLongitudeWeight]
       * @example <caption><h7>按范围跳转</h7></caption>
       * // ES5引入方式
       * const { Map, SceneView } = Zondy
       * const { IGSMapImageLayer } = Zondy.Layer
       * const { LayerEventType } = Zondy.Enum
       * const { Extent } = Zondy.Geometry
       * // ES6引入方式
       * import { Map, SceneView, IGSMapImageLayer, LayerEventType, Extent } from "@mapgis/webclient-cesium-plugin"
       * // 初始化图层管理容器
       * const map = new Map();
       * // 初始化地图视图对象
       * const sceneView = new SceneView({
       *   // 视图id
       *   viewId: "mapgis-3d-viewer",
       *   // 图层管理容器
       *   map: map
       * });
       * // 添加一个地图图层
       * const igsMapImageLayer = new IGSMapImageLayer({
       *   url: 'http://webclient.smaryun.com:8089/igs/rest/services/Map/Hubei4326/MapServer'
       * });
       * map.add(igsMapImageLayer);
       * // 图层加载完毕
       * igsMapImageLayer.on(LayerEventType.layerViewCreated, function (result) {
       *   console.log("加载完毕:", result.layer)
       *   // 视点跳转
       *   sceneView.flyTo({
       *     extent: new Extent({
       *       xmin: 108.34341,
       *       ymin: 29.01258222765238,
       *       xmax: 116.15093956121316,
       *       ymax: 33.29320177370206
       *     })
       *   })
       * })
       * @example <caption><h7>跳转中心点</h7></caption>
       * // ES5引入方式
       * const { Map, SceneView } = Zondy
       * const { IGSMapImageLayer } = Zondy.Layer
       * const { LayerEventType } = Zondy.Enum
       * // ES6引入方式
       * import { Map, SceneView, IGSMapImageLayer, LayerEventType } from "@mapgis/webclient-cesium-plugin"
       * // 初始化图层管理容器
       * const map = new Map();
       * // 初始化地图视图对象
       * const sceneView = new SceneView({
       *   // 视图id
       *   viewId: "mapgis-3d-viewer",
       *   // 图层管理容器
       *   map: map
       * });
       * // 添加一个地图图层
       * const igsMapImageLayer = new IGSMapImageLayer({
       *   url: 'http://webclient.smaryun.com:8089/igs/rest/services/Map/Hubei4326/MapServer'
       * });
       * map.add(igsMapImageLayer);
       * // 图层加载完毕
       * igsMapImageLayer.on(LayerEventType.layerViewCreated, function (result) {
       *   console.log("加载完毕:", result.layer)
       *   // 视点跳转
       *   sceneView.flyTo({
       *     center: [113, 30, 1000000]
       *   })
       * })
       */
      flyTo(options) {
        options = defaultValue(options, {})
        const duration = defaultValue(options.duration, 2)
        const orientation = defaultValue(options.orientation, undefined)
        const complete = defaultValue(options.complete, undefined)
        const cancel = defaultValue(options.cancel, undefined)
        const endTransform = defaultValue(options.endTransform, undefined)
        const maximumHeight = defaultValue(options.maximumHeight, undefined)
        const flyOverLongitude = defaultValue(options.flyOverLongitude, undefined)
        const flyOverLongitudeWeight = defaultValue(
          options.flyOverLongitudeWeight,
          undefined
        )
        const convert = defaultValue(options.convert, undefined)
        const easingFunction = defaultValue(options.easingFunction, undefined)

        // 获取center
        const center = this._getFlyToCenter(options)

        // 获取extent
        const extent = this._getFlyToExtent(options)

        // 中心点跳转
        if (!isNull(center)) {
          this._innerView.camera.flyTo({
            destination: Cesium.Cartesian3.fromDegrees(
              center.coordinates[0],
              center.coordinates[1],
              center.coordinates[2]
            ),
            duration,
            orientation,
            complete,
            cancel,
            endTransform,
            maximumHeight,
            flyOverLongitude,
            flyOverLongitudeWeight,
            convert,
            easingFunction
          })
        }
        // 范围跳转
        else if (!isNull(extent)) {
          this._innerView.camera.flyTo({
            destination: Cesium.Rectangle.fromDegrees(
              extent.xmin,
              extent.ymin,
              extent.xmax,
              extent.ymax
            ),
            duration,
            orientation,
            complete,
            cancel,
            endTransform,
            maximumHeight,
            flyOverLongitude,
            flyOverLongitudeWeight,
            convert,
            easingFunction
          })
        }
      }

      /**
       * @description 创建图层视图
       * @private
       * @param {Layer} layer 图层
       * @param {LayerEvent} event 添加事件
       * @return {LayerView| null}
       */
      _createLayerView(layer) {
        // 获取原型
        const layerView = getLayerView(this, layer) || null
        return layerView
      }

      /**
       * <a id='toJSON'></a>
       * 导出场景视图的配置文件
       * @return {Object} 导出的配置文件
       * */
      toJSON() {
        return {
          viewId: this._viewId,
          enableAnimation: this.enableAnimation,
          skyBox: this.skyBox,
          skyAtmosphere: this.skyAtmosphere,
          sceneMode: this.sceneMode,
          enableShadows: this.enableShadows,
          terrainShadowMode: this.terrainShadowMode,
          enableGeocoderWidget: this.enableGeocoderWidget,
          enableHomeButtonWidget: this.enableHomeButtonWidget,
          enableSceneModePickerWidget: this.enableSceneModePickerWidget,
          enableNavigationHelpButtonWidget: this.enableNavigationHelpButtonWidget,
          enableAnimationWidget: this.enableAnimationWidget,
          enableTimeLineWidget: this.enableTimeLineWidget,
          enableFullScreenButtonWidget: this.enableFullScreenButtonWidget,
          enableFPSWidget: this.enableFPSWidget,
          map: this._map ? this._map.toJSON() : []
        }
      }

      /**
       * <a id='toMap'></a>
       * 屏幕像素坐标点转地理坐标点
       * @param {Object} screenPoint 屏幕像素坐标点，例如{ x: 900, y: 500 }
       * @return {Point} 地理坐标点
       * @example <caption><h5>屏幕像素坐标点转地理坐标示例</h5></caption>
       * // ES6引入方式
       * import { SceneView } from "@mapgis/webclient-cesium-plugin"
       * import { Map, Point } from "@mapgis/webclient-common"
       * // 初始化图层管理容器
       * const map = new Map();
       * // 初始化地图视图对象
       * const sceneView = new SceneView({
       *  // 视图id
       *  viewId: "mapgis-3d-viewer",
       *  // 图层管理容器
       *  map: map,
       *})
       * const screenPoint = { x: 900, y: 500 }
       * sceneView.toMap(screenPoint)
       * */
      toMap(screenPoint) {
        // 屏幕坐标转为世界坐标
        const cartesian = this._innerView.scene.globe.pick(
          this._innerView.camera.getPickRay(screenPoint),
          this._innerView.scene
        )
        let geoPoint = null
        if (cartesian && !isNull(cartesian)) {
          // 世界坐标转换为弧度
          const ellipsoid = this._innerView.scene.globe.ellipsoid
          const cartographic = ellipsoid.cartesianToCartographic(cartesian)
          // 弧度转换为经纬度
          const longitude = Cesium.Math.toDegrees(cartographic.longitude)
          const latitude = Cesium.Math.toDegrees(cartographic.latitude)
          const height = cartographic.height < 0 ? 0 : cartographic.height
          geoPoint = new Point({ coordinates: [longitude, latitude, height] })
        } else {
          geoPoint = new Point({ coordinates: [0, 0, 0] })
        }
        return geoPoint
      }

      /**
       * <a id='toScreen'></a>
       * 地理坐标点转屏幕像素坐标点
       * @param {Point} point 地理坐标点
       * @return {Object} 屏幕像素坐标点
       * @example <caption><h5>地理坐标点转屏幕像素坐标示例</h5></caption>
       * // ES6引入方式
       * import { MapView } from "@mapgis/webclient-leaflet-plugin"
       * import { Map, Point, Extent } from "@mapgis/webclient-common"
       * // 初始化图层管理容器
       * const map = new Map();
       * // 初始化地图视图对象
       * const mapView = new MapView({
       *   // 视图id
       *   viewId: "mapgis-2d-viewer",
       *   // 图层管理容器
       *   map: map
       * });
       * const geoPoint = new Point({ coordinates: [123, 23, 0] })
       * sceneView.toScreen(geoPoint)
       * */
      toScreen(point) {
        const cartesian3 = Cesium.Cartesian3.fromDegrees(
          point.coordinates[0],
          point.coordinates[1],
          point.coordinates[2]
        )
        const screenPoint = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
          this._innerView.scene,
          cartesian3
        )
        return screenPoint
      }

      /**
       * <a id='getSize'></a>
       * 获取当前视图容器的宽高，单位像素<a id='getSize'></a>
       * @return {Object} 当前视图容器的宽高对象
       * */
      getSize() {
        return {
          x: this._innerView._container.clientWidth,
          y: this._innerView._container.clientHeight
        }
      }

      /**
       * <a id='getCenter'></a>
       * 获取当前视图中心点
       * @return {Object} 当前视图容器的宽高对象
       * */
      getCenter() {
        const position = Cesium.Cartographic.fromCartesian(
          this._innerView.camera.position
        )
        const longitude = Cesium.Math.toDegrees(position.longitude)
        const latitude = Cesium.Math.toDegrees(position.latitude)
        const height = position.height
        const centerPoint = new Point({
          coordinates: [longitude, latitude, height]
        })
        this._center = centerPoint
        return centerPoint
      }

      /**
       * <a id='setCenter'></a>
       * 设置缩视野中心<a id='setCenter'></a>
       * @private
       * @param {Point} value 视图中心
       * */
      setCenter(value) {
        if (!this._innerView || !this._center) return
        let isValid = false
        const altitude = this._center.coordinates[2]
        if (Array.isArray(value) && value.length > 1) {
          this._center = new Point({
            coordinates: [value[0], value[1], altitude]
          })
          isValid = true
        } else if (value instanceof Point) {
          this._center = new Point({
            coordinates: [value.coordinates[0], value.coordinates[1], altitude]
          })
          isValid = true
        }
        if (isValid) {
          this.flyTo({ center: this._center })
        }
      }

      /**
       * <a id='getExtent'></a>
       * 获取当前视图的地理范围<a id='getExtent'></a>
       * @return {Extent}  获取当前视图的地理范围
       * */
      getExtent() {
        if (!this._innerView) return
        const rectangle = this._innerView.camera.computeViewRectangle()
        const extent = new Extent({
          xmin: (rectangle.west / Math.PI) * 180,
          ymin: (rectangle.south / Math.PI) * 180,
          xmax: (rectangle.east / Math.PI) * 180,
          ymax: (rectangle.north / Math.PI) * 180
        })
        this.extent = extent
        return extent
      }

      /**
       * <a id='getInnerLayer'></a>
       * @public
       * 重载基类方法，支持传入IGSSceneLayer或IGSSceneSubLayer，并返回相应的对象
       * @param { IGSSceneLayer | IGSSceneSubLayer} layer 场景图层或场景图的子图层
       * @return { Array<MapGISM3DSet> | MapGISM3DSet | undefined } MapGISM3DSet数组或MapGISM3DSet对象或空对象
       * */
      getInnerLayer(layer) {
        if (layer instanceof IGSSceneLayer) {
          return super.getInnerLayer(layer)
        } else if (layer instanceof IGSSceneSubLayer) {
          const _innerSceneLayer = super.getInnerLayer(layer.layer)
          for (let i = 0; i < _innerSceneLayer.length; i++) {
            if (_innerSceneLayer[i]._layerIndex === layer.layerIndex) {
              return _innerSceneLayer[i]
            }
          }
        }
        return undefined
      }

      /**
       * @description mouse move事件处理器
       * @private
       * */
      _mouseMoveHandler() {
        // 更新地图视野中心点坐标
        this.getCenter()
        // 更新地图视野范围
        // this.getExtent()
        // 更新地图比例尺
        this.getZoom()
        // 更新地图比例尺
        this.getScale()
      }

      /**
       * @description 初始化获取视图尺寸大小
       * @private
       */
      _initSize() {
        const canvas = this._innerView.canvas
        this.width = canvas.width
        this.height = canvas.height
      }

      /**
       * @description 初始化设置地图视图比例尺
       * @private
       */
      _initScale() {
        if (this.scale && this._center) {
          this.zoom = this.getZoomByScale(this.scale)
          const altitude = this._getAltitudeByZoom(this.zoom)
          const lng = this._center.coordinates[0]
          const lat = this._center.coordinates[1]
          this._center = new Point({ coordinates: [lng, lat, altitude] })
          this.flyTo({ center: this._center })
        }
      }

      /**
       * @description 初始化设置地图视图层级
       * @private
       */
      _initZoom() {
        if (!this.scale && this._zoom && this._center) {
          this._zoom = this._getZoomByAltitude(this._center.coordinates[2])
          // 根据zoom计算scale
          this.scale = this.getScaleByZoom(this._zoom)
          const altitude = this._getAltitudeByZoom(this._zoom)
          const lng = this._center.coordinates[0]
          const lat = this._center.coordinates[1]
          this._center = new Point({ coordinates: [lng, lat, altitude] })
          this.flyTo({ center: this._center })
        }
        if (this.maxZoom) {
          const minAltitude = this._getAltitudeByZoom(this.maxZoom)
          this._innerView.scene.screenSpaceCameraController.minimumZoomDistance =
            minAltitude
        }
        if (this.minZoom) {
          const maxAltitude = this._getAltitudeByZoom(this.minZoom)
          this._innerView.scene.screenSpaceCameraController.maximumZoomDistance =
            maxAltitude
        }
      }

      /**
       * <a id='getZoom'></a>
       * @description 获取当前层级
       * @return {Number}  层级
       * */
      getZoom() {
        const zoom = this._getZoomByAltitude(this._center.coordinates[2])
        this._zoom = zoom
      }

      /**
       * <a id='setZoom'></a>
       * 设置缩放级数
       * @private
       * @param {Number} value 视图层级
       * */
      setZoom(value) {
        if (this._innerView && this._zoom && this._center) {
          this._zoom = value
          const altitude = this._getAltitudeByZoom(this._zoom)
          const lng = this._center.coordinates[0]
          const lat = this._center.coordinates[1]
          const center = new Point({ coordinates: [lng, lat, altitude] })
          this.flyTo({ center })
        }
      }

      /**
       * <a id='getScale'></a>
       * @description 获取当前比例尺
       * @return {Number}  比例尺 实际10000米:地图1米
       * */
      getScale() {
        this._scale = this.getScaleByZoom(this._zoom)
      }

      /**
       * <a id='setScale'></a>
       * 设置当前比例尺
       * @private
       * @param {Number} value 比例尺 实际10000米:地图1米
       * */
      setScale(value) {
        if (this._innerView && this._scale && this._center) {
          this._scale = value
          const zoom = this.getZoomByScale(value)
          const altitude = this._getAltitudeByZoom(zoom)
          const lng = this._center.coordinates[0]
          const lat = this._center.coordinates[1]
          const center = new Point({ coordinates: [lng, lat, altitude] })
          this.flyTo({ center })
        }
      }

      /**
       * <a id='getZoomByScale'></a>
       * @description 地图比例尺对应的层级
       * @private
       * @param {Number}  scale 地图比例尺
       * @return {Number}  层级
       */
      getZoomByScale(scale) {
        const ppi = 96
        const initialResolution = (20037508.3427892 * 2) / 256
        const resolution = scale / (ppi / 0.0254)
        const zoom = Math.round(Math.log2(initialResolution / resolution))
        return zoom
      }

      /**
       * <a id='getScaleByZoom'></a>
       * @description 地图层级对应的比例尺
       * @private
       * @param {Number}  zoom 地图层级
       * @return {Number}  比例尺
       */
      getScaleByZoom(zoom) {
        const ppi = 96
        const initialResolution = (20037508.3427892 * 2) / 256
        const resolution = initialResolution / Math.pow(2, zoom)
        // const scale = resolution * ppi * 0.0254
        const scale = (ppi / 0.0254) * resolution
        return scale
      }

      /**
       * @description 根据高度获取当前层级
       * @private
       * @return {Number}  层级
       * */
      _getZoomByAltitude(altitude) {
        const A = 40487.57
        const B = 0.00007096758
        const C = 91610.74
        const D = -40467.74
        const zoom = Math.round(D + (A - D) / (1 + Math.pow(altitude / C, B)))
        return zoom
      }

      /**
       * @description 根据当前层级获取高度
       * @private
       * @return {Number}  高度
       * */
      _getAltitudeByZoom(zoom) {
        const A = 40487.57
        const B = 0.00007096758
        const C = 91610.74
        const D = -40467.74
        const altitude = C * Math.pow((A - D) / (zoom - D) - 1, 1 / B)
        return altitude
      }
    }

    /**
     * <a id='fromJSON'></a>
     * 通过一个配置生成一个场景视图对象
     * @param {Object} json 场景视图配置
     * @return {SceneView}
     * */
    SceneView.fromJSON = function (json) {
      json = defaultValue(json, {})

      return new SceneView(json)
    }

    Object.defineProperties(SceneView.prototype, {
      enableGeocoderWidget: {
        get() {
          return this._enableGeocoderWidget
        },
        set(value) {
          this._enableGeocoderWidget = value
          document.querySelector('.cesium-viewer-geocoderContainer').style.display =
            value ? 'inline-block' : 'none'
        }
      },
      enableHomeButtonWidget: {
        get() {
          return this._enableHomeButtonWidget
        },
        set(value) {
          this._enableHomeButtonWidget = value
          document.querySelector('.cesium-home-button').style.display = value
            ? 'inline-block'
            : 'none'
        }
      },
      enableSceneModePickerWidget: {
        get() {
          return this._enableSceneModePickerWidget
        },
        set(value) {
          this._enableSceneModePickerWidget = value
          document.querySelector('.cesium-sceneModePicker-wrapper').style.display =
            value ? 'inline-block' : 'none'
        }
      },
      enableBaseLayerPickerWidget: {
        get() {
          return this._enableBaseLayerPickerWidget
        },
        set(value) {
          this._enableBaseLayerPickerWidget = value
          document.querySelector('.cesium-baseLayerPicker-selected').style.display =
            value ? 'inline-block' : 'none'
        }
      },
      enableNavigationHelpButtonWidget: {
        get() {
          return this._enableNavigationHelpButtonWidget
        },
        set(value) {
          this._enableNavigationHelpButtonWidget = value
          document.querySelector(
            '.cesium-navigationHelpButton-wrapper'
          ).style.display = value ? 'inline-block' : 'none'
        }
      },
      enableAnimationWidget: {
        get() {
          return this._enableAnimationWidget
        },
        set(value) {
          this._enableAnimationWidget = value
          document.querySelector(
            '.cesium-viewer-animationContainer'
          ).style.display = value ? 'inline-block' : 'none'
        }
      },
      enableTimeLineWidget: {
        get() {
          return this._enableTimeLineWidget
        },
        set(value) {
          this._enableTimeLineWidget = value
          document.querySelector('.cesium-viewer-timelineContainer').style.display =
            value ? 'inline-block' : 'none'
        }
      },
      enableFullScreenButtonWidget: {
        get() {
          return this._enableFullScreenButtonWidget
        },
        set(value) {
          this._enableFullScreenButtonWidget = value
          document.querySelector(
            '.cesium-viewer-fullscreenContainer'
          ).style.display = value ? 'inline-block' : 'none'
        }
      },
      enableVRButtonWidget: {
        get() {
          return this._enableVRButtonWidget
        },
        set(value) {
          this._enableVRButtonWidget = value
          document.querySelector('.cesium-vrButton').style.display = value
            ? 'inline-block'
            : 'none'
        }
      },
      enableFPSWidget: {
        get() {
          return this._enableFPSWidget
        },
        set(value) {
          this._enableFPSWidget = value
          this._innerView.scene.debugShowFramesPerSecond = value
        }
      },
      scale: {
        get() {
          return this._scale
        },
        set(value) {
          this.setScale(value)
        }
      },
      zoom: {
        get() {
          return this._zoom
        },
        set(value) {
          this.setZoom(value)
        }
      },
      center: {
        get() {
          return this._center
        },
        set(value) {
          this.setCenter(value)
        }
      }
    })

    Zondy.PluginVersion = '16.5.2'
    Zondy.SceneView = SceneView
    export default SceneView