VTPMarkerProvider.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  1. /**
  2. * 地名注记数据提供者,通过改变LSGlobe实现地名注记数据的加载。
  3. *
  4. * * @alias CesiumTerrainProvider
  5. * @constructor
  6. *
  7. * @param {LSGlobe} LSGlobe The result of LSGlobe.js
  8. * @param {Object} options The options include:
  9. * @param {String} options.url 地形服务的url。
  10. * @param {Proxy} [options.proxy] 请求的代理。
  11. * @param {String} [options.tileUrlTemplate] url模板。
  12. * @param {Ellipsoid} [options.ellipsoid] 椭球体,默认为WGS84椭球体。
  13. * @param {String} [options.metadataUrl] 元数据文件路径。
  14. */
  15. var VTPMarkerProvider = function (LSGlobe, options) {
  16. "use strict"; // 进入严格模式
  17. if (typeof LSGlobe === 'undefined') {
  18. throw 'LSGlobe must be defined for this plugin to work.';
  19. }
  20. if (typeof LSGlobe.defined === 'undefined' || !LSGlobe.defined(LSGlobe.GlobeSurfaceTile)) {
  21. throw 'Your version of LSGlobe is out of date, please upgrade LSGlobe.';
  22. }
  23. this.LSGlobe = LSGlobe;
  24. // Provider自有的内容
  25. if (!LSGlobe.defined(options) || !LSGlobe.defined(options.url)) {
  26. throw new LSGlobe.DeveloperError('options.url is required.');
  27. }
  28. this.viewer = undefined;
  29. // 字体设置
  30. this.fontSize = LSGlobe.defaultValue(options.fontSize, 16);
  31. this.fontFamily = LSGlobe.defaultValue(options.fontFamily, "Microsoft YaHei");
  32. this._url = options.url;
  33. this._proxy = options.proxy;
  34. this.fatherGroup = options.fatherGroup;
  35. var tileUrlTemplate = this._url + '/ReadTerrainLrp?layer=' + options.layer + '&x={row}&y={col}&z={level}';
  36. this._tileUrlTemplate = LSGlobe.defaultValue(options.tileUrlTemplate, tileUrlTemplate);
  37. this._tilingScheme = new LSGlobe.GeographicTilingScheme({
  38. numberOfLevelZeroTilesX: 2,
  39. numberOfLevelZeroTilesY: 1,
  40. ellipsoid: options.ellipsoid
  41. });
  42. this._errorEvent = new LSGlobe.Event();
  43. this._availability = undefined;
  44. this._ready = false;
  45. this._readyPromise = LSGlobe.when.defer();
  46. var metadataUrl = this._url + '/CreateTerrainLrc?layer=' + options.layer;
  47. if (LSGlobe.defined(this._proxy)) {
  48. metadataUrl = this._proxy.getURL(metadataUrl);
  49. }
  50. metadataUrl = LSGlobe.defaultValue(options.metadataUrl, metadataUrl);
  51. var metadataError;
  52. var that = this;
  53. /**
  54. * 元数据请求成功函数,用于解析元数据文件。
  55. * @param {#document} xml 元数据文件
  56. * @private
  57. */
  58. function metadataSuccess(xml) {
  59. that._minimumLevel = parseInt(xml.getElementsByTagName('LevelBegin')[0].childNodes[0].nodeValue);
  60. that._maximumLevel = parseInt(xml.getElementsByTagName('LevelEnd')[0].childNodes[0].nodeValue);
  61. var west = LSGlobe.Math.toRadians(xml.getElementsByTagName('West')[0].childNodes[0].nodeValue);
  62. var south = LSGlobe.Math.toRadians(xml.getElementsByTagName('South')[0].childNodes[0].nodeValue);
  63. var east = LSGlobe.Math.toRadians(xml.getElementsByTagName('East')[0].childNodes[0].nodeValue);
  64. var north = LSGlobe.Math.toRadians(xml.getElementsByTagName('North')[0].childNodes[0].nodeValue);
  65. that._rectangle = new LSGlobe.Rectangle(west, south, east, north);
  66. that._ready = true;
  67. that._readyPromise.resolve(true);
  68. }
  69. /**
  70. * 元数据请求失败函数。
  71. * @private
  72. */
  73. function metadataFailure(data) {
  74. var message = 'An error occurred while accessing ' + metadataUrl + '.';
  75. metadataError = TileProviderError.handleError(metadataError, that, that._errorEvent, message, undefined, undefined, undefined, requestMetadata);
  76. }
  77. /**
  78. * 元数据请求函数。
  79. * @private
  80. */
  81. function requestMetadata() {
  82. function getxmlDoc(xmlFile) {
  83. var xmlDoc;
  84. if (window.ActiveXObject) {
  85. xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); //IE
  86. xmlDoc.async = false;
  87. xmlDoc.load(xmlFile);
  88. } else if (navigator.userAgent.indexOf("Firefox") > 0) { //火狐
  89. try {
  90. xmlDoc = document.implementation.createDocument('', '', null);
  91. xmlDoc.load(xmlFile);
  92. } catch (e) {
  93. var xmlhttp = new window.XMLHttpRequest();
  94. xmlhttp.open("GET", xmlFile, false);
  95. xmlhttp.send(null);
  96. if (xmlhttp.readyState == 4) {
  97. xmlDoc = xmlhttp.responseXML.documentElement;
  98. }
  99. }
  100. } else { //谷歌
  101. var xmlhttp = new window.XMLHttpRequest();
  102. xmlhttp.open("GET", xmlFile, false);
  103. xmlhttp.send(null);
  104. if (xmlhttp.readyState == 4) {
  105. xmlDoc = xmlhttp.responseXML.documentElement;
  106. }
  107. }
  108. return xmlDoc;
  109. }
  110. //加载XML
  111. var metadata = getxmlDoc(metadataUrl);
  112. //var metadata = LSGlobe.loadXML(metadataUrl);
  113. LSGlobe.when(metadata, metadataSuccess, metadataFailure);
  114. }
  115. // 请求元数据
  116. requestMetadata();
  117. /**
  118. * Modifying the passed in LSGlobe to allow for loading VTP markers...
  119. */
  120. // 使用新的 processStateMachine 函数,增加对地名注记的处理
  121. LSGlobe.GlobeSurfaceTile._oldProcessStateMachine = LSGlobe.GlobeSurfaceTile.processStateMachine;
  122. LSGlobe.GlobeSurfaceTile.processStateMachine = function (tile, frameState,
  123. terrainLayerCollection, imageryLayerCollection, vertexArraysToDestroy) {
  124. var priorityFunc = tile._priorityFunction; // _oldProcessStateMachine可能会改变tile._priorityFunction,提前备份。
  125. LSGlobe.GlobeSurfaceTile._oldProcessStateMachine(tile, frameState,
  126. terrainLayerCollection, imageryLayerCollection, vertexArraysToDestroy);
  127. // 地名注记的处理
  128. var surfaceTile = tile.data;
  129. var tileEntity = surfaceTile.tileEntity;
  130. if (!LSGlobe.defined(tileEntity)) {
  131. tileEntity = new TileEntity(that);
  132. surfaceTile.tileEntity = tileEntity;
  133. }
  134. // 地名注记没有加载完成,修改tile的状态不为QuadtreeTileLoadState.DONE
  135. var isDoneLoading = tileEntity.processStateMachine(frameState, that, tile.x, tile.y, tile.level, tile._priorityFunction);
  136. if (!isDoneLoading && tile.state === LSGlobe.QuadtreeTileLoadState.DONE) {
  137. tile.state = LSGlobe.QuadtreeTileLoadState.LOADING;
  138. tile._priorityFunction = priorityFunc;
  139. }
  140. };
  141. // 使用新的 freeResources 函数,增加对 tileEntity 的释放。
  142. LSGlobe.GlobeSurfaceTile.prototype._oldFreeResources = LSGlobe.GlobeSurfaceTile.prototype.freeResources;
  143. LSGlobe.GlobeSurfaceTile.prototype.freeResources = function () {
  144. this._oldFreeResources();
  145. if (LSGlobe.defined(this.tileEntity)) {
  146. this.tileEntity.freeResources();
  147. this.tileEntity = undefined;
  148. }
  149. };
  150. // 是否需要隐藏当前没有渲染的tile对应的地标,待确认.
  151. LSGlobe.GlobeSurfaceTileProvider.prototype._oldEndUpdate = LSGlobe.GlobeSurfaceTileProvider.prototype.endUpdate;
  152. LSGlobe.GlobeSurfaceTileProvider.prototype.endUpdate = function (frameState) {
  153. // Call the original update
  154. this._oldEndUpdate(frameState);
  155. // 先把所有的设置为不可见,然后把所有要渲染的瓦片设置可见。
  156. // 会晚一帧,因为给其添加command在这之前已经做了
  157. // var entities = that.viewer.entities;
  158. // for (var i = 0, len = entities.length; i < len; ++i) {
  159. // entities[i]._show = false;
  160. // }
  161. //
  162. // var tilesToRenderByTextureCount = this._tilesToRenderByTextureCount;
  163. // for (var textureCountIndex = 0, textureCountLength = tilesToRenderByTextureCount.length; textureCountIndex < textureCountLength; ++textureCountIndex) {
  164. // var tilesToRender = tilesToRenderByTextureCount[textureCountIndex];
  165. // if (!LSGlobe.defined(tilesToRender)) {
  166. // continue;
  167. // }
  168. //
  169. // for (var tileIndex = 0, tileLength = tilesToRender.length; tileIndex < tileLength; ++tileIndex) {
  170. // var tileEntity = tilesToRender[tileIndex].data.tileEntity;
  171. // for (var i = 0, len = tileEntity.dataList.length; i < len; ++i) {
  172. // entities.getById(tileEntity.dataList[i])._show = true;
  173. // }
  174. // }
  175. // }
  176. };
  177. };
  178. /**
  179. * 为给定瓦片请求几何数据。
  180. *
  181. * @param {Number} x x坐标。
  182. * @param {Number} y y坐标。
  183. * @param {Number} level tile等级。
  184. *
  185. * @returns {Promise.<TerrainData>|undefined} 地形数据对象。
  186. *
  187. * @exception {DeveloperError} 函数必须在{@link DTPTerrainProvider#ready}为ture之后调用。
  188. */
  189. VTPMarkerProvider.prototype.requestEntityData = function (x, y, level, request) {
  190. if (!this._ready) {
  191. return undefined; //throw new DeveloperError('requestTileGeometry must not be called before the terrain provider is ready.');
  192. }
  193. var urlTemplate = this._tileUrlTemplate;
  194. if (!isatCesium.defined(urlTemplate)) {
  195. return undefined;
  196. }
  197. if (!this.getTileDataAvailable(x, y, level)) {
  198. return undefined;
  199. }
  200. // 计算瓦片对应的地标块范围(一个瓦片可能对应多个地标块数据)
  201. var yTiles = this._tilingScheme.getNumberOfYTilesAtLevel(level) * 2;
  202. var minXY = new isatCesium.Cartesian2(-1, -1);
  203. var maxXY = new isatCesium.Cartesian2(-1, -1);
  204. calcMinMaxRowCol(this, x, y, level, minXY, maxXY);
  205. if (maxXY.x >= yTiles) {
  206. maxXY.x = yTiles - 1;
  207. }
  208. if (maxXY.y >= yTiles) {
  209. maxXY.y = yTiles - 1;
  210. }
  211. if (minXY.y >= yTiles || maxXY.x >= yTiles || // 无效范围
  212. minXY.y < 0 || maxXY.y < 0 || minXY.x < 0 || maxXY.x < 0) {
  213. return undefined;
  214. }
  215. // 数据请求数组
  216. var promiseArray = [];
  217. for (var i = minXY.y; i <= maxXY.y; ++i) {
  218. for (var j = minXY.x; j <= maxXY.x; ++j) {
  219. var url = buildUrl(this, j, yTiles - i - 1, level + 1);
  220. var promise = isatCesium.loadArrayBuffer(url);
  221. if (!isatCesium.defined(promise)) {
  222. return undefined;
  223. }
  224. promiseArray.push(promise);
  225. }
  226. }
  227. var that = this;
  228. return isatCesium.when.all(promiseArray, function (buffers) {
  229. return buffers;
  230. }, function () {
  231. return isatCesium.when.reject();
  232. });
  233. };
  234. /**
  235. * 判断瓦片数据是否可以加载。
  236. *
  237. * @param {Number} x 列号.
  238. * @param {Number} y 行号.
  239. * @param {Number} level 层号.
  240. * @returns {Boolean} Undefined if not supported, otherwise true or false.
  241. */
  242. VTPMarkerProvider.prototype.getTileDataAvailable = function (x, y, level) {
  243. if (!this._ready) {
  244. return undefined;
  245. }
  246. if (level > this._maximumLevel - 1 || level < this._minimumLevel - 1) {
  247. return false; // 不在层级范围内
  248. }
  249. var result = undefined;
  250. result = this._tilingScheme.tileXYToRectangle(x, y, level, result);
  251. if (Cesium.Rectangle.intersection(this._rectangle, result) == undefined) {
  252. return false; // 不在地理范围内
  253. }
  254. return true;
  255. };
  256. // 根据层号、行号和列号构建请求地址
  257. function buildUrl(provider, x, y, level) {
  258. var url = provider._tileUrlTemplate.replace('{z}', level).replace('{x}', x).replace('{y}', y);
  259. var proxy = provider._proxy;
  260. if (isatCesium.defined(proxy)) {
  261. url = proxy.getURL(url);
  262. }
  263. return url;
  264. }
  265. // 根据tile的层号、行号和列号计算地标块索引范围
  266. function calcMinMaxRowCol(provider, x, y, level, minXY, maxXY) {
  267. var tileRect = provider._tilingScheme.tileXYToRectangle(x, y, level);
  268. var tileSize = tileRect.width;
  269. var sample = 18;
  270. var sampleGap = tileSize / sample;
  271. var val = tileRect.west;
  272. while (val < tileRect.east) {
  273. adjustMinMaxRowCol(val, tileRect.south, tileSize, minXY, maxXY);
  274. adjustMinMaxRowCol(val, tileRect.north, tileSize, minXY, maxXY);
  275. val += sampleGap;
  276. }
  277. val = tileRect.south;
  278. while (val < tileRect.north) {
  279. adjustMinMaxRowCol(tileRect.west, val, tileSize, minXY, maxXY);
  280. adjustMinMaxRowCol(tileRect.east, val, tileSize, minXY, maxXY);
  281. val += sampleGap;
  282. }
  283. }
  284. // 根据经纬度及瓦片范围调整地标块索引范围
  285. function adjustMinMaxRowCol(lon, lat, tileSize, minXY, maxXY) {
  286. var result = getRowCol(lon, lat, tileSize);
  287. var x = Math.floor(result.x);
  288. var y = Math.floor(result.y);
  289. if (x >= 0) {
  290. if (minXY.x < 0 || x < minXY.x) {
  291. minXY.x = x;
  292. }
  293. if (maxXY.x < 0 || x > maxXY.x) {
  294. maxXY.x = x;
  295. }
  296. }
  297. if (y >= 0) {
  298. if (minXY.y < 0 || y < minXY.y) {
  299. minXY.y = y;
  300. }
  301. if (maxXY.y < 0 || y > maxXY.y) {
  302. maxXY.y = y;
  303. }
  304. }
  305. }
  306. // 根据经纬度及瓦片范围计算对应的地标块索引
  307. function getRowCol(lon, lat, tileSize, result) {
  308. if (!isatCesium.defined(result)) {
  309. result = new isatCesium.Cartesian2();
  310. }
  311. result.x = (lon + Math.PI) / tileSize;
  312. var temp = Math.tan(Math.PI / 4.0 + lat / 2.0);
  313. if (temp > 0) {
  314. result.y = (Math.log(temp) + Math.PI) / tileSize;
  315. } else {
  316. result.y = -1;
  317. }
  318. return result;
  319. }