类名 common/document/layer/support/TileInfoUtil.js
import { SpatialReference, Point } from '../../../base/geometry'
import { Log } from '../../../util'
import LOD from './LOD'
import TileInfo from './TileInfo'
import { LayerType } from '../../../base/enum'
import { Projection } from '../../../base'
/**
 * @description: 瓦片解析工具
 * @return {*}
 */
export default class TileInfoUtil {
  /**
   * @description: 解析igs1.0 tileInfo
   * @param {Object} tileInfo
   * @return {TileInfo}
   */
  static parseTileInfo1(tileInfo) {
    if (!tileInfo) {
      Log.error('tileInfo未定义')
    }
    const { tileWidth, tileHeight, lods, originX, originY } = tileInfo
    return new TileInfo({
      origin: new Point({
        coordinates: [originX, originY]
      }),
      lods: lods.map((lod) => {
        return LOD.fromJSON(lod)
      }),
      size: [tileWidth, tileHeight]
    })
    // igs1.0 tileInfo
    // {
    //   name: 'EPSG_4326_WORLD_TILE',
    //   type: 'tile',
    //   xMin: -180,
    //   xMax: 180,
    //   yMin: -90,
    //   yMax: 90,
    //   tileWidth: 256,
    //   tileHeight: 256,
    //   startLevel: 0,
    //   endLevel: 9,
    //   resolutions: [
    //     0.7031249999891483, 0.3515624999945742, 0.1757812499972871,
    //     0.08789062499864354, 0.04394531249932177, 0.021972656249660886,
    //     0.010986328124830443, 0.005493164062415209, 0.0027465820312076047,
    //     0.001373291015603805
    //   ],
    //   lods: [
    //     {
    //       level: 0,
    //       resolution: 0.7031249999891483,
    //       scale: 295829355.45,
    //       dxTileLogic: 179.99999999722198,
    //       dyTileLogic: 179.99999999722198,
    //       tileLogicRect: {
    //         xmin: -180,
    //         ymin: -89.99999999722198,
    //         xmax: 179.99999999444395,
    //         ymax: 90
    //       }
    //     },
    //     {
    //       level: 1,
    //       resolution: 0.3515624999945742,
    //       scale: 147914677.725,
    //       dxTileLogic: 89.99999999861099,
    //       dyTileLogic: 89.99999999861099,
    //       tileLogicRect: {
    //         xmin: -180,
    //         ymin: -89.99999999722198,
    //         xmax: 179.99999999444395,
    //         ymax: 90
    //       }
    //     }
    //   ],
    //   originX: -180,
    //   originY: 90,
    //   originType: 'LeftTop'
    // }
  }

  /**
   * @description: 解析igs2.0 tileInfo
   * @param {Object} tileInfo
   * @return {TileInfo}
   */
  static parseTileInfo2(tileInfo) {
    if (!tileInfo) {
      Log.error('tileInfo未定义')
    }

    const { cols, rows, dpi, format, origin, lods, spatialReference } = tileInfo

    return new TileInfo({
      dpi,
      format,
      origin: new Point({
        coordinates: [origin.x, origin.y],
        spatialReference: new SpatialReference(spatialReference)
      }),
      lods: lods.map((lod) => {
        return LOD.fromJSON(lod)
      }),
      size: [cols, rows],
      spatialReference: new SpatialReference(spatialReference)
    })
    // igs2.0 tileInfo
    //  {
    //   endLevel: 14,
    //   startLevel: 0,
    //   cols: 256,
    //   rows: 256,
    //   compressionQuality: null,
    //   dpi: 0,
    //   format: 'PNG',
    //   origin: {
    //     x: -5123200,
    //     y: 10002100
    //   },
    //   lods: [
    //     {
    //       level: 0,
    //       resolution: 156367.47632692187,
    //       scale: 590995186.1175
    //     },
    //     {
    //       level: 1,
    //       resolution: 78183.73816346093,
    //       scale: 295497593.05875
    //     }
    //   ],
    //   spatialReference: {
    //     wkid: 4547,
    //     name: '高斯大地坐标系_中国2000_38带3_北'
    //   }
    // }
  }

