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
)
}
}
})
}
}
}