|
@@ -21,7 +21,7 @@ const texLoader = new THREE.TextureLoader()
|
|
|
const rotQua = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0,0,1), Math.PI)
|
|
|
const lineMats = {}
|
|
|
const circleMats = {}
|
|
|
-
|
|
|
+
|
|
|
const renderOrders = {
|
|
|
circleSelected:3,
|
|
|
circle:2,
|
|
@@ -67,6 +67,7 @@ class PanoEditor extends THREE.EventDispatcher{
|
|
|
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;
|
|
@@ -94,54 +95,6 @@ class PanoEditor extends THREE.EventDispatcher{
|
|
|
|
|
|
}
|
|
|
|
|
|
- {
|
|
|
- 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:[], 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(),
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- this.fakeMarkerForTran.addEventListener('position_changed', afterMoveCircle.bind(this,'position'))
|
|
|
- this.fakeMarkerForTran.addEventListener("rotation_changed", afterMoveCircle.bind(this,'rotation') )
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
|
|
|
|
|
|
this.initViews()
|
|
@@ -159,6 +112,69 @@ class PanoEditor extends THREE.EventDispatcher{
|
|
|
viewer.scene.scene.add(this.lineMeshes)
|
|
|
|
|
|
|
|
|
+
|
|
|
+ {
|
|
|
+ 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:[], 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.writeToHistory( 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.prepareRecord = true
|
|
|
+ })
|
|
|
+
|
|
|
+ Alignment.history.addEventListener('undo',()=>{
|
|
|
+ this.updateTranCtl()
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
this.initPanoLink()
|
|
|
|
|
|
this.addPanoMesh()
|
|
@@ -206,7 +222,7 @@ class PanoEditor extends THREE.EventDispatcher{
|
|
|
|
|
|
|
|
|
|
|
|
- {//旋转时的辅助线
|
|
|
+ /* {//旋转时的辅助线
|
|
|
this.rotGuideLine = LineDraw.createLine([], {color:'#aaffee'})
|
|
|
this.rotGuideLine.visible = false
|
|
|
this.rotGuideLine.name = 'rotGuideLine'
|
|
@@ -225,7 +241,7 @@ class PanoEditor extends THREE.EventDispatcher{
|
|
|
startPoint = null
|
|
|
this.rotGuideLine.visible = false
|
|
|
})
|
|
|
- }
|
|
|
+ } */
|
|
|
|
|
|
{//连接时的辅助线
|
|
|
this.linkGuideLine = LineDraw.createLine([], {color:'#aaa', deshed:true, dashSize:0.1,gapSize:0.1,})
|
|
@@ -249,6 +265,15 @@ class PanoEditor extends THREE.EventDispatcher{
|
|
|
//为何打开调试时移动很卡
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ viewer.inputHandler.addEventListener('keydown', (e)=>{
|
|
|
+ if(e.event.key == "r" ){
|
|
|
+ this.setTranMode('rotate')
|
|
|
+ }else if(e.event.key == "t"){
|
|
|
+ this.setTranMode('translate')
|
|
|
+ }
|
|
|
+ }) */
|
|
|
+
|
|
|
})
|
|
|
}
|
|
|
|
|
@@ -339,10 +364,10 @@ class PanoEditor extends THREE.EventDispatcher{
|
|
|
})
|
|
|
viewer.updateVisible(viewer.reticule, 'force', true)
|
|
|
|
|
|
- if(lastView){
|
|
|
+ if(lastView){//2d->3d
|
|
|
|
|
|
view.copy(lastView)
|
|
|
- //view.position.
|
|
|
+
|
|
|
let direction = view.direction
|
|
|
let panos = images360.panos.filter(e=>e.circle.visible)
|
|
|
let nearestPano = Common.sortByScore(panos , [], [(pano)=>{
|
|
@@ -365,33 +390,74 @@ class PanoEditor extends THREE.EventDispatcher{
|
|
|
viewer.fpControls.lockKey = false
|
|
|
|
|
|
}else{
|
|
|
-
|
|
|
- if(prop.openCount == 0){//只需执行一次
|
|
|
- this.viewportFitBound(name, boundSize, center)
|
|
|
- }else{
|
|
|
- if(this.lastViewName == 'mainView'){
|
|
|
- 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);
|
|
|
- return -vec.dot(direction);
|
|
|
- }], true);
|
|
|
+
|
|
|
+ if(this.lastViewName == 'mainView'){//3d->2d
|
|
|
+ let direction = lastView.direction
|
|
|
+ let panos = images360.panos.filter(e=>e.circle.visible)
|
|
|
|
|
|
- if(nearestPano && nearestPano[0] ){
|
|
|
- let pos1 = nearestPano[0].item.position.clone()
|
|
|
- let pos2 = pos1.clone()
|
|
|
- let dis = -nearestPano[0].score
|
|
|
- pos1.project(lastCamera)
|
|
|
- pos2.project(camera)
|
|
|
-
|
|
|
- let vecOnscreen = new THREE.Vector3().subVectors(pos1,pos2)
|
|
|
- let moveVec = Potree.Utils.getOrthoCameraMoveVec(vecOnscreen, camera )
|
|
|
- console.log('moveVec',moveVec)
|
|
|
- view.position.sub(moveVec)
|
|
|
+ //尽量靠近画布中心,且距离相机较近
|
|
|
+ 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)
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
prop.openCount ++;
|
|
|
|
|
|
|
|
@@ -423,7 +489,7 @@ class PanoEditor extends THREE.EventDispatcher{
|
|
|
|
|
|
|
|
|
this.updateTranCtl()
|
|
|
- this.setTranMode() // update
|
|
|
+ this.setTranMode(this.tranMode) // update
|
|
|
this.setZoomInState(false) //取消放大模式
|
|
|
|
|
|
}
|
|
@@ -520,7 +586,7 @@ class PanoEditor extends THREE.EventDispatcher{
|
|
|
|
|
|
zoomIn(intersect, pointer){
|
|
|
let camera = viewer.mainViewport.camera
|
|
|
- let endZoom = 700
|
|
|
+ let endZoom = 200
|
|
|
//this.moveFit(intersect, {endZoom:viewer.mainViewport.camera.zoom < aimZoom ? aimZoom : null} , 300)
|
|
|
let startZoom = camera.zoom
|
|
|
if(startZoom >= endZoom){return}
|