类名 common/document/layer/support/Utils.js
/**
 * 通过TileMatrixSetId来获取EPSG号码
 * @param {String} tileMatrixSetId tileMatrixSetId
 * @return {String} EPSG号码
 * */
import {
  RendererType,
  SymbolType,
  UrlServerType,
  WMTSCorporation
} from '../../../base/enum'
import { defaultValue } from '../../../util'
import { Color } from '../../../base'

function getEPSGFromTileMatrixSetId(tileMatrixSetId) {
  if (!tileMatrixSetId) return 'EPSG:4326'
  let epsg = tileMatrixSetId
  if (tileMatrixSetId.indexOf('EPSG:4326') > -1) {
    epsg = 'EPSG:4326'
  } else if (tileMatrixSetId.indexOf('EPSG:4490') > -1) {
    epsg = 'EPSG:4490'
  } else if (tileMatrixSetId.indexOf('EPSG:4610') > -1) {
    epsg = 'EPSG:4610'
  } else if (tileMatrixSetId.indexOf('EPSG:3857') > -1) {
    epsg = 'EPSG:3857'
  }
  return epsg
}

/**
 * 检查url对应的服务类型
 * @param {String} url 服务地址
 * @return {String} 服务类型
 * */
function getUrlType(url) {
  let type = undefined

  // 天地图正则
  const tdtReg = new RegExp(
    '^http://t[0-6].tianditu.gov.cn/[a-z]{3}_[w|c]{1}/wmts$'
  )
  // igs2.0的http服务正则
  const igsHttp2 = new RegExp(
    '^http://[0-9.a-zA-Z]+:[0-9]{1,5}/igs/rest/services/[一-龟\\w/:_]+/WMTSServer$'
  )
  // igs2.0的https服务正则
  const igsHttps2 = new RegExp(
    '^https://[0-9.a-zA-Z]+:[0-9]{1,5}/igs/rest/services/[一-龟\\w/:_]+/WMTSServer$'
  )
  // igs2.0的http服务没有端口号的正则
  const igsHttpNoPort2 = new RegExp(
    '^http://[0-9.a-zA-Z]+/igs/rest/services/[一-龟\\w/:_]+/WMTSServer$'
  )
  // igs2.0的https服务没有端口号的正则
  const igsHttpsNoPort2 = new RegExp(
    '^https://[0-9.a-zA-Z]+/igs/rest/services/[一-龟\\w/:_]+/WMTSServer$'
  )
  // arcgis的http服务正则
  const arcgisHttp = new RegExp(
    '^http://[0-9.a-zA-Z]+:[0-9]{1,5}/arcgis/rest/services/[一-龟\\w/:_]+/WMTSServer$'
  )
  // arcgis的https服务正则
  const arcgisHttps = new RegExp(
    '^https://[0-9.a-zA-Z]+:[0-9]{1,5}/arcgis/rest/services/[一-龟\\w/:_]+/WMTSServer$'
  )
  // arcgis的http服务没有端口号的正则
  const arcgisHttpNoPort = new RegExp(
    '^http://[0-9.a-zA-Z]+/arcgis/rest/services/[一-龟\\w/:_]+/WMTSServer$'
  )
  // arcgis的https服务没有端口号的正则
  const arcgisHttpsNoPort = new RegExp(
    '^https://[0-9.a-zA-Z]+/arcgis/rest/services/[一-龟\\w/:_]+/WMTSServer$'
  )
  if (tdtReg.test(url)) {
    type = UrlServerType.tdt
  } else if (
    igsHttp2.test(url) ||
    igsHttps2.test(url) ||
    igsHttpNoPort2.test(url) ||
    igsHttpsNoPort2.test(url)
  ) {
    type = UrlServerType.igs_2
  } else if (
    arcgisHttp.test(url) ||
    arcgisHttps.test(url) ||
    arcgisHttpNoPort.test(url) ||
    arcgisHttpsNoPort.test(url)
  ) {
    type = UrlServerType.igs_2
  }

  return type
}

/**
 * 是否为4326坐标系
 * @param {SpatialReference} spatialReference 坐标系对象
 * @return {Boolean} 是否为4326坐标系
 * */
