import * as THREE from "../../../libs/three.js/build/three.module.js"; import { EventDispatcher } from "../../EventDispatcher.js"; import {TextSprite} from "../../TextSprite.js"; import ModelTextureMaterial from "./ModelTextureMaterial.js"; import Common from "../../utils/Common.js"; import math from "../../utils/math.js"; import cameraLight from "../../utils/cameraLight.js"; import Panorama from "./Panorama.js"; import QualityManager from './tile/QualityManager' import TileDownloader from './tile/TileDownloader' import PanoRenderer from './tile/PanoRenderer' import TilePrioritizer from './tile/TilePrioritizer' import { PanoSizeClass,Vectors} from '../../defines' //import Axis from '../../viewer/Axis' let raycaster = new THREE.Raycaster(); //let currentlyHovered = null; var texLoader = new THREE.TextureLoader() let cm = new ModelTextureMaterial() let previousView = { controls: null, position: null, target: null, }; let sm = new THREE.MeshBasicMaterial({side: THREE.BackSide}); var tileArr = [] /* let sgHigh = new THREE.SphereGeometry(1, 128, 128); */ export class Images360 extends EventDispatcher{ constructor(viewer, params){ super(); this.viewer = viewer; this.selectingEnabled = true; this.panos = []; this.node = new THREE.Object3D(); this.node.name = 'ImagesNode' //this.node2 = new THREE.Object3D(); //add: let size = params.boundSize this.cube = new THREE.Mesh(new THREE.BoxBufferGeometry( size.x, size.y, size.z ), cm); this.cube.position.copy(params.center) this.cube.visible = false; this.cube.layers.set(Potree.config.renderLayers.skybox) this.cube.name = 'skybox' viewer.scene.scene.add(this.cube) this._visible = true; this.currentPano = null; this.mouseLastMoveTime = Date.now() this.tileDownloader = new TileDownloader; this.qualityManager = new QualityManager this.panoRenderer = new PanoRenderer(viewer, this.tileDownloader, this.qualityManager) this.basePanoSize = this.qualityManager.getPanoSize(PanoSizeClass.BASE); this.standardPanoSize = this.qualityManager.getPanoSize(PanoSizeClass.STANDARD); this.highPanoSize = this.qualityManager.getPanoSize(PanoSizeClass.HIGH); this.ultraHighPanoSize = this.qualityManager.getPanoSize(PanoSizeClass.ULTRAHIGH); this.tileDownloader.processPriorityQueue = !1; this.tileDownloader.tilePrioritizer = new TilePrioritizer(this.qualityManager, this.basePanoSize, this.standardPanoSize, this.highPanoSize, this.ultraHighPanoSize); viewer.addEventListener('global_click'/* "global_drop" */, (e) => {//不用"mouseup" 是因为 mouseup有drag object时也会触发 if(Potree.settings.unableNavigate || this.flying || e.button != THREE.MOUSE.LEFT )return // /* if(currentlyHovered && currentlyHovered.pano){ this.focusPano(currentlyHovered.pano); }else{//add */ if(!Potree.settings.dblToFocusPoint || this.currentPano){//双击不会focus点云 或者 已经focusPano了 this.flyToPanoClosestToMouse() } //} }) viewer.addEventListener("global_mousemove", (e) => { if(!Potree.settings.unableNavigate && Potree.settings.ifShowMarker && e.hoverViewport == viewer.mainViewport){//如果不显示marker,就在点击时再更新 this.updateClosestPano(e.intersectPoint) } }); if(!Potree.settings.isOfficial){ this.domRoot = viewer.renderer.domElement.parentElement; let elUnfocus = $(""); elUnfocus.css({ position : "absolute", right : '25%', bottom: '20px', zIndex: "10000", fontSize:'1em', color:"black", display:'none', background:'rgba(255,255,255,0.8)', }) elUnfocus.on("click", () => this.unfocus()); this.elUnfocus = elUnfocus; this.domRoot.appendChild(elUnfocus[0]); let elHide = $("") elHide.css({ position : "absolute", right : '40%', bottom: '20px', zIndex: "10000", fontSize:'1em' ,color:"black", width : '100px', background:'rgba(255,255,255,0.8)', }) this.domRoot.appendChild(elHide[0]); elHide.on("click", (e) => { let visi = viewer.getObjVisiByReason(viewer.scene.pointclouds[0], 'force') viewer.scene.pointclouds.forEach(e=>{ viewer.updateVisible(e, 'force', !visi) }) elHide.val(!visi ? "隐藏点云" : "显示点云") }); let elDisplayModel = $("") elDisplayModel.css({ position : "absolute", right : '65%', bottom: '20px', zIndex: "10000", fontSize:'1em',color:"black", width : '100px', background:'rgba(255,255,255,0.8)', }) this.domRoot.appendChild(elDisplayModel[0]); elDisplayModel.on("click", (e) => { Potree.settings.displayMode = Potree.settings.displayMode == 'showPointCloud' ? 'showPanos' : 'showPointCloud' }); this.elDisplayModel = elDisplayModel } {//切换模式 let displayMode = ''; Object.defineProperty(Potree.settings , "displayMode",{ get: function() { return displayMode }, set: (mode)=> { if(mode != displayMode){ let config = Potree.config.displayMode[mode] let config2 if(this.isAtPano() ){//this.currentPano if(this.flying)config2 = config.transition else config2 = config.atPano }else{ config2 = config.atPano if(mode == 'showPanos'){//自动飞入一个pano //要改成飞进最近的。。。 this.flyToPano({ pano: /* this.currentPano || */Common.sortByScore(this.panos,null,[e=>-e.position.distanceTo(this.position)])[0].item, callback: ()=>{ Potree.settings.displayMode = mode } }) return; }else{ } } if(config2.showSkybox || config2.showPoint && config2.pointUsePanoTex){ this.tileDownloader.start() }else{ this.tileDownloader.stop() } if(config2.showSkybox || config2.pointUsePanoTex){ if(this.checkAndWaitForPanoLoad(this.currentPano, "low", "low", this.basePanoSize, ()=> { setTimeout( ()=>{ Potree.settings.displayMode = mode },1) }) ){ return } } viewer.scene.pointclouds.forEach(e=>{ viewer.updateVisible(e, 'displayMode', config2.showPoint) }) this.cube.visible = config2.showSkybox if(config2.pointUsePanoTex){ viewer.scene.pointclouds.forEach(e=>{ e.material.setProjectedPanos(this.currentPano,this.currentPano, 1) }) }else{ viewer.scene.pointclouds.forEach(e=>{ e.material.stopProjectedPanos() }) } this.cube.visible = config.atPano.showSkybox this.cube.visible && this.cube.material.setProjectedPanos(this.currentPano, this.currentPano, 1) /* viewer.dispatchEvent({ type: "enableChangePos", canLeavePano : config.canLeavePano , viewport: }) */ viewer.mainViewport.unableChangePos = !config.canLeavePano displayMode = mode if(this.elDisplayModel){ this.elDisplayModel.value = mode == 'showPointCloud' ? ">>全景" : '>>点云' } } } }) Potree.settings.displayMode = 'showPointCloud' }// 切换模式 end {// let currentPano = null; Object.defineProperty(this , "currentPano",{ get: function() { return currentPano }, set: function(e) { if(e != currentPano){ currentPano && currentPano.exit() e && e.enter() currentPano = e } } }) } {//是否显示marker let ifShowMarker = true; Object.defineProperty(Potree.settings, "ifShowMarker",{ get: function() { return ifShowMarker }, set: (show)=>{ show = !!show if(show != ifShowMarker){ this.panos.forEach(pano=>{ viewer.updateVisible(pano, 'ifShowMarker', show) }) //this.emit('markersDisplayChange', show) ifShowMarker = show } } }) } viewer.addEventListener("update", () => { this.update(viewer); }); //viewer.inputHandler.addInputListener(this); var keys = { FORWARD: ['W'.charCodeAt(0), 38], BACKWARD: ['S'.charCodeAt(0), 40], LEFT: ['A'.charCodeAt(0), 37], RIGHT: ['D'.charCodeAt(0), 39], } viewer.inputHandler.addEventListener('keydown',(e)=>{ if(Potree.settings.displayMode == 'showPanos'){ for(let i in keys){ if(keys[i].some(a => a == e.keyCode)){ switch(i){ case 'FORWARD': this.flyLocalDirection(Vectors.FORWARD.clone()); break; case 'BACKWARD': this.flyLocalDirection(Vectors.BACK.clone()); break; case 'LEFT': this.flyLocalDirection(Vectors.LEFT.clone()); break; case 'RIGHT': this.flyLocalDirection(Vectors.RIGHT.clone()); break; } break; } } } }) }; flyLocalDirection(dir) { var direction = this.getDirection(dir), option1 = 1 === dir.y ? .4 : .75, option2 = 1 === Math.abs(dir.x); return this.flyDirection(direction, option1, option2) } getDirection(e) { if(!e){ return viewer.scene.view.direction }else{ return e = e ? e : (new THREE.Vector3).copy(Vectors.FORWARD), e.applyQuaternion(viewer.scene.getActiveCamera().quaternion) } } get position(){ return this.viewer.scene.view.position.clone() } get visible(){ return this._visible; } set visible(visible){ if(this._visible === visible){ return; } for(const image of this.panos){ image.mesh.visible = visible && (this.currentPano == null); } //this.sphere.visible = visible && (this.currentPano != null); this._visible = visible; this.dispatchEvent({ type: "visibility_changed", panos: this, }); } isAtPano(){// return this.currentPano && viewer.scene.view.position.equals(this.currentPano.position) } flyToPano(toPano) { if(toPano instanceof Panorama){ toPano = {pano: toPano} } if(!this.currentPano){ return this.focusPano(toPano) } let done = (makeIt)=>{ toPano.deferred && toPano.deferred.resolve(makeIt) makeIt && toPano.callback && toPano.callback() } if(this.currentPano == pano && this.isAtPano() && !toPano.target ){ return done(true); } if(this.flying){ return done(false) } let target = toPano.target let easeName = toPano.easeName || 'easeInOutQuad' let config = Potree.config.displayMode[Potree.settings.displayMode] var pointcloudVisi = config.atPano.showPoint //viewer.scene.pointclouds[0].visible var pano = toPano.pano var duration = toPano.duration || 300+Math.min(Potree.config.transitionsTime.flySpeed * this.position.distanceTo(pano.position), Potree.config.transitionsTime.panoToPano ) //console.log("flyto "+pano.id + ' duration: ' + duration ) this.nextPano = pano //不飞的话是否不要执行这段? if(config.atPano.showSkybox || config.atPano.pointUsePanoTex){ if(this.checkAndWaitForPanoLoad(pano, "high", "low", this.basePanoSize, ()=> { setTimeout( ()=>{ this.flyToPano(toPano) },1) }) ){ return } } //this.load(pano).then( () => { this.cube.visible = config.atPano.showSkybox this.cube.visible && this.cube.material.setProjectedPanos(this.currentPano, pano, 0) viewer.scene.pointclouds.forEach(e=>{ viewer.updateVisible(e, 'displayMode',config.transition.showPoint) }) if(config.transition.pointUsePanoTex){ let easeInOutRatio = pointcloudVisi ? 0.3 : 0 viewer.scene.pointclouds.forEach(e=>{ e.material.setProjectedPanos(this.currentPano, pano, 0, easeInOutRatio) }) } const endPosition = pano.position.clone() this.flying = true viewer.scene.view.setView(endPosition, target ,duration, ()=>{//done if(!config.atPano.pointUsePanoTex){ viewer.scene.pointclouds.forEach(e=>{ e.material.stopProjectedPanos() }) } //this.currentPano.exit() //pano.enter() this.currentPano = pano; this.flying = false this.nextPano = null; viewer.scene.pointclouds.forEach(e=>{ viewer.updateVisible(e, 'displayMode',pointcloudVisi) }) done(true); },(progress)=>{//onUpdate this.cube.material.uniforms.progress.value = progress viewer.scene.pointclouds.forEach(e=>{ e.material.uniforms.progress.value = progress }) }, easeName ) { toPano.duration = duration toPano.easeName = easeName this.emit('flyToPano', toPano) } //}) } focusPano(toPano ){ if(this.currentPano !== null){ return this.flyToPano(toPano); } if(toPano instanceof Panorama){ toPano = {pano: toPano} } let done = (makeIt)=>{ toPano.deferred && toPano.deferred.resolve(makeIt) makeIt && toPano.callback && toPano.callback() } var pano = toPano.pano let config = Potree.config.displayMode[Potree.settings.displayMode] previousView = { //controls: this.viewer.controls, position: this.position, target: viewer.scene.view.getPivot(), }; //this.viewer.setControls(this.viewer.orbitControls); this.viewer.orbitControls.doubleClockZoomEnabled = false; for(let image of this.panos){ image.mesh.visible = false; } this.selectingEnabled = false; //console.log("flyto "+pano.file.split('/').pop() ) var dur = toPano.duration == void 0 ? 700 : toPano.duration if(config.atPano.showSkybox){ if ( this.checkAndWaitForPanoLoad(pano, "low", "low", this.basePanoSize, ()=> { setTimeout( ()=>{ this.focusPano(toPano) },1) }) ) { return ; } } //this.load(pano).then( () => { //this.panos.forEach(e=>e.marker.material.depthTest = false) this.cube.visible = config.atPano.showSkybox this.cube.visible && this.cube.material.setProjectedPanos(pano, pano, 0) if(config.atPano.pointUsePanoTex){//false viewer.scene.pointclouds.forEach(e=>{ e.material.setProjectedPanos(pano, pano, 0) }) } //}); let newCamPos = pano.position.clone() let target = newCamPos.clone().add(viewer.scene.view.direction) this.flying = true viewer.scene.view.setView( newCamPos, target, dur , ()=>{//done //pano.enter() this.flying = false /* viewer.scene.pointclouds.forEach(e=>{ e.visible = pointcloudVisi }) */ this.currentPano = pano; done(true) },(progress)=>{//onUpdate /* this.cube.material.uniforms.progress.value = progress viewer.scene.pointclouds.forEach(e=>{ e.material.uniforms.progress.value = progress }) */ } ) this.elUnfocus && (this.elUnfocus[0].style.display = ""); } unfocus(o={}){ this.selectingEnabled = true; Potree.settings.displayMode = 'showPointCloud' if(!this.currentPano && !o.position){ return; } this.cube.visible = false viewer.orbitControls.doubleClockZoomEnabled = true; viewer.scene.view.setView( o.position || previousView.position, o.target || previousView.target, o.duration || 500, ()=>{ //done for(let pano of this.panos){ pano.mesh.visible = true; //pano.marker.material.depthTest = true } o.callback && o.callback() } ); //this.currentPano.exit() this.currentPano = null; this.elUnfocus && (this.elUnfocus[0].style.display = "none"); } /* bump(direction) {//撞墙弹回效果 if (!this.flying) { var t, i, n, r = settings.transition, o = (r.flytimeMaxDistanceThreshold * r.flytimeDistanceMultiplier + r.flyTime) / 10, a = this.camera.getWorldDirection().dot(direction), s = Math.abs(a) > .5; if (s) t = function() { transitions.start(lerp.property(this.cameraControls.cameras[ViewMode.PANORAMA], "zoom", a > 0 ? 1.04 : .96), o, i, 0, easing.easeInOutSine, "bumpZStart") } .bind(this), i = function() { transitions.start(lerp.property(this.cameraControls.cameras[ViewMode.PANORAMA], "zoom", 1), 3 * o, n, 0, easing.easeInOutSine, "bumpZRelax") } .bind(this); else { var l = this.camera.position.clone(), c = direction.clone(); this.raycaster.set(l, c); var h = this.model.floors.reduce(function(e, t) { return e.concat(t.collider.children) }, []), d = this.raycaster.intersectObjects(h), p = d.length > 0 ? d[0].distance / 25 : .04, g = l.clone().add(c.multiplyScalar(p)); t = function() { transitions.start(lerp.vector(this.cameraControls.cameras[ViewMode.PANORAMA].position, g), o, i, 0, easing.easeInOutSine, "bumpTStart") } .bind(this), i = function() { transitions.start(lerp.vector(this.cameraControls.cameras[ViewMode.PANORAMA].position, l), 5 * o, n, 0, easing.easeInOutSine, "bumpTRelax") } .bind(this) } n = (){ this.mode == "panorama" && (this.flying = !1) //改 } this.flying = !0, t() } }; */ /* load(pano, ){ return new Promise(resolve => { let texture = texLoader.load(pano.file, resolve); texture.wrapS = THREE.RepeatWrapping; texture.repeat.x = -1; texture.flipY = false//add pano.texture = texture; //add texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping; texture.minFilter = THREE.LinearFilter; texture.magFilter = THREE.LinearFilter; texture.generateMipmaps = true; }); } */ flyToPanoClosestToMouse() { /* if (Date.now() - this.mouseLastMoveTime > 50) { //this.intersect = this.getMouseIntersect(); this.intersect && this.updateClosestPano(this.intersect); } */ if(!Potree.settings.ifShowMarker){//不显示marker的时候mousemove没更新鼠标最近点所以更新 this.updateClosestPano(viewer.inputHandler.intersectPoint) } if (this.closestPano) { return this.flyToPano({ pano: this.closestPano }); } var direction = this.viewer.inputHandler.getMouseDirection().direction; this.flyDirection(direction) } flyDirection(direction, option1, option2) { var deferred = $.Deferred(); //this.history.invalidate(); var panoSet = this.closestPanoInDirection(direction, option1, option2); if (panoSet) { this.flyToPano({ pano: panoSet, callback: deferred.resolve.bind(deferred, !0) } ); } else { //this.bump(direction); deferred.resolve(!1); } return deferred.promise(); } closestPanoInDirection(direction, option1, option2) { return this.rankedPanoInDirection(0, direction, option1, option2) } rankedPanoInDirection(t, direction, option1, option2){ var panoSet = { pano: null, candidates: [] //缓存顺序--如果需要打印的话 }; t || (t = 0); option1 = void 0 !== option1 ? option1 : .75; var o = option2 ? "angle" : "direction"; var request = [//必要条件 Images360.filters.inPanoDirection( this.position, direction, option1), //Images360.filters.isNeighbourPanoTo(this.currentPano), Images360.filters.not(this.currentPano) ] var list = [//决胜项目 Images360.scoreFunctions.distanceSquared(this.currentPano), Images360.scoreFunctions[o]( this.position, direction) ]; this.findRankedByScore(t,request,list,panoSet); return panoSet.pano; } updateClosestPano(intersect) {//距离reticule最近的点 可以是null intersect = intersect && intersect.location if(!intersect)return //intersect = intersect && (intersect.location || intersect) var filterFuncs = []; //if (this.mode === ViewMode.PANORAMA) { /* if (!Potree.settings.isOfficial && !this.currentPano) { return; } */ if(this.isAtPano() ){ filterFuncs.push(Images360.filters.not(this.currentPano)); filterFuncs.push(Images360.filters.inFloorDirection(this.position, viewer.scene.view.direction, .25)),//许钟文改 //filterFuncs.push(Images360.filters.isNeighbourPanoTo(this.currentPano)); filterFuncs.push(Images360.filters.isCloseEnoughTo(intersect, 0.35)); /* } else { if(!this.linkEditor.noPanoHasNeighbor){//xzw add 如果不是全孤立点的话,就要避开孤立点 filterFuncs.push((pano)=>{return this.linkEditor.checkHasNeighbor(pano)}) } objects.record.control.isRecording || filterFuncs.push(Panorama.filters.isOnVisibleFloor()); this.mode !== ViewMode.FLOORPLAN && filterFuncs.push(Panorama.filters.inDirection(this.position, this.getDirection(), .25)); } */ } var pano = Common.find(this.panos, filterFuncs, [Images360.sortFunctions.floorDistanceToPoint(intersect)]); if (pano != this.closestPano) { pano && (this.isPanoHover = !0); //触发事件,导致地面的marker变清晰 //this.emit(PlayerEvents.ClosestPanoChanging, this.closestPano, pano, this.mode); this.closestPanoChanging(this.closestPano, pano) this.closestPano = pano; } else { this.isPanoHover = !1; } } closestPanoChanging(oldPano, newPano){ if(!Potree.settings.ifShowMarker)return oldPano && oldPano.hoverOff() newPano && newPano.hoverOn() } /* handleHovering(){ let pointer = viewer.inputHandler.pointer; let camera = viewer.scene.getActiveCamera(); let domElement = viewer.renderer.domElement; let ray = Potree.Utils.mouseToRay(pointer, camera, domElement.clientWidth, domElement.clientHeight); // let tStart = performance.now(); raycaster.ray.copy(ray); let intersections = raycaster.intersectObjects(this.node.children); if(intersections.length === 0){ // label.visible = false; return; } let intersection = intersections[0]; currentlyHovered = intersection.object; currentlyHovered.material = smHovered; //label.visible = true; //label.setText(currentlyHovered.pano.file); //currentlyHovered.getWorldPosition(label.position); } */ update(){ let {viewer} = this; /* if(currentlyHovered){ currentlyHovered.material = sm; currentlyHovered = null; } if(this.selectingEnabled){ this.handleHovering(); } */ if(this.tileDownloader.started){ var vectorForward = viewer.scene.view.direction.clone() vectorForward = math.convertVector.ZupToYup(vectorForward) this.updateTileDownloader(tileArr,vectorForward); this.updatePanoRenderer(vectorForward) } } findRankedByScore(e, t, i, n) { n && (n.candidates = null, //candidates 缓存顺序--如果需要打印的话 n.pano = null), e || (e = 0); var r = Common.sortByScore(this.panos, t, i); return !r || 0 === r.length || e >= r.length ? null : (n && (n.candidates = r, n.pano = r[e].item), r[e].item) } updateTileDownloader(t, vectorForward) { var i = this.nextPano || this.currentPano; if(i){ this.tileDownloader.tilePrioritizer.updateCriteria(i, viewer.scene.view.position.clone() , vectorForward, t.length > 0 ? t : null), this.tileDownloader.processPriorityQueue = !0 } } updatePanoRenderer(vectorForward) { var i = this.nextPano || this.currentPano; if(i){ if (this.panoRenderer.hasQueuedTiles() && i) { this.panoRenderer.updateDirection(vectorForward); } } } checkAndWaitForTiledPanoLoad(pano, basePanoSize, callback1, callback2, progressCallback, iswait, isclear, l) { if (!pano) { console.error("Player.checkAndWaitForTiledPanoLoad() -> Cannot load texture for null pano."); } var vectorForward = viewer.scene.view.direction.clone() vectorForward = math.convertVector.ZupToYup(vectorForward) if (!pano.isLoaded(basePanoSize)) { iswait && viewer.waitForLoad(pano, function() {//发送loading return pano.isLoaded(basePanoSize) }); var fov = {//test for direction 预加载的边缘有一丢丢不准确,尤其在相机倾斜时(4dkk也是)。 hFov: cameraLight.getHFOVForCamera(viewer.scene.getActiveCamera(), viewer.renderArea.clientWidth, viewer.renderArea.clientHeight), vFov: viewer.scene.getActiveCamera().fov }//原先是null,不要求方向 pano.loadTiledPano(/* 1024 */ basePanoSize , vectorForward, fov, isclear, l, null).done(function(e, t) { callback1 && callback1(e, t) } .bind(this)).fail(function(msg) { callback2 && callback2(msg) } .bind(this)).progress(function(e, t, i) { progressCallback && progressCallback(e, t, i) } .bind(this)); return !0; } } fitPanoTowardPoint(o){ //寻找最适合的点位 var point = o.point, require = o.require || [], rank = o.rank || [], force = o.force, getAll = o.getAll, bestDistance = o.bestDistance || 0 let camera = viewer.scene.getActiveCamera() //if(o.floor)require.push(Panorama.filters.atFloor(o.floor)) if(o.boundSphere){//只接受boundSphere let aspect = 1//size.x / size.y let dis if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定 dis = /* size.y */o.boundSphere.radius/* / 2 *// THREE.Math.degToRad(camera.fov / 2) }else{ let hfov = cameraLight.getHFOVForCamera(camera, camera.aspect, 1 ); dis = /* size.x */ o.boundSphere.radius /* / 2 */ / THREE.Math.degToRad(hfov / 2) } bestDistance = dis*0.8 } let bestDisSquared = bestDistance * bestDistance rank.push((pano)=>{ return -Math.abs(pano.position.distanceToSquared(point) - bestDisSquared) }) /* var temp = {position:point} rank.push(Panorama.scoreFunctions.distanceSquared(temp, -2)); */ var g = Common.sortByScore(this.panos, require, rank); if(getAll)return g; return g && g.length > 0 && g[0].item } }; //判断当前点是否加载了全景图 Images360.prototype.checkAndWaitForPanoLoad = function() { var isLoadedPanos = {}, LoadedTimePanos = {}, maxTime = 5e3; var overtime = function() { for (var panoId in isLoadedPanos) if (isLoadedPanos.hasOwnProperty(panoId) && isLoadedPanos[panoId]) { var differTime = performance.now() - LoadedTimePanos[panoId]; if (differTime < maxTime) return !0 } return !1 } return function(pano, imgQuality1, imgQuality2, basePanoSize, doneFun1, doneFun2, progressCallback, iswait, isclear, p ) { if (overtime()) return !0; var callback1 = (param1, param2)=>{ setTimeout(()=>{ isLoadedPanos[pano.id] = !1; doneFun1 && doneFun1(param1, param2); },1) } var callback2 = (param)=>{//没有看到有传doneFun2的 setTimeout(()=>{ isLoadedPanos[pano.id] = !1; doneFun2 && doneFun2(param); },1) } try { null !== iswait && void 0 !== iswait || (iswait = !0); isLoadedPanos[pano.id] = this.checkAndWaitForTiledPanoLoad(pano, basePanoSize, callback1, callback2, progressCallback, iswait, isclear, p ); isLoadedPanos[pano.id] && (LoadedTimePanos[pano.id] = performance.now()); return isLoadedPanos[pano.id]; } catch (msg) { isLoadedPanos[pano.id] = !1; LoadedTimePanos[pano.id] = performance.now() - maxTime; throw msg; } } }() Images360.filters = { inPanoDirection : function(e, t, i) { return function(n) { var r = n.floorPosition.clone().sub(e).setZ(0).normalize() //忽略上下角度,这样即使看得很低也能走 , o = n.position.clone().sub(e).normalize(); return r.dot(t.clone().setZ(0).normalize()) > i || o.dot(t) > i } }, inFloorDirection: function(pos, e, o) {//许钟文 改 for鱼眼 return function(n) { var i = n.floorPosition.clone().sub(pos).setZ(0).normalize();//改成在xz方向上,否则点击墙面不会移动 return i.dot(e) > o } }, isNotBehindNormal: function(e, t) { var i = new THREE.Vector3; return t = t.clone(), function(n) { var r = i.copy(n.position).sub(e).normalize(); return r.dot(t) > 0 } }, isCloseEnoughTo: function(e, t) { return function(i) {//因为marker可能比地面高,所以识别范围要比marker看起来更近一些。(因为投影到地板的位置比marker更近) return e.distanceTo(i.floorPosition) < t //许钟文 } }, not: function(e) { return function(t) { return t !== e } } } Images360.scoreFunctions = { direction: function(e, t) { return function(i) { var pos = i.position.clone() var n = pos.clone().sub(e).normalize(); return n.dot(t) * 10 } }, distanceSquared: function(e) { var pos1 = e.position.clone() return function(i) {//许钟文 改 var pos2 = i.position.clone() return pos1.distanceToSquared(pos2) * -1 } }, angle: function(e, t) { return function(i) { var n = i.position.clone().sub(e).normalize(); return n.angleTo(t) * Potree.config.navigation.angleFactor } }, } Images360.sortFunctions = {//排序函数,涉及到两个item相减 floorDistanceToPoint: function(e) { return function(t, i) { return t.floorPosition.distanceTo(e) - i.floorPosition.distanceTo(e) } }, } export class Images360Loader{ static async load(viewer, params, callback ){ let center = viewer.transform.lonlatToLocal.inverse(viewer.bound.center) center = {lat:center.y, lon:center.x} //中心点 Potree.loadPanos(center,(data)=>{ let images360 = new Images360(viewer, params); data = data.sort(function(a,b){return a.id-b.id}) data.forEach((info,i)=>{ if(Potree.fileServer){ info.id = i //info的id是一长串数字,改简单点 } let pano = new Panorama( info, params.transform, images360 ); /* pano.mesh.layers.set(Potree.config.renderLayers.marker) pano.marker.layers.set(Potree.config.renderLayers.marker) */ images360.panos.push(pano); }) viewer.setObjectLayers(images360.node, 'marker') viewer.images360 = window.images360 = images360//add images360.tileDownloader.setPanoData(images360.panos, [] /* , Potree.settings.number */); { var panosBound = new THREE.Box3 images360.panos.forEach(pano=>{ panosBound.expandByPoint(pano.position) }) images360.bound = { bounding:panosBound, size: panosBound.getSize(new THREE.Vector3), center: panosBound.getCenter(new THREE.Vector3) } } callback && callback(images360) }) } };