OrbitControlsNew.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  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. let minRadius = 2
  18. export class OrbitControls extends THREE.EventDispatcher{
  19. constructor(viewer){
  20. super();
  21. this.viewer = viewer;
  22. this.renderer = viewer.renderer;
  23. this.scene = null;
  24. this.sceneControls = new THREE.Scene();
  25. this.rotationSpeed = 3; //旋转速度
  26. this.fadeFactor = 100;
  27. this.yawDelta = 0;
  28. this.pitchDelta = 0;
  29. this.panDelta = new THREE.Vector2(0, 0);
  30. this.radiusDelta = 0;
  31. this.doubleClockZoomEnabled = true;
  32. this.tweens = [];
  33. this.dollyStart = new THREE.Vector2
  34. this.dollyEnd = new THREE.Vector2
  35. this.keys = {
  36. FORWARD: ['W'.charCodeAt(0), 38],
  37. BACKWARD: ['S'.charCodeAt(0), 40],
  38. LEFT: ['A'.charCodeAt(0), 37],
  39. RIGHT: ['D'.charCodeAt(0), 39],
  40. UP: ['Q'.charCodeAt(0)],
  41. DOWN: ['E'.charCodeAt(0)],
  42. };
  43. let drag = (e) => {
  44. if(!this.enabled)return
  45. let viewport = e.dragViewport;
  46. if(!viewport || viewport.camera.type == "OrthographicCamera" )return
  47. //let camera = viewport.camera
  48. if (e.drag.object !== null) {
  49. return;
  50. }
  51. let mode
  52. if(e.isTouch){
  53. if(e.touches.length == 1){
  54. mode = 'rotate'
  55. }else{
  56. mode = 'scale-pan'
  57. }
  58. }else{
  59. mode = e.buttons === Potree.defines.Buttons.LEFT ? 'rotate' : 'pan'
  60. }
  61. if (e.drag.startHandled === undefined) {
  62. e.drag.startHandled = true;
  63. this.dispatchEvent({type: 'start'});
  64. }
  65. let ndrag = e.drag.pointerDelta.clone()//.add(new THREE.Vector2(1,1)).multiplyScalar(0.5)
  66. ndrag.y *= -1
  67. if (mode == 'rotate') {
  68. this.yawDelta += ndrag.x * this.rotationSpeed;
  69. this.pitchDelta += ndrag.y * this.rotationSpeed;
  70. } else if(mode == 'pan'){
  71. this.panDelta.x += ndrag.x;
  72. this.panDelta.y += ndrag.y;
  73. }else if(mode == 'scale-pan'){ //add
  74. this.dollyEnd.subVectors(e.touches[0].pointer, e.touches[1].pointer);
  75. var scale = this.dollyEnd.length() / this.dollyStart.length()
  76. this.dollyStart.copy(this.dollyEnd);
  77. this.radiusDelta = (1-scale) * this.scene.view.radius
  78. //------------------------
  79. //平移
  80. let pointer = new THREE.Vector2().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
  81. let delta = new THREE.Vector2().subVectors(pointer, this.lastScalePointer)
  82. delta.y *= -1
  83. this.panDelta.add(delta)
  84. this.lastScalePointer = pointer.clone()
  85. //console.log('scale ',scale, this.radiusDelta)
  86. }
  87. this.stopTweens();
  88. };
  89. let drop = e => {
  90. if(!this.enabled)return
  91. this.dispatchEvent({type: 'end'});
  92. };
  93. let scroll = (e) => {
  94. if(!this.enabled)return
  95. let resolvedRadius = this.scene.view.radius + this.radiusDelta;
  96. if(resolvedRadius < 0.1 && e.delta>0)return; //防止缩放太小,导致很慢
  97. this.radiusDelta += -e.delta * resolvedRadius * 0.1;
  98. this.stopTweens();
  99. };
  100. let dblclick = (e) => {
  101. if(!this.enabled)return
  102. if(this.doubleClockZoomEnabled){
  103. this.zoomToLocation(e.mouse);
  104. }
  105. };
  106. let previousTouch = null;
  107. let touchStart = e => {
  108. previousTouch = e;
  109. };
  110. let touchEnd = e => {
  111. previousTouch = e;
  112. };
  113. let touchMove = e => {
  114. if(!this.enabled)return
  115. if (e.touches.length === 2 && previousTouch.touches.length === 2){
  116. let prev = previousTouch;
  117. let curr = e;
  118. let prevDX = prev.touches[0].pageX - prev.touches[1].pageX;
  119. let prevDY = prev.touches[0].pageY - prev.touches[1].pageY;
  120. let prevDist = Math.sqrt(prevDX * prevDX + prevDY * prevDY);
  121. let currDX = curr.touches[0].pageX - curr.touches[1].pageX;
  122. let currDY = curr.touches[0].pageY - curr.touches[1].pageY;
  123. let currDist = Math.sqrt(currDX * currDX + currDY * currDY);
  124. let delta = currDist / prevDist;
  125. let resolvedRadius = this.scene.view.radius + this.radiusDelta;
  126. let newRadius = resolvedRadius / delta;
  127. this.radiusDelta = newRadius - resolvedRadius;
  128. this.stopTweens();
  129. }else if(e.touches.length === 3 && previousTouch.touches.length === 3){
  130. let prev = previousTouch;
  131. let curr = e;
  132. let prevMeanX = (prev.touches[0].pageX + prev.touches[1].pageX + prev.touches[2].pageX) / 3;
  133. let prevMeanY = (prev.touches[0].pageY + prev.touches[1].pageY + prev.touches[2].pageY) / 3;
  134. let currMeanX = (curr.touches[0].pageX + curr.touches[1].pageX + curr.touches[2].pageX) / 3;
  135. let currMeanY = (curr.touches[0].pageY + curr.touches[1].pageY + curr.touches[2].pageY) / 3;
  136. let delta = {
  137. x: (currMeanX - prevMeanX) / this.renderer.domElement.clientWidth,
  138. y: (currMeanY - prevMeanY) / this.renderer.domElement.clientHeight
  139. };
  140. this.panDelta.x += delta.x;
  141. this.panDelta.y += delta.y;
  142. this.stopTweens();
  143. }
  144. previousTouch = e;
  145. };
  146. this.addEventListener('touchstart', touchStart);
  147. this.addEventListener('touchend', touchEnd);
  148. this.addEventListener('touchmove', touchMove);
  149. this.viewer.addEventListener('global_drag', drag);
  150. this.viewer.addEventListener('global_drop', drop);
  151. this.viewer.addEventListener('global_mousewheel', scroll);
  152. this.viewer.addEventListener('global_dblclick', dblclick);
  153. this.viewer.addEventListener('global_touchmove', (e)=>{
  154. if(e.touches.length>1){//单指的就触发上一句
  155. //console.log('global_touchmove' )
  156. drag(e)
  157. }
  158. });
  159. let prepareScale = (e)=>{//触屏的scale
  160. this.dollyStart.subVectors(e.touches[0].pointer, e.touches[1].pointer);
  161. this.lastScalePointer = new THREE.Vector2().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
  162. }
  163. this.viewer.addEventListener('global_touchstart', (e)=>{
  164. if(this.enabled && e.touches.length==2){//只监听开头两个指头
  165. prepareScale(e)
  166. }
  167. })
  168. /* this.viewer.addEventListener('global_touchend', (e)=>{
  169. if(!this.enabled)return
  170. if(e.touches.length==1){//停止scale,开始rotate
  171. prepareRotate(e)
  172. //this.pointerDragStart = null
  173. //console.log('只剩一个', e.pointer.toArray())
  174. }
  175. }) */
  176. this.viewer.addEventListener('focusOnObject',(o)=>{
  177. if(o.position && o.CamTarget){
  178. let distance = o.position.distanceTo(o.CamTarget)
  179. if(distance < minRadius) minRadius = distance * 0.5 //融合页面当focus一个很小的物体时,需要将minRadius也调小
  180. }
  181. })
  182. }
  183. setScene (scene) {
  184. this.scene = scene;
  185. }
  186. setEnable(enabled){
  187. this.enabled = enabled
  188. }
  189. stop(){
  190. this.yawDelta = 0;
  191. this.pitchDelta = 0;
  192. this.radiusDelta = 0;
  193. this.panDelta.set(0, 0);
  194. }
  195. /* zoomToLocation(mouse){
  196. if(!this.enabled)return
  197. let camera = this.scene.getActiveCamera();
  198. let I = Utils.getMousePointCloudIntersection(
  199. null, mouse, this.viewer.inputHandler.pointer,
  200. camera,
  201. this.viewer,
  202. this.scene.pointclouds,
  203. {pickClipped: true});
  204. if (I === null) {
  205. return;
  206. }
  207. let targetRadius = 0;
  208. {
  209. let minimumJumpDistance = 0.2;
  210. let domElement = this.renderer.domElement;
  211. let ray = Utils.mouseToRay(this.viewer.inputHandler.pointer , camera, domElement.clientWidth, domElement.clientHeight);
  212. let nodes = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, ray);
  213. let lastNode = nodes[nodes.length - 1];
  214. let radius = lastNode.getBoundingSphere(new THREE.Sphere()).radius;
  215. targetRadius = Math.min(this.scene.view.radius, radius);
  216. targetRadius = Math.max(minimumJumpDistance, targetRadius);
  217. }
  218. let d = this.scene.view.direction.multiplyScalar(-1);
  219. let cameraTargetPosition = new THREE.Vector3().addVectors(I.location, d.multiplyScalar(targetRadius));
  220. // TODO Unused: let controlsTargetPosition = I.location;
  221. let animationDuration = 600;
  222. let easing = TWEEN.Easing.Quartic.Out;
  223. { // animate
  224. let value = {x: 0};
  225. let tween = new TWEEN.Tween(value).to({x: 1}, animationDuration);
  226. tween.easing(easing);
  227. this.tweens.push(tween);
  228. let startPos = this.scene.view.position.clone();
  229. let targetPos = cameraTargetPosition.clone();
  230. let startRadius = this.scene.view.radius;
  231. let targetRadius = cameraTargetPosition.distanceTo(I.location);
  232. tween.onUpdate(() => {
  233. let t = value.x;
  234. this.scene.view.position.x = (1 - t) * startPos.x + t * targetPos.x;
  235. this.scene.view.position.y = (1 - t) * startPos.y + t * targetPos.y;
  236. this.scene.view.position.z = (1 - t) * startPos.z + t * targetPos.z;
  237. this.scene.view.radius = (1 - t) * startRadius + t * targetRadius;
  238. this.viewer.setMoveSpeed(this.scene.view.radius);
  239. });
  240. tween.onComplete(() => {
  241. this.tweens = this.tweens.filter(e => e !== tween);
  242. });
  243. tween.start();
  244. }
  245. } */
  246. zoomToLocation(mouse){
  247. let I = viewer.inputHandler.intersect;
  248. if(!I)return
  249. let object = I.object || I.pointcloud;
  250. I = I.location
  251. if(!I || !object)return;
  252. let dis = this.scene.view.position.distanceTo(I);
  253. let bound = object.boundingBox.clone().applyMatrix4(object.matrixWorld)
  254. let size = bound.getSize(new THREE.Vector3);
  255. let len = size.length()
  256. let distance = THREE.Math.clamp(dis, 0.1, Math.max(len * 0.1, 3) );
  257. minRadius = distance
  258. viewer.focusOnObject({ position:I }, 'point', null, {distance})
  259. }
  260. stopTweens () {
  261. this.tweens.forEach(e => e.stop());
  262. this.tweens = [];
  263. }
  264. update (delta) {
  265. if(!this.enabled)return
  266. let view = this.scene.view;
  267. { // accelerate while input is given
  268. let ih = this.viewer.inputHandler;
  269. let moveForward = this.keys.FORWARD.some(e => ih.pressedKeys[e]);
  270. let moveBackward = this.keys.BACKWARD.some(e => ih.pressedKeys[e]);
  271. let moveLeft = this.keys.LEFT.some(e => ih.pressedKeys[e]);
  272. let moveRight = this.keys.RIGHT.some(e => ih.pressedKeys[e]);
  273. let moveUp = this.keys.UP.some(e => ih.pressedKeys[e]);
  274. let moveDown = this.keys.DOWN.some(e => ih.pressedKeys[e]);
  275. let px = 0 , py = 0, pz = 0
  276. if(moveForward){
  277. py = 1
  278. }else if(moveBackward){
  279. py = -1
  280. }
  281. if(moveLeft){
  282. px = -1
  283. }else if(moveRight){
  284. px = 1
  285. }
  286. if(moveUp){
  287. pz = 1
  288. }else if(moveDown){
  289. pz = -1
  290. }
  291. (px!=0 || py!=0 || pz!=0) && view.translate(px, py, pz, true);
  292. }
  293. { // apply rotation
  294. let progression = Math.min(1, this.fadeFactor * delta);
  295. let yaw = view.yaw;
  296. let pitch = view.pitch;
  297. let pivot = view.getPivot();
  298. yaw -= progression * this.yawDelta;
  299. pitch -= progression * this.pitchDelta;
  300. view.yaw = yaw;
  301. view.pitch = pitch;
  302. let V = this.scene.view.direction.multiplyScalar(-view.radius);
  303. let position = new THREE.Vector3().addVectors(pivot, V);
  304. view.position.copy(position);
  305. }
  306. { // apply pan
  307. /* let progression = Math.min(1, this.fadeFactor * delta);
  308. let panDistance = progression * view.radius * 3; */
  309. let camera = this.scene.getActiveCamera()
  310. let panDistance = 2 * view.radius * Math.tan(THREE.Math.degToRad(camera.fov / 2));//参照4dkk。 平移target(也就是平移镜头位置),但还是难以保证跟手(navvis也不一定跟手,但是很奇怪在居中时中心点居然是跟手的,可能计算方式不同)
  311. //计算了下确实是这么算的。 平移pivot。
  312. let px = -this.panDelta.x * panDistance;
  313. let py = this.panDelta.y * panDistance;
  314. view.pan(px, py);
  315. }
  316. { // apply zoom
  317. let progression = 1//Math.min(1, this.fadeFactor * delta);
  318. // let radius = view.radius + progression * this.radiusDelta * view.radius * 0.1;
  319. let radius = view.radius + progression * this.radiusDelta;
  320. let V = view.direction.multiplyScalar(-radius);
  321. let position = new THREE.Vector3().addVectors(view.getPivot(), V);
  322. if(this.constantlyForward) {// 到达中心点后还能继续向前移动,也就是能推进中心点
  323. if(radius < minRadius){
  324. radius = minRadius
  325. }
  326. }
  327. view.radius = radius;
  328. view.position.copy(position);
  329. }
  330. {
  331. let speed = view.radius;
  332. this.viewer.setMoveSpeed(speed);
  333. }
  334. { // decelerate over time
  335. /* let progression = Math.min(1, this.fadeFactor * delta);
  336. let attenuation = Math.max(0, 1 - this.fadeFactor * delta);
  337. this.yawDelta *= attenuation;
  338. this.pitchDelta *= attenuation;
  339. this.panDelta.multiplyScalar(attenuation);
  340. // this.radiusDelta *= attenuation;
  341. this.radiusDelta -= progression * this.radiusDelta; */
  342. //取消衰减,直接stop
  343. this.stop()
  344. }
  345. }
  346. };