function is4326(spatialReference) {
  if (
    String(spatialReference.wkid) === '4326' ||
    String(spatialReference.wkid) === '4214' ||
    String(spatialReference.wkid) === '4490' ||
    String(spatialReference.wkid) === '4610'
  ) {
    return true
  }
  return false
}

/**
 * 是否为自定义坐标系
 * @param {SpatialReference} spatialReference 坐标系对象
 * @return {Boolean} 是否为自定义坐标系
 * */
function isCustomSP(spatialReference) {
  if (
    String(spatialReference.wkid) !== '4326' &&
    String(spatialReference.wkid) !== '4214' &&
    String(spatialReference.wkid) !== '4490' &&
    String(spatialReference.wkid) !== '4610' &&
    String(spatialReference.wkid) !== '3857' &&
    String(spatialReference.wkid) !== '900913'
  ) {
    return true
  }
  return false
}

/**
 * 根据比例尺显示或隐藏图层
 * @private
 * @param {BaseView} view 地图视图对象
 * @param {BaseLayer} layer 基础图层对象
 * */
function showLayerByScale(view, layer) {
  let _scale = view.scale
  // 不在比例尺范围内,隐藏图层
  if (!view.scale) {
    _scale = view.getScale()
  }
  if (layer.maxScale && layer.minScale && layer.minScale < layer.maxScale) {
    if (_scale >= layer.minScale && _scale <= layer.maxScale) {
      layer.visible = true
    } else {
      layer.visible = false
    }
  } else if (layer.maxScale) {
    if (_scale > layer.maxScale) {
      layer.visible = false
    } else {
      layer.visible = true
    }
  } else if (layer.minScale) {
    if (_scale < layer.minScale) {
      layer.visible = false
    } else {
      layer.visible = true
    }
  }
}

/**
 * 将IGS的符号构造参数转为前端的符号构造参数
 * @private
 * @param {Object} symbol IGS的符号构造参数
 * @return {Object} symbol 前端的符号构造参数
 * */
function formatIGSSymbol(symbol) {
  symbol = defaultValue(symbol, {})
  switch (symbol.type) {
    case SymbolType.simpleMarker:
    case SymbolType.simpleFill:
      if (symbol.color) {
        symbol.color = new Color(
          symbol.color[0],
          symbol.color[1],
          symbol.color[2],
          symbol.color[3] / 255
        )
      }
      if (symbol.outline && symbol.outline.color) {
        symbol.outline.color = new Color(
          symbol.outline.color[0],
          symbol.outline.color[1],
          symbol.outline.color[2],
          symbol.outline.color[3] / 255
        )
      }
      break
    case SymbolType.simpleLine:
      if (symbol.color) {
        symbol.color = new Color(
          symbol.color[0],
          symbol.color[1],
          symbol.color[2],
          symbol.color[3] / 255
        )
      }
      break
    case SymbolType.pictureMarker:
      if (symbol.color) {
        symbol.color = new Color(
          symbol.color[0],
          symbol.color[1],
          symbol.color[2],
          symbol.color[3] / 255
        )
      }
      if (!symbol.url) {
        symbol.url = symbol.imageData
      }
      break
    case SymbolType.pictureFill:
      if (symbol.outline && symbol.outline.color) {
        symbol.outline.color = new Color(
          symbol.outline.color[0],
          symbol.outline.color[1],
          symbol.outline.color[2],
          symbol.outline.color[3] / 255
        )
      }
      if (!symbol.url) {
        symbol.url = symbol.imageData
      }
      break
    case SymbolType.text:
      if (symbol.color) {
        symbol.color = new Color(
          symbol.color[0],
          symbol.color[1],
          symbol.color[2],
          symbol.color[3] / 255
        )
      }
      if (symbol.backgroundColor) {
        symbol.backgroundColor = new Color(
          symbol.backgroundColor[0],
          symbol.backgroundColor[1],
          symbol.backgroundColor[2],
          symbol.backgroundColor[3] / 255
        )
      }
      if (symbol.borderLineColor) {
        symbol.borderLineColor = new Color(
          symbol.borderLineColor[0],
          symbol.borderLineColor[1],
          symbol.borderLineColor[2],
          symbol.borderLineColor[3] / 255
        )
      }
      if (symbol.haloColor) {
        symbol.haloColor = new Color(
          symbol.haloColor[0],
          symbol.haloColor[1],
          symbol.haloColor[2],
          symbol.haloColor[3] / 255
        )
      }
      break
    default:
      break
  }
  return symbol
}