  /**
   * @description: 解析arcgis tileInfo
   * @param {Object} tileInfo
   * @return {TileInfo}
   */
  static parseArcgisTileInfo(tileInfo) {
    if (!tileInfo) {
      Log.error('tileInfo未定义')
    }
    const { cols, rows, dpi, format, origin, lods, spatialReference } = tileInfo
    return new TileInfo({
      dpi,
      format,
      origin: new Point({
        coordinates: [origin.x, origin.y],
        spatialReference: new SpatialReference({
          wkid: spatialReference.latestWkid || spatialReference.wkid
        })
      }),
      lods: lods.map((lod) => {
        return LOD.fromJSON(lod)
      }),
      size: [cols, rows],
      spatialReference: new SpatialReference({
        wkid: spatialReference.latestWkid || spatialReference.wkid
      })
    })
    //  arcgis tileInfo
    // {
    //   rows: 256,
    //   cols: 256,
    //   dpi: 96,
    //   format: 'JPEG',
    //   compressionQuality: 90,
    //   origin: {
    //     x: -20037508.342787,
    //     y: 20037508.342787
    //   },
    //   spatialReference: {
    //     wkid: 102100,
    //     latestWkid: 3857
    //   },
    //   lods: [
    //     {
    //       level: 0,
    //       resolution: 156543.03392800014,
    //       scale: 591657527.591555
    //     },
    //     {
    //       level: 1,
    //       resolution: 78271.51696399994,
    //       scale: 295828763.795777
    //     }
    //   ]
    // }
  }

  /**
   * @description: WMS tileInfo
   * @param {WMSLayer} layer
   * @return {TileInfo}
   */
  static parseWMSTileInfo(layer) {
    if (!layer) {
      Log.error('wmsLayer未定义')
    }
    // 处理wms 图层
    const extent = layer.extent
    const tileSize = Math.max(layer.imageWidth, layer.imageHeight)
    const resolution0 =
      Math.max(extent.ymax - extent.ymin, extent.xmax - extent.xmin) / tileSize
    const resolutions = []
    resolutions.push(resolution0)
    for (let r = 0; r < 20; r++) {
      resolutions.push(resolutions[r] / 2)
    }

    const origin = new Point({
      coordinates: [extent.xmin, extent.ymax],
      spatialReference: layer.spatialReferences[0]
    })

    return new TileInfo({
      origin,
      lods: resolutions.map((resolution, index) => {
        return LOD.fromJSON({
          level: index,
          resolution,
          scale: (resolution * 96) / 0.0254
        })
      }),
      size: [layer.imageWidth, layer.imageHeight],
      spatialReference: layer.spatialReferences[0]
    })
  }

  /**
   * @description: MapImage tileInfo
   * @param {IGSMapImageLayer} layer
   * @return {TileInfo}
   */
  static parseMapImageTileInfo(layer, extent) {
    if (!layer) {
      Log.error('IGSMapImageLayer未定义')
    }
    // 处理wms 图层
    extent = extent || layer.extent
    let tileWidth = 256
    let tileHeight = 256
    // 对于igsMapImage layer图层,如果是瓦片渲染模式,
    // 则tileSize取imageWidth/imageHeight(后续该参数名称改为tileWidth/tileHeight)。
    // 否则tileSize为默认值。
    if (layer.type === LayerType.igsMapImage && layer.renderMode === 'tile') {
      tileWidth = layer.imageWidth
      tileHeight = layer.imageHeight
    }
    const tileSize = Math.max(tileWidth, tileHeight)
    const resolution0 =
      Math.max(extent.ymax - extent.ymin, extent.xmax - extent.xmin) / tileSize
    const resolutions = []
    resolutions.push(resolution0)
    for (let r = 0; r < 20; r++) {
      resolutions.push(resolutions[r] / 2)
    }

    const origin = new Point({
      coordinates: [extent.xmin, extent.ymax],
      spatialReference: layer.spatialReference
    })
    return new TileInfo({
      origin,
      lods: resolutions.map((resolution, index) => {
        return LOD.fromJSON({
          level: index,
          resolution,
          scale: (resolution * 96) / 0.0254
        })
      }),
      size: [tileWidth, tileHeight],
      spatialReference: layer.spatialReference
    })
  }

  /**
   * @description: WMTS tileInfo
   * @param {WMTSLayer} layer
   * @return {TileInfo}
   */
  static parseWMTSTileInfo(layer) {
    if (!layer) {
      Log.error('wmtsLayer未定义')
    }

    // 处理wmts 图层
    // 对于igs服务优先取dpi96的数据信息,没有dpi96_GB,且有028mm_GB信息,则用028mm_GB数据.
    const tileMatrixSets = layer.tileMatrixSets
    const id = layer.activeLayer.tileMatrixSetId
    let tileMatrixSet
    let resolutions
    tileMatrixSet = tileMatrixSets.find(
      (item) => item.id.indexOf('dpi96_GB') > -1
    )
    const isGeographic = layer._spatialReference.isGeographic
    if (tileMatrixSet) {
      resolutions = tileMatrixSet.getTileResolution(
        (0.0254 / 96) * 1000,
        isGeographic
      )
    } else {
      const tileMatrixSet28 = tileMatrixSets.find(
        (item) => item.id.indexOf('028mm_GB') > -1
      )
      if (tileMatrixSet28) {
        tileMatrixSet = tileMatrixSet28
        resolutions = tileMatrixSet.getTileResolution()
      } else {
        tileMatrixSet = tileMatrixSets.find((item) => item.id === id)
        // 如果天地图的3857坐标,比标准3857少一级,第一级增加一层数据
        if (
          layer.url.indexOf('.tianditu.gov.cn/') > -1 &&
          layer.url.indexOf('_w/') > -1
        ) {
          if (tileMatrixSet.tileMatrix.length < 20) {
            const level0 = JSON.parse(
              JSON.stringify(tileMatrixSet.tileMatrix[0])
            )
            // 第零级ScaleDenominator为 5.916587109e8
            level0.scaleDenominator = Number(level0.scaleDenominator) * 2
            level0.identifier = 0
            level0.matrixHeight = 1
            level0.matrixWidth = 1
            tileMatrixSet.tileMatrix.unshift(level0)
          }
        }
        resolutions = tileMatrixSet.getTileResolution(
          (0.0254 / 96) * 1000,
          isGeographic
        )
      }
    }

    const origin = tileMatrixSet.tileInfo.origin
    return new TileInfo({
      origin,
      lods: tileMatrixSet.tileMatrix.map((tm, index) => {
        return LOD.fromJSON({
          level: index,
          resolution: resolutions[index],
          scale: parseFloat(tm.scaleDenominator)
        })
      }),
      size: [layer.imageWidth, layer.imageHeight],
      spatialReference: SpatialReference.fromJSON(
        layer.spatialReference.toJSON()
      )
    })
  }

  /**
   * @description: 获取lods
   * @param {Number} firstLod 第一级分辨率
   * @param {String} unit 单位,'m' or 'degree'
   * @param {Number} zoom 级数
   * @return {Array<LOD>}
   */
  static getLods(firstLod, unit, zoom) {
    const len = Math.max(0, zoom)
    const lods = []
    const R = 6378137
    const radius = 2 * Math.PI * R
    const pxToM = radius / 360
    for (let i = 0; i < len; i++) {
      const resolution = firstLod / Math.pow(2, i)
      let scale
      if (unit === 'degree') {
        scale = pxToM * resolution
      } else {
        scale = (resolution * 96) / 0.0254
      }
      lods.push(
        new LOD({
          level: i,
          resolution,
          scale
        })
      )
    }
    return lods
  }

