import * as THREE from "../../../libs/three.js/build/three.module.js"; import {transitions, easing, lerp} from '../utils/transitions.js' import math from '../utils/math.js' let texLoader = new THREE.TextureLoader() let defaultOpacity = 0.7 let Buttons = Potree.defines.Buttons //鼠标指示小圆片 export default class Reticule extends THREE.Mesh{ constructor(viewer){ var defaultTex = texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png'/* reticule-256x256.png' */) super(new THREE.PlaneBufferGeometry(0.11,0.11,1,1),new THREE.MeshBasicMaterial({ side: THREE.DoubleSide , map: defaultTex, transparent:true, depthTest: !1, opacity: defaultOpacity, //depthWrite: !1, })) this.name = 'reticule' this.defaultTex = defaultTex this.crosshairTex = texLoader.load(Potree.resourcePath+'/textures/reticule_cross_hair.png') this.forbitTex = texLoader.load(Potree.resourcePath+'/textures/pic-forbid.png') this.defaultTex.anisotropy = 4 this.crosshairTex.anisotropy = 4 this.forbitTex.anisotropy = 4 //this.layers.set(0/* RenderLayers.RETICULE */); this.renderOrder = 100 this.layers.set(Potree.config.renderLayers.marker); this.direction = new THREE.Vector3; this.mouseLastMoveTime = Date.now(); this.hoverViewport; this.matrixMap = new Map this.matrixAutoUpdate = false this.hide(0) //viewer.inputHandler.addInputListener(this); Potree.settings.intersectWhenHover && viewer.addEventListener('global_mousemove',this.move.bind(this)) //viewer.addEventListener('global_click',this.move.bind(this)) viewer.addEventListener('global_mousedown',this.move.bind(this))//主要针对触屏 this.state = {} let startCrossStyle = ()=>{ this.state.cross = true this.judgeTex() } let endCrossStyle = ()=>{ this.state.cross = false this.judgeTex() } viewer.addEventListener('measureMovePoint',startCrossStyle) viewer.addEventListener('endMeasureMove',endCrossStyle) viewer.addEventListener('start_inserting_tag',startCrossStyle) viewer.addEventListener('endTagMove',endCrossStyle) viewer.addEventListener('reticule_forbit',(e)=>{ /* if(this.state.forbit != e.v){ console.log('change forbit ',e.v) } */ this.state.forbit = e.v this.judgeTex() }) Potree.Utils.setObjectLayers(this, 'sceneObjects' ) } judgeTex(){ if(this.state.forbit){ this.material.map = this.forbitTex }else if(this.state.cross){ this.material.map = this.crosshairTex }else{ this.material.map = this.defaultTex } viewer.mapViewer && viewer.mapViewer.dispatchEvent({type:'content_changed'}) } move(e){ if(e.type == "global_mousemove" && (e.isTouch || e.buttons != Buttons.NONE) && this.state != 'crosshair'){ return//按下时不更新,除非拖拽测量 } this.mouseLastMoveTime = Date.now() this.updatePosition(e.intersect, e.hoverViewport) } hide(duration = 500){ if(this.hidden)return this.hidden = !0 transitions.start(lerp.property(this.material , "opacity", 0, ()=>{//progress viewer.dispatchEvent('content_changed') }), duration,()=>{//done this.dispatchEvent({type:'update', visible:false}) }) this.dispatchEvent({type:'update', visible:false}) setTimeout(()=>{ },duration) } show(duration = 300){ if(!Potree.Utils.getObjVisiByReason(this, 'force'))return //console.log("show Reticule") this.hidden = !1 if(this.material.opacity <= 0){ transitions.start(lerp.property(this.material, "opacity", defaultOpacity, ()=>{//progress viewer.dispatchEvent('content_changed') }), duration,()=>{//done this.dispatchEvent({type:'update', visible:false}) }) this.dispatchEvent({type:'update', visible:true}) } } //鼠标静止一段时间它就会消失 updateVisible(){ Date.now() - this.mouseLastMoveTime > 1500 && !this.hidden && this.hide() } updateScale(viewport){ let s, camera = viewport.camera if(camera.type == "OrthographicCamera"){ var sizeInfo = this.state.cross ? {width2d:500} : {minSize : 100, maxSize : 400, nearBound : 100 , farBound : 700} s = math.getScaleForConstantSize($.extend( sizeInfo , {position:this.position, camera, resolution:viewport.resolution/* 2 */} )) }else{ let n = camera.position.distanceTo(this.position) s = 1 + .1 * n; n < 1 && (s -= 1 - n) } this.scale.set(s, s, s); } updateAtViewports(viewport){//当多个viewports时更新。更新大小等 if(viewport.name == 'magnifier' )return if(this.orthoPos && this.hoverViewport && this.hoverViewport.name == 'mapViewport' && viewport != this.hoverViewport){ //若是在地图上更新,在其他viewport要隐藏。因为在地图上无法得知高度。 Potree.Utils.updateVisible(this, 'hoverMap', false) return; } Potree.Utils.updateVisible(this, 'hoverMap', true) if(viewport.name == 'mapViewport'){ Potree.Utils.setObjectLayers(this, "bothMapAndScene") }else{//通常地图不显示reticule,只有在特殊编辑时才显示 Potree.Utils.setObjectLayers(this, 'sceneObjects') } var matrix = this.matrixMap.get(viewport) if(!matrix){ this.updateScale(viewport) this.updateMatrix(); //this.updateMatrixWorld() this.matrixMap.set(viewport, this.matrix.clone()) }else{ this.matrix.copy(matrix) //this.updateMatrixWorld() } } updatePosition(intersect, viewport ){ //在地图(当地图融合到viewer时)和场景里都显示且完全相同(大小可能不同) if (Potree.Utils.getObjVisiByReason(this, 'force')) {//没有被强制隐藏,如进入某个页面后强制不显示 if (!intersect /* || !intersect.point.normal */){ return //this.hide(); } let location = intersect.location //|| intersect.orthoIntersect.clone() let normal if(!location)return this.show( 300); normal = intersect.normal if(normal){ let ratio = /* Potree.settings.useDepthTex ? 1 : */ 0.2; this.direction = this.direction.multiplyScalar(1-ratio); this.direction.add(normal.clone().multiplyScalar(ratio)); } this.position.copy(location)/* .add(normal.clone().multiplyScalar(.01)); */ this.updateMatrix(); //lookAt之前要保证得到matrix this.lookAt(this.position.clone().add(this.direction)); this.hoverViewport = viewport //记录下最近一次hover过的viewport this.updateScale(viewport) {//存储matrix,节省计算 this.updateMatrix(); //this.updateMatrixWorld() this.matrixMap.clear();//重新计算 this.matrixMap.set(viewport, this.matrix.clone()) //别处会updateMatrixWorld } this.dispatchEvent({type:'update'}) //为什么navvis在校准数据集时每个viewport里reticule的朝向都刚好垂直于屏幕,似乎限定在了一定范围内,还是在pick时就只pick范围内的点? } } //navvis在地图等地方看reticule是有厚度的 /* updateMatrixWorld(force){ console.log('updateMatrixWorld', force) super.updateMatrixWorld(force) } */ }