/**
 * 将IGS的渲染器构造参数转为前端的渲染器构造参数
 * @private
 * @param {Object} renderer IGS的渲染器构造参数
 * @return {Object} renderer 前端的渲染器构造参数
 * */
function formatIGSRenderer(renderer) {
  renderer = defaultValue(renderer, {})
  switch (renderer.type) {
    case RendererType.simple:
      renderer.symbol = formatIGSSymbol(renderer.symbol)
      break
    case RendererType.uniqueValue:
      renderer.defaultSymbol = formatIGSSymbol(renderer.defaultSymbol)
      for (let i = 0; i < renderer.uniqueValueInfos.length; i++) {
        renderer.uniqueValueInfos[i].symbol = formatIGSSymbol(
          renderer.uniqueValueInfos[i].symbol
        )
      }
      break
    case RendererType.classBreak:
      renderer.defaultSymbol = formatIGSSymbol(renderer.defaultSymbol)
      for (let i = 0; i < renderer.classBreakInfos.length; i++) {
        renderer.classBreakInfos[i].symbol = formatIGSSymbol(
          renderer.classBreakInfos[i].symbol
        )
      }
      if (renderer.classBreakInfos.length > 0) {
        renderer.classBreakInfos[0].minValue = renderer.minValue
        renderer.classBreakInfos[0].maxValue =
          renderer.classBreakInfos[0].classMaxValue
        for (let i = 1; i < renderer.classBreakInfos.length; i++) {
          renderer.classBreakInfos[i].minValue =
            renderer.classBreakInfos[i - 1].classMaxValue
          renderer.classBreakInfos[i].maxValue =
            renderer.classBreakInfos[i].classMaxValue
        }
      }
      break
    default:
      break
  }
  return renderer
}

/**
 * 从ogc的ows:SupportedCRS标签上解析出epsg号
 * @private
 * @param {string} supportedCRS
 * @return {Number} EPSG编号
 */
function getEPSGCodeFromOGCSupportedCRSString(supportedCRS) {
  let epsgCode = 4326
  let pos = -1
  // 1.查找字符串中是否含有EPSG::,如果有则EPSG::后面的即为epsg号。
  pos = supportedCRS.search('EPSG::')
  if (pos > -1) {
    epsgCode = parseInt(supportedCRS.substring(pos + 'EPSG::'.length))
  } else {
    // 2.查找字符串中是否同时含有EPSG:和3857,如果有则表明,对应的epsg号为3857
    pos = supportedCRS.search('EPSG:')
    if (pos > -1 && supportedCRS.search('3857') > 0) {
      epsgCode = 3857
    } else {
      // 3.查找字符串中是否含有"OGC:2:84"或"OGC:1.3:CRS84",如果有则epsg号为3857
      pos = supportedCRS.search('OGC:2:84')
      if (pos < 0) {
        pos = supportedCRS.search('OGC:1.3:CRS84')
      }

      if (pos > -1) {
        epsgCode = 4326
      }
    }
  }

  // 4.将web墨卡托的epsg号统一为3857.
  if (epsgCode === 3867 || epsgCode === 900913 || epsgCode === 102100) {
    epsgCode = 3857
  }

  return epsgCode
}

