TileDownloader.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  1. import {TileDownloaderEvents, DownloadStatus} from '../../../defines.js'
  2. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  3. import TilePrioritizer from './TilePrioritizer.js'
  4. import TileUtils from './TileUtils.js'
  5. import {settings, config} from '../../../settings.js'
  6. import {
  7. http
  8. } from '../../../utils/request.js'
  9. window.downloaded = {}
  10. window.startdownloads = [];
  11. class TileDownloader extends THREE.EventDispatcher{
  12. constructor( ) {
  13. super()
  14. this.panos = null;
  15. this.retryMinimumTime = 1e4;
  16. this.panoLoadCallbacks = {};
  17. this.downloadDescriptors = {};
  18. this.priorityQueue = [];
  19. this.forceQueue = [];
  20. this.activeDownloads = [];
  21. this.tilePrioritizer = null;
  22. this.refreshInterval = null;
  23. this.processPriorityQueue = !1;
  24. this.concurrentDownloads = 6;//e.concurrentDownloads || 1;
  25. this.downloadTestResults = {};
  26. this.freeze = Object.freeze({
  27. Testing: 1,
  28. Success: 2,
  29. Fail: 3
  30. });
  31. this.visible = true //add 借用viewer.updateVisible来判断是否start
  32. viewer.addEventListener('pageVisible', (e)=>{//不可见时不refreshUpdateInterval
  33. //console.log('visibilitychange:', state)
  34. viewer.updateVisible(this, 'pageVisible', e.v)
  35. this.judgeStart()
  36. })
  37. }
  38. setPanoData(e, t /* , i */) {
  39. this.panos = e,
  40. this.imagePanos = t
  41. // this.panoGroupId = i
  42. }
  43. start() {
  44. this.downloadCubeTex = true
  45. if(!Potree.settings.useDepthTex){
  46. viewer.updateVisible(this,'showPanos', true )
  47. this.judgeStart()
  48. }else{
  49. this.refreshInterval || this.judgeStart()
  50. }
  51. }
  52. stop() {
  53. this.downloadCubeTex = false
  54. if(!Potree.settings.useDepthTex){
  55. viewer.updateVisible(this,'showPanos', false )
  56. this.judgeStart()
  57. }
  58. }
  59. judgeStart(){//add
  60. if(this.visible){
  61. //console.log('judgeStart true')
  62. this.started = true
  63. this.refreshUpdateInterval(0)
  64. }else{
  65. //console.log('judgeStart false')
  66. this.started = false
  67. window.clearTimeout(this.refreshInterval)
  68. }
  69. }
  70. refreshUpdateInterval(e) {
  71. e || (e = 0),
  72. this.refreshInterval = window.setTimeout(function() {
  73. var e = this.update();
  74. e ? this.refreshUpdateInterval(TileDownloader.ACTIVE_REFRESH_DELAY) : this.refreshUpdateInterval(TileDownloader.IDLE_REFRESH_DELAY)
  75. }
  76. .bind(this), e)
  77. }
  78. update() {
  79. if(this.downloadCubeTex){ //可以下载贴图
  80. var e = this.forceQueue.length > 0;
  81. this.processQueueForDownloading(this.forceQueue);
  82. if (this.processPriorityQueue) {
  83. this.queuePrioritizedTilesForPanos(this.panos);
  84. this.priorityQueue.length > 0 && (e = !0);
  85. this.processQueueForDownloading(this.priorityQueue);
  86. }
  87. return e
  88. }else{//仅下载depthTex
  89. this.tilePrioritizer.filterDepthTex(this.panos)
  90. }
  91. }
  92. queuePrioritizedTilesForPanos(e) {
  93. this.tilePrioritizer && (this.clearQueue(this.priorityQueue),
  94. this.tilePrioritizer.filterAndPrioritize(this.priorityQueue, e, this),
  95. this.clearFromQueue(this.priorityQueue, DownloadStatus.None, !0), //去除state为DownloadStatus.None的(可能是去除已经在下载的)
  96. this.setStatusOrRemoveForAllDescriptors(this.priorityQueue, DownloadStatus.Queued))
  97. }
  98. clearQueue(e) {//停止下载并清空
  99. this.setStatusForAllDescriptors(e, DownloadStatus.None),
  100. e.length = 0
  101. }
  102. clearForceQueue() {
  103. this.clearQueue(this.forceQueue)
  104. }
  105. clearFromQueue(e, t, i) {
  106. for (var n = 0; n < e.length; n++) {
  107. var r = e[n];
  108. r && (t === r.status && !i || t !== r.status && i) && (e[n] = null)
  109. }
  110. }
  111. setStatusForAllDescriptors(e, t) {
  112. for (var i = 0; i < e.length; i++) {
  113. var n = e[i];
  114. n && (n.status = t)
  115. }
  116. }
  117. setStatusOrRemoveForAllDescriptors(e, t) {
  118. for (var i = 0; i < e.length; i++) {
  119. var n = e[i];
  120. n && (n.status !== t ? n.status = t : e[i] = null)
  121. }
  122. }
  123. getTileDownloadDescriptors(pano, size) {//获取该pano的该size的全部的tile的descriptor
  124. var i = this.getAllTileDownloadDescriptorsForPano(pano),
  125. n = i[size];
  126. return n || (n = this.buildDownloadDescriptorArray(size),//创建的全部是空的
  127. i[size] = n,
  128. this.initTileDownloadDescriptors(n, pano, size)),//绑定到该pano size
  129. n
  130. }
  131. getAllTileDownloadDescriptorsForPano(pano) {//新建空Descriptors
  132. var t = this.downloadDescriptors[pano.id];
  133. return t || (t = {},
  134. this.downloadDescriptors[pano.id] = t),
  135. t
  136. }
  137. processQueueForDownloading(e, t) {//执行下载任务
  138. this.cleanupActiveDownloads();
  139. if (this.activeDownloads.length < this.concurrentDownloads || t) {
  140. var i = t ? e.length : this.concurrentDownloads - this.activeDownloads.length;
  141. for (var n = 0, r = 0; n < i && e.length > 0; r++) {
  142. var o = e.shift();
  143. if(o){
  144. //add 为了防止1024的在512前下载完,这里强行等待512下载完毕再开始下载
  145. if(o.panoSize > 512 && !this.isPanoDownloaded(o.pano, 512) ){
  146. //console.log('512的还没下载好呢!')
  147. e.push(o)
  148. break;//一般512的都是连续下载的,所以后面就都不是512了直接中断
  149. }
  150. this.startDownload(o)
  151. n++
  152. }
  153. }
  154. }
  155. }
  156. testDownload(panoSize, tileSize, callback) {
  157. var n = this.downloadTestResults[panoSize];
  158. if (n)
  159. return void(n === this.freeze.Success ? callback(!0) : n === this.freeze.Fail && callback(!1));
  160. this.downloadTestResults[panoSize] = this.freeze.Testing;
  161. var r = this.panos[0],
  162. o = this.getTileUrl({pano:r, panoSize, tileSize, tileIndex:0} /* r.id, panoSize, tileSize, 0 */),
  163. a = function(t) {
  164. this.downloadTestResults[panoSize] = this.freeze.Success,
  165. callback(!0)
  166. }
  167. .bind(this),
  168. s = function() {
  169. this.downloadTestResults[panoSize] = this.freeze.Fail,
  170. callback(!1)
  171. }
  172. .bind(this);
  173. this.loadImage(o, 0, a, s)
  174. }
  175. startDownload(e) {//开始下载啦
  176. //console.log('startDownload')
  177. startdownloads.push(e)
  178. e.local2SrcFailed = this.local2SrcFailed
  179. e.status = DownloadStatus.Downloading;
  180. var t = this.getTileUrl(e/* e.pano.id, e.panoSize, e.tileSize, e.tileIndex, e.pano.alignmentType */);//xzw add alignmentType
  181. if(!t)return;
  182. this.activeDownloads.push(e);
  183. this.loadImage(t, TileDownloader.DOWNLOAD_RETRIES, this.downloadComplete.bind(this, e), this.downloadFailed.bind(this, e))
  184. }
  185. downloadFailed(e, t) {
  186. //add
  187. if(Potree.settings.isLocal2 && !e.local2SrcFailed){//为了兼容旧的数据src,如果新src没加载成功,就加载旧的
  188. e.local2SrcFailed = this.local2SrcFailed = true
  189. //this.startDownload(e)//重新下载
  190. var t = this.getTileUrl(e);
  191. this.loadImage(t, TileDownloader.DOWNLOAD_RETRIES, this.downloadComplete.bind(this, e), this.downloadFailed.bind(this, e))
  192. }
  193. }
  194. downloadComplete(e, t) {//下载成功时
  195. //if (e.panoGroupId === this.panoGroupId) {
  196. var i = this.getPanoLoadCallbacks(e.pano, e.panoSize);
  197. e.status = DownloadStatus.Downloaded,
  198. i && i.onProgress && i.onProgress(e.pano, e.panoSize);
  199. var n = {
  200. panoId: e.pano.id,
  201. image: t,
  202. tileSize: e.tileSize,
  203. panoSize: e.panoSize,
  204. tileIndex: e.tileIndex,
  205. faceTileIndex: e.faceTileIndex,
  206. totalTiles: e.totalTiles,
  207. face: e.face,
  208. tileX: e.tileX,
  209. tileY: e.tileY,
  210. direction: e.direction
  211. };
  212. downloaded[e.pano.id] || (downloaded[e.pano.id]={512:[],1024:[],2048:[]})
  213. downloaded[e.pano.id][e.panoSize] || (downloaded[e.pano.id][e.panoSize] = [])
  214. downloaded[e.pano.id][e.panoSize].push(e)
  215. if(e.panoSize != 512 && downloaded[e.pano.id][512].length<6){
  216. console.warn('没下完')
  217. }
  218. e.image = t,
  219. this.dispatchEvent({type:TileDownloaderEvents.TileDownloadSuccess, desc:n} )
  220. this.isPanoDownloaded(e.pano, e.panoSize) && (n = {
  221. panoId: e.pano.id,
  222. tileSize: e.tileSize,
  223. panoSize: e.panoSize
  224. },
  225. this.dispatchEvent({type:TileDownloaderEvents.PanoDownloadComplete, desc:n}),
  226. i && i.onLoad && i.onLoad(e.pano, e.panoSize))
  227. //}
  228. }
  229. isPanoDownloaded(e, t) {
  230. var i = this.getTileDownloadDescriptors(e, t);
  231. if (i.length <= 0)
  232. return !1;
  233. for (var n = 0; n < i.length; n++) {
  234. var r = i[n];
  235. if (r.status !== DownloadStatus.Downloaded)
  236. return !1
  237. }
  238. return !0
  239. }
  240. setPanoLoadCallbacks(e, t, i, n, r) {
  241. var o = e.id + ":" + this.qualityManager.getPanoSize(t);
  242. this.panoLoadCallbacks[o] = {
  243. onLoad: i,
  244. onFail: n,
  245. onProgress: r
  246. }
  247. }
  248. getPanoLoadCallbacks(e, t) {
  249. var i = e.id + ":" + t;
  250. return this.panoLoadCallbacks[i]
  251. }
  252. buildDownloadDescriptorArray(e) {
  253. for (var t = TileUtils.getTileCountForSize(e), i = [], n = 0; n < t; n++) {
  254. var r = this.buildDownloadDescriptor();
  255. i.push(r)
  256. }
  257. return i
  258. }
  259. buildDownloadDescriptor() {//Descriptor!
  260. var e = {
  261. panoGroupId: null,
  262. pano: null,
  263. panoSize: -1,
  264. tileSize: -1,
  265. tileIndex: -1,
  266. totalTiles: -1,
  267. faceTileIndex: -1,
  268. status: DownloadStatus.None,
  269. url: null,
  270. image: null,
  271. direction: new THREE.Vector3, //该tile在cube中的方向
  272. face: -1,
  273. cubeFace: -1,
  274. tileX: -1,
  275. tileY: -1
  276. };
  277. return e
  278. }
  279. initTileDownloadDescriptors(e, t, i) {
  280. for (var n = 0; n < e.length; n++) {
  281. var r = e[n];
  282. this.initTileDownloadDescriptor(r, t, i, n)
  283. }
  284. }
  285. initTileDownloadDescriptor(desc, pano, size, index) {
  286. var r = size >= TileUtils.TILE_SIZE ? TileUtils.TILE_SIZE : size;
  287. desc.face = TileUtils.getFaceForTile(size, index);//根据顺序得到的face的index
  288. desc.cubeFace = TileUtils.mapFaceToCubemapFace(desc.face);//为了贴图而转化的face index
  289. //desc.panoGroupId = this.panoGroupId;//就是场景号
  290. desc.pano = pano;
  291. desc.panoSize = size;
  292. desc.tileSize = r; //瓦片图size 512
  293. desc.tileIndex = index;
  294. desc.totalTiles = TileUtils.getTileCountForSize(size);
  295. desc.status = DownloadStatus.None;
  296. desc.image = null;
  297. TileUtils.getTileLocation(desc.panoSize, desc.tileIndex, desc);//得到该tile在这个face中的具体位置(tileX等)
  298. TileUtils.getTileVector(desc.panoSize, desc.tileSize, desc.cubeFace, desc.tileX, desc.tileY, TileUtils.LocationOnTile.Center, 0, desc.direction);
  299. }
  300. getTiles(d, sceneNum, useV4url){
  301. if(Potree.settings.isLocal2 && !this.local2SrcFailed || useV4url){//新的地址 scene_view_data/场景码/images/tiles
  302. return `${Potree.settings.urls.prefix3}/scene_view_data/${sceneNum}/images/${d}`
  303. }
  304. return `${Potree.settings.urls.prefix3}/images/images${sceneNum}/${d}`
  305. }
  306. loadImage(e, t, i, n) {
  307. //自己修改了ajax,把getImage改成了loadImg
  308. http.loadImage(e, t).then(function(e) {
  309. i(e)
  310. }).fail(n)
  311. }
  312. }
  313. TileDownloader.prototype.forceQueueTilesForPano = function() {//根据条件开始加载tile
  314. var e = [],
  315. t = [];
  316. return function(pano, size, dir, hFov, vFov, download) {
  317. e.length = 0;
  318. for (var u = this.getTileDownloadDescriptors(pano, size), d = 0; d < u.length; d++) {
  319. var p = u[d];
  320. p.status !== DownloadStatus.None && p.status !== DownloadStatus.Queued || e.push(p)
  321. }
  322. if (dir && e.length > 0) {
  323. TilePrioritizer.sortPanoTiles(e, pano, dir) //按最佳方向排序e
  324. t.length = 0
  325. TileUtils.matchingTilesInDirection(pano, size, dir, hFov, vFov, t);//得到在符合视野标准的集合t
  326. for (var f = 0, g = function(e) {
  327. return e.face === m.face && e.faceTileIndex === m.faceTileIndex
  328. }; f < e.length;) { //过滤掉不符合角度要求的
  329. var m = e[f],
  330. v = t.findIndex(g);
  331. v < 0 ? e.splice(f, 1) : f++
  332. }
  333. }
  334. for (var A = 0; A < e.length; A++){
  335. this.forceQueue.push(e[A]); //装载
  336. }
  337. /* if(e.length){
  338. console.log(e)
  339. } */
  340. this.setStatusForAllDescriptors(this.forceQueue, DownloadStatus.ForceQueued);
  341. this.clearFromQueue(this.priorityQueue, DownloadStatus.ForceQueued, !1);
  342. download && this.processQueueForDownloading(this.forceQueue, !0);
  343. }
  344. }()
  345. TileDownloader.prototype.cleanupActiveDownloads = function() {
  346. var e = [];
  347. return function() {
  348. e.length = 0;
  349. for (var t = 0; t < this.activeDownloads.length; t++) {
  350. var i = this.activeDownloads[t];
  351. i.status !== DownloadStatus.Downloaded && i.status !== DownloadStatus.Failed && e.push(i)
  352. }
  353. this.activeDownloads.length = 0,
  354. this.activeDownloads.push.apply(this.activeDownloads, e)
  355. }
  356. }()
  357. TileDownloader.prototype.getTileUrl = function() {
  358. var e = {
  359. 256: "256",
  360. 512: "512",
  361. 1024: "1k",
  362. 2048: "2k",
  363. 4096: "4k"
  364. },
  365. t = {
  366. face: -1,
  367. faceTileIndex: -1,
  368. tileX: -1,
  369. tileY: -1
  370. };
  371. return function(o={} ) {
  372. var id = o.pano.originID, ////////
  373. panoSize = o.panoSize,
  374. tileSize = o.tileSize,
  375. tileIndex = o.tileIndex,
  376. sceneCode = o.pano.pointcloud.sceneCode,
  377. useV4url = Potree.settings.testV4url /* && o.pano.pointcloud.useV4url */ //v4的全景图等路径不一样
  378. var metadata = {sceneScheme:10}
  379. TileUtils.getTileLocation(panoSize, tileIndex, t);
  380. var s = Math.floor(panoSize / tileSize),
  381. l = s * s,
  382. h = Math.floor(tileIndex / l),
  383. u = "",
  384. d = '', g = '';
  385. if(Potree.settings.isLocal){//原始规则
  386. //1 === config.tiling.customCompression && (u = "_" + config.tiling["q" + e[panoSize]]);
  387. //1 === o.tiling.customCompression && (u = "_" + o.tiling["q" + e[n]]);
  388. d = "tiles/" + id + "/" + e[panoSize] + u + "_face" + h + "_" + t.tileX + "_" + t.tileY + ".jpg"
  389. d = this.getTiles(d, sceneCode, useV4url);
  390. g = "?"
  391. }else{//阿里云oss的规则 if (metadata.sceneScheme == 10)
  392. d = 'tiles/4k/' + id + '_skybox' + h + '.jpg?x-oss-process=';
  393. if (e[panoSize] == '512') {
  394. d += 'image/resize,h_512';
  395. } else {
  396. //4k的图,移动端是1k,pc端是2k,放大才是4k
  397. if (e[panoSize] == '1k' || e[panoSize] == '2k') { //https://4dkk.4dage.com/images/imagesx4iqYDG3/tiles/4k/122_skybox0.jpg?x-oss-process=image/resize,m_lfit,w_1024/crop,w_512,h_512,x_511,y_0
  398. d += 'image/resize,m_lfit,w_' + panoSize + '/crop,w_512,h_512,';
  399. } else {
  400. d = 'tiles/4k/' + id + '_skybox' + h + '.jpg?x-oss-process=image/crop,w_512,h_512,';
  401. }
  402. //起始位置
  403. if (t.tileX == 0) {
  404. d += 'x_0,';
  405. } else {
  406. d += 'x_' + (512 * t.tileX - 1) + ',';
  407. }
  408. if (t.tileY == 0) {
  409. d += 'y_0';
  410. } else {
  411. d += 'y_' + (512 * t.tileY - 1);
  412. }
  413. }
  414. d = this.getTiles(d, sceneCode, useV4url);
  415. g = "&"
  416. }
  417. d += g + 'time='+o.pano.pointcloud.timeStamp //加后缀
  418. return d;
  419. }
  420. }();
  421. TileDownloader.tilegen = true;
  422. TileDownloader.IDLE_REFRESH_DELAY = 500;
  423. TileDownloader.ACTIVE_REFRESH_DELAY = 16;
  424. TileDownloader.DOWNLOAD_RETRIES = 4;
  425. /*
  426. 源:https://4dkk.4dage.com/images/imagesSS-t-ZZR7oKnlIl
  427. 目标:https://4dkk.4dage.com/scene_view_data/SS-t-ZZR7oKnlIl/images
  428. 源:https://4dkk.4dage.com/data/dataSS-t-ZZR7oKnlIl
  429. 目标:https://4dkk.4dage.com/scene_view_data/SS-t-ZZR7oKnlIl/data
  430. 源:https://4dkk.4dage.com/video/videoSS-t-ZZR7oKnlIl
  431. 目标:https://4dkk.4dage.com/scene_view_data/SS-t-ZZR7oKnlIl/video
  432. */
  433. // var tileconc = TileDownloader.tilegen ? 6 : 2;
  434. // publicObjectSet.tileDownloader = new TileDownloader({
  435. // concurrentDownloads: tileconc
  436. // });
  437. // export default new TileDownloader({
  438. // concurrentDownloads: TileDownloader.tilegen ? 6 : 2
  439. // })
  440. /* export default new TileDownloader({
  441. concurrentDownloads: TileDownloader.tilegen ? 6 : 2
  442. }) */
  443. export default TileDownloader