CrImageServerLayer.js 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028
  1. /**
  2. * 创建者:王成
  3. * 操作系统:MAC
  4. * 创建日期:2023年1月30日
  5. * 描述:通过矩形渲染tile,从而达到渲染图片可以浮动在实景三维上面的效果
  6. */
  7. /* 扩展系统Date属性Format 用于格式化日期 yyMMdd HH:ss:mm */
  8. Date.prototype.Format = function(fmt) { // author: meizz
  9. var o = {
  10. "M+": this.getMonth() + 1, // 月份
  11. "d+": this.getDate(), // 日
  12. "h+": this.getHours(), // 小时
  13. "m+": this.getMinutes(), // 分
  14. "s+": this.getSeconds(), // 秒
  15. "q+": Math.floor((this.getMonth() + 3) / 3), // 季度
  16. "S": this.getMilliseconds() // 毫秒
  17. };
  18. if (/(y+)/.test(fmt)) fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
  19. for (var k in o)
  20. if (new RegExp("(" + k + ")").test(fmt)) fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : ((
  21. "00" + o[k]).substr(("" + o[k]).length)));
  22. return fmt;
  23. }
  24. /* 引入Cesium */
  25. import * as Cesium from 'cesium';
  26. /* 扩展primivite方法 */
  27. /**
  28. * 设置Id
  29. * @param {String} id
  30. */
  31. Cesium.GroundPrimitive.prototype.setId = function(id) {
  32. this._id = id;
  33. }
  34. /**
  35. * 获取Id
  36. */
  37. Cesium.GroundPrimitive.prototype.getId = function() {
  38. return this._id;
  39. }
  40. /**
  41. * 根据Id进行查询
  42. * @param {String} id
  43. * @return {Cesium.GroundPrimitive} 返回查询到的Primivite 未查询到 则返回undefined
  44. */
  45. Cesium.PrimitiveCollection.prototype.getById = function(id) {
  46. let findPrimivite = this._primitives.find(obj => {
  47. if (obj._id === id) return obj;
  48. })
  49. return findPrimivite;
  50. }
  51. /**
  52. * 根据Id进行移除操作
  53. * @param {String} id
  54. */
  55. Cesium.PrimitiveCollection.prototype.removeById = function(id) {
  56. let findPrimitive = this.getById(id);
  57. if (findPrimitive !== undefined) {
  58. return this.remove(findPrimitive);
  59. } else {
  60. return false;
  61. }
  62. }
  63. /* 创建类 */
  64. class CrImageServerLayer {
  65. /**
  66. * 构造函数
  67. * @param {Cesium.Viewer} options.viewer 地图视图容器
  68. * @param {CrImageServerLayer.ProviderType} options.providerType 数据提供器类型
  69. * @param {JSON} options.config 对应该提供器的配置参数
  70. * @param {Number} options.opacity 图层透明度[0.0~1.0] [默认0.3]
  71. */
  72. constructor({
  73. viewer,
  74. providerType = CrImageServerLayer.ArcGisMapServerImageryProvider,
  75. config = {},
  76. opacity = 0.75,
  77. show = true,
  78. } = {}) {
  79. let _self = this;
  80. /* 地图视图 外部传入 必须参数 */
  81. this._viewer = viewer;
  82. /* 服务提供者配置参数 */
  83. this._providerType = providerType;
  84. /* 服务提供者 */
  85. this._provider = undefined;
  86. /* 服务提供者切片方案 */
  87. this._tilingScheme = undefined;
  88. /* 服务的切片的最大/最小层级 */
  89. this._maximumLevel = 0;
  90. this._minimumLevel = 20;
  91. /* 切片大小 */
  92. this._tileWidth = 0;
  93. this._tileHeight = 0;
  94. /* 服务数据范围 */
  95. this._rectangle = undefined;
  96. /* 服务提供者的配置参数 */
  97. this._config = config;
  98. /* 透明度 外部传入 */
  99. this._opacity = opacity;
  100. /* 图层随机标识 */
  101. this._renderName = this._guid();
  102. /* 当前图层的渲染集合 */
  103. this._primitives = new Cesium.PrimitiveCollection();
  104. this._viewer.scene.primitives.add(this._primitives);
  105. /* 渲染集合 */
  106. this._renderPrimitives = new Map();
  107. /* 移除渲染集合 */
  108. this._removePrimitives = new Map();
  109. /* 是否渲染标志 */
  110. this._isUpdateTile = show;
  111. /* 是否输出测试信息 */
  112. this._isDebug = true;
  113. /* 缓存 */
  114. this._chacheImages = new Map();
  115. /* 创建一个线程 用于处理移除任务 */
  116. this._sendTask = true;
  117. let workerBlob = new Blob([`(${downloadWorker.toString ()})()`]); // 把函数转成一个自执行函数
  118. this._worker = new Worker(URL.createObjectURL(workerBlob));
  119. /* 接收反馈 */
  120. this._worker.onmessage = function(event) {
  121. for (let key of event.data) {
  122. _self._primitives.removeById(key);
  123. _self._removePrimitives.delete(key);
  124. _self._renderPrimitives.delete(key);
  125. }
  126. _self._sendTask = true;
  127. }
  128. /* 初始化 */
  129. this._init();
  130. }
  131. /**
  132. * 初始化
  133. */
  134. _init() {
  135. let _self = this;
  136. /* 创建服务提供者 */
  137. switch (this._providerType) {
  138. case CrImageServerLayer.ProviderType.ArcGisMapServerImageryProvider:
  139. this._provider = new Cesium.ArcGisMapServerImageryProvider(this._config);
  140. break;
  141. case CrImageServerLayer.ProviderType.UrlTemplateImageryProvider:
  142. this._provider = new Cesium.UrlTemplateImageryProvider(this._config);
  143. break;
  144. case CrImageServerLayer.ProviderType.WebMapTileServiceImageryProvider:
  145. this._provider = new Cesium.WebMapTileServiceImageryProvider({
  146. url: _self._config.url,
  147. layer: 1,
  148. style: 'default',
  149. format: 'image/png',
  150. tileMatrixSetID: 'default028mm',
  151. maximumLevel: _self._config.maxLevel ? _self._config.maxLevel : 19,
  152. minimumLevel: _self._config.minLevel ? _self._config.maxLevel : 0,
  153. });
  154. break;
  155. }
  156. /* 服务提供者判断 */
  157. if (this._provider === undefined) {
  158. this._console('没有服务提供者,无法初始化!');
  159. return;
  160. }
  161. /* 激活服务提供者 注册刷帧事件 */
  162. this._provider.readyPromise.then(function(result) {
  163. /* 初始化参数 */
  164. _self._rectangle = _self._provider.rectangle;
  165. _self._tilingScheme = _self._provider.tilingScheme;
  166. _self._maximumLevel = _self._provider.maximumLevel === undefined ? 22 : _self._provider
  167. .maximumLevel;
  168. _self._minimumLevel = _self._provider.minimumLevel === undefined ? 0 : _self._provider
  169. .minimumLevel;
  170. _self._tileWidth = _self._provider.tileWidth;
  171. _self._tileHeight = _self._provider.tileHeight;
  172. /* 输出调试信息 */
  173. if (_self._isDebug) _self._printDebug();
  174. /* 注册事件 */
  175. _self._viewer.scene.postRender.addEventListener(() => {
  176. if (_self._isUpdateTile) {
  177. /* 设置运行标志为false 等待计算完成 */
  178. _self._isUpdateTile = false;
  179. /* 投影瓦片集合 */
  180. _self._renderTiles();
  181. }
  182. });
  183. /* 测试 */
  184. // for (let i = 0; i < 20; i++) {
  185. // /* 找到对应级别的子节点 */
  186. // let filterQuadTree = quadTree.filter(function(obj) {
  187. // return obj.level === i;
  188. // })
  189. // /* 创建子节点 */
  190. // for (let findQuadTree of filterQuadTree) {
  191. // let rectangle = findQuadTree.rectangle;
  192. // /* 将该矩形按照四叉树规则分割为4个高层级的矩形 */
  193. // let rect1 = Cesium.Rectangle.subsection(rectangle, 0, 0, 0.5, 0.5);
  194. // let rect2 = Cesium.Rectangle.subsection(rectangle, 0.5, 0, 1.0, 0.5);
  195. // let rect3 = Cesium.Rectangle.subsection(rectangle, 0, 0.5, 0.5, 1.0);
  196. // let rect4 = Cesium.Rectangle.subsection(rectangle, 0.5, 0.5, 1.0, 1.0);
  197. // /* 查询当前节点的行列号 */
  198. // let centerPoint = Cesium.Rectangle.center(rectangle);
  199. // let xy = _self._tilingScheme.positionToTileXY(centerPoint, 0);
  200. // findQuadTree.x = xy.x;
  201. // findQuadTree.y = xy.y;
  202. // }
  203. // }
  204. // let quadTree = new QuadTreeTile(0, 0, _self._tilingScheme, _self._rectangle, 0, 20);
  205. // _self._console(quadTree);
  206. /* 找到有效数据 */
  207. // _self._findTile(quadTree);
  208. })
  209. }
  210. _findTile(tile) {
  211. // this._console(tile);
  212. if (tile.children.length > 0) {
  213. if (Cesium.Rectangle.intersection(tile.rectangle, this._rectangle)) {
  214. this._console(tile.x, tile.y, tile.level);
  215. }
  216. this._findTile(tile.children[0]);
  217. this._findTile(tile.children[1]);
  218. this._findTile(tile.children[2]);
  219. this._findTile(tile.children[3]);
  220. } else {
  221. this._console('结束');
  222. }
  223. }
  224. /**
  225. * 生成GUID随机数
  226. */
  227. _guid() {
  228. function S4() {
  229. return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
  230. }
  231. return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
  232. }
  233. /**
  234. * 输出调试信息
  235. */
  236. _printDebug() {
  237. /* 数据提供者的切片方案 */
  238. let tiling = this._provider.tilingScheme;
  239. /* WGS84坐标系的切片方案 */
  240. let tiling84 = new Cesium.GeographicTilingScheme();
  241. /* 绘制数据提供者的数据范围 */
  242. this._drawDebugRectangle(this._rectangle, Cesium.Color.GREEN);
  243. /* 根据行列号和等级创建调试矩形 */
  244. let rect = tiling84.tileXYToRectangle(1696, 312, 10);
  245. }
  246. /**
  247. * 绘制调试矩形
  248. * @param {Cesium.Rectangle} rectangle 绘制的矩形
  249. * @param {Cesium.Color} color 矩形边框颜色
  250. */
  251. _drawDebugRectangle(rectangle, color) {
  252. /* 计算矩形的外包范围 */
  253. let positions = this._calculateRectangleOutlineCoordinates(rectangle);
  254. /* 创建矩形图元 */
  255. let rectangleInstance = new Cesium.GeometryInstance({
  256. geometry: new Cesium.GroundPolylineGeometry({
  257. positions: positions,
  258. width: 8,
  259. })
  260. })
  261. /* 创建对象 */
  262. let primivite = new Cesium.GroundPolylinePrimitive({
  263. geometryInstances: rectangleInstance,
  264. appearance: this._createMaterialColorAppearance('rgba(0,255,0,1)'),
  265. classificationType: Cesium.ClassificationType.BOTH,
  266. })
  267. /* 加入数据集 */
  268. this._primitives.add(primivite);
  269. }
  270. /**
  271. * 创建颜色着色器
  272. * @param {String} color rgba(r,g,b,a)
  273. */
  274. _createMaterialColorAppearance(color) {
  275. /* 创建材质 */
  276. let material = new Cesium.Material({
  277. fabric: {
  278. type: 'Color',
  279. uniforms: {
  280. color: new Cesium.Color.fromCssColorString(color),
  281. }
  282. }
  283. });
  284. /* 创建着色器 */
  285. let appearance = new Cesium.MaterialAppearance({
  286. material: material,
  287. });
  288. /* 返回 */
  289. return appearance;
  290. }
  291. /**
  292. * 根据画布创建材质
  293. * @param {Canvas} canvas 画布
  294. */
  295. _createMaterialImageAppearance(canvas) {
  296. /* 创建着色器 */
  297. let material = Cesium.Material.fromType('Image', {
  298. image: canvas,
  299. })
  300. let appearance = new Cesium.MaterialAppearance({
  301. material: material,
  302. })
  303. /* 返回 */
  304. return appearance;
  305. }
  306. /**
  307. * 输出消息
  308. * @param {Object} res
  309. */
  310. _console(...rest) {
  311. if (this._isDebug)
  312. console.log('===' + new Date().Format('yyyy-MM-dd HH:mm:ss') + '>>>', rest);
  313. }
  314. /**
  315. * 渲染瓦片集合
  316. */
  317. _renderTiles() {
  318. let _self = this;
  319. /* 获取当前视图渲染的瓦片集合 */
  320. let tilesToRender = this._viewer.scene.globe._surface._tilesToRender;
  321. if (tilesToRender === undefined || tilesToRender.length === 0) {
  322. this._isUpdateTile = true;
  323. return;
  324. } else {
  325. new Promise((resolve, reject) => {
  326. /* 对瓦片数组按照level进行排序 以保证后续瓦片重投影时的重叠移除无误 */
  327. tilesToRender.sort(function(obj1, obj2) {
  328. let level1 = parseInt(obj1.level);
  329. let level2 = parseInt(obj2.level);
  330. return level1 - level2;
  331. })
  332. /* 返回排序后的渲染瓦片数据集 开始异步计算 */
  333. resolve(tilesToRender);
  334. }).then(tiles => {
  335. /* Cesium渲染瓦片为84投影,如果不一致需要异步重投影瓦片数据集 */
  336. _self._asyncProjectionTiles(tiles);
  337. })
  338. }
  339. }
  340. /**
  341. * 根据行列和等级生成key
  342. * @param {Number} x 行
  343. * @param {Number} y 列
  344. * @param {Number} level 等级
  345. */
  346. _createKey(x, y, level) {
  347. let key = `${this._renderName}_${x}_${y}_${level}`;
  348. return key;
  349. }
  350. /**
  351. * 投影瓦片集合
  352. * @param {Object} tiles 原始渲染瓦片集合
  353. */
  354. _asyncProjectionTiles(tiles) {
  355. let renderTiles = [];
  356. /* 循环投影 */
  357. for (let tile of tiles) {
  358. /* 对单个瓦片进行重投影 */
  359. let proTiles = this._projectionTile(tile);
  360. for (let proTile of proTiles) {
  361. /* 瓦片实体唯一标识 */
  362. let key = this._createKey(proTile.x, proTile.y, proTile.level);
  363. /* 查找瓦片是否已经存在 存在则过滤 以免重复存在 */
  364. let subTile = renderTiles.find(obj => {
  365. return obj.x === proTile.x && obj.y === proTile.y;
  366. })
  367. if (subTile === undefined) {
  368. /* 重投影瓦片范围与数据范围的叠合计算 */
  369. let isExists = false;
  370. for (let eTile of renderTiles) {
  371. if (Cesium.Rectangle.intersection(eTile.rectangle, proTile.rectangle)) {
  372. /* 追加子集 方便后期进行层级处理 */
  373. eTile.childTiles.push(key);
  374. isExists = true;
  375. break;
  376. }
  377. }
  378. /* 加入渲染集合 */
  379. if (!isExists) {
  380. renderTiles.push({
  381. key: key,
  382. x: proTile.x,
  383. y: proTile.y,
  384. level: proTile.level,
  385. rectangle: proTile.rectangle,
  386. childTiles: [],
  387. });
  388. }
  389. }
  390. }
  391. }
  392. /* 清理低层级元素 */
  393. let i = renderTiles.length;
  394. let appendTiles = [];
  395. while (i--) {
  396. let findTile = renderTiles[i];
  397. if (findTile.childTiles.length >= 1) {
  398. /* 创建高层级的瓦片 */
  399. let tiles = this._createFourTiles(findTile);
  400. for (let tile of tiles) {
  401. appendTiles.push(tile);
  402. }
  403. /* 如果存在高层级 则删除低层级 */
  404. renderTiles.splice(i, 1);
  405. }
  406. }
  407. /* 将四叉树追加的层级数据加入到渲染集合中 */
  408. for (let appendTile of appendTiles) {
  409. renderTiles.push(appendTile);
  410. }
  411. /* 对数组进行排序 */
  412. renderTiles.sort(function(obj1, obj2) {
  413. let level1 = parseInt(obj1.level);
  414. let level2 = parseInt(obj2.level);
  415. return level1 - level2;
  416. })
  417. /* 渲染数据到视图中 */
  418. this._renderTilesToViewer(renderTiles);
  419. }
  420. /**
  421. * 根据矩形和登记查询高一等级的行列号
  422. * @param {Cesium.Rectangle} rectangle
  423. */
  424. _createTileByRectangleAndLevel(rectangle, level) {
  425. /* 获取矩形中心点 */
  426. let center = Cesium.Rectangle.center(rectangle);
  427. /* 新层级 */
  428. let nLevel = parseInt(level) + 1;
  429. /* 查询高一层级的行列号 */
  430. let query = this._provider.tilingScheme.positionToTileXY(center, nLevel);
  431. if (query === undefined) return undefined;
  432. /* 返回结果 */
  433. return {
  434. key: this._createKey(query.x, query.y, nLevel),
  435. x: query.x,
  436. y: query.y,
  437. level: nLevel,
  438. rectangle: rectangle,
  439. childTiles: [],
  440. }
  441. }
  442. /**
  443. * 创建四个高层级的瓦片
  444. * @param {Object} tile 当前瓦片
  445. */
  446. _createFourTiles(tile) {
  447. let rects = [];
  448. let results = [];
  449. let rectangle = tile.rectangle;
  450. /* 将该矩形按照四叉树规则分割为4个高层级的矩形 */
  451. rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0, 0.5, 0.5));
  452. rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0, 1.0, 0.5));
  453. rects.push(Cesium.Rectangle.subsection(rectangle, 0, 0.5, 0.5, 1.0));
  454. rects.push(Cesium.Rectangle.subsection(rectangle, 0.5, 0.5, 1.0, 1.0));
  455. for (let rect of rects) {
  456. /* 判断高层级的矩形是否与谁范围存在交集 */
  457. if (Cesium.Rectangle.intersection(rect, this._rectangle)) {
  458. /* 查询高一层级的Tile */
  459. let newTile = this._createTileByRectangleAndLevel(rect, tile.level);
  460. /* 如果存在加入到返回集合中 */
  461. if (newTile !== undefined) results.push(newTile);
  462. }
  463. }
  464. return results;
  465. }
  466. /**
  467. * 渲染瓦片到视图中
  468. * @param {Object} tiles
  469. */
  470. _renderTilesToViewer(tiles) {
  471. let _self = this;
  472. /* 确定哪些渲染瓦片已失效 对失效的实体进行清理 */
  473. let deleteKeys = [];
  474. for (let [key, tile] of this._renderPrimitives) {
  475. let findTile = tiles.find(obj => {
  476. return obj.key === key;
  477. })
  478. if (findTile === undefined) {
  479. deleteKeys.push(key);
  480. }
  481. }
  482. for (let key of deleteKeys) {
  483. /* 从当前渲染集合中将失效瓦片移除元素 */
  484. // this._renderPrimitives.delete(key);
  485. /* 移除渲染元素 */
  486. // this._primitives.removeById(key);
  487. this._removePrimitives.set(key, {
  488. key: key,
  489. });
  490. }
  491. /* 对过滤后的数据集进行渲染 */
  492. for (let tile of tiles) {
  493. /* 判断当前渲染的数据是否已经渲染且有效 */
  494. if (!this._renderPrimitives.has(tile.key)) {
  495. /* 将数据渲染到视图中 */
  496. this._renderSimpleTileToViewer(tile);
  497. /* 追加到渲染集合中 该集合中始终保持当前渲染的最新数据 */
  498. this._renderPrimitives.set(tile.key, {
  499. key: tile.key,
  500. renderImage: false,
  501. });
  502. /* 初始化y */
  503. let tile_y = tile.y;
  504. /* 利用数据提供器获取图片 */
  505. this._provider.requestImage(tile.x, tile_y, tile.level).then(function(image) {
  506. /* 判断是否返回图片资源 */
  507. if (image !== undefined) {
  508. /* 对图片资源进行Y轴翻转 */
  509. let primise = createImageBitmap(image, {
  510. imageOrientation: 'flipY',
  511. });
  512. primise.then(function(resImage) {
  513. let renderPrimitive = _self._primitives.getById(tile
  514. .key);
  515. if (renderPrimitive !== undefined) {
  516. let canvas = _self._createCanvas(tile, resImage,
  517. _self
  518. ._isDebug);
  519. renderPrimitive.appearance = _self
  520. ._createMaterialImageAppearance(
  521. canvas);
  522. /* 修改集合中内容 */
  523. if (_self._renderPrimitives.has(tile.key)) {
  524. let item = _self._renderPrimitives.get(tile
  525. .key);
  526. item.renderImage = true;
  527. _self._renderPrimitives.set(tile.key, item);
  528. }
  529. /* 缓存起来备用 */
  530. // if (!_self._chacheImages.has(tile.key)) {
  531. // _self._chacheImages.set(tile.key, resImage);
  532. // }
  533. }
  534. /* 释放图片资源 */
  535. image.close();
  536. })
  537. }
  538. }).catch(err => {
  539. _self._console('错误', err);
  540. /* 修改集合中内容 */
  541. if (_self._renderPrimitives.has(tile.key)) {
  542. let item = _self._renderPrimitives.get(tile.key);
  543. item.renderImage = true;
  544. _self._renderPrimitives.set(tile.key, item);
  545. }
  546. });
  547. }
  548. }
  549. if (this._sendTask && this._removePrimitives.size > 0) {
  550. this._sendTask = false;
  551. this._console('发送处理任务...');
  552. let renderPrimitives = new Map();
  553. /* 传递之前深度克隆 */
  554. for (let [key, item] of this._renderPrimitives) {
  555. let strItem = JSON.stringify(item);
  556. renderPrimitives.set(key, JSON.parse(strItem));
  557. }
  558. /* 深度克隆需要移除的实体集合 */
  559. let removePrimitives = [];
  560. for (let [key, removeEntity] of this._removePrimitives) {
  561. removePrimitives.push(key);
  562. }
  563. /* 发送处理任务 */
  564. this._worker.postMessage({
  565. removePrimitives: removePrimitives,
  566. renderPrimitives: renderPrimitives,
  567. });
  568. }
  569. /* 重启计算标志 */
  570. // this._console('循环结束...');
  571. this._isUpdateTile = true;
  572. }
  573. /**
  574. * 渲染单个瓦片到视图中
  575. * @param {Object} tile
  576. */
  577. _renderSimpleTileToViewer(tile) {
  578. /* 创建画布 */
  579. const canvas = this._createCanvas(tile, undefined, this._isDebug);
  580. let bjPositions = this._calculateRectangleOutlineCoordinates(tile
  581. .rectangle);
  582. /* 创建图形要素 */
  583. let instance = new Cesium.GeometryInstance({
  584. geometry: new Cesium.RectangleGeometry({
  585. rectangle: tile.rectangle,
  586. })
  587. });
  588. /* 创建着色器 */
  589. let appearance = this._createMaterialImageAppearance(canvas);
  590. /* 创建源语 */
  591. let primitive = new Cesium.GroundPrimitive({
  592. geometryInstances: instance,
  593. appearance: appearance,
  594. });
  595. /* 设置Id */
  596. primitive.setId(tile.key);
  597. /* 加入集合 */
  598. return this._primitives.add(primitive);
  599. }
  600. /**
  601. * 根据瓦片创建画布
  602. * @param {Object} tile 瓦片
  603. * @param {Object} image 绘制的图片
  604. * @param {boolean} islabel 是否绘制标签
  605. */
  606. _createCanvas(tile, image, islabel) {
  607. /* 获取服务提供者的切片方案 */
  608. let provider = this._provider;
  609. const canvas = document.createElement("canvas");
  610. canvas.width = provider.tileWidth;
  611. canvas.height = provider.tileHeight;
  612. const context = canvas.getContext("2d");
  613. if (image !== undefined) {
  614. context.globalAlpha = this._opacity;
  615. context.drawImage(image, 0, 0, canvas.width, canvas.height);
  616. }
  617. if (this._isDebug) {
  618. context.strokeStyle = 'rgba(255,255,0,1)';
  619. context.lineWidth = 2;
  620. context.strokeRect(0, 0, canvas.width, canvas.height);
  621. }
  622. if (islabel !== undefined && islabel === true) {
  623. context.globalAlpha = 1.0;
  624. /* 创建标签 */
  625. context.font = "20px Arial";
  626. context.textAlign = "center";
  627. context.fillStyle = 'rgba(255,255,0)';
  628. context.strokeStyle = 'rgba(255,255,255,1)';
  629. context.lineWidth = 2;
  630. context.strokeText(`L: ${tile.level}`, 126, 86);
  631. context.fillText(`L: ${tile.level}`, 126, 86);
  632. context.strokeText(`X: ${tile.x}`, 126, 136);
  633. context.fillText(`X: ${tile.x}`, 126, 136);
  634. context.strokeText(`Y: ${tile.y}`, 126, 186);
  635. context.fillText(`Y: ${tile.y}`, 126, 186);
  636. }
  637. /* 返回画布 */
  638. return canvas;
  639. }
  640. /**
  641. * 投影当前瓦片
  642. * @param {Object} tile
  643. */
  644. _projectionTile(tile) {
  645. if (this._tilingScheme instanceof Cesium.GeographicTilingScheme) {
  646. return [{
  647. x: tile.x,
  648. y: tile.y,
  649. level: tile.level,
  650. rectangle: tile._rectangle,
  651. }];
  652. }
  653. /* 获取矩形 */
  654. let rectangle = tile._rectangle;
  655. // let imageryLevel = parseInt(tile.level) + 1;
  656. let imageryLevel = parseInt(tile.level);
  657. let mercatorTilingScheme = this._provider.tilingScheme;
  658. let res = [];
  659. /* 先判断当前的切片范围是否与提供者的数据范围有交集 */
  660. let interRectangle = Cesium.Rectangle.intersection(rectangle, this._rectangle);
  661. /* 如果当前计算的瓦片与数据范围无交集 则舍弃 */
  662. if (interRectangle === undefined) return res;
  663. /* 判断北西角点的墨卡托投影瓦片信息 */
  664. let northwestTileCoordinates = mercatorTilingScheme.positionToTileXY(
  665. Cesium.Rectangle.northwest(rectangle),
  666. imageryLevel
  667. );
  668. /* 判断南东角点的墨卡托投影瓦片信息 */
  669. let southeastTileCoordinates = mercatorTilingScheme.positionToTileXY(
  670. Cesium.Rectangle.southeast(rectangle),
  671. imageryLevel
  672. );
  673. /* 根据不同类型分别进行计算 */
  674. if (northwestTileCoordinates !== undefined && southeastTileCoordinates !== undefined) {
  675. for (let i = northwestTileCoordinates.x; i <= southeastTileCoordinates.x; i++) {
  676. for (let j = northwestTileCoordinates.y; j <= southeastTileCoordinates.y; j++) {
  677. let _webRectangle = mercatorTilingScheme.tileXYToRectangle(i, j, imageryLevel);
  678. if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
  679. res.push({
  680. x: i,
  681. y: j,
  682. level: imageryLevel,
  683. rectangle: _webRectangle,
  684. });
  685. }
  686. }
  687. }
  688. } else if (northwestTileCoordinates !== undefined) {
  689. let _webRectangle = mercatorTilingScheme.tileXYToRectangle(northwestTileCoordinates.x,
  690. northwestTileCoordinates.y,
  691. imageryLevel);
  692. if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
  693. res.push({
  694. x: northwestTileCoordinates.x,
  695. y: northwestTileCoordinates.y,
  696. level: imageryLevel,
  697. rectangle: _webRectangle,
  698. });
  699. }
  700. } else if (southeastTileCoordinates !== undefined) {
  701. let _webRectangle = mercatorTilingScheme.tileXYToRectangle(southeastTileCoordinates.x,
  702. southeastTileCoordinates.y,
  703. imageryLevel);
  704. if (Cesium.Rectangle.intersection(_webRectangle, this._rectangle)) {
  705. res.push({
  706. x: southeastTileCoordinates.x,
  707. y: southeastTileCoordinates.y,
  708. level: imageryLevel,
  709. rectangle: _webRectangle,
  710. });
  711. }
  712. }
  713. return res;
  714. }
  715. /**
  716. * 计算矩形的外围坐标串
  717. * @param {Cesium.Rectangle} rectangle 矩形
  718. * @return {Array<Cesium.Cartesian3>} 坐标串集合
  719. */
  720. _calculateRectangleOutlineCoordinates(rectangle) {
  721. /* 计算东南角 */
  722. let south_east = Cesium.Rectangle.southeast(rectangle);
  723. let se = Cesium.Cartographic.toCartesian(south_east);
  724. /* 计算西南角 */
  725. let south_west = Cesium.Rectangle.southwest(rectangle);
  726. let sw = Cesium.Cartographic.toCartesian(south_west);
  727. /* 计算东北角 */
  728. let north_east = Cesium.Rectangle.northeast(rectangle);
  729. let ne = Cesium.Cartographic.toCartesian(north_east);
  730. /* 计算西北角 */
  731. let north_west = Cesium.Rectangle.northwest(rectangle);
  732. let nw = Cesium.Cartographic.toCartesian(north_west);
  733. return [sw, se, ne, nw, sw];
  734. }
  735. /**
  736. * 根据Entity的名称批量删除Entity
  737. * @param {String} entityName 实体名称
  738. */
  739. _removeEntityByName(entityName) {
  740. /* 获取实体集合 */
  741. var entities = this._primitives;
  742. /* 如果不存在实体集合或集合中没有数据 则返回 */
  743. if (!entities || !entities.values) return;
  744. var delEntitys = [];
  745. /* 循环获取当前集合中的所有实体 */
  746. for (var i = 0; i < entities.values.length; i++) {
  747. if (entities.values[i].name == entityName) {
  748. delEntitys.push(entities.values[i]);
  749. }
  750. }
  751. /* 删除符合条件的所有实体 */
  752. for (var i = 0; i < delEntitys.length; i++) {
  753. entities.remove(delEntitys[i]);
  754. }
  755. }
  756. }
  757. /* 对外方法 */
  758. Object.assign(CrImageServerLayer.prototype, {
  759. /**
  760. * 隐藏
  761. */
  762. hide: function() {
  763. this._console('隐藏');
  764. this._isUpdateTile = false;
  765. /* 清理资源 */
  766. this._removeEntityByName(this._renderName);
  767. /* 清理渲染 */
  768. this._renderPrimitives.clear();
  769. },
  770. /**
  771. * 显示
  772. */
  773. show: function() {
  774. this._console('显示');
  775. this._isUpdateTile = true;
  776. },
  777. /**
  778. * 设置透明度
  779. * @param {Number} opacity [0-1]
  780. */
  781. setOpacity: function(opacity) {
  782. if (opacity === undefined || typeof opacity !== 'number') return;
  783. if (opacity >= 1) this._opacity = 1.0;
  784. if (opacity <= 0) this._opacity = 0.0;
  785. this._opacity = parseFloat(opacity);
  786. }
  787. })
  788. /* 下载线程函数 */
  789. function downloadWorker() {
  790. /**
  791. * 判断矩形相交函数
  792. * @ignore
  793. * @param {Object} rectangle
  794. * @param {Object} otherRectangle
  795. * @param {Object} result
  796. */
  797. function intersection(rectangle, otherRectangle, result) {
  798. let TWO_PI = 2.0 * Math.PI;
  799. let rectangleEast = rectangle.east;
  800. let rectangleWest = rectangle.west;
  801. let otherRectangleEast = otherRectangle.east;
  802. let otherRectangleWest = otherRectangle.west;
  803. if (rectangleEast < rectangleWest && otherRectangleEast > 0.0) {
  804. rectangleEast += TWO_PI;
  805. } else if (otherRectangleEast < otherRectangleWest && rectangleEast > 0.0) {
  806. otherRectangleEast += TWO_PI;
  807. }
  808. if (rectangleEast < rectangleWest && otherRectangleWest < 0.0) {
  809. otherRectangleWest += TWO_PI;
  810. } else if (otherRectangleEast < otherRectangleWest && rectangleWest < 0.0) {
  811. rectangleWest += TWO_PI;
  812. }
  813. const west = negativePiToPi(
  814. Math.max(rectangleWest, otherRectangleWest)
  815. );
  816. const east = negativePiToPi(
  817. Math.min(rectangleEast, otherRectangleEast)
  818. );
  819. if (
  820. (rectangle.west < rectangle.east ||
  821. otherRectangle.west < otherRectangle.east) &&
  822. east <= west
  823. ) {
  824. return undefined;
  825. }
  826. const south = Math.max(rectangle.south, otherRectangle.south);
  827. const north = Math.min(rectangle.north, otherRectangle.north);
  828. if (south >= north) {
  829. return undefined;
  830. }
  831. if (result === undefined) {
  832. return {
  833. west: west,
  834. south: south,
  835. east: east,
  836. north: north
  837. };
  838. }
  839. result.west = west;
  840. result.south = south;
  841. result.east = east;
  842. result.north = north;
  843. return result;
  844. };
  845. /**
  846. * 判断矩形相交辅助函数
  847. * @ignore
  848. * @param {Object} angle
  849. */
  850. function negativePiToPi(angle) {
  851. if (angle >= -Math.PI && angle <= Math.PI) {
  852. return angle;
  853. }
  854. return zeroToTwoPi(angle + Math.PI) - Math.PI;
  855. };
  856. /**
  857. * 判断矩形相交辅助函数
  858. * @ignore
  859. * @param {Object} angle
  860. */
  861. function zeroToTwoPi(angle) {
  862. let TWO_PI = 2.0 * Math.PI;
  863. let EPSILON14 = 0.00000000000001;
  864. if (angle >= 0 && angle <= TWO_PI) {
  865. return angle;
  866. }
  867. const mod = mod(angle, TWO_PI);
  868. if (
  869. Math.abs(mod) < EPSILON14 &&
  870. Math.abs(angle) > EPSILON14
  871. ) {
  872. return TWO_PI;
  873. }
  874. return mod;
  875. };
  876. /**
  877. * 判断矩形相交辅助函数
  878. * @ignore
  879. * @param {Object} m
  880. * @param {Object} n
  881. */
  882. function mod(m, n) {
  883. if (sign(m) === sign(n) && Math.abs(m) < Math.abs(n)) {
  884. return m;
  885. }
  886. return ((m % n) + n) % n;
  887. };
  888. /**
  889. * 判断矩形相交辅助函数
  890. * @ignore
  891. * @param {Object} value
  892. */
  893. function sign(value) {
  894. value = +value;
  895. if (value === 0 || value !== value) {
  896. return value;
  897. }
  898. return value > 0 ? 1 : -1;
  899. };
  900. /**
  901. * 接收主线发送的处理任务
  902. * @ignore
  903. * @param {Object} event
  904. * @param {JSON} event.data
  905. * @param {Array<String>} event.data.removePrimitives 存储当前需要移除的集合
  906. * @param {Array<JSON>} event.data.renderPrimitives 当前渲染的数据集合
  907. * event.data.entities 参数说明
  908. * @param {String} key 主键<对应Id>
  909. * @param {Boolean} renderImage 是否已经渲染了图片
  910. */
  911. onmessage = function(event) {
  912. let data = event.data;
  913. let isRemove = true;
  914. for (let [key, item] of data.renderPrimitives) {
  915. if (item.renderImage === false) isRemove = false;
  916. break;
  917. }
  918. if (isRemove) {
  919. setTimeout(function() {
  920. postMessage(data.removePrimitives);
  921. }, 300);
  922. } else {
  923. postMessage([]);
  924. console.log('===>>>', '渲染未完成!');
  925. }
  926. }
  927. }
  928. /**
  929. * 数据提供器类型
  930. */
  931. CrImageServerLayer.ProviderType = Object.freeze({
  932. ArcGisMapServerImageryProvider: 'ArcGisMapServerImageryProvider',
  933. BingMapsImageryProvider: 'BingMapsImageryProvider',
  934. OpenStreetMapImageryProvider: 'OpenStreetMapImageryProvider',
  935. TileMapServiceImageryProvider: 'TileMapServiceImageryProvider',
  936. GoogleEarthEnterpriseImageryProvider: 'GoogleEarthEnterpriseImageryProvider',
  937. GoogleEarthEnterpriseMapsProvider: 'GoogleEarthEnterpriseMapsProvider',
  938. GridImageryProvider: 'GridImageryProvider',
  939. IonImageryProvider: 'IonImageryProvider',
  940. MapboxImageryProvider: 'MapboxImageryProvider',
  941. MapboxStyleImageryProvider: 'MapboxStyleImageryProvider',
  942. SingleTileImageryProvider: 'SingleTileImageryProvider',
  943. TileCoordinatesImageryProvider: 'TileCoordinatesImageryProvider',
  944. UrlTemplateImageryProvider: 'UrlTemplateImageryProvider',
  945. WebMapServiceImageryProvider: 'WebMapServiceImageryProvider',
  946. WebMapTileServiceImageryProvider: 'WebMapTileServiceImageryProvider',
  947. })
  948. function QuadTreeTile(x, y, tilingScheme, dataRectangle, depth, maxDepth) {
  949. this.x = x;
  950. this.y = y;
  951. this.level = depth; //最小层数 this.maxDepth = maxDepth; //最大分几层 下面规则就是每次4分直到到达规定最大层数
  952. // this.rectangle = tilingScheme.tileXYToRectangle(this.x, this.y, this.level);
  953. // let tempRectangle = tilingScheme.tileXYToNativeRectangle(this.x, this.y, this.level);
  954. // if (Cesium.Rectangle.intersection(tempRectangle, dataRectangle)) {
  955. // console.log('===>>>', this.x, this.y, this.level, this.rectangle);
  956. // // let center = Cesium.Rectangle.center(this.rectangle);
  957. // // let xy = tilingScheme.positionToTileXY(center);
  958. // // if (xy !== undefined) {
  959. // // console.log('===>>>', xy.x, xy.y, this.level);
  960. // // }
  961. // }
  962. if (this.level === 11 && this.x === 1695 && this.y === 808) {
  963. console.log('===>>>', this.x, this.y, this.level, this.rectangle);
  964. }
  965. if (depth < maxDepth) {
  966. this.children = [
  967. // 北西
  968. new QuadTreeTile(this.x * 2, this.y * 2, tilingScheme, dataRectangle, depth + 1, maxDepth),
  969. // 北东
  970. new QuadTreeTile(this.x * 2, this.y * 2 + 1, tilingScheme, dataRectangle, depth + 1, maxDepth),
  971. // 南西
  972. new QuadTreeTile(this.x * 2, this.y * 2 + 1, tilingScheme, dataRectangle, depth + 1, maxDepth),
  973. // 南东
  974. new QuadTreeTile(this.x * 2 + 1, this.y * 2 + 1, tilingScheme, dataRectangle, depth + 1, maxDepth),
  975. ]
  976. } else {
  977. this.children = []
  978. }
  979. }
  980. /* 输出类 */
  981. export default CrImageServerLayer