/**
 * @summary
 *    该函数支持MapGIS IGServer 发布的JWD,MKT瓦片只有一个矩阵集(老版本,地调局原来有用),
 支持MapGIS IGServer 发布的JWD 三个矩阵集,MKT 的两个矩阵集(新版本,该版本MapGIS发布的WMTS可以再Arcmap 和ArcGIS Server发布的WMTS完美叠加,ArcGIS Online中和地图完美叠加)
 支持ArcGIS Server   发布的JWD,MKT瓦片
 支持天地图(全国)    JWD,MKT两种
 支持GeoServer       JWD,MKT两种
 各个厂家以及MapGIS IGServer发布的老版本和新版本之间关于1逻辑单位代表多少毫米的理解如下:
 服务名              坐标系          矩阵集个数/名称           1逻辑单位代表多少毫米      1像素等于多少毫米
 IGServer老服务      JWD             一个矩阵集                111194872.221777			    25.4/96
 IGServer老服务      MKT             一个矩阵集                1000						          25.4/96
 IGServer新服务      JWD      3个(EPSG:4326_XXXX_028mm_GB)     111319490.79327358        0.28
 IGServer新服务      JWD      3个(EPSG:4326_XXXX_arcgis_GB)    111194872.221777			    0.28
 IGServer新服务      JWD      3个(EPSG:4326_XXXX_dpi96_GB)     111319490.79327358		    25.4/96
 IGServer新服务      MKT      2个(GoogleMapsCompatible_GB)     1000						          0.28
 IGServer新服务      MKT      2个(EPSG:3857_XXXX_dpi96_GB)     1000						          25.4/96

 ArcGIS Server       JWD      2个(default028mm)				        111194872.221777			  25.4000508/96(0.28的比例尺反算96DPI的比例尺后,用96DPI的计算,这种情况下1英寸等于25.4000508毫米)
 ArcGIS Server       JWD      2个(native)					            111194872.221777			  25.4000508/96
 ArcGIS Server       MKT      3个(default028mm)				        1000						        25.4000508/96(0.28的比例尺反算96DPI的比例尺后,用96DPI的计算,这种情况下1英寸等于25.4000508毫米)
 ArcGIS Server       MKT      3个(native)					            1000						        25.4000508/96
 ArcGIS Server       MKT      3个(GoogleMapsCompatible)		    1000						        0.28

 GeoServer           JWD             一个矩阵集                111319490.79327358 		  0.28
 GeoServer			      MKT             一个矩阵集                1000						        0.28

 tianditu            JWD             一个矩阵集                111319490.79327358 		  25.4/96
 tianditu			      MKT             一个矩阵集                1000						        25.4/96
 *
 */
