FirstPersonControlsNew.js 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  1. /**
  2. * @author mschuetz / http://mschuetz.at
  3. *
  4. * adapted from THREE.OrbitControls by
  5. *
  6. * @author qiao / https://github.com/qiao
  7. * @author mrdoob / http://mrdoob.com
  8. * @author alteredq / http://alteredqualia.com/
  9. * @author WestLangley / http://github.com/WestLangley
  10. * @author erich666 / http://erichaines.com
  11. *
  12. *
  13. *
  14. */
  15. import * as THREE from "../../libs/three.js/build/three.module.js";
  16. import {Utils} from "../utils.js";
  17. import cameraLight from "../custom/utils/cameraLight.js";
  18. import Common from "../custom/utils/Common.js";
  19. let Buttons = Potree.defines.Buttons
  20. export class FirstPersonControls extends THREE.EventDispatcher {
  21. constructor (viewer, viewport) {
  22. super();
  23. this.viewer = viewer;
  24. this.renderer = viewer.renderer;
  25. this.scene = viewer.scene;
  26. this.rotationSpeed = 200;
  27. this.moveSpeed = 10;
  28. this.setCurrentViewport({hoverViewport:viewport, force:true}) //this.currentViewport = viewport
  29. this.keys = {
  30. FORWARD: ['W'.charCodeAt(0), 38],
  31. BACKWARD: ['S'.charCodeAt(0), 40],
  32. LEFT: ['A'.charCodeAt(0), 37],
  33. RIGHT: ['D'.charCodeAt(0), 39],
  34. UP: ['Q'.charCodeAt(0)],
  35. DOWN: ['E'.charCodeAt(0)],
  36. //SHIFT : [16],
  37. ALT : [18],
  38. Rotate_LEFT : ['L'.charCodeAt(0)],
  39. Rotate_RIGHT : ['J'.charCodeAt(0)],
  40. Rotate_UP : ['K'.charCodeAt(0)],
  41. Rotate_DOWN : ['I'.charCodeAt(0)],
  42. };
  43. this.fadeFactor = 20;
  44. this.yawDelta = 0;
  45. this.pitchDelta = 0;
  46. this.translationDelta = new THREE.Vector3(0, 0, 0);
  47. this.translationWorldDelta = new THREE.Vector3(0, 0, 0);
  48. this.tweens = [];
  49. this.dollyStart = new THREE.Vector2
  50. this.dollyEnd = new THREE.Vector2
  51. //this.enableChangePos = true
  52. this.viewer.addEventListener('camera_changed',(e)=>{
  53. if(this.viewer.name == 'mapViewer' || e.changeInfo && e.changeInfo.positionChanged && !viewer.mainViewport.view.isFlying() ){
  54. this.setFPCMoveSpeed(e.viewport)
  55. }
  56. })
  57. let drag = (e) => {
  58. if(!this.enabled)return
  59. let viewport = e.dragViewport;
  60. if(!viewport)return
  61. let camera = viewport.camera
  62. let mode
  63. if(e.isTouch){
  64. if(e.touches.length == 1){
  65. mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan'
  66. }else if(e.touches.length == 2){
  67. mode = 'scale'
  68. }else{
  69. mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'pan' : 'scale'
  70. }
  71. }else{
  72. //mode = e.buttons === Buttons.LEFT && (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan'
  73. mode = e.buttons === Buttons.LEFT && camera.type != 'OrthographicCamera' ? 'rotate' : 'pan'
  74. }
  75. //console.log('mode ', mode )
  76. let moveSpeed = this.currentViewport.getMoveSpeed();
  77. if (e.drag.startHandled === undefined) {///???????
  78. e.drag.startHandled = true;
  79. this.dispatchEvent({type: 'start'});
  80. }
  81. if (mode.includes('rotate')) {//旋转
  82. //来自panoramaControl updateRotation
  83. if(!this.pointerDragStart){
  84. return this.pointerDragStart = e.pointer.clone()
  85. }
  86. let view = this.scene.view;
  87. if(this.rotateStartInfo.rotAroundPoint){//定点旋转: 以当前intersect的点为target旋转,不改点在屏幕中的位置
  88. let distance = camera.position.distanceTo(this.rotateStartInfo.rotCenter/* this.intersectStart.location */) //不按下ctrl的话
  89. if(this.rotateStartInfo.rotCenter2d.z>1)distance *= -1 //在背面
  90. //按照orbitControl的方式旋转:
  91. let rotationSpeed = 2;
  92. this.yawDelta -= e.drag.pointerDelta.x * rotationSpeed;
  93. this.pitchDelta += e.drag.pointerDelta.y * rotationSpeed;
  94. /* //旋转方向和偏移量尽量和在漫游点处旋转方式的一样
  95. this.yawDelta += e.drag.pointerDelta.x / 500 * viewport.resolution.x
  96. this.pitchDelta -= e.drag.pointerDelta.y / 500 * viewport.resolution.y */
  97. //先更新一下相机:
  98. this.update()
  99. view.applyToCamera(camera)
  100. //然后得到新的相机角度下,原先点在屏幕中的位置所对应的3d点现在的坐标。只需要平移一下新旧坐标差值即可。//感觉貌似也可以用project和unproject后的差值的方式,还不用判断z背面
  101. let newPointerDir = viewer.inputHandler.getMouseDirection(this.rotateStartInfo.rotCenter2d).direction.clone().multiplyScalar(distance)
  102. let pivot = new THREE.Vector3().addVectors(camera.position, newPointerDir) //新的3d点
  103. let moveVec = new THREE.Vector3().subVectors(pivot, this.rotateStartInfo.rotCenter)
  104. this.translationWorldDelta.copy(moveVec.negate())
  105. //立即更新下,防止因update和此drag频率不同而打滑。
  106. this.update()
  107. view.applyToCamera(camera)
  108. }else{
  109. let _matrixWorld = camera.matrixWorld
  110. camera.matrixWorld = new THREE.Matrix4;//unproject 前先把相机置于原点
  111. var e1 = new THREE.Vector3(this.pointerDragStart.x,this.pointerDragStart.y,-1).unproject(camera)
  112. , t = new THREE.Vector3(e.pointer.x,e.pointer.y,-1).unproject(camera)
  113. , i = Math.sqrt(e1.x * e1.x + e1.z * e1.z)
  114. , n = Math.sqrt(t.x * t.x + t.z * t.z)
  115. , o = Math.atan2(e1.y, i)
  116. , a = Math.atan2(t.y, n);
  117. this.pitchDelta += o - a //上下旋转
  118. e1.y = 0,
  119. t.y = 0;
  120. var s = Math.acos(e1.dot(t) / e1.length() / t.length());
  121. if(!isNaN(s)){
  122. var yawDelta = s //左右旋转
  123. this.pointerDragStart.x > e.pointer.x && (yawDelta *= -1)
  124. this.yawDelta += yawDelta
  125. }
  126. //console.log('rotate:', this.pitchDelta, e.pointer.toArray(), this.pointerDragStart.toArray())
  127. this.pointerDragStart.copy(e.pointer)
  128. camera.matrixWorld = _matrixWorld ;
  129. }
  130. }
  131. if (mode.includes('pan')) {//平移
  132. if(!this.canMovePos(viewport)){
  133. return
  134. }
  135. if(camera.type == "OrthographicCamera"){
  136. //console.log(e.drag.pointerDelta, e.pointer, e.drag.end)
  137. let moveVec = Utils.getOrthoCameraMoveVec(e.drag.pointerDelta, camera )//最近一次移动向量
  138. let pointclouds;
  139. let Alignment = window.viewer.modules.Alignment
  140. let MergeEditor = window.viewer.modules.MergeEditor
  141. let handleState = Alignment.handleState
  142. //右键平移视图、左键操作点云
  143. let a = e.buttons === Buttons.LEFT && viewport.alignment && handleState && viewport.alignment[handleState]
  144. if(Potree.settings.editType == 'pano'){
  145. let PanoEditor = window.viewer.modules.PanoEditor
  146. if(a && PanoEditor.selectedPano){
  147. if(!PanoEditor.selectedGroup || !PanoEditor.checkIfAllLinked({group:PanoEditor.selectedGroup}) ){
  148. if(handleState == 'translate' && ( e.drag.intersectStart.pointclouds && Common.getMixedSet(PanoEditor.selectedClouds, e.drag.intersectStart.pointclouds).length || PanoEditor.selectedPano.hovered)//平移时 拖拽到点云上 或 circle。(其中点云只需要intersect的点云中包含选择的点云中之一即可)
  149. || handleState == 'rotate' ) //旋转模式不需要intersect
  150. {
  151. pointclouds = PanoEditor.selectedClouds
  152. }
  153. }else{
  154. PanoEditor.dispatchEvent('needToDisConnect')
  155. console.warn('选中的漫游点连通了整个数据集,不允许移动')
  156. }
  157. }
  158. if(!pointclouds && e.buttons === Buttons.LEFT && viewport.rotateSide){//侧视图
  159. return PanoEditor.rotateSideCamera(-e.drag.pointerDelta.x)
  160. }
  161. }else if(Potree.settings.editType == 'merge'){
  162. if(e.buttons === Buttons.LEFT && viewport.rotateSide){
  163. return MergeEditor.rotateSideCamera(-e.drag.pointerDelta.x)
  164. }
  165. }else{
  166. /* if(Alignment.selectedClouds && Alignment.selectedClouds.length){//多个点云
  167. pointclouds = a && e.drag.intersectStart.pointclouds && Common.getMixedSet(Alignment.selectedClouds, e.drag.intersectStart.pointclouds).length && Alignment.selectedClouds
  168. }else{ */
  169. pointclouds = a && e.drag.intersectStart.pointcloud && [e.drag.intersectStart.pointcloud]
  170. //}
  171. }
  172. if(pointclouds){
  173. if(handleState == 'translate' && viewport.alignment.translateVec){//只能沿某个方向移动
  174. moveVec.projectOnVector(viewport.alignment.translateVec)
  175. }
  176. this.dispatchEvent({
  177. type : "transformPointcloud",
  178. intersect: e.intersect.orthoIntersect,
  179. intersectStart: e.drag.intersectStart.orthoIntersect,
  180. moveVec,
  181. pointclouds,
  182. camera
  183. })
  184. }else{
  185. this.translationWorldDelta.add(moveVec.negate())
  186. }
  187. }else{
  188. if(e.drag.intersectStart){//如果拖拽着点云
  189. if(e.drag.z == void 0){//拖拽开始
  190. let pointerStartPos2d = e.drag.intersectStart.location.clone().project(camera);//识别到的点云点的位置
  191. e.drag.z = pointerStartPos2d.z //记录z,保持拖拽物体到屏幕距离不变,所以z深度不变
  192. e.drag.projectionMatrixInverse = camera.projectionMatrixInverse.clone()
  193. //防止吸附到最近点上(因为鼠标所在位置并非识别到的点云点的位置,需要得到鼠标所在位置的3d坐标。)
  194. let pointerStartPos2dReal = new THREE.Vector3(this.pointerDragStart.x,this.pointerDragStart.y, e.drag.z);
  195. e.drag.translateStartPos = pointerStartPos2dReal.clone().unproject(camera);
  196. /* this.viewer.dispatchEvent({
  197. type: 'dragPanBegin',
  198. projectionMatrixInverse : e.drag.projectionMatrixInverse
  199. }); */
  200. //console.log('开始拖拽', e.pointer.clone())
  201. }
  202. //拖拽的过程中将projectionMatrixInverse替换成开始拖拽时的,因为near、far一直在变,会导致unproject计算出的3d坐标改变很大而闪烁。
  203. var _projectionMatrixInverse = camera.projectionMatrixInverse;
  204. camera.projectionMatrixInverse = e.drag.projectionMatrixInverse;
  205. let newPos2d = new THREE.Vector3(e.pointer.x,e.pointer.y, e.drag.z );
  206. let newPos3d = newPos2d.clone().unproject(camera);
  207. let moveVec = newPos3d.clone().sub( e.drag.translateStartPos /* e.drag.intersectStart.location */ );//移动相机,保持鼠标下的位置永远不变,所以用鼠标下的新位置减去鼠标下的原始位置
  208. camera.projectionMatrixInverse = _projectionMatrixInverse
  209. this.translationWorldDelta.copy(moveVec.negate()) //这里没法用add,原因未知,会跳动
  210. //console.log('pan 1', this.translationWorldDelta.clone())
  211. //四指松开剩三指时会偏移一下,暂不知道哪里的问题,或许跟开头防止点云吸附有关?
  212. }else{ //如果鼠标没有找到和点云的交点,就假设移动整个模型(也可以去扩大范围寻找最近点云)
  213. /* let center = viewer.scene.pointclouds[0].position;
  214. let radius = camera.position.distanceTo(center);
  215. let ratio = radius * Math.tan(THREE.Math.degToRad(camera.fov)/2) / 1000 */
  216. /* let speed = this.currentViewport.getMoveSpeed()
  217. if(FirstPersonControls.boundPlane){
  218. speed = FirstPersonControls.boundPlane.distanceToPoint(this.currentViewport.position)
  219. speed = Math.max(1 , speed)
  220. } */
  221. let lastIntersect = this.target || viewport.lastIntersect && (viewport.lastIntersect.location || viewport.lastIntersect)//该viewport的最近一次鼠标和点云的交点
  222. if(!lastIntersect || !(lastIntersect instanceof THREE.Vector3))lastIntersect = viewer.bound.center
  223. let speed = camera.position.distanceTo(lastIntersect)
  224. let fov = cameraLight.getHFOVForCamera(camera, true)
  225. let ratio = speed * Math.tan(fov/2)
  226. this.translationDelta.x -= e.drag.pointerDelta.x * ratio
  227. this.translationDelta.z -= e.drag.pointerDelta.y * ratio
  228. //console.log('pan2', e.drag.pointerDelta)
  229. }
  230. }
  231. this.useAttenuation = false
  232. }
  233. if(mode.includes('scale')){
  234. this.dollyEnd.subVectors(e.touches[0].pointer, e.touches[1].pointer);
  235. //if(!this.dollyStart)return
  236. var scale = this.dollyEnd.length() / this.dollyStart.length()
  237. //console.log('scale ',scale)
  238. let pointer = new THREE.Vector2().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
  239. dolly({
  240. pointer,
  241. scale, camera
  242. })
  243. this.dollyStart.copy(this.dollyEnd);
  244. }
  245. //最好按ctrl可以变为dollhouse的那种旋转
  246. };
  247. let drop = e => {
  248. if(!this.enabled)return
  249. this.dispatchEvent({type: 'end'});
  250. };
  251. let dolly = (e={})=>{
  252. if(Potree.settings.displayMode == 'showPanos' && this.currentViewport == viewer.mainViewport/* this.currentViewport.unableChangePos */){//全景时
  253. this.dispatchEvent({type:'dollyStopCauseUnable',delta:e.delta, scale:e.scale})
  254. return
  255. }
  256. let camera = e.camera
  257. if(camera.type == "OrthographicCamera"){
  258. let ratio
  259. if(e.delta != void 0){//滚轮缩放
  260. if(e.delta == 0){//mac
  261. return
  262. }else if (e.delta < 0) {
  263. ratio = 0.9
  264. } else if (e.delta > 0) {
  265. ratio = 1.12 //增加的需要比减少的多一些,否则缩放相同次数下,r0 * ([1+s)(1-s)]^n = r0 * (1-s^2)^n < r0
  266. }
  267. }else{
  268. ratio = e.scale //触屏缩放
  269. }
  270. let zoom = camera.zoom * ratio
  271. let limit = camera.zoomLimit
  272. if(limit) zoom = THREE.Math.clamp(zoom, limit.min,limit.max )
  273. let pointerPos = new THREE.Vector3(e.pointer.x, e.pointer.y,0.5);
  274. let oldPos = pointerPos.clone().unproject(camera);
  275. if(camera.zoom != zoom){
  276. camera.zoom = zoom
  277. camera.updateProjectionMatrix()
  278. }
  279. let newPos = pointerPos.clone().unproject(camera);
  280. //定点缩放, 恢复一下鼠标所在位置的位置改变量
  281. let moveVec = new THREE.Vector3().subVectors(newPos,oldPos)
  282. this.translationWorldDelta.add(moveVec.negate())
  283. this.useAttenuation = false
  284. }else{
  285. let speed , direction
  286. if(e.delta != void 0){//滚轮缩放
  287. speed = this.currentViewport.getMoveSpeed() * 15
  288. //var direction = this.currentViewport.view.direction.clone();
  289. /* if(this.target && !e.intersect){//如果没有intersect点云且有target的话,就朝target的方向. 但无限靠近时有问题,且到背面时前进却是后退
  290. direction = new THREE.Vector3().subVectors(this.target, camera.position).normalize()
  291. }else{ */
  292. direction = this.viewer.inputHandler.getMouseDirection().direction //定点缩放
  293. //}
  294. if(e.delta == 0){//mac
  295. return
  296. }else if (e.delta < 0) {
  297. speed *= -1
  298. }
  299. }else{
  300. const constantDis = this.currentViewport.getMoveSpeed() * 200 //constantDis = 10;//常量系数,当放大一倍时前进的距离。可以调整
  301. speed = (e.scale-1)*constantDis //触屏缩放
  302. //pointer = new THREE.Vector2().addVectors().multiplyScalar(0.5);//两个指头的中心点
  303. direction = this.viewer.inputHandler.getMouseDirection(e.pointer).direction //定点缩放
  304. }
  305. this.useAttenuation = true
  306. var vec = direction.multiplyScalar(speed )
  307. this.translationWorldDelta.copy(vec)
  308. }
  309. }
  310. let scroll = (e) => {
  311. if(!this.enabled || !e.hoverViewport)return
  312. this.setCurrentViewport(e)
  313. e.camera = e.hoverViewport.camera
  314. dolly(e)
  315. };
  316. let dblclick = (e) => {
  317. if(!this.enabled)return
  318. if(!Potree.settings.dblToFocusPoint)return;//调试时才可双击
  319. if(Potree.settings.displayMode == 'showPointCloud'/* !viewer.images360.isAtPano() */) this.zoomToLocation(e.mouse);
  320. };
  321. this.viewer.addEventListener('global_drag', drag);
  322. /* this.viewer.addEventListener('global_touchmove', (e)=>{
  323. if(!this.enabled)return
  324. if(e.touches.length>1){//单指的就触发上一句
  325. //console.log('global_touchmove' )
  326. drag(e)
  327. }
  328. }); */
  329. this.viewer.addEventListener('global_drop', drop);
  330. this.viewer.addEventListener('global_mousewheel', scroll);
  331. this.viewer.addEventListener('global_dblclick', dblclick);
  332. let prepareScale = (e)=>{//触屏的scale
  333. this.dollyStart.subVectors(e.touches[0].pointer, e.touches[1].pointer);
  334. }
  335. let prepareRotate = (e)=>{
  336. this.pointerDragStart = e.pointer.clone()
  337. if(e.viewer.name != 'mainViewer' )return
  338. let intersect = e.intersect || e.dragViewport.lastIntersect
  339. //在数据集外部时绕中心点旋转,在数据集内部时绕intersect点旋转(其他数据集的点也可以) 或者 原地旋转镜头
  340. let rotAroundPoint = Potree.settings.rotAroundPoint && e.dragViewport.camera.type != 'OrthographicCamera' && (viewer.atDatasets.length == 0 || intersect) && this.canMovePos(viewport) && !viewer.images360.isAtPano() && !this.viewer.inputHandler.pressedKeys[32]
  341. let rotCenter2d, rotCenter
  342. if(rotAroundPoint){
  343. let pivotType = this.target ? 'target' : viewer.atDatasets.length > 0 ? 'intersect' : viewer.inputHandler.selection.length ? 'selection' : 'boundCenter'
  344. rotCenter = pivotType == 'target'? this.target :pivotType == 'intersect' ? intersect.location : pivotType == 'selection' ? viewer.inputHandler.selection[0].position : viewer.bound.center
  345. if(rotCenter){
  346. rotCenter2d = rotCenter.clone().project(e.dragViewport.camera) //点在屏幕中的位置
  347. }else{
  348. rotAroundPoint = false
  349. }
  350. }
  351. this.rotateStartInfo = {
  352. rotAroundPoint, //定点旋转
  353. rotCenter,
  354. rotCenter2d
  355. }
  356. //缺点:多数据集绕中心点转很难操作,感觉可以也改为绕lastIntersect
  357. //console.log('prepareRotate' )
  358. }
  359. let preparePan = (e)=>{//触屏的pan点云 还是会偏移
  360. this.pointerDragStart = e.pointer.clone()
  361. e.drag.z = void 0 //清空
  362. drag(e) //触屏点击时更新的pointer直接用一次drag
  363. //console.log('preparePan ' )
  364. }
  365. this.viewer.addEventListener('global_mousedown'/* 'startDragging' */, (e)=>{
  366. if(!this.enabled)return
  367. this.setCurrentViewport(e)
  368. prepareRotate(e)
  369. })
  370. //注意,每次增减指头都会修改pointer,需要更新下状态
  371. this.viewer.addEventListener('global_touchstart', (e)=>{
  372. if(!this.enabled)return
  373. if(e.touches.length==2){//只监听开头两个指头
  374. prepareScale(e)
  375. }else if(e.touches.length>=3){
  376. preparePan(e)
  377. }
  378. })
  379. this.viewer.addEventListener('global_touchend', (e)=>{
  380. if(!this.enabled)return
  381. if(e.touches.length==2){//停止平移,开始scale
  382. prepareScale(e)
  383. }else if(e.touches.length==1){//停止scale,开始rotate
  384. prepareRotate(e)
  385. }else if(e.touches.length>=3){//重新准备下平移(因为抬起的指头可能包含平移使用的数据),否则抬起时漂移
  386. preparePan(e)
  387. }
  388. })
  389. /* this.viewer.addEventListener('enableChangePos', (e)=>{
  390. if(!this.enabled)return
  391. this.enableChangePos = e.canLeavePano
  392. }) */
  393. }
  394. canMovePos(viewport){
  395. if(viewport == viewer.mainViewport && (Potree.settings.displayMode == 'showPanos'
  396. || viewer.images360.bumping || viewer.images360.latestToPano))return false
  397. else return true
  398. }
  399. setEnable(enabled){
  400. this.enabled = enabled;
  401. }
  402. setTarget(target){//绕该点旋转,类似orbitControl
  403. this.target = target
  404. }
  405. setFPCMoveSpeed(viewport){
  406. if(viewport.camera.type == 'OrthographicCamera'){
  407. let s = 1 / viewport.camera.zoom
  408. viewport.setMoveSpeed(s)
  409. }else{
  410. //根据和漫游点的最短距离算moveSpeed。缺点:对于导入的无漫游点的数据集没有意义。
  411. if(viewport == viewer.mainViewport && viewer.images360){
  412. let position = viewer.mainViewport.view.position
  413. //let pointclouds = [viewer.atDatasets, ...viewer.scene.pointclouds.filter(pointcloud=>pointcloud.bound2.distanceToPoint(position) < )]
  414. let pano = viewer.images360.findNearestPano()
  415. if(!pano)return
  416. let dis = pano.position.distanceTo(position)
  417. let minSpeed = 0.05, minDis = 3, multiplier = 0.005;
  418. let speed = dis <= minDis ? minSpeed : minSpeed + (dis-minDis) * multiplier
  419. //console.log('dis', dis, 'speed', speed, pano.id )
  420. viewer.setMoveSpeed(speed)
  421. }
  422. //调试场景t-FhDWmV5xur 两个数据集,大的数据集没有漫游点。
  423. }
  424. }
  425. setCurrentViewport(o={}){//add
  426. if(!this.enabled && !o.force )return
  427. if(o.hoverViewport && this.currentViewport != o.hoverViewport ){
  428. this.currentViewport = o.hoverViewport
  429. //this.viewer.setMoveSpeed(this.currentViewport.radius/100);
  430. this.setFPCMoveSpeed(this.currentViewport)
  431. }
  432. if(this.currentViewport.camera.type == 'OrthographicCamera'){
  433. this.lockElevationOri = true
  434. this.lockRotation = true
  435. }else{
  436. this.lockElevationOri = false
  437. this.lockRotation = false
  438. }
  439. }
  440. setScene (scene) {
  441. this.scene = scene;
  442. }
  443. stop(){
  444. this.yawDelta = 0;
  445. this.pitchDelta = 0;
  446. this.translationDelta.set(0, 0, 0);
  447. }
  448. zoomToLocation(mouse){
  449. if(!this.enabled)return
  450. let camera = this.scene.getActiveCamera();
  451. /* let I = Utils.getMousePointCloudIntersection(
  452. mouse,
  453. camera,
  454. this.viewer,
  455. this.scene.pointclouds); */
  456. var I = this.viewer.inputHandler.intersect
  457. if (!I) {
  458. return;
  459. }
  460. let targetRadius = 0;
  461. {
  462. let minimumJumpDistance = 0.2;
  463. let domElement = this.renderer.domElement;
  464. let ray = Utils.mouseToRay(this.viewer.inputHandler.pointer, camera);
  465. let {origin, direction} = this.viewer.inputHandler.getMouseDirection()
  466. let raycaster = new THREE.Raycaster();
  467. raycaster.ray.set(origin, direction);
  468. let nodes = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, ray);
  469. let nodes2 = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, raycaster.ray);
  470. let lastNode = nodes[nodes.length - 1];
  471. let radius = lastNode.getBoundingSphere(new THREE.Sphere()).radius;
  472. targetRadius = Math.min(this.scene.view.radius, radius);
  473. targetRadius = Math.max(minimumJumpDistance, targetRadius);
  474. }
  475. let d = this.scene.view.direction.multiplyScalar(-1);
  476. let cameraTargetPosition = new THREE.Vector3().addVectors(I.location, d.multiplyScalar(targetRadius));
  477. // TODO Unused: let controlsTargetPosition = I.location;
  478. let animationDuration = 600;
  479. let easing = TWEEN.Easing.Quartic.Out;
  480. { // animate
  481. let value = {x: 0};
  482. let tween = new TWEEN.Tween(value).to({x: 1}, animationDuration);
  483. tween.easing(easing);
  484. this.tweens.push(tween);
  485. let startPos = this.scene.view.position.clone();
  486. let targetPos = cameraTargetPosition.clone();
  487. let startRadius = this.scene.view.radius;
  488. let targetRadius = cameraTargetPosition.distanceTo(I.location);
  489. tween.onUpdate(() => {
  490. let t = value.x;
  491. this.scene.view.position.x = (1 - t) * startPos.x + t * targetPos.x;
  492. this.scene.view.position.y = (1 - t) * startPos.y + t * targetPos.y;
  493. this.scene.view.position.z = (1 - t) * startPos.z + t * targetPos.z;
  494. this.scene.view.radius = (1 - t) * startRadius + t * targetRadius;
  495. this.viewer.setMoveSpeed(this.scene.view.radius / 2.5);
  496. });
  497. tween.onComplete(() => {
  498. this.tweens = this.tweens.filter(e => e !== tween);
  499. });
  500. tween.start();
  501. }
  502. }
  503. update (delta=1) {
  504. if(!this.enabled)return
  505. //console.log('update')
  506. let view = this.currentViewport.view
  507. { // cancel move animations on user input
  508. let changes = [ this.yawDelta,
  509. this.pitchDelta,
  510. this.translationDelta.length(),
  511. this.translationWorldDelta.length() ];
  512. let changeHappens = changes.some(e => Math.abs(e) > 0.001);
  513. if (changeHappens && this.tweens.length > 0) {
  514. this.tweens.forEach(e => e.stop());
  515. this.tweens = [];
  516. }
  517. }
  518. { // accelerate while input is given
  519. let ih = this.viewer.inputHandler;
  520. let moveForward = this.keys.FORWARD.some(e => ih.pressedKeys[e]);
  521. let moveBackward = this.keys.BACKWARD.some(e => ih.pressedKeys[e]);
  522. let moveLeft = this.keys.LEFT.some(e => ih.pressedKeys[e]);
  523. let moveRight = this.keys.RIGHT.some(e => ih.pressedKeys[e]);
  524. let moveUp = this.keys.UP.some(e => ih.pressedKeys[e]);
  525. let moveDown = this.keys.DOWN.some(e => ih.pressedKeys[e]);
  526. let rotateLeft = this.keys.Rotate_LEFT.some(e => ih.pressedKeys[e]);
  527. let rotateRight = this.keys.Rotate_RIGHT.some(e => ih.pressedKeys[e]);
  528. let rotateUp = this.keys.Rotate_UP.some(e => ih.pressedKeys[e]);
  529. let rotateDown = this.keys.Rotate_DOWN.some(e => ih.pressedKeys[e]);
  530. this.lockElevation = this.lockElevationOri || this.keys.ALT.some(e => ih.pressedKeys[e]);
  531. if(!this.lockRotation){
  532. if(rotateLeft){
  533. this.yawDelta -= 0.01
  534. }else if(rotateRight){
  535. this.yawDelta += 0.01
  536. }
  537. if(rotateUp){
  538. this.pitchDelta -= 0.01
  539. }else if(rotateDown){
  540. this.pitchDelta += 0.01
  541. }
  542. }
  543. if(this.canMovePos(this.currentViewport) && !this.lockKey){
  544. if(this.lockElevation){
  545. let dir = view.direction;
  546. dir.z = 0;
  547. dir.normalize();
  548. if (moveForward && moveBackward) {
  549. this.translationWorldDelta.set(0, 0, 0);
  550. } else if (moveForward) {
  551. this.translationWorldDelta.copy(dir.multiplyScalar(this.currentViewport.getMoveSpeed()));
  552. } else if (moveBackward) {
  553. this.translationWorldDelta.copy(dir.multiplyScalar(-this.currentViewport.getMoveSpeed()));
  554. }
  555. }else{
  556. if (moveForward && moveBackward) {
  557. this.translationDelta.y = 0;
  558. } else if (moveForward) {
  559. this.translationDelta.y = this.currentViewport.getMoveSpeed();
  560. } else if (moveBackward) {
  561. this.translationDelta.y = -this.currentViewport.getMoveSpeed();
  562. }
  563. }
  564. if (moveLeft && moveRight) {
  565. this.translationDelta.x = 0;
  566. } else if (moveLeft) {
  567. this.translationDelta.x = -this.currentViewport.getMoveSpeed();
  568. } else if (moveRight) {
  569. this.translationDelta.x = this.currentViewport.getMoveSpeed();
  570. }
  571. if (moveUp && moveDown) {
  572. this.translationWorldDelta.z = 0;
  573. } else if (moveUp) {
  574. this.translationWorldDelta.z = this.currentViewport.getMoveSpeed();
  575. } else if (moveDown) {
  576. this.translationWorldDelta.z = -this.currentViewport.getMoveSpeed();
  577. }
  578. if(moveUp || moveDown || moveForward || moveBackward){
  579. this.useAttenuation = false
  580. }
  581. }
  582. }
  583. { // apply rotation
  584. let yaw = view.yaw;
  585. let pitch = view.pitch;
  586. yaw += this.yawDelta /* * delta; */
  587. pitch += this.pitchDelta/* * delta; */
  588. view.yaw = yaw;
  589. view.pitch = pitch;
  590. this.yawDelta = 0
  591. this.pitchDelta = 0
  592. }
  593. /* if(this.translationWorldDelta.length()>0) {
  594. // console.log('translationDelta')
  595. } */
  596. { // apply translation
  597. view.translate(
  598. this.translationDelta.x, /* * delta, */
  599. this.translationDelta.y, /* * delta, */
  600. this.translationDelta.z, /* * delta */
  601. );
  602. this.translationDelta.set(0,0,0)
  603. //if(this.translationWorldDelta.length())console.log(translationWorldDelta)
  604. view.translateWorld(
  605. this.translationWorldDelta.x /* * delta */,
  606. this.translationWorldDelta.y /* * delta */,
  607. this.translationWorldDelta.z /* * delta */
  608. );
  609. //this.translationWorldDelta.set(0,0,0)
  610. }
  611. { // set view target according to speed
  612. //view.radius = 1 * this.currentViewport.getMoveSpeed();
  613. /* if(viewer.bound) view.radius = view.position.distanceTo(viewer.bound.center)
  614. let speed = view.radius/100;
  615. this.viewer.setMoveSpeed(speed); */
  616. //this.setMoveSpeed()
  617. }
  618. if(this.useAttenuation){ //只有滚轮缩放时开启
  619. let attenuation = Math.max(0, 1 - this.fadeFactor * delta);
  620. /*this.yawDelta *= attenuation;
  621. this.pitchDelta *= attenuation;
  622. this.translationDelta.multiplyScalar(attenuation);*/
  623. this.translationWorldDelta.multiplyScalar(attenuation);
  624. }else{
  625. this.translationWorldDelta.set(0,0,0)
  626. }
  627. }
  628. };