123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376 |
- 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 History from "../../utils/History.js"
- const cameraProps = [
- {
- name : 'top',
- axis:["x","y"],
- direction : new THREE.Vector3(0,0,-1), //镜头朝向
- openCount:0,
- }
- ]
- export class Clipping extends THREE.EventDispatcher{ //实时剪裁
-
- constructor(){
- super()
- this.views = {}
- this.cameras = {}
- this.orthoCamera = new THREE.OrthographicCamera(-100, 100, 100, 100, 0.01, 10000)
- this.orthoCamera.up.set(0,0,1)
-
- }
-
- init(){
- if(this.inited)return
- this.initViews()
- this.inited = true
- this.prepareRecord = true
- this.activeViewName = 'mainView'
-
- this.events = {
- transfromCallback:(e)=>{//拖拽变化时
- this.adjustCamHeight()
- //检测漫游点、回退等
- /* if(this.prepareRecord){
- let box = viewer.transformationTool.selection[0]
- this.history.writeIn({box, matrix:box.matrix.clone()})
- this.prepareRecord = false
- } */
- },
- /* onTransfromEnd:(e)=>{//拖拽结束、松开
- this.prepareRecord = true
- }, */
- selectCallback:(e)=>{
- this.adjustCamHeight()
-
- let unableNavigate = this.activeViewName != 'mainView' || e.selection.length > 0
- if(Potree.settings.unableNavigate && !unableNavigate){
- setTimeout(()=>{
- Potree.settings.unableNavigate = this.activeViewName != 'mainView' || e.selection.length > 0
- },300)//延迟是因为点击时取消选择后可能立即就会触发flyToPano。 而且有的人喜欢点两下
- }else Potree.settings.unableNavigate = unableNavigate
-
-
- },
- onkeydown:(e)=>{
- if(e.keyCode == 8 || e.keyCode == 46){// Backspace or Delete
- viewer.inputHandler.selection[0] && viewer.scene.removeVolume(viewer.inputHandler.selection[0]);
- }
- }
-
- }
-
- /* this.history = new History({ //也可以写到全局,但需要加个判断物品是否存在的函数
- applyData: (data)=>{
- if(viewer.scene.volumes.includes(data.box)){
- data.matrix.decompose( data.box.position, data.box.quaternion, data.box.scale );
- }else{
- this.history.undo()//找不到就回退下一个。(直接写这?)
- }
- }
- }) */
- }
- initViews(){
-
- this.splitScreenTool = new SplitScreen
-
-
-
- for(let i=0;i<1;i++){
- let prop = cameraProps[i];
- let view = new ExtendView()
- this.views[prop.name] = view
- this.cameras[prop.name] = this.orthoCamera
-
- view.direction = prop.direction
- }
- this.views.mainView = viewer.mainViewport.view
- this.cameras.mainView = viewer.mainViewport.camera
-
-
- }
-
- switchView(name){//替换view和camera到mainViewport
- if(this.activeViewName == name)return
-
- let view = this.views[name]
- let camera = this.cameras[name]
- let prop = cameraProps.find(e=>e.name == name)
-
- let {boundSize, center, boundingBox} = 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
-
-
-
- /* if(lastView){//2d->3d
- view.copy(lastView)
- } */
- if(name == 'mainView'){
- Potree.settings.unableNavigate = false
- /* viewer.transformationTool.handles['scale.z+'].node.visible = true
- viewer.transformationTool.handles['scale.z-'].node.visible = true */
- }else{
- Potree.settings.unableNavigate = true
- /* viewer.transformationTool.handles['scale.z+'].node.visible = false
- viewer.transformationTool.handles['scale.z-'].node.visible = false */
- if(prop.openCount == 0){//至多执行一次
- //this.viewportFitBound(name, boundSize, center)
- this.orthoMoveFit(center, {bound:boundingBox}, 0)
- this.camHeightOutOfModel = view.position.z //记录下此刻相机高度。
- }
- prop.openCount++
-
- this.adjustCamHeight()
-
- /* 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等
- if(viewer.inputHandler.selection.length){
- this.focusOnObject(viewer.inputHandler.selection[0])
- }
-
- }
-
-
-
- focusOnObject(box, duration=0){
- if(this.activeViewName == 'mainView'){
- viewer.focusOnObject({boundingBox:box.boundingBox.clone().applyMatrix4(box.matrixWorld)}, 'boundingBox', duration)
- }else{
- this.orthoMoveFit(box.position, {bound:box.boundingBox.clone().applyMatrix4(box.matrixWorld)}, duration)
- }
- this.adjustCamHeight()
- }
-
- orthoMoveFit(pos, info, duration){
- var margin = {x:viewer.mainViewport.resolution.x*0.4, y:viewer.mainViewport.resolution.y*0.4}
- this.splitScreenTool.viewportFitBound(viewer.mainViewport, info.bound, pos, duration, margin )
- }
-
- adjustCamHeight(){
- if(this.activeViewName != 'top')return
- let view = this.views.top
- let height
-
- if(viewer.inputHandler.selection.length){ //相机高度位于选中的box的顶部
- let box = viewer.inputHandler.selection[0]
- height = box.boundingBox.clone().applyMatrix4(box.matrixWorld).max.z;
-
- }else{
- height = this.camHeightOutOfModel //显示全部点云
- }
- view.position.z = height
- //console.log('adjustCamHeight',height)
-
- //缺点:1 会导致缩放很小的时候,transformationTool的轴因放大到了相机背面。(只有scale轴做了处理)
- //2 无法直接切换 看不到的box,但可以先取消选择
- //3 但是俯视图中无法切换到被上层盖住的box(不过把俯视图作为辅助,只针对单个box调动的话,问题不大)
- }
-
- enter(){
- this.init()
- viewer.transformationTool.setModeEnable(['translation'])
- //viewer.transformationTool.handles['rotation.x'].node.visible = false
- viewer.transformationTool.frame.material.visible = false //不盖住boxVolume的frame
- this.targetPlane = viewer.mainViewport.targetPlane = new THREE.Plane()
- this.shiftTarget = viewer.mainViewport.shiftTarget = new THREE.Vector3 //project在targetPlane上的位置
- this.getAllBoxes().forEach(box=>{
- Potree.Utils.updateVisible(box,'hidden',true) //显现
- })
-
- viewer.transformationTool.history.clear()
-
- viewer.transformationTool.addEventListener('transformed', this.events.transfromCallback)
- //viewer.transformationTool.addEventListener('stopDrag', this.events.onTransfromEnd)
- viewer.inputHandler.addEventListener('selection_changed', this.events.selectCallback)
- viewer.inputHandler.addEventListener('keydown', this.events.onkeydown)
-
-
- this.setPointLevelAuto()
- var initialPointcloud = viewer.scene.pointclouds.find(p => p.dataset_id == Potree.settings.originDatasetId)
- //隐藏 初始数据集以外的数据集
- viewer.scene.pointclouds.forEach(e=>{
- if(e.dataset_id!=Potree.settings.originDatasetId){
- Potree.Utils.updateVisible(e,'enterClipping',false)
- //Potree.settings.floorplanEnables[e.dataset_id] = false
- e.panos.forEach(pano=>pano.setEnable(false)) //禁止漫游
-
- }else{
- Potree.Utils.updateVisible(e,'enterClipping',true, 1, 'add')
- //Potree.settings.floorplanEnables[e.dataset_id] = true
- }
- })
-
- viewer.flyToDataset({ pointcloud : initialPointcloud, duration:0})
-
- }
-
-
- leave(){
-
- viewer.transformationTool.setModeEnable(['scale', 'translation', 'rotation'] )
-
- viewer.transformationTool.frame.material.visible = true //恢复
- this.switchView( 'mainView' )
-
-
- this.getAllBoxes().forEach(box=>{
- Potree.Utils.updateVisible(box,'hidden',false)//隐身
- })
- viewer.transformationTool.removeEventListener('transformed', this.events.transfromCallback)
- //viewer.transformationTool.removeEventListener('stopDrag', this.events.onTransfromEnd)
- viewer.inputHandler.removeEventListener('selection_changed', this.events.selectCallback)
- //viewer.inputHandler.removeEventListener('keydown', this.events.onkeydown)
- viewer.transformObject(null)
- viewer.transformationTool.history.clear()
-
- //恢复 初始数据集以外的数据集
- viewer.scene.pointclouds.forEach(e=>{
- if(e.dataset_id!=Potree.settings.originDatasetId){
- Potree.Utils.updateVisible(e,'enterClipping',true)
- e.panos.forEach(pano=>pano.setEnable(true))
- }else{
- Potree.Utils.updateVisible(e,'enterClipping',false, 0, 'cancel')
- }
- })
-
- }
-
- setTranMode(mode){//rotate or translate
- this.tranMode = mode
-
- viewer.transformationTool.setModeEnable([mode])
-
- }
-
-
- //问:是否要显示其他数据集
- setPointLevelAuto(){
- /*
-
- let visiCount = viewer.images360.panos.length
- let maxCount = 200, minCount = 20, minPer = 0.7, maxPer = 1
- let percent = maxPer - ( maxPer - minPer) * THREE.Math.clamp((visiCount - minCount) / (maxCount - minCount),0,1)
-
- Potree.settings.UserDensityPercent = percent ---还是不限制了,尤其是平面图希望更细致点,毕竟剪裁主要要看清剪裁的部位。
-
- */
-
- viewer.setPointBudget(5*1000*1000); //给个中等到高等之间的质量
- Potree.settings.sizeFitToLevel = true
- viewer.setPointLevels()
-
- }
-
-
-
-
-
-
-
- getAllBoxes(){
- return viewer.scene.volumes.filter(v=>v.clip && v instanceof Potree.BoxVolume )
- }
-
-
- getCalcData(){//给后台矩阵数据,以裁剪点云。
- let Clip = viewer.modules.Clip //裁剪下载模块
-
- let data = {
- transformation_matrix: viewer.scene.pointclouds.filter(p=>p.dataset_id == Potree.settings.originDatasetId).map((cloud)=>{
- let data = {
- id: cloud.dataset_id,
- matrix : new THREE.Matrix4().elements, //参照downloadNoCrop,给默认值,表示没有最外层裁剪
- VisiMatrixes: cloud.material.clipBoxes_in.filter(e=>!e.box.isNew).map(e=>Clip.getTransformationMatrix(cloud, e.inverse).elements),
- UnVisiMatrixes: cloud.material.clipBoxes_out.filter(e=>!e.box.isNew).map(e=>Clip.getTransformationMatrix(cloud, e.inverse).elements),
- modelMatrix:(new THREE.Matrix4).copy(cloud.transformMatrix).transpose().elements
- }
- return data
- }) ,
- aabb: "b-12742000 -12742000 -12742000 12742000 12742000 12742000" //剪裁空间
-
- }
-
- return data
- }
-
-
-
- saveClipData(){//输出所有的clip volumeBox
- let oldState = !viewer.clipUnabled;
- viewer.setClipState(true)
- let data = this.getAllBoxes().filter(e=>!e.isNew).map(volume=>{
- return {
- clipTask: volume.clipTask,
- position: Potree.Utils.datasetPosTransform({position:volume.position, toDataset: true, datasetId: Potree.settings.originDatasetId}).toArray(),
- rotation: Potree.Utils.datasetRotTransform({rotation:volume.rotation, toDataset: true, datasetId: Potree.settings.originDatasetId, getRotation:true}).toArray().slice(0,3),
- scale: volume.scale.toArray(),
- }
- })
- console.log(data)
- console.log(JSON.stringify(data))
- viewer.setClipState(oldState)
- return data
- }
-
- loadFromData(data=[]){
- data.forEach(v=>{
- let volume = new Potree.BoxVolume({clip:true, clipTask:v.clipTask});
- volume.scale.fromArray(v.scale);
- volume.position.fromArray(v.position);
- volume.rotation.fromArray(v.rotation);
-
- volume.position.copy(Potree.Utils.datasetPosTransform({position:volume.position, fromDataset: true, datasetId:Potree.settings.originDatasetId}))
- volume.rotation.copy(Potree.Utils.datasetRotTransform({rotation:volume.rotation, fromDataset: true, datasetId:Potree.settings.originDatasetId, getRotation:true}))
-
- viewer.scene.addVolume(volume);
- viewer.volumeTool.scene.add(volume);
- })
- }
-
-
- }
- //注意:实时裁剪只对初始数据集有效
|