function getTileResolution(
  identifier,
  corporationType,
  dScale,
  spatialReference
) {
  const ARCGIS_METERPERUNIT = 111194872.221777
  const MAPGIS_OLD_METERPERUNIT = ARCGIS_METERPERUNIT
  const GEOSERVER_METERPERUNIT = 111319490.79327358
  const MAPGIS_METERPERUNIT = GEOSERVER_METERPERUNIT
  const OTHER_METERPERUNIT = GEOSERVER_METERPERUNIT
  let szTmp = ''
  const szWellKnownScaleSetName = ''
  let nPos = -1
  let nMapGISType = 0 // 0是国标标准的0.28,1是Arcgis0.28,2是96dpi,3是GoogleMapsCompatible(OGC MKT 0.28)
  let nArcGISTyep = 0 // 0是default0.28,1是nativeTileMatrixSet,2是GoogleMapsCompatible(OGC MKT 0.28),3其它
  let nOtherType = 0 // 0是国标的96DPI(严格的标准),1可能是用ArcGIS发布的但是基地址又不能判断出是ArcGIS的情况(吉威广西: http://121.40.62.120:8066/ime-server/rest/gxyx/wmts?service=wmts&request=GetCapabilities)
  let dMMPerPix = 25.4 / 96 // 一个像素等于多少毫米
  let dScaleEx = 0
  let dConst = 1000

  // 不支持获取WellKnownScaleSet名称。
  // szWellKnownScaleSetName = pMatrixSet->matriSet.szWellKnownScaleSetName;

  if (corporationType === WMTSCorporation.corporationZD) {
    // 新版本2016-1-27之后 MapGIS IGServer发布的JWD有三个矩阵集: 如下
    // EPSG:4326_武汉1~12级_028mm_GB
    // EPSG:4326_武汉1~12级_arcgis_GB
    // EPSG:4326_武汉1~12级_dpi96_GB
    // MKT数据有2个矩阵集
    // GoogleMapsCompatible_GB
    // EPSG:3857_WH_MKT_1~16级_dpi96_GB

    nPos = identifier.lastIndexOf('_GB')

    if (nPos > 0) {
      szTmp = identifier.slice(0, identifier.length - 3)
      nPos = szTmp.lastIndexOf('_')
      if (nPos > 0) {
        // 028mm_GB,arcgis_GB,dpi96_GB三种
        szTmp = szTmp.slice(nPos + 1)
      }

      if (szTmp === '028mm') nMapGISType = 0
      else if (szTmp === 'arcgis') nMapGISType = 1
      else if (szTmp === 'dpi96') nMapGISType = 2
      else if (szTmp === 'GoogleMapsCompatible') nMapGISType = 3

      if (spatialReference.isGeographic) {
        if (nMapGISType === 0) {
          // 标准的国标
          dConst = MAPGIS_METERPERUNIT
          dMMPerPix = 0.28
        } else if (nMapGISType === 1) {
          // ArcGIS的0.28
          dMMPerPix = 0.28
          dConst = ARCGIS_METERPERUNIT
        } else if (nMapGISType === 2) {
          dConst = MAPGIS_METERPERUNIT
          dMMPerPix = 25.4 / 96
        }
      } else {
        if (nMapGISType === 0) {
          // 标准的国标
          dMMPerPix = 0.28
        } else if (nMapGISType === 1) {
          // ArcGIS的0.28
          dMMPerPix = 0.28
        } else if (nMapGISType === 2) {
          dMMPerPix = 25.4 / 96
        } else if (nMapGISType === 3) {
          dMMPerPix = 0.28
        }
      }
    } // 老版本
    else {
      if (spatialReference.isGeographic) {
        dConst = MAPGIS_OLD_METERPERUNIT
        dMMPerPix = 25.4 / 96
      } else {
        dMMPerPix = 25.4 / 96
      }
    }
  } else if (
    corporationType === WMTSCorporation.corporationArcGIS
  ) {
    // http://portal.smartxspace.com/arcgis/rest/services/wuhan_base/MapServer/WMTS/1.0.0/WMTSCapabilities.xml
    // 修改说明:ArcGIS的部分WMTS服务的dpi为0.28,但其矩阵集名称为default,原有写法会造成该类服务无法显示。
    // 修改人:马原野 2018-12-26
    if (identifier.includes('default')) nArcGISTyep = 0
    else if (identifier.includes('native')) nArcGISTyep = 1
    else if (identifier.includes('GoogleMapsCompatible')) nArcGISTyep = 2
    else nArcGISTyep = 3
    if (spatialReference.isGeographic) {
      if (nArcGISTyep === 0) {
        dScaleEx = (dScale * 0.28 * 96) / 25.4 // 反算96DPI对应的比例尺,直接用0.28对应的比例尺不准确
        dScale = dScaleEx
        dConst = ARCGIS_METERPERUNIT
        dMMPerPix = 25.4000508 / 96
      } else if (nArcGISTyep === 1) {
        dConst = ARCGIS_METERPERUNIT
        dMMPerPix = 25.4000508 / 96
      }
    } else {
      if (nArcGISTyep === 0) {
        dScaleEx = (dScale * 0.28 * 96) / 25.4 // 反算96DPI对应的比例尺,直接用0.28对应的比例尺不准确
        dScale = dScaleEx
        dMMPerPix = 25.4000508 / 96
      } else if (nArcGISTyep === 1) {
        dMMPerPix = 25.4000508 / 96
      } else if (nArcGISTyep === 2) {
        dMMPerPix = 0.28
      }
    }
  } else if (
    corporationType === WMTSCorporation.corporationGeoServer
  ) {
    if (spatialReference.isGeographic) {
      dConst = GEOSERVER_METERPERUNIT
      dMMPerPix = 0.28
    } else {
      dMMPerPix = 0.28
    }
  } else if (corporationType === WMTSCorporation.corporationTianDiTu) {
    if (spatialReference.isGeographic) {
      dConst = OTHER_METERPERUNIT
      dMMPerPix = 25.4 / 96
    } else {
      dMMPerPix = 25.4 / 96
    }
  }
  // 修改说明:修订bug7584 对吉威发布的类似于ArcGIS规则的WMTS的支持.本质需要按照ArcGIS方式计算
  //           其它厂商发布的WMTS认为都是严格按照国家标准执行(都只处理一个矩阵级,且认为是96DPI,一度等于多少米为111319490.79327358)
  // 修改人: 潘明敏 2016-04-14
  else {
    // 对于其它厂家发布的WMTS原则上认为是严格执行国家标准(关键参数同天地图)
    // 但是对于吉威发布的WMTS特殊处理下,吉威发布的WMTS有两套标准
    // 1.http:// 121.40.62.120:8066/ime-server/rest/gxyx/wmts?service=wmts&request=GetCapabilities  其实内部比例尺是符合ArcGIS的标准发布,包含了default028mm矩阵集,计算时需要用ArcGIS的计算方法才能对
    // 2.http://www.mapgx.com/ime-server/rest/tdtgx_vec/wmts/wmts?service=wmts&request=getcapabilities 符合国家标准执行,使用国家标准的参数计算即可
    if (identifier.includes('028')) nOtherType = 1

    // 修改说明:某些服务szWellKnownScaleSetName中含有"GoogleMapsCompatible"关键词,计算时需要用ArcGIS的计算方法。
    // 如:中国地质调查局西安地质调查中心发布的服务,url:http://219.144.130.58:6400/getcapabilities?Theme=HillShade  bug[12561]
    // 修改人:马原野 2019-07-20
    if (szWellKnownScaleSetName.includes('GoogleMapsCompatible')) {
      nOtherType = 1
    }

    // 修改说明:szWellKnownScaleSetName中含有"GoogleMapsCompatible"关键词,计算时也需要用ArcGIS的计算方法。
    // 修改恩:王必聪 2019-07-26
    if (szWellKnownScaleSetName.includes('GoogleCRS84Quad')) nOtherType = 1

    if (spatialReference.isGeographic) {
      if (nOtherType === 1) {
        dScaleEx = (dScale * 0.28 * 96) / 25.4 // 反算96DPI对应的比例尺,直接用0.28对应的比例尺不准确
        dScale = dScaleEx
        dConst = ARCGIS_METERPERUNIT
        dMMPerPix = 25.4000508 / 96
      } else {
        dConst = OTHER_METERPERUNIT
        dMMPerPix = 25.4 / 96
      }
    } else {
      if (nOtherType === 1) {
        dScaleEx = (dScale * 0.28 * 96) / 25.4 // 反算96DPI对应的比例尺,直接用0.28对应的比例尺不准确
        dScale = dScaleEx
        dMMPerPix = 25.4000508 / 96
      } else dMMPerPix = 25.4 / 96
    }
  }
  return (dScale * dMMPerPix) / dConst
}

