对于ArcGIS Server发布的切片服务,在地理坐标系中Cesium默认只支持wgs84的4326坐标系,无法通过ArcGisMapServerImageryProvider直接加载CGCS2000的4490坐标系,虽然可以使用WebMapTileServiceImageryProvider加载符合OGC标准的WMTS类型,但只能针对于原点在orgin X: -180.0Y: 90.0的情况,对于原点在orgin X: -400.0Y: 400.0时还是无法正常加载,为了能够实现加载,以下通过修改源码方式来达到目的。
笔者以Cesium 1.91版本为例。
目录
1、修改ArcGisMapServerImageryProvider类
2、修改GeographicTilingScheme类
3、定义2000椭球参数
4、底图调用实现
1、修改ArcGisMapServerImageryProvider类
在metadataSuccess方法中修改
(1)读取切片模式时增加支持wkid 4490坐标系的判断,同时将切片信息也传入,目的是为了后面在获取行列号xy时,可以通过读取切片信息,使用自定义方法改写行列号的获取方式。
else if (data.fullExtent.spatialReference.wkid === 4490) {
that._tilingScheme = new GeographicTilingScheme({
ellipsoid: options.ellipsoid,
tileInfo: data.tileInfo,
rectangle: that._rectangle
});
that._tilingScheme._tileInfo = data.tileInfo;//附加自定义属性
}
如截图所示:
(2)增加最大层级定义(用来限制最大可缩放多少层级,达到一定层级后不显示,根据项目需要为可选修改项)
//修改最大层级定义
that._maximumLevel = defaultValue(options.maximumLevel, data.tileInfo.lods.length - 1);
(3)矩阵范围定义中 增加wkid 4490坐标系判断。
2、修改GeographicTilingScheme类
(1)增加4490坐标系的椭球、矩阵范围等定义,4490坐标系默认椭球为CGCS2000,矩阵范围为(-180,-90,180,90),开放矩阵范围的目的就是为了支持自定义的origin原点。
if (defined(options.tileInfo)
&& defined(options.tileInfo.spatialReference)
&& defined(options.tileInfo.spatialReference.wkid)
&& options.tileInfo.spatialReference.wkid == 4490) {
this._tileInfo = options.tileInfo;
this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.CGCS2000);
this._rectangle = defaultValue(options.rectangle, Rectangle.fromDegrees(-180, -90, 180, 90));
this._numberOfLevelZeroTilesX = defaultValue(options.numberOfLevelZeroTilesX, 4);
this._numberOfLevelZeroTilesY = defaultValue(options.numberOfLevelZeroTilesY, 2);
}
else {
this._ellipsoid = defaultValue(options.ellipsoid, Ellipsoid.WGS84);
this._rectangle = defaultValue(options.rectangle, Rectangle.MAX_VALUE);
this._numberOfLevelZeroTilesX = defaultValue(options.numberOfLevelZeroTilesX, 2);
this._numberOfLevelZeroTilesY = defaultValue(options.numberOfLevelZeroTilesY, 1);
}
(2)修改切片矩阵计算获取行列号xy值的原型方法getNumberOfXTilesAtLevel和getNumberOfYTilesAtLevel
/**
* Gets the total number of tiles in the X direction at a specified level-of-detail.
*
* @param {Number} level The level-of-detail.
* @returns {Number} The number of tiles in the X direction at the given level.
*/
GeographicTilingScheme.prototype.getNumberOfXTilesAtLevel = function (level) {
if (!defined(this._tileInfo)) {
return this._numberOfLevelZeroTilesX << level
} else { // 使用切片矩阵计算
var currentMatrix = this._tileInfo.lods.filter(function (item) {
return item.level === level
})
var currentResolution = currentMatrix[0].resolution
// return Math.round(360 / (this._tileInfo.rows * currentResolution))
return Math.round(CesiumMath.toDegrees(CesiumMath.TWO_PI) / (this._tileInfo.rows * currentResolution));
}
};
/**
* Gets the total number of tiles in the Y direction at a specified level-of-detail.
*
* @param {Number} level The level-of-detail.
* @returns {Number} The number of tiles in the Y direction at the given level.
*/
GeographicTilingScheme.prototype.getNumberOfYTilesAtLevel = function (level) {
if (!defined(this._tileInfo)) {
return this._numberOfLevelZeroTilesY << level
} else { // 使用切片矩阵计算
var currentMatrix = this._tileInfo.lods.filter(function (item) {
return item.level === level
})
var currentResolution = currentMatrix[0].resolution
// return Math.round(180 / (this._tileInfo.cols * currentResolution))
return Math.round(CesiumMath.toDegrees(CesiumMath.TWO_PI / 2) / (this._tileInfo.cols * currentResolution));
}
};
3、定义2000椭球参数
Ellipsoid.CGCS2000 = Object.freeze(
new Ellipsoid(6378137.0, 6378137.0, 6356752.31414035585)
);
4、底图调用实现
以上修改完后,接下来就是如何调用的问题了。
调用方式比一般的调用相对更复杂些,具体如下:
(1)确定椭球参数
如 CGCS2000椭球如下
var cgs2000Ellipsolid = new Cesium.Ellipsoid(6378137.0, 6378137.0, 6356752.31414035585)
或者直接用源码中已修改过的Ellipsoid.CGCS2000
var cgs2000Ellipsolid=Cesium.Ellipsoid.CGCS2000
(2) 定义切片模式
如orgin 为-400 400时
var myGeographicTilingScheme = new Cesium.GeographicTilingScheme({
ellipsoid: cgs2000Ellipsolid,
rectangle: Cesium.Rectangle.fromDegrees(-400, -399.9999999999998, 400, 399.9999999999998),
numberOfLevelZeroTilesX: 2,
numberOfLevelZeroTilesY: 1
})
orgin -180 90时 等等
var myGeographicTilingScheme = new Cesium.GeographicTilingScheme({
ellipsoid: cgs2000Ellipsolid,
rectangle: Cesium.Rectangle.fromDegrees(-180, -90, 180, 90),
numberOfLevelZeroTilesX: 4,
numberOfLevelZeroTilesY: 2
})
(3)创建ArcGisMapServerImageryProvider
url为MapServer地址
layer的名称可在wmts下找到,这个大家应该都知道,我就不截图了,
具体参数设置如下:
生成的provider赋值到Viewer参数的imageryProvider下
(4)初始化地图投影
var cgs2000GeographicProj = new Cesium.GeographicProjection(cgs2000Ellipsolid)
将其赋值到Viewer参数的mapProjection下
(5)初始化生成三维球体
let viewer2 = new Cesium.Viewer('map3D', {
animation: false,
baseLayerPicker: false,
fullscreenButton: false,
geocoder: false,
homeButton: false,
sceneModePicker: false,
selectionIndicator: false,
timeline: false,
navigationHelpButton: false,
infoBox: false,
navigationInstructionsInitiallyVisible: false,
mapProjection: cgs2000GeographicProj,
imageryProvider: esriWMTS,
scene3DOnly: false,
sceneMode: Cesium.SceneMode.SCENE2D,
terrainExaggeration: 1,
showRenderLoopErrors: false,
});
OK完成,效果图如下: