|
@@ -1,27 +1,41 @@
|
|
|
import * as THREE from "../../../libs/three.js/build/three.module.js";
|
|
|
import {transitions, easing, lerp} from '../../utils/transitions.js'
|
|
|
-import TileUtils from './tile/TileUtils'
|
|
|
-import { PanoRendererEvents, PanoramaEvents, PanoSizeClass} from '../../defines'
|
|
|
-import math from '../../utils/math'
|
|
|
-import { EventDispatcher } from "../../EventDispatcher.js";
|
|
|
-import {TextSprite} from '../../TextSprite'
|
|
|
+import TileUtils from './tile/TileUtils.js'
|
|
|
+import { PanoRendererEvents, PanoramaEvents, PanoSizeClass} from '../../defines.js'
|
|
|
+import math from '../../utils/math.js'
|
|
|
+import {TextSprite} from '../../objects/TextSprite.js'
|
|
|
+import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
|
|
|
+
|
|
|
|
|
|
var texLoader = new THREE.TextureLoader()
|
|
|
|
|
|
const labelProp = {
|
|
|
- sizeInfo: {minSize : 120 , maxSize : 200, nearBound : 0.8, farBound : 10},
|
|
|
- backgroundColor:{r: 255, g: 255, b: 255, a: 0.2 },
|
|
|
+ sizeInfo: {minSize : 200 , maxSize : 250, nearBound : 0.8, farBound : 10},
|
|
|
+ backgroundColor:{r: 255, g: 255, b: 255, a: 0.4 },
|
|
|
+ textColor:{r: 0, g: 0, b: 0, a: 1 },
|
|
|
borderRadius: 15,
|
|
|
+ renderOrder:10
|
|
|
}
|
|
|
|
|
|
let standardMarkerMat
|
|
|
+let markerTex
|
|
|
let getMarerMat = function(){
|
|
|
- if(!standardMarkerMat) {
|
|
|
- let map = texLoader.load( Potree.resourcePath+'/textures/marker.png' )
|
|
|
- map.anisotropy = 4 // 各向异性过滤 .防止倾斜模糊
|
|
|
- standardMarkerMat = new THREE.MeshBasicMaterial({opacity:0.7, side: THREE.DoubleSide , map ,transparent:true, depthTest:false})//总是被点云遮住,所以depthTest:false
|
|
|
+ if(!markerTex) {
|
|
|
+ markerTex = {
|
|
|
+ default:texLoader.load( Potree.resourcePath+'/textures/marker.png' ),
|
|
|
+ ring:texLoader.load( Potree.resourcePath+'/textures/marker2.png' )
|
|
|
+ }
|
|
|
+ markerTex.default.anisotropy = 4 // 各向异性过滤 .防止倾斜模糊
|
|
|
+ markerTex.ring.anisotropy = 4
|
|
|
+ //有可能被点云遮住吗。
|
|
|
+
|
|
|
}
|
|
|
- return standardMarkerMat.clone()
|
|
|
+ return new DepthBasicMaterial({opacity:0.7, side: THREE.DoubleSide , map:markerTex.default ,transparent:true,
|
|
|
+ clipDistance: 2, occlusionDistance:1, //不能设置太短,因为过渡时深度不准确
|
|
|
+ //depthTest: !!Potree.settings.useDepthTex,
|
|
|
+ useDepth: !!Potree.settings.useDepthTex
|
|
|
+ //改为DepthBasicMaterial是因为原Basic的材质过渡时会先隐藏后出现
|
|
|
+ })
|
|
|
}
|
|
|
//显示全景图时marker没有被遮挡,如果需要,要换成depthBasicMaterial 或者直接把skybox的深度修改(拿到深度贴图后更如此)
|
|
|
let planeGeo = new THREE.PlaneBufferGeometry(0.2,0.2);
|
|
@@ -50,78 +64,130 @@ var a = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), THREE.
|
|
|
*/
|
|
|
|
|
|
//暂时直接用4dkkconsole输出的数据
|
|
|
-class Panorama extends EventDispatcher{
|
|
|
+class Panorama extends THREE.EventDispatcher{
|
|
|
|
|
|
- constructor(o, transform, images360){//file, time, longitude, latitude, altitude, course, pitch, roll
|
|
|
+ constructor(o, images360){//file, time, longitude, latitude, altitude, course, pitch, roll
|
|
|
super()
|
|
|
- this.id = o.id;
|
|
|
+ this.id = o.id; //唯一标识
|
|
|
this.images360 = images360
|
|
|
- this.transform = transform
|
|
|
this.visible = true //for viewer updateVisible
|
|
|
-
|
|
|
- this.originPosition = new THREE.Vector3().fromArray(o.dataset_location)
|
|
|
- this.originFloorPosition = new THREE.Vector3().fromArray(o.dataset_floor_location)
|
|
|
-
|
|
|
- this.originID = parseInt(o.file_id)//"file_id":"00022"对应是原本的4dkk的id --来自vision.txt
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- this.pointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == o.dataset_id) || viewer.scene.pointclouds[0]
|
|
|
- this.pointcloud.panos.push(this)
|
|
|
- this.pointcloud.addEventListener('isVisible',(e)=>{
|
|
|
- /* if(!e.visible){//数据集隐藏时漫游点也隐藏
|
|
|
- e.reason == 'datasetSelection' && viewer.updateVisible(this, 'pointcloudVisi', false)
|
|
|
- }else{
|
|
|
- console.log('pointcloudVisi 1')
|
|
|
- viewer.updateVisible(this, 'pointcloudVisi', true)
|
|
|
- } */
|
|
|
- e.reason == 'datasetSelection' && viewer.updateVisible(this, 'pointcloudVisi', e.visible)
|
|
|
-
|
|
|
- })
|
|
|
+ this.enabled = true//是否可以走
|
|
|
this.addEventListener('isVisible',(e)=>{//是否显示该点的mesh(不显示也能走)
|
|
|
- this.marker.visible = e.visible
|
|
|
+ //console.log('pano isVisible', this.id, e.visible)
|
|
|
+ viewer.updateVisible(this.marker, 'panoVisi', e.visible)
|
|
|
Potree.settings.showPanoMesh && (this.mesh.visible = e.visible)
|
|
|
if(e.reason == 'screenshot' || e.visible){
|
|
|
this.label && (this.label.visible = e.visible)//截图时隐藏下
|
|
|
}
|
|
|
+ viewer.updateVisible(this.label2, 'panoVisi', e.visible)
|
|
|
})
|
|
|
+ /*
|
|
|
+ 漫游点可见性:旧
|
|
|
+ level reason 类型
|
|
|
+ 2(最高)buildingChange(不在此楼层) unvisible
|
|
|
+ 1 modeIsShowPanos(漫游模式) visible //不记得为什么加这个了,所以重写
|
|
|
+ 0 pointcloudVisi(隐藏了数据集) unvisible
|
|
|
+ */
|
|
|
+
|
|
|
+ /*
|
|
|
+ 漫游点可见性:新
|
|
|
+ level reason 类型
|
|
|
+ 2(最高)buildingChange(不在此楼层) unvisible
|
|
|
+ 1 ifShowMarker(marker显示开关) unvisible
|
|
|
+ 0 pointcloudVisi(隐藏了数据集) unvisible
|
|
|
+ */
|
|
|
+
|
|
|
|
|
|
-
|
|
|
- //全景图和Cube的水平采样起始坐标相差90度
|
|
|
-
|
|
|
-
|
|
|
- /* if(from4dkk){
|
|
|
- var qua = o.dataset_orientation
|
|
|
+ if(Potree.settings.editType == 'pano'){//漫游点拼合编辑
|
|
|
+ this.uuid = o.uuid //因为有多个数据集 所以会重复
|
|
|
+ this.index = o.index //下标, 用于visibles
|
|
|
+ this.pointcloud = viewer.scene.pointclouds.find(e=>e.panoUuid == o.uuid)
|
|
|
+ this.pointcloud.panos.push(this)
|
|
|
+ this.sid = this.pointcloud.dataset_id + '|' + this.uuid //不会更改的标记 用于entity.panos里的标记
|
|
|
|
|
|
- var quaternion = new THREE.Quaternion().fromArray(qua)
|
|
|
- quaternion = new THREE.Quaternion().multiplyQuaternions(quaternion, rot901);//整张球幕图要旋转下 因为在4dkk里转过,还原。如果是tiles的不用
|
|
|
- this.quaternion = new THREE.Quaternion(quaternion.x, -quaternion.z, quaternion.y, quaternion.w) //转化坐标
|
|
|
-
|
|
|
- }else{ */
|
|
|
-
|
|
|
|
|
|
- var qua = o.dataset_orientation
|
|
|
- qua = [qua[1], qua[2], qua[3], qua[0]]
|
|
|
- this.quaternion = new THREE.Quaternion().fromArray(qua)
|
|
|
- this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion
|
|
|
+ this.panosData = o
|
|
|
|
|
|
- this.quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion, rot90);//全景图和Cube的水平采样起始坐标相差90度,cubeTex转90度
|
|
|
+ //数据中原本的位置朝向
|
|
|
+ this.dataPosition = new THREE.Vector3().copy(o.pose.translation)
|
|
|
+ this.dataQuaternion = new THREE.Quaternion().copy(o.pose.rotation)
|
|
|
+ this.dataRotation = new THREE.Euler().setFromQuaternion(this.dataQuaternion)
|
|
|
|
|
|
- this.rotation4dkk = new THREE.Euler().setFromQuaternion(this.quaternion4dkk)
|
|
|
- this.rotation = new THREE.Euler().setFromQuaternion(this.quaternion)
|
|
|
- //}
|
|
|
-
|
|
|
-
|
|
|
- //this.quaternion1 = Potree.Utils.QuaternionFactory.fromArray(o.dataset_orientation)
|
|
|
- //同quaternion
|
|
|
+
|
|
|
+ //因为位置朝向随着点云位置改变,所以直接运用到点云上,这里清零
|
|
|
+ this.originPosition = new THREE.Vector3() //{x: 0, y: 0, z: 0}
|
|
|
+ this.quaternion = new THREE.Quaternion() //{w: 0, x: 0, y: 0, z: 1}
|
|
|
+ //this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion
|
|
|
+ this.visibles = o.visibles
|
|
|
+
|
|
|
+
|
|
|
+ const height = 1.4; //相机高度
|
|
|
+ this.originFloorPosition = this.originPosition.clone()
|
|
|
+ this.originFloorPosition.z -= height
|
|
|
+
|
|
|
+
|
|
|
+ /* this.originPosition = new THREE.Vector3().copy(o.pose.translation) //{x: 0, y: 0, z: 0}
|
|
|
+ this.quaternion = new THREE.Quaternion().copy(o.pose.rotation) //{w: 0, x: 0, y: 0, z: 1}
|
|
|
+ //this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion
|
|
|
+ this.visibles = o.visibles
|
|
|
+ this.pointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == o.uuid)
|
|
|
+ this.pointcloud.panos.push(this)
|
|
|
+
|
|
|
+ const height = 1.5; //相机高度
|
|
|
+ this.originFloorPosition = this.originPosition.clone()
|
|
|
+ this.originFloorPosition.z -= height
|
|
|
+ */
|
|
|
+
|
|
|
+
|
|
|
+ }else{
|
|
|
+ this.originPosition = new THREE.Vector3().fromArray(o.dataset_location)
|
|
|
+ this.originFloorPosition = new THREE.Vector3().fromArray(o.dataset_floor_location)
|
|
|
+
|
|
|
+ this.originID = parseInt(o.file_id)//"file_id":"00022"对应是原本的4dkk的id --来自vision.txt
|
|
|
+
|
|
|
+ this.pointcloud = viewer.scene.pointclouds.find(e=>e.dataset_id == o.dataset_id) || viewer.scene.pointclouds[0]
|
|
|
+ this.pointcloud.panos.push(this)
|
|
|
+
|
|
|
+ //this.sid = this.pointcloud.sceneCode + '|' + this.originID //不会更改的标记
|
|
|
+ this.sid = this.pointcloud.dataset_id + '|' + this.originID //不会更改的标记
|
|
|
+ //全景图和Cube的水平采样起始坐标相差90度
|
|
|
+
|
|
|
+
|
|
|
+ /* if(from4dkk){
|
|
|
+ var qua = o.dataset_orientation
|
|
|
+
|
|
|
+ var quaternion = new THREE.Quaternion().fromArray(qua)
|
|
|
+ quaternion = new THREE.Quaternion().multiplyQuaternions(quaternion, rot901);//整张球幕图要旋转下 因为在4dkk里转过,还原。如果是tiles的不用
|
|
|
+ this.quaternion = new THREE.Quaternion(quaternion.x, -quaternion.z, quaternion.y, quaternion.w) //转化坐标
|
|
|
+
|
|
|
+ }else{ */
|
|
|
+
|
|
|
+
|
|
|
+ var qua = o.dataset_orientation
|
|
|
+ qua = [qua[1], qua[2], qua[3], qua[0]]
|
|
|
+ this.quaternion = new THREE.Quaternion().fromArray(qua)
|
|
|
+ this.quaternion4dkk = math.convertVisionQuaternion(this.quaternion)//4dkk内使用的quaternion
|
|
|
+ this.quaternion2 = this.quaternion.clone()
|
|
|
+ this.quaternion = new THREE.Quaternion().multiplyQuaternions(this.quaternion, rot90);//全景图和Cube的水平采样起始坐标相差90度,cubeTex转90度
|
|
|
+
|
|
|
+ this.rotation4dkk = new THREE.Euler().setFromQuaternion(this.quaternion4dkk)
|
|
|
+
|
|
|
+ //}
|
|
|
+
|
|
|
+
|
|
|
+ //this.quaternion1 = Potree.Utils.QuaternionFactory.fromArray(o.dataset_orientation)
|
|
|
+ //同quaternion
|
|
|
|
|
|
-
|
|
|
- //let xy = this.transform.forward([this.longitude, this.latitude]);
|
|
|
- this.file = `https://4dkk.4dage.com/images/images${Potree.settings.number}/pan/high/${this.id}.jpg`
|
|
|
+
|
|
|
+ //let xy = this.transform.forward([this.longitude, this.latitude]);
|
|
|
+ this.file = `https://4dkk.4dage.com/images/images${Potree.settings.number}/pan/high/${this.id}.jpg`
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+ this.rotation = new THREE.Euler().setFromQuaternion(this.quaternion)
|
|
|
this.build()
|
|
|
this.transformByPointcloud() //初始化位移
|
|
|
-
|
|
|
-
|
|
|
|
|
|
{//tile
|
|
|
this.minimumTiledPanoLoaded = !1;
|
|
@@ -135,22 +201,22 @@ class Panorama extends EventDispatcher{
|
|
|
|
|
|
|
|
|
|
|
|
- images360.panoRenderer.on(PanoRendererEvents.TileRenderSuccess, this.onTileRendered.bind(this));
|
|
|
- images360.panoRenderer.on(PanoRendererEvents.PanoRenderComplete, this.onPanoRendered.bind(this));
|
|
|
- images360.panoRenderer.on(PanoRendererEvents.TileRenderFailure, this.onTileRenderFail.bind(this));
|
|
|
- images360.panoRenderer.on(PanoRendererEvents.UploadAttemptedForAllTiles, this.onUploadAttemptedForAllTiles.bind(this));
|
|
|
+ images360.panoRenderer.addEventListener(PanoRendererEvents.TileRenderSuccess, this.onTileRendered.bind(this));
|
|
|
+ images360.panoRenderer.addEventListener(PanoRendererEvents.PanoRenderComplete, this.onPanoRendered.bind(this));
|
|
|
+ images360.panoRenderer.addEventListener(PanoRendererEvents.TileRenderFailure, this.onTileRenderFail.bind(this));
|
|
|
+ images360.panoRenderer.addEventListener(PanoRendererEvents.UploadAttemptedForAllTiles, this.onUploadAttemptedForAllTiles.bind(this));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
- this.on('hoverOn', (e)=>{//from Map
|
|
|
+ this.addEventListener('hoverOn', (e)=>{//from Map
|
|
|
if(!e.byMainView){
|
|
|
this.hoverOn(e)
|
|
|
}
|
|
|
})
|
|
|
|
|
|
- this.on('hoverOff', (e)=>{
|
|
|
+ this.addEventListener('hoverOff', (e)=>{
|
|
|
if(!e.byMainView){
|
|
|
this.hoverOff(e)
|
|
|
}
|
|
@@ -159,15 +225,38 @@ class Panorama extends EventDispatcher{
|
|
|
|
|
|
|
|
|
|
|
|
+ setEnable(enable){//是否可以走
|
|
|
+ viewer.updateVisible(this, 'isEnabled', enable) //令所有marker不可见
|
|
|
|
|
|
+ this.enabled = enable
|
|
|
+ //如果当前在全景模式且在这个点,需要切换显示吗? 目前用不到
|
|
|
+ }
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+ loadDepthImg(){
|
|
|
+ if(!this.pointcloud.hasDepthTex || this.depthTex || this.depthTexLoading)return
|
|
|
+ this.depthTexLoading = true
|
|
|
+ let src = Potree.settings.number == 'SS-t-7DUfWAUZ3V' ? `${Potree.scriptPath}/data/${Potree.settings.number}/depthMap/${this.originID}.png`
|
|
|
+ : `https://laser-oss.4dkankan.com/${Potree.settings.webSite}/${this.pointcloud.sceneCode}/data/${this.pointcloud.sceneCode}/depthmap/${this.originID}.png`
|
|
|
+ let texture = texLoader.load( src, ()=>{
|
|
|
+ this.depthTex = texture
|
|
|
+ this.images360.dispatchEvent({type:'loadedDepthImg', pano:this, loaded:true})
|
|
|
+ this.depthTexLoading = false
|
|
|
+ },(e)=>{//error
|
|
|
+ console.error('loadDepthImg失败, 数据集sceneCode'+ this.pointcloud.sceneCode, this.id )
|
|
|
+ this.pointcloud.hasDepthTex = false
|
|
|
+ this.images360.dispatchEvent({type:'loadedDepthImg', pano:this, })
|
|
|
+ });
|
|
|
+ texture.wrapS = THREE.RepeatWrapping;
|
|
|
+ texture.flipY = false
|
|
|
+ texture.magFilter = THREE.LinearFilter
|
|
|
+ texture.minFilter = THREE.LinearFilter
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
build(){
|
|
|
|
|
|
- let mesh = new THREE.Mesh(sg, sm);
|
|
|
+ /* let mesh = new THREE.Mesh(sg, sm);
|
|
|
mesh.scale.set(1, 1, 1);
|
|
|
mesh.material.transparent = true;
|
|
|
mesh.material.opacity = 0.75;
|
|
@@ -181,7 +270,12 @@ class Panorama extends EventDispatcher{
|
|
|
})
|
|
|
mesh.addEventListener('click',(e)=>{
|
|
|
this.images360.focusPano(this)
|
|
|
- })
|
|
|
+ })
|
|
|
+ this.mesh = mesh;
|
|
|
+ if(!Potree.settings.showPanoMesh) mesh.visible = false
|
|
|
+ this.images360.node.add(mesh)
|
|
|
+ */
|
|
|
+
|
|
|
{ // orientation
|
|
|
//var {course, pitch, roll} = this;
|
|
|
//mesh.quaternion.copy(this.quaternion)
|
|
@@ -191,49 +285,98 @@ class Panorama extends EventDispatcher{
|
|
|
//quaternion.premultiply(rot90)
|
|
|
this.panoMatrix = new THREE.Matrix4().makeRotationFromQuaternion(this.quaternion)
|
|
|
this.oriPanoMatrix = this.panoMatrix.clone()
|
|
|
+
|
|
|
+ if(this.quaternion2)this.oriPanoMatrix2 = new THREE.Matrix4().makeRotationFromQuaternion(this.quaternion2)
|
|
|
+
|
|
|
+
|
|
|
//console.log(this.quaternion)
|
|
|
//this.quaternion = quaternion
|
|
|
}
|
|
|
- this.mesh = mesh;
|
|
|
- if(!Potree.settings.showPanoMesh) mesh.visible = false
|
|
|
+
|
|
|
+
|
|
|
|
|
|
let marker = new THREE.Mesh(planeGeo, getMarerMat() )
|
|
|
+ marker.name = 'marker_'+this.id
|
|
|
marker.up.set(0,0,1)
|
|
|
marker.lookAt(marker.up)
|
|
|
marker.scale.set(2,2,2)
|
|
|
-
|
|
|
+ this.addEventListener('changeMarkerTex',(e)=>{
|
|
|
+ marker.material.map = markerTex[e.name]
|
|
|
+ })
|
|
|
|
|
|
this.marker = marker
|
|
|
+ if(Potree.settings.editType == 'pano'){
|
|
|
+ viewer.updateVisible(marker, 'panoEdit', false, 4)
|
|
|
+ }
|
|
|
|
|
|
- this.images360.node.add(mesh)
|
|
|
this.images360.node.add(marker)
|
|
|
Potree.settings.isTest && this.createTextLabel()
|
|
|
+ this.createTextLabel2()
|
|
|
|
|
|
+ /* let mouseover = (e)=>{
|
|
|
+ if(!e.byMap){
|
|
|
+ pano.mapMarker.material = panoMarkerMats.selected
|
|
|
+ if(!e.byMainView) pano.dispatchEvent({type: "hoverOn", byMap:true})
|
|
|
+ this.needRender = true
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let mouseleave = (e)=>{
|
|
|
+ if(!e.byMap){
|
|
|
+ pano.mapMarker.material = panoMarkerMats.default
|
|
|
+ if(!e.byMainView) pano.dispatchEvent({type: "hoverOff", byMap:true})
|
|
|
+ this.needRender = true
|
|
|
+ }
|
|
|
+ } */
|
|
|
+
|
|
|
+
|
|
|
+ marker.addEventListener('mouseover', this.hoverOn.bind(this));
|
|
|
+ marker.addEventListener('mouseleave', this.hoverOff.bind(this));
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
transformByPointcloud(){
|
|
|
-
|
|
|
- let position = this.originPosition.clone().applyMatrix4(this.pointcloud.transformMatrix);
|
|
|
+
|
|
|
+ let position = this.originPosition.clone().applyMatrix4(this.pointcloud.transformMatrix);//也可以用datasetPosTransform算
|
|
|
let floorPosition = this.originFloorPosition.clone().applyMatrix4(this.pointcloud.transformMatrix);
|
|
|
this.setPosition(position, floorPosition)
|
|
|
this.panoMatrix = new THREE.Matrix4().multiplyMatrices(this.pointcloud.rotateMatrix, this.oriPanoMatrix )
|
|
|
-
|
|
|
- //quaternion也变下
|
|
|
+ //this.panoMatrix2 = Potree.Utils.datasetRotTransform({fromDataset:true, pointcloud:this.pointcloud, matrix:this.oriPanoMatrix, getMatrix:true}) //和上一行结果一样
|
|
|
+ //quaternion也变下
|
|
|
+ if(this.oriPanoMatrix2){
|
|
|
+ this.panoMatrix2 = new THREE.Matrix4().multiplyMatrices(this.pointcloud.rotateMatrix, this.oriPanoMatrix2 )//供DepthImageSampler使用
|
|
|
+ this.panoMatrix2Inverse = this.panoMatrix2.clone().invert();
|
|
|
+ }
|
|
|
+ this.dispatchEvent('rePos')
|
|
|
}
|
|
|
|
|
|
setPosition(position, floorPosition){
|
|
|
this.position = position
|
|
|
this.floorPosition = floorPosition
|
|
|
- this.mesh.position.copy(this.position)
|
|
|
+ //this.mesh.position.copy(this.position)
|
|
|
this.marker.position.copy(this.floorPosition)
|
|
|
- this.marker.position.z+=0.1//会被点云遮住
|
|
|
- if(this.label){
|
|
|
- this.label.position.copy(this.floorPosition), this.label.position.z+=0.2
|
|
|
+ this.marker.position.z+=0.04//会被点云遮住
|
|
|
+ if(this.label){
|
|
|
+ if(Potree.settings.editType == 'pano'){
|
|
|
+ this.label.position.copy(this.position)
|
|
|
+ }else{
|
|
|
+ this.label.position.copy(this.floorPosition)
|
|
|
+ }
|
|
|
+ this.label.position.z+=0.14
|
|
|
this.label.update()
|
|
|
}
|
|
|
+
|
|
|
+ if(this.label2){
|
|
|
+ if(Potree.settings.editType == 'pano'){
|
|
|
+ this.label2.position.copy(this.position)
|
|
|
+ }else{
|
|
|
+ this.label2.position.copy(this.floorPosition)
|
|
|
+ }
|
|
|
+ this.label2.position.copy(this.marker.position)
|
|
|
+ this.label2.update()
|
|
|
+ }
|
|
|
|
|
|
}
|
|
|
|
|
@@ -247,7 +390,8 @@ class Panorama extends EventDispatcher{
|
|
|
hoverOn(e={}) {
|
|
|
//console.log("hoverOn " + this.id )
|
|
|
transitions.start(lerp.property(this.marker.material, "opacity", 1), 250)
|
|
|
- if(!e.byMap) this.emit('hoverOn', {byMainView:true})
|
|
|
+ if(!e.byMap) this.dispatchEvent({type:'hoverOn', byMainView:true})
|
|
|
+ if(!e.byImages360) this.images360.dispatchEvent({type:'markerHover', hovered:true, pano:this})
|
|
|
}
|
|
|
|
|
|
|
|
@@ -256,7 +400,8 @@ class Panorama extends EventDispatcher{
|
|
|
hoverOff(e={}){
|
|
|
//console.log("hoverOff " + this.id )
|
|
|
transitions.start(lerp.property(this.marker.material, "opacity", 0.5), 250)
|
|
|
- if(!e.byMap) this.emit('hoverOff', {byMainView:true})
|
|
|
+ if(!e.byMap) this.dispatchEvent({type:'hoverOff', byMainView:true})
|
|
|
+ if(!e.byImages360) this.images360.dispatchEvent({type:'markerHover', hovered:false, pano:this})
|
|
|
}
|
|
|
|
|
|
|
|
@@ -264,14 +409,14 @@ class Panorama extends EventDispatcher{
|
|
|
setZoomed(zoomed){
|
|
|
this.zoomed = zoomed;
|
|
|
Potree.settings.displayMode == 'showPanos' && this.updateSkyboxForZoomLevel(); //放大后换成zoomTarget贴图
|
|
|
- viewer.emit('panoSetZoom', this, zoomed)
|
|
|
+ viewer.dispatchEvent({type:'panoSetZoom', zoomed})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
enter(){
|
|
|
this.setZoomed(!1),
|
|
|
- viewer.emit(PanoramaEvents.Enter, {oldPano:old, newPano:this } )
|
|
|
+ viewer.dispatchEvent({type:PanoramaEvents.Enter, oldPano:old, newPano:this } )
|
|
|
old = this
|
|
|
//console.log("enter pano "+ this.id)
|
|
|
}
|
|
@@ -296,7 +441,7 @@ class Panorama extends EventDispatcher{
|
|
|
|
|
|
//console.log("exit pano "+ this.id)
|
|
|
|
|
|
- viewer.emit(PanoramaEvents.Exit, this);
|
|
|
+ viewer.dispatchEvent({type:PanoramaEvents.Exit, pano:this});
|
|
|
}
|
|
|
|
|
|
|
|
@@ -331,15 +476,11 @@ class Panorama extends EventDispatcher{
|
|
|
|
|
|
|
|
|
|
|
|
- isLoaded(e){
|
|
|
- //if (this.tiled) {
|
|
|
- if (e && "string" == typeof e)
|
|
|
- console.error("Wrong panoSize given to Panorama.isLoaded(); a tiled pano uses PanoSizeClass");
|
|
|
- return !!this.minimumTiledPanoLoaded && (!e || this.highestPartialTileRenderOpCompleted >= e)
|
|
|
- //}
|
|
|
- /* if (e && "number" == typeof e)
|
|
|
- throw new BasicException("Wrong panoSize given to Panorama.isLoaded(); a non-tiled pano uses high/low.");
|
|
|
- return !!this.solidSkybox.high || e in this.solidSkybox */
|
|
|
+ isLoaded(e){
|
|
|
+ if (e && "string" == typeof e)
|
|
|
+ console.error("Wrong panoSize given to Panorama.isLoaded(); a tiled pano uses PanoSizeClass");
|
|
|
+ return !!this.minimumTiledPanoLoaded && (!e || this.highestFullTileRenderOpCompleted >= e)//改:原本是:this.highestPartialTileRenderOpCompleted >= e, 希望这代表全部加载完
|
|
|
+
|
|
|
}
|
|
|
|
|
|
getWaitDeferred(size){//获取不同size的tile贴图的promiss
|
|
@@ -370,30 +511,33 @@ class Panorama extends EventDispatcher{
|
|
|
t.active = !1;
|
|
|
t.deferred = $.Deferred();
|
|
|
}
|
|
|
- onTileRendered(e, t, i, n){
|
|
|
- e === this.id && this.dispatchEvent({type:PanoramaEvents.TileLoaded, size:t, index:i, count:n});
|
|
|
+ onTileRendered(ev){
|
|
|
+ ev.id === this.id && this.dispatchEvent({
|
|
|
+ type:PanoramaEvents.TileLoaded,
|
|
|
+ size:ev.panoSize, index:ev.tileIndex, count:ev.totalTiles
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- onPanoRendered(e, t, i, n) {
|
|
|
- if(e === this.id)
|
|
|
+ onPanoRendered(ev) {
|
|
|
+ if(ev.id === this.id)
|
|
|
{
|
|
|
this.minimumTiledPanoLoaded = !0;
|
|
|
this.updateSkyboxForZoomLevel();//更新贴图 setProjected
|
|
|
- t > this.highestPartialTileRenderOpCompleted && (this.highestPartialTileRenderOpCompleted = t);//应该是更新最高获取到的Partial size
|
|
|
- !n && t > this.highestFullTileRenderOpCompleted && (this.highestFullTileRenderOpCompleted = t); //应该是更新最高获取到的Full size
|
|
|
- //this.emit("load", t);
|
|
|
+ ev.panoSize > this.highestPartialTileRenderOpCompleted && (this.highestPartialTileRenderOpCompleted = ev.panoSize);//应该是更新最高获取到的Partial size
|
|
|
+ ev.updateFullComplete && ev.panoSize > this.highestFullTileRenderOpCompleted && (this.highestFullTileRenderOpCompleted = ev.panoSize); //应该是更新最高获取到的Full size
|
|
|
+ //this.dispatchEvent("load", ev.panoSize);
|
|
|
viewer.ifAllLoaded( this);
|
|
|
- this.dispatchEvent({type:PanoramaEvents.LoadComplete, size:t, count:i});
|
|
|
+ this.dispatchEvent({type:PanoramaEvents.LoadComplete, size:ev.panoSize, count:ev.totalTiles});
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- onTileRenderFail(e, t, i) {
|
|
|
- e === this.id && this.dispatchEvent({type:PanoramaEvents.LoadFailed, t});
|
|
|
+ onTileRenderFail(ev) {
|
|
|
+ ev.id === this.id && this.dispatchEvent({type:PanoramaEvents.LoadFailed });
|
|
|
}
|
|
|
- onUploadAttemptedForAllTiles(e, t, i) {
|
|
|
- if (e === this.id) {
|
|
|
+ onUploadAttemptedForAllTiles(ev) {
|
|
|
+ if (ev.id === this.id) {
|
|
|
var n = this.images360.qualityManager.getPanoSize(PanoSizeClass.BASE);
|
|
|
- if(t === n && this.shouldRedrawOnBaseLoaded)
|
|
|
+ if(ev.panoSize === n && this.shouldRedrawOnBaseLoaded) //shouldRedrawOnBaseLoaded一直是false。在4dkk里只有初始点在quickstart后变为true。
|
|
|
{
|
|
|
this.shouldRedrawOnBaseLoaded = !1;
|
|
|
this.panoRenderer.resetRenderStatus(this.id, !0, !1);
|
|
@@ -406,58 +550,119 @@ class Panorama extends EventDispatcher{
|
|
|
|
|
|
createTextLabel(){
|
|
|
this.removeTextLabel()
|
|
|
- this.label = new TextSprite($.extend(
|
|
|
- labelProp, {text: this.id}) //{text: `id:${this.id}, dataset:${this.pointcloud.name}, 4dkkId:${this.originID}`}
|
|
|
- );
|
|
|
-
|
|
|
+ this.label = new TextSprite(Object.assign({},
|
|
|
+ labelProp, {text: this.id }) //{text: `id:${this.id}, dataset:${this.pointcloud.name}, 4dkkId:${this.originID}`}
|
|
|
+ );
|
|
|
this.images360.node.add(this.label);
|
|
|
this.floorPosition && this.label.position.copy(this.floorPosition)
|
|
|
}
|
|
|
|
|
|
+ createTextLabel2(){
|
|
|
+ let labelProp2 = {
|
|
|
+ //sizeInfo: {minSize : 200 , maxSize : 250, nearBound : 0.8, farBound : 10},
|
|
|
+ backgroundColor:{r: 255, g: 255, b: 255, a: 0 },
|
|
|
+ textColor:{r:255 , g: 255, b: 255, a: 1 },
|
|
|
+ textBorderColor:{r:30 , g:30, b: 30, a: 1 },
|
|
|
+ textBorderThick:3,
|
|
|
+ dontFixOrient:true,
|
|
|
+ renderOrder:10,
|
|
|
+ fontsize:30,
|
|
|
+ }
|
|
|
+ this.label2 = new TextSprite(Object.assign({},
|
|
|
+ labelProp2, {text: /* this.originID */ parseInt(this.id)+1 }) //{text: `id:${this.id}, dataset:${this.pointcloud.name}, 4dkkId:${this.originID}`}
|
|
|
+ );
|
|
|
+ this.images360.node.add(this.label2);
|
|
|
+ this.floorPosition && this.label2.position.copy(this.floorPosition)
|
|
|
+ let s = 0.4
|
|
|
+ this.label2.scale.set(s,s,s)
|
|
|
+ viewer.updateVisible(this.label2, 'notDisplay', false)
|
|
|
+ }
|
|
|
+
|
|
|
removeTextLabel(){
|
|
|
- if(this.label){
|
|
|
-
|
|
|
+ if(this.label){
|
|
|
this.label.parent.remove(this.label);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
+ dispose(){
|
|
|
+
|
|
|
+ let i = viewer.images360.panos.indexOf(this);
|
|
|
+ if(i==-1)return
|
|
|
+
|
|
|
+ this.marker.parent.remove(this.marker)
|
|
|
+
|
|
|
+
|
|
|
+ this.removeTextLabel()
|
|
|
+ if(this.depthTex) this.depthTex.dispose()
|
|
|
+ viewer.images360.panos.splice(i,1);
|
|
|
+
|
|
|
+ this.dispatchEvent('dispose')
|
|
|
+ //删除tile贴图、depthTex等以后再写
|
|
|
+ }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
-
|
|
|
+
|
|
|
|
|
|
Panorama.prototype.loadTiledPano = function() {
|
|
|
- var downloads = [] , t = [];
|
|
|
-
|
|
|
+ //var downloads = [] , t = [];
|
|
|
+ var downloaded = {} , eventAdded = {}, latestPartialRequest = {}; //每个pano对应一组这些
|
|
|
+
|
|
|
return function(size, dirs, fov, o, a, download) {
|
|
|
- var dir = dirs.find(e=>e.datasetId == this.pointcloud.dataset_id).direction;
|
|
|
+ var dir = dirs.datasetsLocal.find(e=>e.datasetId == this.pointcloud.dataset_id).direction;
|
|
|
//var dir = dirs
|
|
|
-
|
|
|
+
|
|
|
|
|
|
null !== o && void 0 !== o || (o = !0),
|
|
|
null !== a && void 0 !== a || (a = !0);
|
|
|
var l = this.getWaitDeferred(size)
|
|
|
, c = l.deferred
|
|
|
, h = null
|
|
|
- , u = null;
|
|
|
+ , u = null;
|
|
|
fov && ("number" == typeof fov ? h = fov : (h = fov.hFov, u = fov.vFov))
|
|
|
+
|
|
|
if (!this.isLoaded(size)) {
|
|
|
+ //console.log('loadTiledPano', this.id, size, fov)
|
|
|
if (!l.active) {
|
|
|
l.active = !0
|
|
|
+ let name = this.id + ":" + size
|
|
|
+ downloaded[name] = downloaded[name] || []
|
|
|
+ /*
|
|
|
+ this.downloaded = downloaded
|
|
|
+ this.latestPartialRequest = latestPartialRequest
|
|
|
+ */
|
|
|
+ latestPartialRequest[name] = null
|
|
|
+
|
|
|
if (fov) {
|
|
|
- var d = TileUtils.matchingTilesInDirection(this, size, dir, h, u);
|
|
|
- downloads[this.id + ":" + size] = {
|
|
|
- tileCount: 0,
|
|
|
- targetTileCount: d
|
|
|
- }
|
|
|
+ let tileArr = []//add
|
|
|
+ var d = TileUtils.matchingTilesInDirection(this, size, dir, h, u, tileArr);
|
|
|
+
|
|
|
+ latestPartialRequest[name] = tileArr
|
|
|
+ downloaded[name].forEach((e)=>{
|
|
|
+ let item = latestPartialRequest[name].find(a=>e.faceTileIndex == a.faceTileIndex && e.face == a.face)
|
|
|
+ if(item){
|
|
|
+ item.loaded = true
|
|
|
+ }
|
|
|
+ })
|
|
|
+ if(!latestPartialRequest[name].some(e=>!e.loaded)){//所需要的全部加载成功
|
|
|
+ //let total = TileUtils.getTileCountForSize(size)
|
|
|
+ //this.onPanoRendered(this.id, size, total, !0);
|
|
|
+ c.resolve(size/* , total */);
|
|
|
+ this.resetWaitDeferred(size)
|
|
|
+ //console.log('该部分早已经加载好了'+size, this.id)
|
|
|
+ latestPartialRequest[name] = null
|
|
|
+ }
|
|
|
+
|
|
|
//console.log("Loading partial pano: " + this.id + " with " + d + " tiles")
|
|
|
}
|
|
|
- if(!t[this.id]) {
|
|
|
- t[this.id] = !0
|
|
|
+ if(!eventAdded[this.id]) {
|
|
|
+ eventAdded[this.id] = !0
|
|
|
|
|
|
this.addEventListener(PanoramaEvents.LoadComplete, function(ev/* e, t */) {//本次任务全部加载完毕
|
|
|
+
|
|
|
+ //console.warn('点位(可能部分)下载完成 ', 'id:'+this.id, 'size:'+ev.size )
|
|
|
+
|
|
|
var i = this.getWaitDeferred(ev.size).deferred;//"pending"为还未完成
|
|
|
i && "pending" === i.state() && this.highestPartialTileRenderOpCompleted >= ev.size && (i.resolve(ev.size, ev.count),
|
|
|
this.resetWaitDeferred(ev.size))//恢复active为false
|
|
@@ -470,26 +675,62 @@ Panorama.prototype.loadTiledPano = function() {
|
|
|
}.bind(this))
|
|
|
|
|
|
this.addEventListener(PanoramaEvents.TileLoaded, function(ev/* t, i, n */) {//每张加载完时
|
|
|
- var r = this.getWaitDeferred(ev.size).deferred;
|
|
|
+
|
|
|
+ //console.log('tileLoaded', 'id:'+this.id, 'size:'+ev.size, 'tileIndex:'+ev.index )
|
|
|
+ let tileIndex = ev.index
|
|
|
+ let total = ev.count
|
|
|
+ let size = ev.size
|
|
|
+ let name = this.id + ":" + size
|
|
|
+ downloaded[name] = downloaded[name] || [] //不是所有的加载都是从loadTiledPano获取的所以会有未定义的情况
|
|
|
+
|
|
|
+ let {faceTileIndex,face} = TileUtils.getTileLocation(size, tileIndex, {})
|
|
|
+ downloaded[name].push({faceTileIndex,face})
|
|
|
+ var r = this.getWaitDeferred(size).deferred;
|
|
|
+ if (r && "pending" === r.state()) {
|
|
|
+ r.notify(size, tileIndex, total);
|
|
|
+ if(latestPartialRequest[name]){
|
|
|
+ let item = latestPartialRequest[name].find(e=>e.faceTileIndex == faceTileIndex && e.face == face)
|
|
|
+ item && (item.loaded = true )
|
|
|
+
|
|
|
+ if(!latestPartialRequest[name].some(e=>!e.loaded)){//所需要的局部tiles全部加载成功
|
|
|
+ this.onPanoRendered(this.id, size, total, !0); //onPanoRendered还会触发 PanoramaEvents.LoadComplete
|
|
|
+ r.resolve(size, total);
|
|
|
+ this.resetWaitDeferred(size)
|
|
|
+ //console.log('该部分加载好了'+size, this.id)
|
|
|
+ latestPartialRequest[name] = null
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /* var r = this.getWaitDeferred(ev.size).deferred;
|
|
|
if (r && "pending" === r.state()) {
|
|
|
r.notify(ev.size, ev.index, ev.count);
|
|
|
+
|
|
|
var o = downloads[this.id + ":" + ev.size];
|
|
|
if(o){//如果有规定下载哪些tile,只需要下载这些tile则LoadComplete
|
|
|
o.tileCount++
|
|
|
+
|
|
|
if(o.tileCount === o.targetTileCount){//达到下载目标数
|
|
|
this.onPanoRendered(this.id, ev.size, ev.count, !0);
|
|
|
r.resolve(ev.size, ev.count);
|
|
|
this.resetWaitDeferred(ev.size)
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
+ } */
|
|
|
}.bind(this))
|
|
|
}
|
|
|
}
|
|
|
this.images360.tileDownloader.clearForceQueue(),
|
|
|
- this.images360.tileDownloader.forceQueueTilesForPano(this, size, dir, h, u, download),
|
|
|
- this.tiledPanoRenderTarget = this.images360.panoRenderer.activateTiledPano(this, this.images360.qualityManager.getMaxNavPanoSize(), o),
|
|
|
+ this.images360.tileDownloader.forceQueueTilesForPano(this, size, dir, h, u, download)
|
|
|
+ this.tiledPanoRenderTarget = this.images360.panoRenderer.activateTiledPano(this, this.images360.qualityManager.getMaxNavPanoSize(), o)
|
|
|
this.images360.panoRenderer.renderPanoTiles(this.id, dirs, a)
|
|
|
+ }else{
|
|
|
+ //console.log('早已经全加载好了' +size, this.id)
|
|
|
+ c.resolve(size)
|
|
|
}
|
|
|
return c.promise()
|
|
|
}
|