  /**
   * 获取grouplayer的坐标系
   * @param {Array<Layer>|Layer} layer
   * @return {Object}
   *
   */
  static getLayerSpatialReference(layer) {
    // 根据添加的图层更改地图视图的坐标系,第一次创建图层时,检查当前的Map中的地图类型,
    // 循环检查当前map中是否有瓦片或WMTS图层,如果有就用该图层的坐标系,
    // 如果没有,就用第一个遇见的矢量或WMS图层的坐标系
    let spatialReference = null
    let referenceLayer = null
    if (
      layer.type === LayerType.igsTile ||
      layer.type === LayerType.arcgisTile ||
      layer.type === LayerType.wmts ||
      layer.type === LayerType.igsVectorTile ||
      layer.type === LayerType.arcgisVectorTile ||
      layer.type === LayerType.igsMapImage ||
      layer.type === LayerType.arcgisMapImage ||
      layer.type === LayerType.wms ||
      layer.type === LayerType.igsFeature ||
      layer.type === LayerType.wfs ||
      layer.type === LayerType.geojson
    ) {
      referenceLayer = layer
      spatialReference = layer.spatialReference
    } else if (layer.type === LayerType.group || Array.isArray(layer)) {
      const layerList = layer.type === LayerType.group ? layer.layers : layer
      if (layerList.length >= 1) {
        // 循环检查当前map中是否有瓦片或WMTS图层,如果有就用该图层的坐标系,
        for (let i = 0; i < layerList.length; i++) {
          const childLayer = layerList[i]
          if (
            childLayer.type === LayerType.igsTile ||
            childLayer.type === LayerType.arcgisTile ||
            childLayer.type === LayerType.wmts ||
            childLayer.type === LayerType.igsVectorTile ||
            childLayer.type === LayerType.arcgisVectorTile
          ) {
            referenceLayer = childLayer
            spatialReference = childLayer.spatialReference
            break
          }
        }
        if (!spatialReference) {
          // 没有瓦片或WMTS图层,循环检查第一个遇见的矢量或WMS图层的坐标系
          for (let i = 0; i < layerList.length; i++) {
            const childLayer = layerList[i]
            if (
              childLayer.type === LayerType.igsMapImage ||
              childLayer.type === LayerType.arcgisMapImage ||
              childLayer.type === LayerType.wms ||
              childLayer.type === LayerType.igsFeature ||
              childLayer.type === LayerType.wfs ||
              childLayer.type === LayerType.geojson
            ) {
              referenceLayer = childLayer
              spatialReference = childLayer.spatialReference
              break
            }
          }
        }
      }
    }
    if (referenceLayer) {
      referenceLayer._isSRLayer = true
      if (referenceLayer.loaded) {
        referenceLayer._isSRLayer = true
      } else {
        // 如果当前参考系图层没有加载完成,则不当做视图参考系
        referenceLayer = null
        spatialReference = null
      }
    }
    return { spatialReference, referenceLayer }
  }

  /**
   * 获取grouplayer的空间参考系
   * @param {Collection<Layer>} layers
   * @return {Object}
   *
   */
  static getSpatialReference(layers) {
    const layerList = []
    layers.forEach((layer) => {
      if (layer.type === LayerType.group) {
        const groupReference = this.getLayerSpatialReference(layer)
        layerList.push(groupReference.referenceLayer)
      } else {
        layerList.push(layer)
      }
    })
    const reference = this.getLayerSpatialReference(layerList)
    return reference
  }

  /**
   * 设置MapImageLayer、FeatureLayer的空间参考系
   * @param {Collection<Layer>} layers 需要设置参考系的图层集合
   * @param {SpatialReference} spatialReference 被设置的spatialReference
   * @param {SpatialReference} isBasemapLayer 当前参考图层是否为基础底图
   *
   */
  static setLayerSpatialReference(layers, spatialReference, isBasemapLayer) {
    if (spatialReference) {
      layers.forEach((layer) => {
        if (
          layer.type === LayerType.igsMapImage ||
          layer.type === LayerType.arcgisMapImage ||
          layer.type === LayerType.feature
        ) {
          // 如果当前参考图层不是基础底图,则基础底图图层不受该参考系影响
          if (!isBasemapLayer && layer._isBasemapLayer) {
            return
          }
          if (
            layer.loaded &&
            (!layer.spatialReference ||
              (layer.spatialReference &&
                layer.spatialReference.wkid !== spatialReference.wkid))
          ) {
            layer.spatialReference = spatialReference
            layer._extentSrc = Projection.project(
              layer._extentSrc,
              spatialReference
            )
          }
        }
      })
    }
  }
}
构造函数
成员变量
方法
事件