Images360.js 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183
  1. import * as THREE from "../../../libs/three.js/build/three.module.js";
  2. import { EventDispatcher } from "../../EventDispatcher.js";
  3. import {TextSprite} from "../../TextSprite.js";
  4. import ModelTextureMaterial from "./ModelTextureMaterial.js";
  5. import Common from "../../utils/Common.js";
  6. import math from "../../utils/math.js";
  7. import cameraLight from "../../utils/cameraLight.js";
  8. import Panorama from "./Panorama.js";
  9. import QualityManager from './tile/QualityManager'
  10. import TileDownloader from './tile/TileDownloader'
  11. import PanoRenderer from './tile/PanoRenderer'
  12. import TilePrioritizer from './tile/TilePrioritizer'
  13. import { PanoSizeClass,Vectors} from '../../defines'
  14. //import Axis from '../../viewer/Axis'
  15. let raycaster = new THREE.Raycaster();
  16. //let currentlyHovered = null;
  17. var texLoader = new THREE.TextureLoader()
  18. let cm = new ModelTextureMaterial()
  19. let previousView = {
  20. controls: null,
  21. position: null,
  22. target: null,
  23. };
  24. let sm = new THREE.MeshBasicMaterial({side: THREE.BackSide});
  25. var tileArr = []
  26. /* let sgHigh = new THREE.SphereGeometry(1, 128, 128);
  27. */
  28. export class Images360 extends EventDispatcher{
  29. constructor(viewer, params){
  30. super();
  31. this.viewer = viewer;
  32. this.selectingEnabled = true;
  33. this.panos = [];
  34. this.node = new THREE.Object3D();
  35. this.node.name = 'ImagesNode'
  36. //this.node2 = new THREE.Object3D();
  37. //add:
  38. let size = params.boundSize
  39. this.cube = new THREE.Mesh(new THREE.BoxBufferGeometry( size.x, size.y, size.z ), cm);
  40. this.cube.position.copy(params.center)
  41. this.cube.visible = false;
  42. this.cube.layers.set(Potree.config.renderLayers.skybox)
  43. this.cube.name = 'skybox'
  44. viewer.scene.scene.add(this.cube)
  45. this._visible = true;
  46. this.currentPano = null;
  47. this.mouseLastMoveTime = Date.now()
  48. this.tileDownloader = new TileDownloader;
  49. this.qualityManager = new QualityManager
  50. this.panoRenderer = new PanoRenderer(viewer, this.tileDownloader, this.qualityManager)
  51. this.basePanoSize = this.qualityManager.getPanoSize(PanoSizeClass.BASE);
  52. this.standardPanoSize = this.qualityManager.getPanoSize(PanoSizeClass.STANDARD);
  53. this.highPanoSize = this.qualityManager.getPanoSize(PanoSizeClass.HIGH);
  54. this.ultraHighPanoSize = this.qualityManager.getPanoSize(PanoSizeClass.ULTRAHIGH);
  55. this.tileDownloader.processPriorityQueue = !1;
  56. this.tileDownloader.tilePrioritizer = new TilePrioritizer(this.qualityManager, this.basePanoSize, this.standardPanoSize, this.highPanoSize, this.ultraHighPanoSize);
  57. viewer.addEventListener('global_click'/* "global_drop" */, (e) => {//不用"mouseup" 是因为 mouseup有drag object时也会触发
  58. if(Potree.settings.unableNavigate || this.flying || e.button != THREE.MOUSE.LEFT )return //
  59. /* if(currentlyHovered && currentlyHovered.pano){
  60. this.focusPano(currentlyHovered.pano);
  61. }else{//add */
  62. if(!Potree.settings.dblToFocusPoint || this.currentPano){//双击不会focus点云 或者 已经focusPano了
  63. this.flyToPanoClosestToMouse()
  64. }
  65. //}
  66. })
  67. viewer.addEventListener("global_mousemove", (e) => {
  68. if(!Potree.settings.unableNavigate && Potree.settings.ifShowMarker && e.hoverViewport == viewer.mainViewport){//如果不显示marker,就在点击时再更新
  69. this.updateClosestPano(e.intersectPoint)
  70. }
  71. });
  72. if(!Potree.settings.isOfficial){
  73. this.domRoot = viewer.renderer.domElement.parentElement;
  74. let elUnfocus = $("<input type='button' value='unfocus'></input>");
  75. elUnfocus.css({
  76. position : "absolute",
  77. right : '25%',
  78. bottom: '20px',
  79. zIndex: "10000",
  80. fontSize:'1em', color:"black",
  81. display:'none',
  82. background:'rgba(255,255,255,0.8)',
  83. })
  84. elUnfocus.on("click", () => this.unfocus());
  85. this.elUnfocus = elUnfocus;
  86. this.domRoot.appendChild(elUnfocus[0]);
  87. let elHide = $("<input type='button' value='隐藏点云'></input>")
  88. elHide.css({
  89. position : "absolute",
  90. right : '40%',
  91. bottom: '20px',
  92. zIndex: "10000",
  93. fontSize:'1em' ,color:"black",
  94. width : '100px',
  95. background:'rgba(255,255,255,0.8)',
  96. })
  97. this.domRoot.appendChild(elHide[0]);
  98. elHide.on("click", (e) => {
  99. let visi = viewer.getObjVisiByReason(viewer.scene.pointclouds[0], 'force')
  100. viewer.scene.pointclouds.forEach(e=>{
  101. viewer.updateVisible(e, 'force', !visi)
  102. })
  103. elHide.val(!visi ? "隐藏点云" : "显示点云")
  104. });
  105. let elDisplayModel = $("<input type='button' value='>>全景'></input>")
  106. elDisplayModel.css({
  107. position : "absolute",
  108. right : '65%',
  109. bottom: '20px',
  110. zIndex: "10000",
  111. fontSize:'1em',color:"black",
  112. width : '100px',
  113. background:'rgba(255,255,255,0.8)',
  114. })
  115. this.domRoot.appendChild(elDisplayModel[0]);
  116. elDisplayModel.on("click", (e) => {
  117. Potree.settings.displayMode = Potree.settings.displayMode == 'showPointCloud' ? 'showPanos' : 'showPointCloud'
  118. });
  119. this.elDisplayModel = elDisplayModel
  120. }
  121. {//切换模式
  122. let displayMode = '';
  123. Object.defineProperty(Potree.settings , "displayMode",{
  124. get: function() {
  125. return displayMode
  126. },
  127. set: (mode)=> {
  128. if(mode != displayMode){
  129. let config = Potree.config.displayMode[mode]
  130. let config2
  131. if(this.isAtPano() ){//this.currentPano
  132. if(this.flying)config2 = config.transition
  133. else config2 = config.atPano
  134. }else{
  135. config2 = config.atPano
  136. if(mode == 'showPanos'){//自动飞入一个pano
  137. //要改成飞进最近的。。。
  138. this.flyToPano({
  139. pano: /* this.currentPano || */Common.sortByScore(this.panos,null,[e=>-e.position.distanceTo(this.position)])[0].item,
  140. callback: ()=>{
  141. Potree.settings.displayMode = mode
  142. }
  143. })
  144. return;
  145. }else{
  146. }
  147. }
  148. if(config2.showSkybox || config2.showPoint && config2.pointUsePanoTex){
  149. this.tileDownloader.start()
  150. }else{
  151. this.tileDownloader.stop()
  152. }
  153. if(config2.showSkybox || config2.pointUsePanoTex){
  154. if(this.checkAndWaitForPanoLoad(this.currentPano, "low", "low", this.basePanoSize, ()=> {
  155. setTimeout( ()=>{
  156. Potree.settings.displayMode = mode
  157. },1)
  158. })
  159. ){
  160. return
  161. }
  162. }
  163. viewer.scene.pointclouds.forEach(e=>{
  164. viewer.updateVisible(e, 'displayMode', config2.showPoint)
  165. })
  166. this.cube.visible = config2.showSkybox
  167. if(config2.pointUsePanoTex){
  168. viewer.scene.pointclouds.forEach(e=>{
  169. e.material.setProjectedPanos(this.currentPano,this.currentPano, 1)
  170. })
  171. }else{
  172. viewer.scene.pointclouds.forEach(e=>{
  173. e.material.stopProjectedPanos()
  174. })
  175. }
  176. this.cube.visible = config.atPano.showSkybox
  177. this.cube.visible && this.cube.material.setProjectedPanos(this.currentPano, this.currentPano, 1)
  178. /* viewer.dispatchEvent({
  179. type: "enableChangePos",
  180. canLeavePano : config.canLeavePano ,
  181. viewport:
  182. }) */
  183. viewer.mainViewport.unableChangePos = !config.canLeavePano
  184. displayMode = mode
  185. if(this.elDisplayModel){
  186. this.elDisplayModel.value = mode == 'showPointCloud' ? ">>全景" : '>>点云'
  187. }
  188. }
  189. }
  190. })
  191. Potree.settings.displayMode = 'showPointCloud'
  192. }// 切换模式 end
  193. {//
  194. let currentPano = null;
  195. Object.defineProperty(this , "currentPano",{
  196. get: function() {
  197. return currentPano
  198. },
  199. set: function(e) {
  200. if(e != currentPano){
  201. currentPano && currentPano.exit()
  202. e && e.enter()
  203. currentPano = e
  204. }
  205. }
  206. })
  207. }
  208. {//是否显示marker
  209. let ifShowMarker = true;
  210. Object.defineProperty(Potree.settings, "ifShowMarker",{
  211. get: function() {
  212. return ifShowMarker
  213. },
  214. set: (show)=>{
  215. show = !!show
  216. if(show != ifShowMarker){
  217. this.panos.forEach(pano=>{
  218. viewer.updateVisible(pano, 'ifShowMarker', show)
  219. })
  220. //this.emit('markersDisplayChange', show)
  221. ifShowMarker = show
  222. }
  223. }
  224. })
  225. }
  226. viewer.addEventListener("update", () => {
  227. this.update(viewer);
  228. });
  229. //viewer.inputHandler.addInputListener(this);
  230. var keys = {
  231. FORWARD: ['W'.charCodeAt(0), 38],
  232. BACKWARD: ['S'.charCodeAt(0), 40],
  233. LEFT: ['A'.charCodeAt(0), 37],
  234. RIGHT: ['D'.charCodeAt(0), 39],
  235. }
  236. viewer.inputHandler.addEventListener('keydown',(e)=>{
  237. if(Potree.settings.displayMode == 'showPanos'){
  238. for(let i in keys){
  239. if(keys[i].some(a => a == e.keyCode)){
  240. switch(i){
  241. case 'FORWARD':
  242. this.flyLocalDirection(Vectors.FORWARD.clone());
  243. break;
  244. case 'BACKWARD':
  245. this.flyLocalDirection(Vectors.BACK.clone());
  246. break;
  247. case 'LEFT':
  248. this.flyLocalDirection(Vectors.LEFT.clone());
  249. break;
  250. case 'RIGHT':
  251. this.flyLocalDirection(Vectors.RIGHT.clone());
  252. break;
  253. }
  254. break;
  255. }
  256. }
  257. }
  258. })
  259. };
  260. flyLocalDirection(dir) {
  261. var direction = this.getDirection(dir),
  262. option1 = 1 === dir.y ? .4 : .75,
  263. option2 = 1 === Math.abs(dir.x);
  264. return this.flyDirection(direction, option1, option2)
  265. }
  266. getDirection(e) {
  267. if(!e){
  268. return viewer.scene.view.direction
  269. }else{
  270. return e = e ? e : (new THREE.Vector3).copy(Vectors.FORWARD),
  271. e.applyQuaternion(viewer.scene.getActiveCamera().quaternion)
  272. }
  273. }
  274. get position(){
  275. return this.viewer.scene.view.position.clone()
  276. }
  277. get visible(){
  278. return this._visible;
  279. }
  280. set visible(visible){
  281. if(this._visible === visible){
  282. return;
  283. }
  284. for(const image of this.panos){
  285. image.mesh.visible = visible && (this.currentPano == null);
  286. }
  287. //this.sphere.visible = visible && (this.currentPano != null);
  288. this._visible = visible;
  289. this.dispatchEvent({
  290. type: "visibility_changed",
  291. panos: this,
  292. });
  293. }
  294. isAtPano(){//
  295. return this.currentPano && viewer.scene.view.position.equals(this.currentPano.position)
  296. }
  297. flyToPano(toPano) {
  298. if(toPano instanceof Panorama){
  299. toPano = {pano: toPano}
  300. }
  301. if(!this.currentPano){
  302. return this.focusPano(toPano)
  303. }
  304. let done = (makeIt)=>{
  305. toPano.deferred && toPano.deferred.resolve(makeIt)
  306. makeIt && toPano.callback && toPano.callback()
  307. }
  308. if(this.currentPano == pano && this.isAtPano() && !toPano.target ){
  309. return done(true);
  310. }
  311. if(this.flying){
  312. return done(false)
  313. }
  314. let target = toPano.target
  315. let easeName = toPano.easeName || 'easeInOutQuad'
  316. let config = Potree.config.displayMode[Potree.settings.displayMode]
  317. var pointcloudVisi = config.atPano.showPoint //viewer.scene.pointclouds[0].visible
  318. var pano = toPano.pano
  319. var duration = toPano.duration || 300+Math.min(Potree.config.transitionsTime.flySpeed * this.position.distanceTo(pano.position), Potree.config.transitionsTime.panoToPano )
  320. //console.log("flyto "+pano.id + ' duration: ' + duration )
  321. this.nextPano = pano
  322. //不飞的话是否不要执行这段?
  323. if(config.atPano.showSkybox || config.atPano.pointUsePanoTex){
  324. if(this.checkAndWaitForPanoLoad(pano, "high", "low", this.basePanoSize, ()=> {
  325. setTimeout( ()=>{
  326. this.flyToPano(toPano)
  327. },1)
  328. })
  329. ){
  330. return
  331. }
  332. }
  333. //this.load(pano).then( () => {
  334. this.cube.visible = config.atPano.showSkybox
  335. this.cube.visible && this.cube.material.setProjectedPanos(this.currentPano, pano, 0)
  336. viewer.scene.pointclouds.forEach(e=>{
  337. viewer.updateVisible(e, 'displayMode',config.transition.showPoint)
  338. })
  339. if(config.transition.pointUsePanoTex){
  340. let easeInOutRatio = pointcloudVisi ? 0.3 : 0
  341. viewer.scene.pointclouds.forEach(e=>{
  342. e.material.setProjectedPanos(this.currentPano, pano, 0, easeInOutRatio)
  343. })
  344. }
  345. const endPosition = pano.position.clone()
  346. this.flying = true
  347. viewer.scene.view.setView(endPosition, target ,duration, ()=>{//done
  348. if(!config.atPano.pointUsePanoTex){
  349. viewer.scene.pointclouds.forEach(e=>{
  350. e.material.stopProjectedPanos()
  351. })
  352. }
  353. //this.currentPano.exit()
  354. //pano.enter()
  355. this.currentPano = pano;
  356. this.flying = false
  357. this.nextPano = null;
  358. viewer.scene.pointclouds.forEach(e=>{
  359. viewer.updateVisible(e, 'displayMode',pointcloudVisi)
  360. })
  361. done(true);
  362. },(progress)=>{//onUpdate
  363. this.cube.material.uniforms.progress.value = progress
  364. viewer.scene.pointclouds.forEach(e=>{
  365. e.material.uniforms.progress.value = progress
  366. })
  367. }, easeName )
  368. {
  369. toPano.duration = duration
  370. toPano.easeName = easeName
  371. this.emit('flyToPano', toPano)
  372. }
  373. //})
  374. }
  375. focusPano(toPano ){
  376. if(this.currentPano !== null){
  377. return this.flyToPano(toPano);
  378. }
  379. if(toPano instanceof Panorama){
  380. toPano = {pano: toPano}
  381. }
  382. let done = (makeIt)=>{
  383. toPano.deferred && toPano.deferred.resolve(makeIt)
  384. makeIt && toPano.callback && toPano.callback()
  385. }
  386. var pano = toPano.pano
  387. let config = Potree.config.displayMode[Potree.settings.displayMode]
  388. previousView = {
  389. //controls: this.viewer.controls,
  390. position: this.position,
  391. target: viewer.scene.view.getPivot(),
  392. };
  393. //this.viewer.setControls(this.viewer.orbitControls);
  394. this.viewer.orbitControls.doubleClockZoomEnabled = false;
  395. for(let image of this.panos){
  396. image.mesh.visible = false;
  397. }
  398. this.selectingEnabled = false;
  399. //console.log("flyto "+pano.file.split('/').pop() )
  400. var dur = toPano.duration == void 0 ? 700 : toPano.duration
  401. if(config.atPano.showSkybox){
  402. if ( this.checkAndWaitForPanoLoad(pano, "low", "low", this.basePanoSize, ()=> {
  403. setTimeout( ()=>{
  404. this.focusPano(toPano)
  405. },1)
  406. })
  407. ) {
  408. return ;
  409. }
  410. }
  411. //this.load(pano).then( () => {
  412. //this.panos.forEach(e=>e.marker.material.depthTest = false)
  413. this.cube.visible = config.atPano.showSkybox
  414. this.cube.visible && this.cube.material.setProjectedPanos(pano, pano, 0)
  415. if(config.atPano.pointUsePanoTex){//false
  416. viewer.scene.pointclouds.forEach(e=>{
  417. e.material.setProjectedPanos(pano, pano, 0)
  418. })
  419. }
  420. //});
  421. let newCamPos = pano.position.clone()
  422. let target = newCamPos.clone().add(viewer.scene.view.direction)
  423. this.flying = true
  424. viewer.scene.view.setView( newCamPos, target, dur , ()=>{//done
  425. //pano.enter()
  426. this.flying = false
  427. /* viewer.scene.pointclouds.forEach(e=>{
  428. e.visible = pointcloudVisi
  429. }) */
  430. this.currentPano = pano;
  431. done(true)
  432. },(progress)=>{//onUpdate
  433. /* this.cube.material.uniforms.progress.value = progress
  434. viewer.scene.pointclouds.forEach(e=>{
  435. e.material.uniforms.progress.value = progress
  436. }) */
  437. } )
  438. this.elUnfocus && (this.elUnfocus[0].style.display = "");
  439. }
  440. unfocus(o={}){
  441. this.selectingEnabled = true;
  442. Potree.settings.displayMode = 'showPointCloud'
  443. if(!this.currentPano && !o.position){
  444. return;
  445. }
  446. this.cube.visible = false
  447. viewer.orbitControls.doubleClockZoomEnabled = true;
  448. viewer.scene.view.setView(
  449. o.position || previousView.position,
  450. o.target || previousView.target,
  451. o.duration || 500,
  452. ()=>{ //done
  453. for(let pano of this.panos){
  454. pano.mesh.visible = true;
  455. //pano.marker.material.depthTest = true
  456. }
  457. o.callback && o.callback()
  458. }
  459. );
  460. //this.currentPano.exit()
  461. this.currentPano = null;
  462. this.elUnfocus && (this.elUnfocus[0].style.display = "none");
  463. }
  464. /* bump(direction) {//撞墙弹回效果
  465. if (!this.flying) {
  466. var t, i, n, r = settings.transition,
  467. o = (r.flytimeMaxDistanceThreshold * r.flytimeDistanceMultiplier + r.flyTime) / 10,
  468. a = this.camera.getWorldDirection().dot(direction),
  469. s = Math.abs(a) > .5;
  470. if (s)
  471. t = function() {
  472. transitions.start(lerp.property(this.cameraControls.cameras[ViewMode.PANORAMA], "zoom", a > 0 ? 1.04 : .96), o, i, 0, easing.easeInOutSine, "bumpZStart")
  473. }
  474. .bind(this),
  475. i = function() {
  476. transitions.start(lerp.property(this.cameraControls.cameras[ViewMode.PANORAMA], "zoom", 1), 3 * o, n, 0, easing.easeInOutSine, "bumpZRelax")
  477. }
  478. .bind(this);
  479. else {
  480. var l = this.camera.position.clone(),
  481. c = direction.clone();
  482. this.raycaster.set(l, c);
  483. var h = this.model.floors.reduce(function(e, t) {
  484. return e.concat(t.collider.children)
  485. }, []),
  486. d = this.raycaster.intersectObjects(h),
  487. p = d.length > 0 ? d[0].distance / 25 : .04,
  488. g = l.clone().add(c.multiplyScalar(p));
  489. t = function() {
  490. transitions.start(lerp.vector(this.cameraControls.cameras[ViewMode.PANORAMA].position, g), o, i, 0, easing.easeInOutSine, "bumpTStart")
  491. }
  492. .bind(this),
  493. i = function() {
  494. transitions.start(lerp.vector(this.cameraControls.cameras[ViewMode.PANORAMA].position, l), 5 * o, n, 0, easing.easeInOutSine, "bumpTRelax")
  495. }
  496. .bind(this)
  497. }
  498. n = (){
  499. this.mode == "panorama" && (this.flying = !1) //改
  500. }
  501. this.flying = !0,
  502. t()
  503. }
  504. };
  505. */
  506. /* load(pano, ){
  507. return new Promise(resolve => {
  508. let texture = texLoader.load(pano.file, resolve);
  509. texture.wrapS = THREE.RepeatWrapping;
  510. texture.repeat.x = -1;
  511. texture.flipY = false//add
  512. pano.texture = texture;
  513. //add
  514. texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
  515. texture.minFilter = THREE.LinearFilter;
  516. texture.magFilter = THREE.LinearFilter;
  517. texture.generateMipmaps = true;
  518. });
  519. } */
  520. flyToPanoClosestToMouse() {
  521. /* if (Date.now() - this.mouseLastMoveTime > 50) {
  522. //this.intersect = this.getMouseIntersect();
  523. this.intersect && this.updateClosestPano(this.intersect);
  524. } */
  525. if(!Potree.settings.ifShowMarker){//不显示marker的时候mousemove没更新鼠标最近点所以更新
  526. this.updateClosestPano(viewer.inputHandler.intersectPoint)
  527. }
  528. if (this.closestPano) {
  529. return this.flyToPano({
  530. pano: this.closestPano
  531. });
  532. }
  533. var direction = this.viewer.inputHandler.getMouseDirection().direction;
  534. this.flyDirection(direction)
  535. }
  536. flyDirection(direction, option1, option2) {
  537. var deferred = $.Deferred();
  538. //this.history.invalidate();
  539. var panoSet = this.closestPanoInDirection(direction, option1, option2);
  540. if (panoSet) {
  541. this.flyToPano({
  542. pano: panoSet,
  543. callback: deferred.resolve.bind(deferred, !0)
  544. } );
  545. } else {
  546. //this.bump(direction);
  547. deferred.resolve(!1);
  548. }
  549. return deferred.promise();
  550. }
  551. closestPanoInDirection(direction, option1, option2) {
  552. return this.rankedPanoInDirection(0, direction, option1, option2)
  553. }
  554. rankedPanoInDirection(t, direction, option1, option2){
  555. var panoSet = {
  556. pano: null,
  557. candidates: [] //缓存顺序--如果需要打印的话
  558. };
  559. t || (t = 0);
  560. option1 = void 0 !== option1 ? option1 : .75;
  561. var o = option2 ? "angle" : "direction";
  562. var request = [//必要条件
  563. Images360.filters.inPanoDirection( this.position, direction, option1),
  564. //Images360.filters.isNeighbourPanoTo(this.currentPano),
  565. Images360.filters.not(this.currentPano)
  566. ]
  567. var list = [//决胜项目
  568. Images360.scoreFunctions.distanceSquared(this.currentPano),
  569. Images360.scoreFunctions[o]( this.position, direction)
  570. ];
  571. this.findRankedByScore(t,request,list,panoSet);
  572. return panoSet.pano;
  573. }
  574. updateClosestPano(intersect) {//距离reticule最近的点 可以是null
  575. intersect = intersect && intersect.location
  576. if(!intersect)return
  577. //intersect = intersect && (intersect.location || intersect)
  578. var filterFuncs = [];
  579. //if (this.mode === ViewMode.PANORAMA) {
  580. /* if (!Potree.settings.isOfficial && !this.currentPano) {
  581. return;
  582. } */
  583. if(this.isAtPano() ){
  584. filterFuncs.push(Images360.filters.not(this.currentPano));
  585. filterFuncs.push(Images360.filters.inFloorDirection(this.position, viewer.scene.view.direction, .25)),//许钟文改
  586. //filterFuncs.push(Images360.filters.isNeighbourPanoTo(this.currentPano));
  587. filterFuncs.push(Images360.filters.isCloseEnoughTo(intersect, 0.35));
  588. /* } else {
  589. if(!this.linkEditor.noPanoHasNeighbor){//xzw add 如果不是全孤立点的话,就要避开孤立点
  590. filterFuncs.push((pano)=>{return this.linkEditor.checkHasNeighbor(pano)})
  591. }
  592. objects.record.control.isRecording || filterFuncs.push(Panorama.filters.isOnVisibleFloor());
  593. this.mode !== ViewMode.FLOORPLAN && filterFuncs.push(Panorama.filters.inDirection(this.position, this.getDirection(), .25));
  594. } */
  595. }
  596. var pano = Common.find(this.panos, filterFuncs, [Images360.sortFunctions.floorDistanceToPoint(intersect)]);
  597. if (pano != this.closestPano) {
  598. pano && (this.isPanoHover = !0);
  599. //触发事件,导致地面的marker变清晰
  600. //this.emit(PlayerEvents.ClosestPanoChanging, this.closestPano, pano, this.mode);
  601. this.closestPanoChanging(this.closestPano, pano)
  602. this.closestPano = pano;
  603. } else {
  604. this.isPanoHover = !1;
  605. }
  606. }
  607. closestPanoChanging(oldPano, newPano){
  608. if(!Potree.settings.ifShowMarker)return
  609. oldPano && oldPano.hoverOff()
  610. newPano && newPano.hoverOn()
  611. }
  612. /* handleHovering(){
  613. let pointer = viewer.inputHandler.pointer;
  614. let camera = viewer.scene.getActiveCamera();
  615. let domElement = viewer.renderer.domElement;
  616. let ray = Potree.Utils.mouseToRay(pointer, camera, domElement.clientWidth, domElement.clientHeight);
  617. // let tStart = performance.now();
  618. raycaster.ray.copy(ray);
  619. let intersections = raycaster.intersectObjects(this.node.children);
  620. if(intersections.length === 0){
  621. // label.visible = false;
  622. return;
  623. }
  624. let intersection = intersections[0];
  625. currentlyHovered = intersection.object;
  626. currentlyHovered.material = smHovered;
  627. //label.visible = true;
  628. //label.setText(currentlyHovered.pano.file);
  629. //currentlyHovered.getWorldPosition(label.position);
  630. }
  631. */
  632. update(){
  633. let {viewer} = this;
  634. /* if(currentlyHovered){
  635. currentlyHovered.material = sm;
  636. currentlyHovered = null;
  637. }
  638. if(this.selectingEnabled){
  639. this.handleHovering();
  640. } */
  641. if(this.tileDownloader.started){
  642. var vectorForward = viewer.scene.view.direction.clone()
  643. vectorForward = math.convertVector.ZupToYup(vectorForward)
  644. this.updateTileDownloader(tileArr,vectorForward);
  645. this.updatePanoRenderer(vectorForward)
  646. }
  647. }
  648. findRankedByScore(e, t, i, n) {
  649. n && (n.candidates = null, //candidates 缓存顺序--如果需要打印的话
  650. n.pano = null),
  651. e || (e = 0);
  652. var r = Common.sortByScore(this.panos, t, i);
  653. return !r || 0 === r.length || e >= r.length ? null : (n && (n.candidates = r,
  654. n.pano = r[e].item),
  655. r[e].item)
  656. }
  657. updateTileDownloader(t, vectorForward) {
  658. var i = this.nextPano || this.currentPano;
  659. if(i){
  660. this.tileDownloader.tilePrioritizer.updateCriteria(i, viewer.scene.view.position.clone() , vectorForward, t.length > 0 ? t : null),
  661. this.tileDownloader.processPriorityQueue = !0
  662. }
  663. }
  664. updatePanoRenderer(vectorForward) {
  665. var i = this.nextPano || this.currentPano;
  666. if(i){
  667. if (this.panoRenderer.hasQueuedTiles() && i) {
  668. this.panoRenderer.updateDirection(vectorForward);
  669. }
  670. }
  671. }
  672. checkAndWaitForTiledPanoLoad(pano, basePanoSize, callback1, callback2, progressCallback, iswait, isclear, l) {
  673. if (!pano) {
  674. console.error("Player.checkAndWaitForTiledPanoLoad() -> Cannot load texture for null pano.");
  675. }
  676. var vectorForward = viewer.scene.view.direction.clone()
  677. vectorForward = math.convertVector.ZupToYup(vectorForward)
  678. if (!pano.isLoaded(basePanoSize)) {
  679. iswait && viewer.waitForLoad(pano, function() {//发送loading
  680. return pano.isLoaded(basePanoSize)
  681. });
  682. var fov = {//test for direction 预加载的边缘有一丢丢不准确,尤其在相机倾斜时(4dkk也是)。
  683. hFov: cameraLight.getHFOVForCamera(viewer.scene.getActiveCamera(), viewer.renderArea.clientWidth, viewer.renderArea.clientHeight),
  684. vFov: viewer.scene.getActiveCamera().fov
  685. }//原先是null,不要求方向
  686. pano.loadTiledPano(/* 1024 */ basePanoSize , vectorForward, fov, isclear, l, null).done(function(e, t) {
  687. callback1 && callback1(e, t)
  688. }
  689. .bind(this)).fail(function(msg) {
  690. callback2 && callback2(msg)
  691. }
  692. .bind(this)).progress(function(e, t, i) {
  693. progressCallback && progressCallback(e, t, i)
  694. }
  695. .bind(this));
  696. return !0;
  697. }
  698. }
  699. fitPanoTowardPoint(o){ //寻找最适合的点位
  700. var point = o.point,
  701. require = o.require || [],
  702. rank = o.rank || [],
  703. force = o.force,
  704. getAll = o.getAll,
  705. bestDistance = o.bestDistance || 0
  706. let camera = viewer.scene.getActiveCamera()
  707. //if(o.floor)require.push(Panorama.filters.atFloor(o.floor))
  708. if(o.boundSphere){//只接受boundSphere
  709. let aspect = 1//size.x / size.y
  710. let dis
  711. if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定
  712. dis = /* size.y */o.boundSphere.radius/* / 2 *// THREE.Math.degToRad(camera.fov / 2)
  713. }else{
  714. let hfov = cameraLight.getHFOVForCamera(camera, camera.aspect, 1 );
  715. dis = /* size.x */ o.boundSphere.radius /* / 2 */ / THREE.Math.degToRad(hfov / 2)
  716. }
  717. bestDistance = dis*0.8
  718. }
  719. let bestDisSquared = bestDistance * bestDistance
  720. rank.push((pano)=>{
  721. return -Math.abs(pano.position.distanceToSquared(point) - bestDisSquared)
  722. })
  723. /* var temp = {position:point}
  724. rank.push(Panorama.scoreFunctions.distanceSquared(temp, -2)); */
  725. var g = Common.sortByScore(this.panos, require, rank);
  726. if(getAll)return g;
  727. return g && g.length > 0 && g[0].item
  728. }
  729. };
  730. //判断当前点是否加载了全景图
  731. Images360.prototype.checkAndWaitForPanoLoad = function() {
  732. var isLoadedPanos = {},
  733. LoadedTimePanos = {},
  734. maxTime = 5e3;
  735. var overtime = function() {
  736. for (var panoId in isLoadedPanos)
  737. if (isLoadedPanos.hasOwnProperty(panoId) && isLoadedPanos[panoId]) {
  738. var differTime = performance.now() - LoadedTimePanos[panoId];
  739. if (differTime < maxTime)
  740. return !0
  741. }
  742. return !1
  743. }
  744. return function(pano, imgQuality1, imgQuality2, basePanoSize, doneFun1, doneFun2, progressCallback, iswait, isclear, p ) {
  745. if (overtime())
  746. return !0;
  747. var callback1 = (param1, param2)=>{
  748. setTimeout(()=>{
  749. isLoadedPanos[pano.id] = !1;
  750. doneFun1 && doneFun1(param1, param2);
  751. },1)
  752. }
  753. var callback2 = (param)=>{//没有看到有传doneFun2的
  754. setTimeout(()=>{
  755. isLoadedPanos[pano.id] = !1;
  756. doneFun2 && doneFun2(param);
  757. },1)
  758. }
  759. try {
  760. null !== iswait && void 0 !== iswait || (iswait = !0);
  761. isLoadedPanos[pano.id] = this.checkAndWaitForTiledPanoLoad(pano, basePanoSize, callback1, callback2, progressCallback, iswait, isclear, p );
  762. isLoadedPanos[pano.id] && (LoadedTimePanos[pano.id] = performance.now());
  763. return isLoadedPanos[pano.id];
  764. } catch (msg) {
  765. isLoadedPanos[pano.id] = !1;
  766. LoadedTimePanos[pano.id] = performance.now() - maxTime;
  767. throw msg;
  768. }
  769. }
  770. }()
  771. Images360.filters = {
  772. inPanoDirection : function(e, t, i) {
  773. return function(n) {
  774. var r = n.floorPosition.clone().sub(e).setZ(0).normalize() //忽略上下角度,这样即使看得很低也能走
  775. , o = n.position.clone().sub(e).normalize();
  776. return r.dot(t.clone().setZ(0).normalize()) > i || o.dot(t) > i
  777. }
  778. },
  779. inFloorDirection: function(pos, e, o) {//许钟文 改 for鱼眼
  780. return function(n) {
  781. var i = n.floorPosition.clone().sub(pos).setZ(0).normalize();//改成在xz方向上,否则点击墙面不会移动
  782. return i.dot(e) > o
  783. }
  784. },
  785. isNotBehindNormal: function(e, t) {
  786. var i = new THREE.Vector3;
  787. return t = t.clone(),
  788. function(n) {
  789. var r = i.copy(n.position).sub(e).normalize();
  790. return r.dot(t) > 0
  791. }
  792. },
  793. isCloseEnoughTo: function(e, t) {
  794. return function(i) {//因为marker可能比地面高,所以识别范围要比marker看起来更近一些。(因为投影到地板的位置比marker更近)
  795. return e.distanceTo(i.floorPosition) < t //许钟文
  796. }
  797. },
  798. not: function(e) {
  799. return function(t) {
  800. return t !== e
  801. }
  802. }
  803. }
  804. Images360.scoreFunctions = {
  805. direction: function(e, t) {
  806. return function(i) {
  807. var pos = i.position.clone()
  808. var n = pos.clone().sub(e).normalize();
  809. return n.dot(t) * 10
  810. }
  811. },
  812. distanceSquared: function(e) {
  813. var pos1 = e.position.clone()
  814. return function(i) {//许钟文 改
  815. var pos2 = i.position.clone()
  816. return pos1.distanceToSquared(pos2) * -1
  817. }
  818. },
  819. angle: function(e, t) {
  820. return function(i) {
  821. var n = i.position.clone().sub(e).normalize();
  822. return n.angleTo(t) * Potree.config.navigation.angleFactor
  823. }
  824. },
  825. }
  826. Images360.sortFunctions = {//排序函数,涉及到两个item相减
  827. floorDistanceToPoint: function(e) {
  828. return function(t, i) {
  829. return t.floorPosition.distanceTo(e) - i.floorPosition.distanceTo(e)
  830. }
  831. },
  832. }
  833. export class Images360Loader{
  834. static async load(viewer, params, callback ){
  835. let center = viewer.transform.lonlatToLocal.inverse(viewer.bound.center)
  836. center = {lat:center.y, lon:center.x} //中心点
  837. Potree.loadPanos(center,(data)=>{
  838. let images360 = new Images360(viewer, params);
  839. data = data.sort(function(a,b){return a.id-b.id})
  840. data.forEach((info,i)=>{
  841. if(Potree.fileServer){
  842. info.id = i //info的id是一长串数字,改简单点
  843. }
  844. let pano = new Panorama( info, params.transform, images360 );
  845. /* pano.mesh.layers.set(Potree.config.renderLayers.marker)
  846. pano.marker.layers.set(Potree.config.renderLayers.marker) */
  847. images360.panos.push(pano);
  848. })
  849. viewer.setObjectLayers(images360.node, 'marker')
  850. viewer.images360 = window.images360 = images360//add
  851. images360.tileDownloader.setPanoData(images360.panos, [] /* , Potree.settings.number */);
  852. {
  853. var panosBound = new THREE.Box3
  854. images360.panos.forEach(pano=>{
  855. panosBound.expandByPoint(pano.position)
  856. })
  857. images360.bound = {
  858. bounding:panosBound,
  859. size: panosBound.getSize(new THREE.Vector3),
  860. center: panosBound.getCenter(new THREE.Vector3)
  861. }
  862. }
  863. callback && callback(images360)
  864. })
  865. }
  866. };