12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496 |
- import * as THREE from "../../../../libs/three.js/build/three.module.js";
-
- import math from "../../utils/math.js"
- import Common from '../../utils/Common.js'
- import {LineDraw, MeshDraw} from "../../utils/DrawUtil.js";
- import {ExtendView} from "../../../viewer/ExtendView.js";
- import Viewport from "../../viewer/Viewport.js";
- import Sprite from "../../objects/Sprite.js";
- import {transitions, easing, lerp} from '../../utils/transitions.js'
- import {TransformControls} from "../../objects/tool/TransformControls.js";
- import SplitScreen from "../../utils/SplitScreen.js"
- import DepthBasicMaterial from "../../materials/DepthBasicMaterial.js";
- import {BoxVolume} from '../../../utils/VolumeNew.js'
- const clickPanoToDisLink = false;//是否在编辑漫游点连接时,通过点击漫游点能断开连接
- let images360, Alignment, SiteModel, suggestCircleMat
- const texLoader = new THREE.TextureLoader()
- texLoader.crossOrigin = "anonymous"
- const rotQua = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), Math.PI)
- const lineMats = {}
- const circleMats = {}
-
- const renderOrders = {
- circleSelected:3,
- circle:2,
- line:1,
- }
- const pointColor = {
- /* selected:"#c80",
- default:'#1ac' */
- selected:"#c60",
- default:'#17c'
- }
- const opacitys = {//点云透明度
- 'topView':{
- default:0.4,
- selected: 0.6
- },
- 'sideView':{//侧面重叠概率高
- default:0.2,
- selected: 0.5
- },
- }//调这么低是因为有的重叠边缘太亮了
- const cameraProps = [
- {
- name : 'top',
- axis:["x","y"],
- direction : new THREE.Vector3(0,0,-1), //镜头朝向
- openCount:0,
- },
- {
- name : 'right',
- axis:["y","z"],
- direction : new THREE.Vector3(1,0,0),
- openCount:0,
- },
- {
- name : 'mainView',
- openCount:0,
- }
- ]
- class PanoEditor extends THREE.EventDispatcher{
-
- constructor(){
- super()
- this.panoGroup = [], //分组
- this.viewports = {},
- this.panoLink = {},
- this.panoMeshs = new THREE.Object3D,
- this.lineMeshes = new THREE.Object3D
- this.views = {}
- this.cameras = {}
- this.orthoCamera = new THREE.OrthographicCamera(-100, 100, 100, 100, 0.01, 10000)
- this.orthoCamera.up.set(0,0,1)
- this.selectedPano;
- this.selectedGroup;
- this.operation;
- this.visiblePanos = []
-
- this.suggestLines = []
- }
-
- init(){
-
-
- {//init lineMats
- lineMats.default = LineDraw.createFatLineMat({
- color: '#eeeeee',
- lineWidth: 2,
- depthTest:false
- })
- lineMats.hovered = LineDraw.createFatLineMat({
- color: '#00c8af',
- lineWidth: 2,
- depthTest:false
- })
- lineMats.selected = LineDraw.createFatLineMat({
- color: '#00c8af',
- lineWidth: 3,
- depthTest:false
- })
- lineMats.suggestLink = LineDraw.createFatLineMat({
- color: '#ff2222',
- lineWidth: 4, dashed:true,
- depthTest:false
- })
- }
-
- suggestCircleMat = new THREE.MeshBasicMaterial({
- map: texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' ) ,
- color:'#ff2222', transparent:true,
- depthTest:false, depthWrite:false
- })
-
- this.initViews()
-
-
-
- /* {
- this.box = new BoxVolume({
- clip:true
- })
- this.box.clipTask = ClipTask['SHOW_INSIDE_Big' ]
-
- this.box.name = "panoEditClipBox";
-
- } */
-
- viewer.addEventListener('allLoaded',()=>{
- images360 = viewer.images360
- Alignment = viewer.modules.Alignment
- SiteModel = viewer.modules.SiteModel
-
- this.panoMeshs.name = 'panoMeshs'
- viewer.scene.scene.add(this.panoMeshs)
- this.lineMeshes.name = 'lineMeshes'
- viewer.scene.scene.add(this.lineMeshes)
-
- Potree.settings.ifShowMarker = false
-
- {
- this.transformControls = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
- dontHideWhenFaceCamera: true,
- rotFullCircle:true
- });
- this.transformControls.setSize(1.5)
- viewer.scene.scene.add(this.transformControls)
- this.transformControls._gizmo.hideAxis = {/* translate:['x','y'], */ rotate:['x','y','e'] }
- this.transformControls.setRotateMethod(2)
-
- this.fakeMarkerForTran = new THREE.Mesh(new THREE.BoxBufferGeometry(0.3,0.3,0.3) , new THREE.MeshBasicMaterial({
- color:"#FFFFFF", opacity:0.4, transparent:true, visible:false
- }));//一个看不见的mesh,只是为了让transformControls移动点云
- viewer.scene.scene.add(this.fakeMarkerForTran)
-
-
-
- let afterMoveCircle = (type)=>{
-
- if(type == 'position'){
- let moveVec = new THREE.Vector3().subVectors(this.fakeMarkerForTran.position, this.fakeMarkerForTran.oldState.position)
- this.selectedClouds.forEach(cloud=>Alignment.translate(cloud, moveVec))
- }else{
- let center = this.selectedPano.position;
- let forward = new THREE.Vector3(0,1,0);
- let vec1 = forward.clone().applyQuaternion(this.fakeMarkerForTran.oldState.quaternion)
- let vec2 = forward.clone().applyQuaternion(this.fakeMarkerForTran.quaternion)
-
- let diffAngle = math.getAngle(vec1,vec2,'z')
-
- this.selectedClouds.forEach(cloud=>{
- Alignment.rotateAround(center, cloud, null, diffAngle)
- })
- }
-
-
- this.fakeMarkerForTran.oldState = {
- position: this.fakeMarkerForTran.position.clone(),
- quaternion: this.fakeMarkerForTran.quaternion.clone(),
- }
-
- Alignment.history.beforeChange(this.selectedClouds)
- }
-
- this.fakeMarkerForTran.addEventListener('position_changed', afterMoveCircle.bind(this,'position'))
- this.fakeMarkerForTran.addEventListener("rotation_changed", afterMoveCircle.bind(this,'rotation') )
-
- this.transformControls.addEventListener('transform_end',()=>{
- Alignment.history.afterChange(this.selectedClouds)
- })
-
- Alignment.history.addEventListener('undo',()=>{
- this.updateTranCtl()
- })
- }
-
-
-
- this.initPanoLink()
-
- this.addPanoMesh()
-
-
- viewer.scene.pointclouds.forEach(e=>{
- e.material.color = pointColor.default
- })
- viewer.setEDLEnabled(true) //为了降一倍的绘制. 同时用描边增强立体感,弥补点云稀疏
- viewer.setEDLRadius(3)
- viewer.setEDLStrength(0.02)
-
-
-
- this.switchView('top')
-
- {//默认选择一个楼层
- let panoVisiReady, siteModelReady;
- let floorInit = ()=>{
- if(!panoVisiReady || !siteModelReady)return
- setTimeout(()=>{
- if(this.currentFloor == 'all'){//还未选择楼层的话
- let floor = SiteModel.entities.find(e=>e.buildType == 'floor' && e.panos.length) //选择有漫游点的一层
- if(!floor){
- floor = 'all' //SiteModel.entities.find(e=>e.buildType == 'floor')
- console.log('没有一层有漫游点?!')
- }
- console.log('initDataDone')
-
- console.log('gotoFloor 1')
- this.gotoFloor(floor)
- }
- },1) //2d那边用了nextTick ,so setTimeout here
- }
-
- SiteModel.bus.addEventListener('initDataDone',()=>{
- siteModelReady = true;
- floorInit()
- },{once:true})
- this.addEventListener('panoVisiReady',()=>{//2d初始化完成,才可以由3d修改pano显示 (因为在之前2d会给每个pano传来显示的消息,在这之前的修改都会别覆盖)
- panoVisiReady = true
- floorInit()
- },{once:true})
- }
-
- Alignment.bus.addEventListener('switchHandle', this.updateCursor.bind(this))
-
-
- viewer.addEventListener('global_click',(e)=>{
- if(e.button === THREE.MOUSE.RIGHT){//取消旋转和平移
- //console.log('right click',e)
- this.setLinkOperateState('addLink',false)
- this.setLinkOperateState('removeLink',false)
- }else if(this.clickToZoomInEnabled){
- if(this.activeViewName == 'mainView'){
- viewer.controls.zoomToLocation(e.mouse)
- }else{
- this.zoomIn(e.intersect.orthoIntersect, e.pointer)
- }
-
-
- this.setZoomInState(false)
- }
- })
-
-
-
- /* {//旋转时的辅助线--绕某个点旋转的版本
- this.rotGuideLine = LineDraw.createLine([], {color:'#aaffee'})
- this.rotGuideLine.visible = false
- this.rotGuideLine.name = 'rotGuideLine'
- this.rotGuideLine.renderOrder = renderOrders.line
- viewer.scene.scene.add(this.rotGuideLine)
- let startPoint
- Alignment.bus.addEventListener('rotateStart', (e)=>{
- startPoint = e.startPoint
- })
- Alignment.bus.addEventListener('rotate', (e)=>{
- LineDraw.updateLine(this.rotGuideLine, [startPoint, e.endPoint] )
- this.rotGuideLine.visible = true
- })
- viewer.fpControls.addEventListener("end",(e)=>{
- startPoint = null
- this.rotGuideLine.visible = false
- })
- } */
-
- {//连接时的辅助线
- this.linkGuideLine = LineDraw.createLine([], {color:'#ddd', deshed:true, dashSize:0.1,gapSize:0.05, depthTest:false})
- this.linkGuideLine.visible = false
- this.linkGuideLine.name = 'linkGuideLine'
- viewer.scene.scene.add(this.linkGuideLine)
- this.linkGuideLine.renderOrder = renderOrders.line
- let update = (e)=>{
- if(this.operation != 'addLink' || this.activeViewName != 'top' && this.activeViewName != 'mainView' ||!this.selectedPano){
- return this.linkGuideLine.visible = false
- }
- let endPos
- if(this.activeViewName == 'top' ){
- endPos = e.intersect.orthoIntersect.clone().setZ(this.selectedPano.position.z)
- }else if(this.activeViewName == 'mainView' ){
- if(!e.intersect || !e.intersect.point)return
- endPos = e.intersect.point.position
- }
-
- LineDraw.updateLine(this.linkGuideLine, [this.selectedPano.position, endPos] )
- this.linkGuideLine.visible = true
-
- viewer.dispatchEvent('content_changed')
- }
-
- viewer.addEventListener('global_mousemove', (e)=>{
- update(e)
- })
-
- //this.addEventListener('updateLinkGuideLine', update)
-
- }
-
- /*
- viewer.inputHandler.addEventListener('keydown', (e)=>{
- if(e.event.key == "r" ){
- this.setTranMode('rotate')
- }else if(e.event.key == "t"){
- this.setTranMode('translate')
- }
- }) */
- /* {
- viewer.addEventListener('camera_changed', (e)=>{
- Common.intervalTool.isWaiting('updatePointLevels', ()=>{
- this.updatePointLevels()
- }, 1050)
- })
- setTimeout(()=>{
- this.updatePointLevels()
- }, viewer.scene.pointclouds.length*150) //等待差不多updat出了正确的visibleNode时
- } */
-
-
-
- this.panoReposCallback = ()=>{
- viewer.controls.setTarget(this.selectedPano.position) //3d时绕其为中心转动
- }
- })
- }
-
-
- setTranMode(mode){//rotate or translate
- console.log('setTranMode',mode)
- this.tranMode = mode
- if(this.activeViewName == 'mainView'){
- mode && this.transformControls.setMode(mode)
- this.updateTranCtl()
- }else{
- Alignment.switchHandle(mode)
- }
- this.updateIntersectEnable()
- }
-
- updateIntersectEnable(){
- //侧面容易因intersect卡住, 如果非必要关闭intersect. 3d页面也会卡,但controls需要所以不能去掉
- Potree.settings.intersectWhenHover = !!(this.activeViewName == 'mainView' || this.selectedPano && this.tranMode )
-
- }
-
- updateTranCtl(){// 设置3D页面的transformControls相关
- if(!this.tranMode || !this.selectedPano || this.activeViewName != 'mainView' ) {
- return this.transformControls.detach()
- }else if(this.checkIfAllLinked({group:this.selectedGroup})){
- this.dispatchEvent('needToDisConnect')
- return this.transformControls.detach()
- }
- this.transformControls.attach(this.fakeMarkerForTran)
- let {position, quaternion} = this.getPanoPose(this.selectedPano);
- this.fakeMarkerForTran.position.copy(position)
- this.fakeMarkerForTran.quaternion.copy(quaternion)
- this.fakeMarkerForTran.oldState = {
- position: position.clone(),
- quaternion: quaternion.clone(),
- }
- }
-
-
-
- //////////////////////////////////
- initViews(){
- this.splitScreenTool = new SplitScreen
- this.targetPlane = viewer.mainViewport.targetPlane = new THREE.Plane()
- this.shiftTarget = viewer.mainViewport.shiftTarget = new THREE.Vector3 //project在targetPlane上的位置
-
-
- for(let i=0;i<2;i++){
- let prop = cameraProps[i];
- let view = new ExtendView()
- this.views[prop.name] = view
- this.cameras[prop.name] = this.orthoCamera
- view.name = prop.name
- view.direction = prop.direction
- }
- this.views.mainView = viewer.mainViewport.view
- this.cameras.mainView = viewer.mainViewport.camera
-
-
- }
-
- switchView(name ){//替换view和camera到mainViewport
-
- let view = this.views[name]
- let camera = this.cameras[name]
- let prop = cameraProps.find(e=>e.name == name)
-
- let {boundSize, center} = viewer.bound
- this.lastViewName = this.activeViewName
- this.activeViewName = name
- let lastView = this.views[this.lastViewName]
- let lastCamera = this.cameras[this.lastViewName]
- viewer.mainViewport.view = view
- viewer.mainViewport.camera = camera
- if(lastCamera)lastView.zoom = lastCamera.zoom
-
- this.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), center )
- this.targetPlane.projectPoint(view.position, this.shiftTarget ) //target转换到过模型中心的平面,以保证镜头一定在模型外
- view.position.copy(this.splitScreenTool.getPosOutOfModel(viewer.mainViewport))
- if(view.zoom)camera.zoom = view.zoom//恢复上次的zoom
-
-
-
- viewer.updateScreenSize({forceUpdateSize:true})//更新camera aspect left等
- this.updateCursor()
-
- if(name == 'mainView'){
- viewer.mainViewport.alignment = null
-
- let changeMat = ()=>{
- viewer.scene.pointclouds.forEach(e=>{
- e.material.activeAttributeName = 'rgba'
- e.material.useFilterByNormal = false
- e.changePointOpacity(1 )
- })
- }
- /* if(prop.openCount == 0){ //点数较多时,首次转到3D视角会卡顿,因为要切换材质。
- let delay1 = THREE.Math.clamp(viewer.scene.pointclouds.length*0.5, 1, 200)
- setTimeout(()=>{
- this.activeViewName == 'mainView' && changeMat()
- },delay1)
- //console.log('switchview',delay1 )
- }else{ */
- changeMat()
- //}
-
-
-
- Potree.Utils.updateVisible(viewer.reticule, 'force', true)
-
- if(lastView){//2d->3d
-
- view.copy(lastView)
-
- let direction = view.direction
- let panos = images360.panos.filter(e=>e.circle.visible)
- let nearestPano = Common.sortByScore(panos , [], [(pano)=>{
- let vec = new THREE.Vector3().subVectors(pano.position, view.position);
- return -vec.dot(direction);
- }], true);
-
- //console.log('最近',nearestPano )
-
- if(nearestPano && nearestPano[0] ){ //尽量不变画面范围,使pano点保持原位,转换到mainView
- let halfHeight = lastCamera.top/lastCamera.zoom
- let dis = halfHeight / Math.tan( THREE.Math.degToRad(camera.fov/2))
- view.position.add(direction.clone().multiplyScalar(-nearestPano[0].score - dis))
- //console.log('getCloser', -nearestPano[0].score - dis)
- this.lastDisToPano = dis //记录一下
- }
-
- }
-
- viewer.fpControls.lockKey = false
-
- }else{
-
- if(this.lastViewName == 'mainView'){//3d->2d
- let direction = lastView.direction
- let panos = images360.panos.filter(e=>e.circle.visible)
-
- //尽量靠近画布中心,且距离相机较近
- let nearestPano = Common.sortByScore(panos , [], [(pano)=>{
- let vec = new THREE.Vector3().subVectors(pano.position, lastView.position);
- let dis = vec.dot(direction);
- return dis < 0 ? dis * 10 : - dis
- },(pano)=>{
- let vec = new THREE.Vector3().subVectors(pano.position, lastView.position);
- let angle = vec.angleTo(direction)
- return - angle * 70
- }], true);
- //目前还存在的问题就是不知selectedPano和最近点的取舍
- //console.log('panos',nearestPano )
- if(nearestPano && nearestPano[0] ){
- //console.log('nearestPano',nearestPano[0].item.id )
- let pos1 = nearestPano[0].item.position.clone()
- let pos2 = pos1.clone()
- let dis = new THREE.Vector3().subVectors(nearestPano[0].item.position, lastView.position).dot(direction) //-nearestPano[0].score
-
- //根据2d->3d的式子逆求zoom
- let halfHeight = Math.abs(dis) * Math.tan( THREE.Math.degToRad(lastCamera.fov/2))
- camera.zoom = camera.top / halfHeight
- camera.updateProjectionMatrix()
-
- if(name == 'right'){//侧视图
- view.direction = direction.clone().setZ(0) //水平方向设定为3d的方向
- this.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), center )
- this.targetPlane.projectPoint(view.position, this.shiftTarget ) //target转换到过模型中心的平面,以保证镜头一定在模型外
- view.position.copy(this.splitScreenTool.getPosOutOfModel(viewer.mainViewport))
- }
-
- view.applyToCamera(camera)//update
-
- pos1.project(lastCamera)
- pos2.project(camera)
-
-
- //目标是找到画面上最接近中心的一点(最好是漫游点,不然就是点云),让其在转换画面后在画面上的位置不变。万一找到的点不在屏幕中(比如当屏幕中没点云时),就默认让那个点移动到屏幕中央,也就是假设当前它pos1在屏幕中央位置。
-
- //
- if(pos1.z>1){
- console.warn('选取的点在相机背后了!?')
- }
- //如果最近点超出屏幕范围 (-1,1), 最好将其拉到边缘,甚至居中 。这样屏幕上就不会没有漫游点了
- let bound = 0.9
- pos1.x = THREE.Math.clamp(pos1.x, -bound, bound)
- pos1.y = THREE.Math.clamp(pos1.y, -bound, bound)
-
-
-
- let vecOnscreen = new THREE.Vector3().subVectors(pos1,pos2)
- let moveVec = Potree.Utils.getOrthoCameraMoveVec(vecOnscreen, camera )
-
- //console.log('pos1', pos1)
-
- view.position.sub(moveVec)
- }
-
- }else{
- if(prop.openCount == 0){//至多执行一次
- this.viewportFitBound(name, boundSize, center)
- }
- }
-
-
-
-
-
- viewer.scene.pointclouds.forEach(e=>{
- e.material.activeAttributeName = 'color'
- e.material.useFilterByNormal = true
-
- let opaProp = name == 'top' ? opacitys.topView : opacitys.sideView
- if(this.selectedPano && this.selectedClouds.includes(e) ){
- e.changePointOpacity(opaProp.selected,true)
- e.material.color = pointColor.selected;
- }else{
- e.changePointOpacity(opaProp.default,true)
- e.material.color = pointColor.default;
- }
-
- })
- Potree.Utils.updateVisible(viewer.reticule, 'force', false)
-
- if(name == 'top') viewer.mainViewport.alignment = {rotate:true,translate:true};
- if(name == 'right'){
- viewer.mainViewport.alignment = {translate:true, rotateSide:true, translateVec:new THREE.Vector3(0,0,1)}; //只能上下移动
- viewer.mainViewport.rotateSide = true
- }else{
- viewer.mainViewport.rotateSide = false
- }
- viewer.fpControls.lockKey = true
-
- }
-
-
-
- this.updateTranCtl()
- this.setTranMode(this.tranMode) // update
- this.setZoomInState(false) //取消放大模式
- //this.updatePointLevels()
-
- this.updateIntersectEnable()
-
- prop.openCount ++;
- }
-
-
-
- viewportFitBound(){ //使一个viewport聚焦在某个范围
-
- if(viewer.mainViewport.resolution.x == 0 || viewer.mainViewport.resolution.y == 0){
- return setTimeout(()=>{
- this.viewportFitBound()
- },10)
- }
-
- this.gotoFloor(this.currentFloor, true, 0, null, true)
-
- }
-
-
- rotateSideCamera(angle){//侧视图绕模型中心水平旋转
- this.splitScreenTool.rotateSideCamera(viewer.mainViewport, angle)
- }
-
-
- zoomIn(intersect, pointer){
- let camera = viewer.mainViewport.camera
- let endZoom = 200
- //this.orthoMoveFit(intersect, {endZoom:viewer.mainViewport.camera.zoom < aimZoom ? aimZoom : null} , 300)
- let startZoom = camera.zoom
- if(startZoom >= endZoom){return}
-
- viewer.mainViewport.view.zoomOrthoCamera(camera, endZoom, pointer, 300)
-
- }
-
- orthoMoveFit(pos, info, duration){
- var margin = {x:200, y:230}
- this.splitScreenTool.viewportFitBound(viewer.mainViewport, info.bound, pos, duration, margin )
-
- }
-
- setZoomInState(state, informinformBy2d){//是否点击后可放大
- //if(state && this.activeViewName == 'mainView')return console.log('3D不可放大')
- this.clickToZoomInEnabled = !!state
-
-
- if(state){
- viewer.dispatchEvent({type : "CursorChange", action : "add", name:"zoomInCloud"} )
- }else{
- viewer.dispatchEvent({type : "CursorChange", action : "remove", name:"zoomInCloud" })
- }
-
- if(!state && !informinformBy2d){
- this.dispatchEvent({type:'operationCancel', operation: 'zoomIn'})
- }
-
-
- }
-
-
- gotoFloor(floor, force, duration = 600, informBy2d, fitBound=true){// 选择不同楼层, 切换点位显示。 'all'为全部显示
-
- floor = floor || 'all'
-
- if(this.currentFloor == floor && !force)return
-
-
- if(this.currentFloor != floor){//如果楼层没变,不修改可视
- //let pointclouds = viewer.findPointcloudsAtFloor(floor)
- let panos = floor == 'all' ? viewer.images360.panos : floor.panos
-
- viewer.images360.panos.forEach(pano=>{
- let v = panos.includes(pano)
- this.switchPanoVisible(pano,v)
- })
- }
-
- this.updateLinesVisible()
-
-
- //切换楼层时清空选择状态
- if(this.selectedPano && floor != 'all' && !floor.panos.includes(this.selectedPano)){
- this.selectedPano.circle.dispatchEvent('click')
- }
-
- if(this.selectedLine){
- this.selectedLine.dispatchEvent('click')
- }
-
-
-
- let bound, center
- if(floor == 'all'){
- bound = viewer.images360.bound.bounding
- center = viewer.images360.bound.center
- }else{
- bound = this.getPanosBound(floor)
- center = bound.getCenter(new THREE.Vector3())
- if(floor.panos.length == 0)console.log(floor.name, 'floor无漫游点' )
- }
-
- if(this.activeViewName != 'mainView' ){
- fitBound && this.orthoMoveFit(center, {bound}, duration)
- }else if(this.activeViewName == 'mainView'){
- //if(floor != 'all'){ //切换一下位置,因为原处点云会消失
- //viewer.scene.view.setView({position:center, duration })
- viewer.focusOnObject({boundingBox:bound},'boundingBox')
- //}
- }
-
- this.currentFloor = floor
-
- //if(!informBy2d){ //注释原因:2d居然不会自己变
- this.dispatchEvent({type:'changeFloor', floor})
- //}
- }
-
- getPanosBound(floor){
- if(!floor.panosBound){
- if(floor.panos.length == 0){
- floor.panosBound = viewer.images360.bound.bounding.clone()
- }else{
- let minSize = new THREE.Vector3(10,10,10)
- let bound = math.getBoundByPoints(floor.panos.map(e=>e.position), minSize)
- floor.panosBound = bound.bounding
- }
- }
-
- return floor.panosBound
- }
-
-
-
- switchPanoVisible(pano, v, informBy2d){
- //console.log(pano.id,v)
- pano.circle.visible = v
- Potree.Utils.updateVisible(pano, 'panoEditor', v)
- Potree.Utils.updateVisible(pano.pointcloud, 'panoEditor', v)
- if(v){
- this.visiblePanos.includes(pano) || this.visiblePanos.push(pano)
- }else{
- let index = this.visiblePanos.indexOf(pano);
- index>-1 && this.visiblePanos.splice(index,1)
- }
-
- if(informBy2d){
- this.dispatchEvent('panoVisiReady')
- this.updateLinesVisible()
- }
-
- informBy2d || this.dispatchEvent({type:"switchPanoVisible", pano, v})
-
- /* {
- setTimeout(()=>{
- Common.intervalTool.isWaiting('updatePointLevels2', ()=>{
- this.updatePointLevels()
- }, 50)
- },1)//等update过visibleNodes
- } */
- }
-
-
- updateLinesVisible(){
- this.lineMeshes.children.forEach(line=>{
- let names = line.name.split('-')
- var pano0 = images360.getPano(names[0])
- var pano1 = images360.getPano(names[1])
- line.visible = this.visiblePanos.includes(pano0) || this.visiblePanos.includes(pano1)
- })
- }
-
- updateCursor(){
- let cursor
-
-
- if(this.activeViewName == 'mainView' || !this.selectedPano){
- cursor = null
- }else{
- cursor = Alignment.handleState
- }
-
- if(cursor == 'rotate'){
- viewer.dispatchEvent({
- type : "CursorChange", action : "add", name:"rotatePointcloud"
- })
- viewer.dispatchEvent({
- type : "CursorChange", action : "remove", name:"movePointcloud"
- })
-
- }else if(cursor == 'translate'){
- viewer.dispatchEvent({
- type : "CursorChange", action : "add", name:"movePointcloud"
- })
- viewer.dispatchEvent({
- type : "CursorChange", action : "remove", name:"rotatePointcloud"
- })
- }else{
- viewer.dispatchEvent({
- type : "CursorChange", action : "remove", name:"movePointcloud"
- })
- viewer.dispatchEvent({
- type : "CursorChange", action : "remove", name:"rotatePointcloud"
- })
- }
- //this.cursorState = cursor
- }
-
-
-
- setLinkOperateState(name, state, informinformBy2d){
-
- if(state && name == this.operation || !state && name != this.operation)return
-
- let old = this.operation
- this.operation = state ? name : null
-
- if(this.operation == 'removeLink'){
- if(this.selectedLine){
- this.selectedLine.dispatchEvent('click')//删除
- }
- if(this.selectedPano && clickPanoToDisLink){
- this.selectedPano.circle.dispatchEvent('click')//删除
- }
- }
-
- if(this.operation != 'addLink'){
- this.linkGuideLine.visible = false
- }
- if(!state && !informinformBy2d){
- this.dispatchEvent({type: "operationCancel", operation: old})
-
- }
-
- if(this.operation == 'addLink'){
- viewer.dispatchEvent({type : "CursorChange", action : "add", name:"connectPano"} )
- }else{
- viewer.dispatchEvent({type : "CursorChange", action : "remove", name:"connectPano"} )
- }
- if(this.operation == 'removeLink'){
- viewer.dispatchEvent({type : "CursorChange", action : "add", name:"disconnectPano"} )
- }else{
- viewer.dispatchEvent({type : "CursorChange", action : "remove", name:"disconnectPano"} )
- }
- viewer.dispatchEvent('content_changed')
- }
-
-
-
-
- /////////////////////////////////
-
- initPanoLink(){
- images360.panos.forEach((pano)=>{
- this.panoLink[pano.id] = {}
- this.panoGroup.push([pano])
- })
-
- images360.panos.forEach((pano)=>{
- pano.visibles.forEach(index=>{//visibles中存的是下标!
- this.linkChange(pano, images360.getPano(index,'index'), 'add')
- })
- })
-
- //console.log('panoLink',this.panoLink)
- }
-
-
-
- linkChange(pano0, pano1, type){//修改link (type == 'remove'时,pano1可以为空)
-
-
- let temp = []
-
- if(type == 'add'){
- if(!pano1)return console.error('不支持add时pano1为空')
- this.panoLink[pano0.id][pano1.id] = this.panoLink[pano0.id][pano1.id] || {}
- this.panoLink[pano1.id][pano0.id] = this.panoLink[pano1.id][pano0.id] || {}
- }else{
- if(!pano1){
- for(let id in this.panoLink[pano0.id]){
- if(this.panoLink[pano0.id][id]){
- this.panoLink[id][pano0.id] = false
- temp.push(id)
- }
- }
- this.panoLink[pano0.id] = {} //全部断连
- }else{
- this.panoLink[pano0.id][pano1.id] = false
- this.panoLink[pano1.id][pano0.id] = false
- }
- }
-
- if(!pano1){ //全部断连
- temp.forEach(id=>{
- this.lineChange(pano0, images360.getPano(id) , type)
- })
- }else{
- this.lineChange(pano0, pano1, type)
- }
-
- this.groupChange(pano0, pano1, type)
-
- //this.updateSelectGroup()
- this.selectPano(this.selectedPano, false,true) //更新选中点云显示
- }
-
-
-
-
- lineChange(pano0, pano1, type){//修改line
- if(type == 'add'){
- if(this.panoLink[pano0.id][pano1.id].line) return
- let line = LineDraw.createFatLine([pano0.position, pano1.position], {mat:lineMats.default})
- line.name = `${pano0.id}-${pano1.id}`
- line.renderOrder = line.pickOrder = renderOrders.line
- this.lineMeshes.add(line)
- this.panoLink[pano0.id][pano1.id].line = this.panoLink[pano1.id][pano0.id].line = line
-
-
- line.addEventListener('mouseover', ()=>{
- if(this.clickToZoomInEnabled)return
- //if(this.activeViewName == 'mainView')return
- if(this.selectedLine != line)line.material = lineMats.hovered
- viewer.dispatchEvent({
- type : "CursorChange", action : "add", name:"hoverLine"
- });
- });
- line.addEventListener('mouseleave', ()=>{
- if(this.clickToZoomInEnabled)return
- //if(this.activeViewName == 'mainView')return
- if(this.selectedLine != line)line.material = lineMats.default
- viewer.dispatchEvent({
- type : "CursorChange", action : "remove", name:"hoverLine"
- });
- });
- line.addEventListener('click', (e)=>{
- if(this.clickToZoomInEnabled)return
- //if(this.activeViewName == 'mainView')return
- if(this.operation == 'removeLink'){
- if(this.selectedLine == line) this.selectLine(null)
- return this.linkChange(pano0, pano1, 'remove')
- }
- this.selectLine(line)
- })
- }else{
- let line = this.lineMeshes.children.find(e=>e.name == `${pano0.id}-${pano1.id}` || e.name == `${pano1.id}-${pano0.id}` )
- if(line){
- this.lineMeshes.remove(line)
- line.geometry.dispose()
- }
-
- }
-
- }
-
-
-
- groupChange(pano0, pano1, type){//修改group (type == 'remove'时,pano1可以为空)
- if(type == 'add'){
- Common.pushToGroupAuto([pano0, pano1], this.panoGroup )
- }else{
- let atGroup = this.panoGroup.find(e=>e.includes(pano0) && (e.includes(pano1) || !pano1));//所在组
-
- if(!atGroup){
- if(pano1){
- console.log('这两个pano原本就不在一个组', pano0.id, pano1.id)
- }else{
- console.log('pano0不在任何组', pano0)
- }
- return
- }
-
- //断开连接时,因为组内没有其他成员的连接信息,所以需要清除整组,并将剩余的一个个重新连接
- this.panoGroup.splice(this.panoGroup.indexOf(atGroup),1) //删除
-
-
- atGroup.forEach(pano=>{//然后再重新生成这两个和组的关系,各自分组
- this.panoGroup.push([pano])
- for(let id in this.panoLink[pano.id]){
- if(this.panoLink[pano.id][id]){
- let pano_ = images360.getPano(id)
- Common.pushToGroupAuto([pano, pano_], this.panoGroup )
- }
- }
- })
- }
- }
-
-
-
-
- selectLine(line){
- if(this.selectedLine == line)return
- if(this.selectedLine){
- this.selectedLine.material = lineMats.default;
- }
- if(line){
- line.material = lineMats.selected
- }
- this.selectedLine = line
- }
-
-
-
-
-
-
- addPanoMesh(){
- let map = texLoader.load(Potree.resourcePath+'/textures/correct_n.png' )
- /* circleMats.default_normal = new THREE.MeshBasicMaterial({
- map,
- color: 0xffffff,
- transparent: true,
- depthTest: false,
- depthWrite: false,
- }) */
- window.circleMats = circleMats
-
- circleMats.default_normal = new DepthBasicMaterial({
- map,
- color: 0xffffff,
- transparent: true,
- useDepth:true,
- backColor: 0x33ffdd,
- occlusionDistance: 10,//变为backColor距离
- clipDistance : 5,//消失距离
- maxClipFactor: 0.8,
- maxOcclusionFactor: 0.8,
- })
- circleMats.default_rtk_on = circleMats.default_normal.clone();
- circleMats.default_rtk_on.map = texLoader.load(Potree.resourcePath+'/textures/rtk-y-n.png' )
- circleMats.default_rtk_off = circleMats.default_normal.clone();
- circleMats.default_rtk_off.map = texLoader.load(Potree.resourcePath+'/textures/rtk-f-n.png' )
- circleMats.selected_normal = circleMats.default_normal.clone();
- circleMats.selected_normal.map = texLoader.load(Potree.resourcePath+'/textures/correct_s.png' )
- circleMats.selected_normal.useDepth = false;
- circleMats.selected_rtk_on = circleMats.selected_normal.clone();
- circleMats.selected_rtk_on.map = texLoader.load(Potree.resourcePath+'/textures/rtk-y-s.png' )
- circleMats.selected_rtk_off = circleMats.selected_normal.clone();
- circleMats.selected_rtk_off.map = texLoader.load(Potree.resourcePath+'/textures/rtk-f-s.png' )
-
- circleMats.hovered_normal = circleMats.default_normal.clone();
- circleMats.hovered_normal.color.set(0x00ff00)
- circleMats.hovered_normal.useDepth = false
- circleMats.hovered_rtk_on = circleMats.default_rtk_on.clone();
- circleMats.hovered_rtk_on.color.set(0x00ff00)
- circleMats.hovered_rtk_on.useDepth = false
- circleMats.hovered_rtk_off = circleMats.default_rtk_off.clone();
- circleMats.hovered_rtk_off.color.set(0x00ff00)
- circleMats.hovered_rtk_off.useDepth = false
-
-
-
-
-
- let setPos = (circle)=>{
- circle.position.copy(circle.pano.position)
-
- for(let id in this.panoLink[circle.pano.id]){
- let linkInfo = this.panoLink[circle.pano.id][id]
- if(linkInfo){
- LineDraw.updateLine(linkInfo.line, [circle.pano.position, images360.getPano(id).position] )
- }
- }
-
- circle.update() //update sprite Matrix
-
- }
-
-
-
- images360.panos.forEach(pano=>{
- var circle = new Sprite({mat: circleMats['default' + '_'+ this.getPanoRtkState(pano) ] , sizeInfo:{
- minSize : 50 , maxSize : 120, nearBound : 2, farBound : 10,
- },
- renderOrder : renderOrders.circle,
- pickOrder: renderOrders.circle
- })
- circle.pickDontCheckDis = true
- circle.name = 'panoCircle'
- circle.sid = pano.id
- circle.pano = pano;
- pano.circle = circle;
-
- this.panoMeshs.add(circle)
-
-
- setPos(circle)
- pano.addEventListener('rePos', setPos.bind(this,circle))
-
- let drag = ()=>{
- /* if(this.activeViewName == 'mainView' && this.tranMode == 'translate'){//如果3d页不禁止xy的话,这段打开
- this.transformControls.dispatchEvent('dragging')//触发拖拽
- return
- } */
- if(this.tranMode != 'translate' || this.activeViewName == 'mainView')return
- this.selectPano(circle.pano) //为了方便拖拽点云,拖动circle就直接选中
-
- viewer.inputHandler.drag.object = null //取消拖拽状态,否则不触发点云拖动
- }
- circle.addEventListener('drag', drag)
-
-
-
- circle.addEventListener('mouseover', ()=>{
- this.hoverPano(pano,true)
- })
- circle.addEventListener('mouseleave', ()=>{
- this.hoverPano(pano,false)
- })
- circle.addEventListener('click', ()=>{
- //if(this.activeViewName == 'mainView')return
- if(this.clickToZoomInEnabled)return
- if(clickPanoToDisLink && this.operation == 'removeLink'){
- this.linkChange(pano, null, 'remove') //删除所有连接
- }
-
- if(this.selectedPano == circle.pano) return this.selectPano(null)
- if(this.operation == 'addLink' && this.selectedPano){
- this.linkChange(this.selectedPano, circle.pano, 'add')
- //this.setLinkOperateState('addLink',false)
- return
- }
- //if(this.operation == 'removeLink' && this.selectedPano){ //和选择中心点冲突
- // this.linkChange(this.selectedPano, circle.pano, 'remove')
- // //this.setLinkOperateState('removeLink',false)
- // return
- // }
-
-
- this.selectPano(circle.pano)
- })
-
-
- })
- }
-
-
- hoverPano(pano, state){
- if(this.clickToZoomInEnabled)return
- if(pano && state){ //在hover一个pano之前,一定会先取消已经hover的pano, 最多存在一个hovered的pano
- if(this.hoveredPano == pano)return
-
- if(this.hoveredPano){
- this.hoverPano(this.hoveredPano,false)
- }
-
- this.hoveredPano = pano
- pano.hovered = true
-
-
- if(/* this.activeViewName == 'mainView' || */Alignment.handleState && this.selectedPano && this.selectedPano == pano)return
-
- if(this.operation != 'addLink' || !this.selectedPano || this.selectedPano == pano){ // this.selectedPano == pano?
- viewer.dispatchEvent({
- type : "CursorChange", action : "add", name:"hoverPano"
- });
- }
- if(this.selectedPano != pano) pano.circle.material = circleMats['hovered' + '_'+ this.getPanoRtkState(pano) ]
-
- }else if(pano && !state){//unhover
- if(this.hoveredPano != pano)return
- pano.hovered = false
- viewer.dispatchEvent({
- type : "CursorChange", action : "remove", name:"hoverPano"
- });
- if(this.selectedPano != pano) pano.circle.material = circleMats['default' + '_'+ this.getPanoRtkState(pano) ]
- this.hoveredPano = null;
- }else{//unhover any
- if(this.hoveredPano){
- this.hoverPano(this.hoveredPano, false)
- }
- }
- }
-
- selectPano(pano, informinformBy2d, force){
- if(this.selectedPano == pano && !force)return
-
- let lastSeletedPano = this.selectedPano
- let opaProp = this.activeViewName == 'top' ? opacitys.topView : opacitys.sideView
-
- if(this.selectedPano){
-
- this.selectedPano.circle.material = circleMats['default' + '_'+ this.getPanoRtkState(this.selectedPano) ]
- this.selectedPano.circle.renderOrder = renderOrders.circle
-
- this.selectedPano.removeEventListener('rePos',this.panoReposCallback)
- if(this.activeViewName == 'mainView'){
-
- }else{
-
- this.selectedClouds.forEach(e=>{
- e.changePointOpacity(opaProp.default,true)
- e.material.color = pointColor.default;
- })
- }
-
- }
-
-
-
- this.selectedPano = pano || null
-
- this.updateSelectGroup();
-
- if(pano){
- this.selectedPano.circle.material = circleMats['selected' + '_'+ this.getPanoRtkState(this.selectedPano) ]
- this.selectedPano.circle.renderOrder = this.selectedPano.circle.pickOrder = renderOrders.circleSelected //侧视图能显示在最前
-
- viewer.controls.setTarget(this.selectedPano.position) //3d时绕其为中心转动
- this.selectedPano.addEventListener('rePos',this.panoReposCallback)
-
- if(this.activeViewName == 'mainView'){
-
- }else{
- this.selectedClouds.forEach(e=>{
- e.changePointOpacity(opaProp.selected,true)
- e.material.color = pointColor.selected;
- })
- }
-
-
- if(this.currentFloor != 'all'){//如果原本不是展示全部楼层的话,自动切换楼层
-
- let atFloor = SiteModel.entities.find(e=>e.buildType == 'floor' && e.panos.includes(pano))
- if(!atFloor){
- atFloor = 'all'
- }else{
-
- }
-
- this.gotoFloor(atFloor, false, 600 )
- }
-
- }else{
- viewer.controls.setTarget(null)
- }
-
-
- this.updateCursor()
- this.updateTranCtl()
-
- if(informinformBy2d){
- if(this.selectedPano){
- if(this.activeViewName == 'mainView'){ //平移,focus选中的pano
- let distance = this.lastDisToPano || 5;
- if(lastSeletedPano){
- distance = viewer.mainViewport.camera.position.distanceTo(lastSeletedPano.position)
- }
- viewer.focusOnObject({ position:this.selectedPano.position}, 'point', null, {distance })
- }else{
- this.orthoMoveFit(this.selectedPano.position, {}, 500)
- }
- }
- }else{
- this.dispatchEvent({type:'panoSelect', pano })
- }
-
-
- this.updateIntersectEnable()
- viewer.dispatchEvent('content_changed')
- }
-
-
-
- /* updatePointLevels(){
- if(this.pauseUpdateLevels)return
- let maxBudget = Potree.config.pointDensity.panoEdit.pointBudget
- let visiCount1 = viewer.scene.pointclouds.filter(e=>e.visible).length
- let visiCount2 = viewer.scene.pointclouds.filter(e=>e.visibleNodes.length>0).length //屏幕范围内可见的个数
- let maxCount = 200, minCount = 1, minPer = 0.45 , maxPer = 1
- let percent1 = maxPer - ( maxPer - minPer) * THREE.Math.clamp((visiCount1 - minCount) / (maxCount - minCount),0,1)
- let percent2 = maxPer - ( maxPer - minPer) * THREE.Math.clamp((visiCount2 - minCount) / (maxCount - minCount),0,1)
- let percent = percent1*percent2
-
- if(this.activeViewName == 'mainView' ){
- //假设每个pointcloud所带的点个数大致相同,那么当可见点云个数越多,所能展示的level越低,否则因总个数超过budget的话密度会参差不齐。
-
- //pointcloud.changePointSize()
- //console.log('updatePointLevels', percent, visiCount)
- Potree.settings.UserDensityPercent = Math.sqrt(percent2)
- viewer.setPointBudget(maxBudget * percent2)
- }else{
- Potree.settings.UserDensityPercent = 1
- viewer.setPointBudget(maxBudget * percent)
- }
- viewer.setPointBudget(maxBudget * percent)
-
- viewer.setPointLevels()
- //侧面容易卡顿,但和显示的点数无关,似乎是因加载点云多而卡?为何正面不会
- //console.warn('setPointBudget', Potree.pointBudget, visiCount1,visiCount2, Potree.settings.UserDensityPercent)
- } */
-
- getPanoRtkState(pano){
- return pano.panosData.has_rtk ? pano.rtkState ? 'rtk_on' : 'rtk_off' : 'normal'
- }
-
- setPanoRtkState(pano,state){
- pano.rtkState = state
- pano.circle.material = circleMats[(this.selectedPano == pano ? 'selected' : 'default') + '_'+ this.getPanoRtkState(pano) ]
- }
-
- updateSelectGroup(){//更新选中的组
- this.selectedGroup = this.panoGroup.find(e=>e.includes(this.selectedPano))
- if(this.selectedGroup){
- this.selectedGroup = [this.selectedPano, ...this.selectedGroup.filter(e=>e != this.selectedPano)];//将选中的放第一个,便于旋转时绕其旋转。
- }
-
- //this.selectedClouds = this.selectedPano ? (this.selectedGroup || [this.selectedPano]).map(e=>e.pointcloud) : []
- this.selectedClouds = this.selectedPano ? this.selectedGroup.map(e=>e.pointcloud) : []
-
-
- }
-
-
- checkIfCanSave(){//如果未全部相连,不能保存
- for(let datasetId in Potree.settings.datasetsPanos ) {
- if(!this.checkIfAllLinked({datasetId})){
- console.log('没有全部连通,不能保存。其中一个:', datasetId)
- return
- }
- }
- return true
-
- }
-
-
-
- checkIfAllLinked(o){//某个(or组所在的)数据集是否全部连通
-
- let datasetId, group
-
- if(o.group){
- group = o.group
- let pano = o.group[0]
- if(!pano)return //会有没有漫游点的点云来编辑吗
- datasetId = pano.pointcloud.dataset_id
- }else if(o.datasetId){
- datasetId = o.datasetId
- group = this.panoGroup.find(panos=>panos[0].pointcloud.dataset_id == datasetId )
- if(!group)return //要找的数据集的pano全部都孤立了
- }
- if(datasetId == void 0)return
- let panos = Potree.settings.datasetsPanos[datasetId].panos
- return panos.length == group.length
- }
-
-
-
-
- getSuggestLinkPanos(){//给出建议连接的点
- let panos = [];
- let startTime = Date.now()
- for(let datasetId in Potree.settings.datasetsPanos ) {
- if(!this.checkIfAllLinked({datasetId})){
- let groups = this.panoGroup.filter(panos=>panos[0].pointcloud.dataset_id == datasetId )
- groups = groups.sort((a,b)=>{return b.length - a.length})//找出个数最多的一组来连接其他组
-
- let mainGroup = groups[0].slice(), subGroup;
-
- for(let i=1,len=groups.length;i<len;i++){
- subGroup = groups[i]
-
- let minDis = {dis:Infinity, panos:[]}
- for(let a=0, len1=mainGroup.length; a<len1; a++){
- for(let b=0, len2=subGroup.length; b<len2; b++){
-
- let dis = mainGroup[a].position.distanceToSquared(subGroup[b].position)
- if(dis<minDis.dis){
- minDis.dis = dis; minDis.panos = [mainGroup[a], subGroup[b]]
- }
- }
- }
- panos.push(minDis.panos)
-
- //console.log('第i次',minDis)
- mainGroup.push(...subGroup)//连接后,加入集合
- }
-
- }
- }
- //console.log('cost', Date.now() - startTime)
- return panos
-
- }
-
-
-
- showSuggestLinkPanos(){
- let groups = this.getSuggestLinkPanos()
- let s = 0.7
- let createCircle = (pano)=>{
- let circle = new THREE.Mesh(pano.circle.geometry, suggestCircleMat)
- circle.name = 'suggest-circle'
- circle.scale.set(s,s,s)
- circle.renderOrder = 100
- pano.circle.add(circle)
- }
- groups.forEach(panos=>{
- createCircle(panos[0])
- createCircle(panos[1])
- let line = LineDraw.createFatLine([panos[0].position, panos[1].position], {mat: lineMats.suggestLink})
- this.suggestLines.push(line)
- line.renderOrder = renderOrders.line
- viewer.scene.scene.add(line)
- })
-
- }
-
-
- getPanoPose(pano){
- let pose = {
- position: pano.position.clone(),
- quaternion: new THREE.Quaternion().setFromRotationMatrix(pano.panoMatrix).premultiply(rotQua) ,
- }
- return pose
-
- }
-
- exportSavingData(){//输出漫游点新的坐标和朝向、以及连接信息
- let sweepLocations = {}
-
- for(let datasetId in Potree.settings.datasetsPanos ) {
- let {panos} = Potree.settings.datasetsPanos[datasetId]
- let data = panos.map(pano=>{
- let visibles = []
- for(let id in this.panoLink[pano.id]){
- if(this.panoLink[pano.id][id]){
- visibles.push(viewer.images360.getPano(id).index)
- }
- }
- let {position, quaternion} = this.getPanoPose(pano);
- return Object.assign({}, pano.panosData, {
- uuid: pano.uuid,
- /* pose:{
- translation: dealData(pano.position.clone() ),
- rotation: dealData(new THREE.Quaternion().setFromRotationMatrix(pano.panoMatrix).premultiply(rotQua) ),
- }, */
- pose : {
- translation : dealData(position),
- rotation : dealData(quaternion)
- },
-
- visibles,
- use_rtk : !!pano.rtkState
- //subgroup: 0,group: 1, "id_view":..
- })
- })
-
- sweepLocations[datasetId] = {sweepLocations:data}
-
- }
-
-
-
-
- /* this.lineMeshes.children.forEach(e=>{//从line中搜集连接信息,而不从linkInfo,这样visibles不会重复一次
- let names = e.name.split('-') //是不是该转成数字
- var pano0 = names[0]
- var pano1 = names[1]
- sweepLocations.find(s=>s.uuid == pano0).visibles.push(pano1)
- }) */
-
-
- function dealData(value){
- let v = math.toPrecision(value, 6)
- if(v instanceof THREE.Quaternion){
- return {x:v.x, y:v.y, z:v.z, w:v.w}
- }else if(v instanceof THREE.Vector3){
- return {x:v.x, y:v.y, z:v.z}
- }
- }
-
- //console.log(sweepLocations)
- return sweepLocations
- }
- }
- /*
- 不同数据集之间不能连线
- 不同楼层可能也不能
- 如果楼层在不同建筑物怎么办? 楼层切换按钮只能在一个建筑内切换。
- 全部相连时不能移动和旋转
-
- 如果未全部相连,不能保存
-
- */
- export default new PanoEditor()
|