/**
* 通过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
}