/**
 * 根据url获取发布服务的公司
 * @param {String} url 服务基地址
 * @return {WMTSCorporation} 公司代码
 * */
function initCorporationType(url) {
  if (url === undefined) {
    return WMTSCorporation.none
  }

  // 对于MapGIS发布的WMTS,基地址有两种写法,故只用WMTSServer来判断
  // http://192.168.10.44:6163/igs/rest/ogc/WMTSServer(IGserver发布的)
  // http://219.142.81.86/igserver/ogc/kvp/TAS10E52H50E002021/WMTSServer (中国地调局国家地质资料馆里面有用)
  // 修改说明:<天地图服务升级,服务域名变化>
  // 修改人:ldf 2018-12-26
  if (url.search('WMTSServer') > 0) {
    return WMTSCorporation.corporationZD
  } else if (url.search('arcgis/rest/services') > 0) {
    return WMTSCorporation.corporationArcGIS
  } else if (url.search('geoserver') > 0) {
    return WMTSCorporation.corporationGeoServer
  } else if (
    url.search('tianditu.com') > 0 ||
    url.search('tianditu.gov.cn') > 0
  ) {
    return WMTSCorporation.corporationTianDiTu
  } else {
    return WMTSCorporation.corporationOther
  }
}

export {
  getEPSGFromTileMatrixSetId,
  getUrlType,
  is4326,
  isCustomSP,
  showLayerByScale,
  formatIGSSymbol,
  formatIGSRenderer,
  getEPSGCodeFromOGCSupportedCRSString,
  initCorporationType,
  getTileResolution
}
构造函数
成员变量
方法
事件