123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- import * as THREE from "../../../libs/three.js/build/three.module.js";
- import DepthBasicMaterial from "../materials/DepthBasicMaterial.js";
- import math from "../utils/math.js";
- const geo = new THREE.PlaneBufferGeometry(1,1)
- export default class Sprite extends THREE.Mesh{
-
- constructor(options={}){
- super(geo, options.mat || new DepthBasicMaterial(options))/* ({map:options.map, useDepth:options.useDepth})) */
-
- this.root = options.root || this;
- this.renderOrder = options.renderOrder != void 0 ? options.renderOrder : 4;
- this.pickOrder = options.pickOrder || 0
- this.sizeInfo = options.sizeInfo
- this.dontFixOrient = options.dontFixOrient
- this.options = options
- this.position.y = options.disToLine || 0 //离线距离
-
-
- this.matrixAutoUpdate = false;
- this.matrixMap = new Map()
-
- if(this.root != this){
- this.matrixMapRoot = new Map()
- this.root.matrixAutoUpdate = false;
- }
-
-
- this.visiMap = new Map()
- this.name = options.name || 'sprite'
- this.useViewport = null
- this.viewports = options.viewports//指定更新的viewports
- this.visible_ = true
-
-
- let clear = (e)=>{
- this.matrixMap.clear()//清空后在所有viewport上都必须更新才能渲染 //this.needsUpdate = true
- }
- viewer.mapViewer && viewer.mapViewer.addEventListener("camera_changed", clear)
- viewer.addEventListener("camera_changed", clear)
- /* if(viewer.viewports.length == 1){//直接更新。如果有多个不在这更新,在"render.begin"
- this.update(e)
- } */
-
-
- let applyMatrix = (e)=>{
- this.applyMatrix(e)
- }
- viewer.addEventListener("raycaster", applyMatrix) //before render
- viewer.addEventListener("render.begin", applyMatrix) //before render
- viewer.addEventListener("render.begin2", applyMatrix)
- viewer.addEventListener("cameraSetLayers", applyMatrix)
-
-
- this.addEventListener('dispose', ()=>{
- viewer.mapViewer && viewer.mapViewer.removeEventListener("camera_changed", clear)
- viewer.removeEventListener("camera_changed", clear)
- viewer.removeEventListener("raycaster", applyMatrix) //before render
- viewer.removeEventListener("render.begin", applyMatrix)
- viewer.removeEventListener("render.begin2", applyMatrix)
-
- })
-
- }
-
- set visible(v){
- let oldV = this.visible_
- this.visible_ = v
- if(v && !oldV){
- this.matrixMap && this.matrixMap.clear() //this.update() //update内有unableCompute会无限回调
- }
- }
- get visible(){
- return this.visible_
- }
-
-
- realVisible(viewport, interactables/* , raycaster */){
- if(interactables){
- if(!interactables.some((object)=>{//interactables中是否能找到this
- let finded
- object.traverse((object)=>{
- if(object == this){
- finded = true
- return {stopContinue:true}
- }
- })
- return finded
- }))return
- }
-
- /* if(interactables && viewport.name == 'mapViewport'){
- console.log(this)
- } */
- if(!(/* raycaster || */viewport.camera).layers.test(this.layers)){//如地图上一般不可见测量线
- return false
- }
-
- if(!this.visible && this.unvisibleReasons && this.unvisibleReasons.some(e=>e.reason != 'unableCompute')){
- return false
- }
- let v = true
- let parent = this.parent
- let lastParent = this
- while(parent){
- if(parent.visible === false){
- v = false
- break;
- }
- lastParent = parent
- parent = parent.parent
- }
-
- if(v && !(lastParent instanceof THREE.Scene)){//已被删除
- v = false
- }
-
- /* if(!this.latestRealVisi && v){//变为可见后先update
- this.latestRealVisi = true
- setTimeout(()=>{
- this.update()
- },1)//延迟 防止无限调用
- return false
- }
-
- this.latestRealVisi = v */
- return v;
- }
-
- waitUpdate(){
- this.matrixMap.clear()//清空后在所有viewport上都必须更新才能渲染
- //viewer.dispatchEvent('content_changed')
- }
-
-
-
-
- update(e={}){
- if(!e.viewport){
- let viewports = this.viewports || viewer.viewports
- if(!viewports)return
- viewports.forEach(view=>{
- this.update({viewport:view})
- })
- return;
- }
- if(!this.root || ! this.realVisible(e.viewport, e.interactables) /* this.visible */ )return
- if(this.viewports && !this.viewports.includes(e.viewport) )return
- if(e.viewport.name == 'magnifier')return
-
- let camera = e.viewport.camera
- //rotation
-
- if(!this.dontFixOrient){ //orthoCamera一般要加dontFixOrient
- let orient2dAngle
-
- if(this.root.lineDir){
- this.root.updateMatrix();//先更新,getWorldPosition才能得到正确的
- this.root.updateMatrixWorld(true)
- let center = this.root.getWorldPosition(new THREE.Vector3())
- //由于两个端点容易在屏幕外,所以使用center和center加dir
- let setVisi = (state)=>{
- this.visiMap.set(e.viewport, state)
- Potree.Utils.updateVisible(this, 'unableCompute', !!state)
- }
-
-
- let r1 = Potree.Utils.getPos2d(center, e.viewport, viewer.renderArea, viewer.renderer);
- if(!r1.trueSide)return setVisi(false);// 但这句会使realVisible为false从而无法更新//console.error('!r1.trueSide') //中心点如果在背面直接不渲染了
-
- let r2, point2
-
- let p2State = '', len=1, p2StateHistory = []
- while(p2State != 'got' && p2StateHistory.length<10){
- point2 = center.clone().add(this.root.lineDir.clone().multiplyScalar(len));
-
- r2 = Potree.Utils.getPos2d(point2, e.viewport , viewer.renderArea, viewer.renderer );
- if(!r2.trueSide){ //很少遇到点2在背面的
- if(!p2StateHistory.includes('tooLong-reverse')){
- p2State = 'tooLong-reverse' //先尝试反向
- len = -len
- }else{
- p2State = 'tooLong'
- len = len / 2
- }
- }else{
- let dis = r2.pos.distanceTo(r1.pos)
- if(math.closeTo(dis,0)){
- //console.log('dis == 0')
- setVisi(false)
- return
- break
- }
- if(dis<10 && !p2StateHistory.includes('tooLong')){//和r1的屏幕距离太近,要加长,否则精度过低
- p2State = 'tooShort'
- len = 100/dis * len
- }else{
- p2State = 'got'; break;
- }
- }
- p2StateHistory.push(p2State)
- }
- //console.log(p2StateHistory,len)
-
- if(!r2.trueSide){
- return setVisi(false)//, console.log(' !r2.trueSide', )
- }
-
-
- let p1 = r1.pos, p2 = r2.pos
- if(p2StateHistory.filter(e=>e == 'tooLong-reverse').length%2 == 1){//反,for marker
- p2 = r1.pos, p1 = r2.pos
- }
-
-
- let vec = new THREE.Vector2().subVectors(p1,p2);
- orient2dAngle = -vec.angle() //根据测量线在屏幕上的角度在旋转label,使之和屏幕上的二维线平行。
-
- let y = Math.abs(this.position.y)
- let facePlane = this.root.measure && this.root.measure.facePlane
- let eyeDir = new THREE.Vector3().subVectors(center,camera.position)
- let clockWise = facePlane && facePlane.normal.dot(eyeDir/* e.viewport.view.direction */) < 0
- if(p1.x < p2.x){
- orient2dAngle += Math.PI //避免字是倒着的情况。(使字一直在线的下方)
- clockWise != void 0 && (this.position.y = clockWise ? y : -y)
- }else{
- clockWise != void 0 && (this.position.y = clockWise ? -y : y) //使area类型的edgeLabel都在外侧
- }
-
- //this.parent.text && console.log(this.parent.text, clockWise, this.position.y, e.viewport.name /* THREE.Math.radToDeg(angle), p1.x < p2.x */ )
-
-
- setVisi(true)
-
- }
-
-
- let parentQua = this.root.parent.getWorldQuaternion(new THREE.Quaternion)
- this.root.quaternion.multiplyQuaternions(parentQua.invert(),camera.quaternion) //乘上parentQua.invert()是为了中和掉父结点的qua,使只剩下camera.quaternion
-
- if(orient2dAngle){
- let qua = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), orient2dAngle)
- this.root.quaternion.multiply(qua)
- }
-
- }
-
- //scale
- var info = this.sizeInfo
- if(info){
- this.root.updateMatrix();//先更新,getWorldPosition才能得到正确的
- this.root.updateMatrixWorld(true)
-
-
- var scale
- if(info.nearBound == void 0 && info.farBound != void 0 || info.nearBound != void 0 && info.farBound == void 0){//仅限制最大或最小的话,不判断像素大小,直接限制mesh的scale
- //这个判断也可以写到getScaleForConstantSize里,可以更严谨控制像素宽度,这里只简单计算大小
- var dis = camera.position.distanceTo(this.root.getWorldPosition(new THREE.Vector3()))
- if(info.farBound == void 0 && dis < info.nearBound){
- scale = info.scale * dis / info.nearBound
- }else if(info.nearBound == void 0 && dis > info.farBound){
- scale = info.scale * dis / info.farBound
- }else{
- scale = info.scale
- }
- }else{
- scale = math.getScaleForConstantSize($.extend(info,{//规定下最小最大像素
- camera , position:this.root.getWorldPosition(new THREE.Vector3()) ,
- resolution: e.viewport.resolution//2
- }))
- }
-
- if(!isNaN(scale)){
- this.root.scale.set(scale, scale, scale);
- }
- }
-
-
- this.updateMatrix();
- //this.root.updateMatrixWorld(true)
- //console.log(this.root.text, this.root.matrix.elements)
- this.matrixMap.set(e.viewport, this.matrix.clone())
- if(this.root != this){
- this.root.updateMatrix(); //因this.position可能在两个viewport不同
- this.matrixMapRoot.set(e.viewport, this.root.matrix.clone())
- }
-
- this.needsUpdate = false
- this.useViewport = e.viewport
-
- }
-
- applyMatrix(e){
- if(!e)e = {viewport:viewer.mainViewport}//随便写一个viewport
-
- let visi = this.visiMap.get(e.viewport) //还原可见性
- Potree.Utils.updateVisible(this, 'unableCompute', visi == false ? false : true );
- /* if(e.viewport.name == 'mapViewport' && visi && this.visiMap.get(viewer.mainViewport) == false){
- console.log(1)
- } */
-
- if(e.viewport.name == 'magnifier')return
- if(this.viewports && !this.viewports.includes(e.viewport) )return
- if( !this.root || !this.realVisible(e.viewport, e.interactables) )return
-
- var matrix = this.matrixMap.get(e.viewport);
-
- if(!matrix){
- this.update(e)
- matrix = this.matrixMap.get(e.viewport);
- if(!matrix)return
- }
-
- if(e.viewport == this.useViewport){
- return
- }
- this.useViewport = e.viewport
-
- this.matrix.copy(matrix)
-
-
- if(this.root != this){
- var matrix2 = this.matrixMapRoot.get(e.viewport);
- this.root.matrix.copy(matrix2)
- }
-
- e.raycaster && this.root.updateMatrixWorld(true)//渲染前会自动updateMatrixWorld,但raycaster不会
- //console.log(this.root.name + e.viewport.name + " : "+this.root.matrixWorld.elements)
- }
-
- setUniforms(name,value){
- this.material.setUniforms(name,value)
- }
-
-
- dispose(){
- this.removeAllListeners()
- this.parent && this.parent.remove(this)
- this.dispatchEvent('dispose')
- }
- }
- /*
- let orient2d
-
- if(this.lineDir){
- this.root.updateMatrix();//先更新,getWorldPosition才能得到正确的
- this.root.updateMatrixWorld(true)
- let center = this.root.getWorldPosition(new THREE.Vector3())
- //由于两个端点容易在屏幕外,所以使用center和center加dir
- let lineDir = this.lineDir.clone();
-
-
- let r1 = Potree.Utils.getPos2d(center, camera, viewer.renderArea, e.viewport);
- if(!r1.trueSide)return Potree.Utils.updateVisible(this, 'unableCompute', false);// 但这句会使realVisible为false从而无法更新//console.error('!r1.trueSide') //中心点如果在背面直接不渲染了
-
- let r2, point2
-
- let p2State = '', len=1, p2StateHistory = []
- while(p2State != 'got' && p2StateHistory.length<10){
- point2 = center.clone().add(lineDir.multiplyScalar(len));
-
- r2 = Potree.Utils.getPos2d(point2, camera, viewer.renderArea, e.viewport);
- if(!r2.trueSide){ //很少遇到点2在背面的
- if(!p2StateHistory.includes('tooLong-reverse')){
- p2State = 'tooLong-reverse' //先尝试反向
- len = -len
- }else{
- p2State = 'tooLong'
- len = len / 2
- }
- }else{
- let dis = r2.pos.distanceTo(r1.pos)
- if(dis == 0){
- //console.log('dis == 0')
- Potree.Utils.updateVisible(this, 'unableCompute', false)
- return
- break
- }
- if(dis<10 && !p2StateHistory.includes('tooLong')){//和r1的屏幕距离太近,要加长,否则精度过低
- p2State = 'tooShort'
- len = 100/dis * len
- }else{
- p2State = 'got'; break;
- }
- }
- p2StateHistory.push(p2State)
- }
- //console.log(p2StateHistory,len)
-
- if(!r2.trueSide){
- return Potree.Utils.updateVisible(this, 'unableCompute', false)//, console.log(' !r2.trueSide', )
- }
-
- Potree.Utils.updateVisible(this, 'unableCompute', true)
- let p1 = r1.pos, p2 = r2.pos
- let vec = new THREE.Vector2().subVectors(p1,p2);
- let angle = -vec.angle() //根据测量线在屏幕上的角度在旋转label,使之和屏幕上的二维线平行。
- if(p1.x < p2.x) angle += Math.PI //避免字是倒着的情况
-
- orient2d = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), angle)
- //console.log(this.parent.text, THREE.Math.radToDeg(angle), p1.x < p2.x )
- }
- let parentQua = this.root.parent.getWorldQuaternion(new THREE.Quaternion)
- this.root.quaternion.multiplyQuaternions(parentQua.invert(),camera.quaternion) //乘上parentQua.invert()是为了中和掉父结点的qua,使只剩下camera.quaternion
- if(this.lineDir){
- this.root.quaternion.multiply(orient2d)
- }
- */
|