InputHandlerNew.js 47 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460
  1. /**
  2. * @author mschuetz / http://mschuetz.at
  3. *
  4. *
  5. */
  6. import * as THREE from "../../libs/three.js/build/three.module.js";
  7. import {KeyCodes} from "../KeyCodes.js";
  8. import {Utils} from "../utils.js";
  9. import Common from "../custom/utils/Common.js";
  10. import DepthBasicMaterial from '../custom/materials/DepthBasicMaterial.js'
  11. let {Buttons} = Potree.defines
  12. export class InputHandler extends THREE.EventDispatcher {
  13. constructor (viewer,scene) {
  14. super();
  15. this.viewer = viewer;
  16. this.renderer = viewer.renderer;
  17. this.domElement = this.renderer.domElement;
  18. this.enabled = true;
  19. this.scene = scene;
  20. this.interactiveScenes = [];
  21. this.interactiveObjects = new Set();
  22. this.inputListeners = [];
  23. this.blacklist = new Set();
  24. this.drag = null;
  25. this.mouse = new THREE.Vector2(0, 0);
  26. //add:
  27. this.pointer = new THREE.Vector2(0, 0); //交互点的屏幕坐标,有别于DOM坐标,在此存放NDC坐标。(NDC,三维常用坐标系,二维坐标,整个屏幕映射范围(-1,1),屏幕中心为原点,+Y朝上,+X朝右)
  28. this.mouseDownMouse = new THREE.Vector2(0, 0);
  29. this.selection = [];
  30. this.hoveredElements = [];
  31. this.pressedKeys = {};
  32. this.wheelDelta = 0;
  33. this.speed = 1;
  34. this.logMessages = false;
  35. if (this.domElement.tabIndex === -1) {
  36. this.domElement.tabIndex = 2222;
  37. }
  38. this.lastPointerUpTime = 0
  39. this.touches = []
  40. this.interactHistory = {move:0} //add
  41. this.hoverViewport = viewer.viewports[0]
  42. this.domElement.addEventListener('contextmenu', (event) => { event.preventDefault(); }, false);
  43. this.domElement.addEventListener('click', this.onMouseClick.bind(this), false);
  44. this.domElement.addEventListener('mousedown', this.onMouseDown.bind(this), false);
  45. window.addEventListener('mouseup', this.onMouseUp.bind(this), false);
  46. if(Potree.isIframeChild){//子页面的话在父页面也要加侦听(应该不会有多层吧?否则要一直加到最外层)
  47. //window.parent.addEventListener('mouseup', this.onMouseUp.bind(this), false); //可能跨域
  48. //window.parent.postMessage('listenMouseup', '*');
  49. window.addEventListener('mouseout', this.onMouseUp.bind(this), false); //cancel drag
  50. }
  51. this.domElement.addEventListener('mousemove', this.onMouseMove.bind(this), false);
  52. //add
  53. /* this.domElement.addEventListener("pointerout", this.onMouseUp.bind(this)),
  54. this.domElement.addEventListener("pointercancel", this.onMouseUp.bind(this)),
  55. */
  56. this.domElement.addEventListener('mousewheel', this.onMouseWheel.bind(this), false);
  57. this.domElement.addEventListener('DOMMouseScroll', this.onMouseWheel.bind(this), false); // Firefox
  58. //this.domElement.addEventListener('dblclick', this.onDoubleClick.bind(this)); //因为双击时间间隔是跟随系统的所以不好判断
  59. this.domElement.addEventListener('keydown', this.onKeyDown.bind(this));
  60. window.addEventListener('keyup', this.onKeyUp.bind(this));
  61. window.addEventListener('blur',this.onKeyUp.bind(this)); //add
  62. this.domElement.addEventListener('touchstart', this.onTouchStart.bind(this));
  63. this.domElement.addEventListener('touchend', this.onTouchEnd.bind(this));
  64. this.domElement.addEventListener('touchmove', this.onTouchMove.bind(this));
  65. {
  66. this.addEventListener('isMeasuring',(e)=>{
  67. //console.log('isMeasuring',e.v,e.cause)
  68. this.isMeasuring = e.v
  69. })
  70. }
  71. window.viewer.addEventListener('loopStart',()=>{
  72. this.interactHistory = {} //清空
  73. })
  74. }
  75. /* addInputListener (listener) {
  76. this.inputListeners.push(listener);
  77. }
  78. removeInputListener (listener) {
  79. this.inputListeners = this.inputListeners.filter(e => e !== listener);
  80. }
  81. getSortedListeners(){
  82. return this.inputListeners.sort( (a, b) => {
  83. let ia = (a.importance !== undefined) ? a.importance : 0;
  84. let ib = (b.importance !== undefined) ? b.importance : 0;
  85. return ib - ia;
  86. });
  87. } */
  88. //统一跟第一个触碰的viewport相同
  89. updateTouchesInfo(e){
  90. var viewport, pointer, camera
  91. let oldTouches = this.touches
  92. let changedTouches = Array.from(e.changedTouches)
  93. let touches = Array.from(e.touches)
  94. this.touches = touches.map(touch=>{
  95. let touch_ = oldTouches.find(a=>a.touch.identifier == touch.identifier)
  96. let pointer = touch_ && touch_.pointer //复制原先的值
  97. return {
  98. touch, pointer,
  99. }
  100. })
  101. if(e.touches.length > 0){
  102. let newTouches = touches.filter(e=>!
  103. oldTouches.some(a=>a.touch.identifier == e.identifier) && !changedTouches.some(a=>a.identifier == e.identifier)
  104. ) //从按钮处划过时e.touches中会出现this.touches和changedTouches中都没有的identifier
  105. if(newTouches.length>0){
  106. console.warn('has new',newTouches.map(e=>e.identifier))
  107. }
  108. newTouches.concat(changedTouches).forEach(touch=>{ //修改changedTouches的
  109. let touch_ = this.touches.find(a=>a.touch.identifier == touch.identifier)
  110. if(touch_){
  111. let a = this.getPointerInViewport(touch.pageX, touch.pageY, this.dragViewport||viewport, new THREE.Vector2)
  112. touch_.pointer = a.pointer.clone()
  113. viewport = a.viewport; camera = a.camera
  114. }
  115. })
  116. //使用当前touches的平均
  117. if(e.touches.length > 1){
  118. let pageX = Common.average(e.touches, "pageX")
  119. let pageY = Common.average(e.touches, "pageY")
  120. let a = this.getPointerInViewport(pageX, pageY, viewport, new THREE.Vector2)
  121. this.pointer.copy(a.pointer)
  122. //console.log('updateTouchesInfo', this.pointer.clone())
  123. }else{
  124. this.pointer = this.touches[0].pointer.clone() //更新,使用当前touches中的第一个
  125. }
  126. /* if(this.touches.find(e=>!e.pointer)){
  127. console.error(' touches has no pointer', oldTouches.map(e=>e.touch.identifier),
  128. Array.from(e.touches).map(e=>e.identifier), Array.from(e.changedTouches).map(e=>e.identifier) )
  129. } */
  130. //console.log(this.touches)
  131. //console.log('更新pointer1',this.pointer.toArray())
  132. return {viewport, camera/* , pointer:this.pointer */}
  133. }
  134. }
  135. onTouchStart (e) {
  136. if (this.logMessages) console.log(this.constructor.name + ': onTouchStart');
  137. e.preventDefault();
  138. /* if (e.touches.length === 1 || !this.drag) { //!this.drag代表一次性下了两个指头
  139. let rect = this.domElement.getBoundingClientRect();
  140. let x = e.touches[0].pageX
  141. let y = e.touches[0].pageY
  142. this.dealPointerDown(x,y,e,true)
  143. }else{
  144. this.updateTouchesInfo(e)
  145. this.drag.end.copy(this.pointer)
  146. } */
  147. this.dealPointerDown(e,true)
  148. this.viewer.dispatchEvent($.extend(
  149. this.getEventDesc(e,true),
  150. {
  151. type: 'global_' + e.type,
  152. changedTouches: e.changedTouches
  153. }
  154. ));
  155. /* console.log('targetTouches :', Array.from(e.targetTouches).map(e=>'| identifier: '+ e.identifier),
  156. 'changedTouches :', Array.from(e.changedTouches).map(e=>'| identifier: '+ e.identifier)
  157. ) */
  158. //console.log('')
  159. }
  160. onTouchMove (e) {
  161. if (this.logMessages) console.log(this.constructor.name + ': onTouchMove');
  162. e.preventDefault();
  163. /* if (e.touches.length === 1) {
  164. let rect = this.domElement.getBoundingClientRect();
  165. let x = e.touches[0].pageX;
  166. let y = e.touches[0].pageY;
  167. }else{
  168. this.updateTouchesInfo(e)
  169. this.drag.pointerDelta.subVectors(this.pointer, this.drag.end)
  170. this.drag.end.copy(this.pointer)
  171. }
  172. */
  173. this.dealPointerMove(e, true)
  174. this.viewer.dispatchEvent($.extend(
  175. this.getEventDesc(e,true),
  176. {
  177. type: 'global_' + e.type,
  178. changedTouches: e.changedTouches
  179. }
  180. ));
  181. /* console.log('targetTouches :', Array.from(e.targetTouches).map(e=>'| identifier: '+ e.identifier),
  182. 'changedTouches :', Array.from(e.changedTouches).map(e=>'| identifier: '+ e.identifier)
  183. ) */
  184. }
  185. onTouchEnd (e) {
  186. if (this.logMessages) console.log(this.constructor.name + ': onTouchEnd');
  187. e.preventDefault();
  188. //console.log('onTouchEnd')
  189. this.updateTouchesInfo(e)
  190. /* if (e.touches.length === 0) {
  191. let rect = this.domElement.getBoundingClientRect();
  192. let x = e.changedTouches[0].pageX //万一一次松开两个指头的怎么办
  193. let y = e.changedTouches[0].pageY
  194. this.dealPointerUp(x,y,e,true)
  195. }else {
  196. this.drag.end.copy(this.pointer)
  197. } */
  198. this.dealPointerUp(e,true)
  199. this.viewer.dispatchEvent($.extend(
  200. this.getEventDesc(e,true),
  201. {
  202. type: 'global_' + e.type,
  203. }
  204. ));
  205. //console.log('touchend length '+e.touches.length, this.touches.length)
  206. }
  207. onKeyDown (e) {
  208. if (this.logMessages) console.log(this.constructor.name + ': onKeyDown');
  209. // DELETE
  210. /* if (e.keyCode === KeyCodes.DELETE && this.selection.length > 0) {
  211. this.dispatchEvent({
  212. type: 'delete',
  213. selection: this.selection
  214. });
  215. this.deselectAll();
  216. } */
  217. this.dispatchEvent({
  218. type: 'keydown',
  219. keyCode: e.keyCode,
  220. event: e
  221. });
  222. // for(let l of this.getSortedListeners()){
  223. // l.dispatchEvent({
  224. // type: "keydown",
  225. // keyCode: e.keyCode,
  226. // event: e
  227. // });
  228. // }
  229. this.pressedKeys[e.keyCode] = true;
  230. // e.preventDefault();
  231. }
  232. onKeyUp (e) {
  233. if (this.logMessages) console.log(this.constructor.name + ': onKeyUp');
  234. if(e.keyCode != void 0){
  235. delete this.pressedKeys[e.keyCode];
  236. }else{
  237. this.pressedKeys = {}
  238. }
  239. e.preventDefault();
  240. }
  241. onDoubleClick (e) {
  242. if (this.logMessages) console.log(this.constructor.name + ': onDoubleClick');
  243. let consumed = false;
  244. for (let hovered of this.hoveredElements) {
  245. if (hovered._listeners && hovered._listeners['dblclick']) {
  246. hovered.object.dispatchEvent({
  247. type: 'dblclick',
  248. mouse: this.mouse,
  249. object: hovered.object
  250. });
  251. consumed = true;
  252. break;
  253. }
  254. }
  255. if (!consumed) {
  256. /* for (let inputListener of this.getSortedListeners()) {
  257. inputListener. */this.viewer.dispatchEvent({
  258. type: 'global_dblclick',
  259. mouse: this.mouse,
  260. object: null
  261. });
  262. //}
  263. }
  264. this.needSingleClick = false//add
  265. e.preventDefault();
  266. }
  267. onMouseClick (e) {
  268. if (this.logMessages) console.log(this.constructor.name + ': onMouseClick');
  269. e.preventDefault();
  270. }
  271. dealPointerDown(e,isTouch){
  272. e.preventDefault();
  273. //重新获取一下pointer, 因点击了浏览器的按钮展开列表时 move回来不会触发onmousemove,所以pointer是旧的
  274. if(isTouch){
  275. var { camera, viewport } = this.updateTouchesInfo(e)
  276. if(this.drag){
  277. //因为触屏在按下前缺少pointermove所以要更新下
  278. this.drag.end = this.pointer.clone()
  279. }
  280. }else{
  281. var { camera, viewport } = this.getPointerInViewport(e.clientX, e.clientY )
  282. }
  283. this.dragViewport = this.hoverViewport = viewport
  284. //if(isTouch || !Potree.settings.intersectWhenHover ){
  285. if(isTouch || !this.dragViewport.view.isFlying() && Potree.settings.intersectWhenHover && Potree.settings.editType != 'pano' ){//漫游点编辑如果拖拽前getIntersect旋转会延迟
  286. //isTouch必须更新 否则是旧的
  287. this.hoveredElements = this.getHoveredElements();
  288. let dontIntersect = false
  289. this.intersect = this.getIntersect(viewport,null,null,dontIntersect) //更新intersect,避免在没有mousemove但flyToPano后intersect未更新。
  290. //this.intersect = this.getWholeIntersect()
  291. }
  292. if(!viewport)return //why add this?
  293. if (!this.drag) {
  294. let target = (isTouch||e.button == THREE.MOUSE.LEFT) && this.hoveredElements.find(el => (//只有左键能拖拽
  295. el.object._listeners &&
  296. el.object._listeners['drag'] &&
  297. el.object._listeners['drag'].length > 0));
  298. if (target) {
  299. this.startDragging(target.object, {location: target.point});
  300. } else {
  301. this.startDragging(null);
  302. }
  303. }
  304. this.drag.intersectStart = this.intersect;
  305. if(!isTouch || e.touches.length == 1){
  306. let consumed = false;
  307. let consume = () => { return consumed = true; };
  308. //if (this.hoveredElements.length === 0) {
  309. this.viewer.dispatchEvent($.extend(
  310. this.getEventDesc(e,isTouch),
  311. {
  312. type: 'global_mousedown'
  313. }
  314. ));
  315. for(let hovered of this.hoveredElements){
  316. let object = hovered.object;
  317. object.dispatchEvent({
  318. type: 'mousedown',
  319. viewer: this.viewer,
  320. consume: consume
  321. });
  322. if(consumed){
  323. break;
  324. }
  325. }
  326. }
  327. this.mouseDownMouse = this.mouse.clone()
  328. this.pointerDownTime = Date.now()
  329. }
  330. onMouseDown (e) {
  331. if (this.logMessages) console.log(this.constructor.name + ': onMouseDown');
  332. this.dealPointerDown(e)
  333. }
  334. /* getWholeIntersect(hoveredElements, intersectPoint){//add
  335. hoveredElements = hoveredElements || this.hoveredElements
  336. intersectPoint = intersectPoint || this.intersectPoint
  337. if(Potree.settings.intersectOnObjs && hoveredElements[0] && hoveredElements[0].object.isModel){
  338. return {//模拟点云的intersectPoint的结构写法
  339. hoveredElement : hoveredElements[0] ,
  340. location: hoveredElements[0].point,
  341. point: {normal: hoveredElements[0].face.normal },
  342. distance: hoveredElements[0].distance,
  343. object: hoveredElements[0].object
  344. }
  345. }else return intersectPoint
  346. } */
  347. getEventDesc(e,isTouch){//搜集dispatchEvent要给的一般数据
  348. let o = {
  349. viewer: this.viewer,
  350. mouse: this.mouse,
  351. pointer:this.pointer,
  352. drag :this.drag,
  353. isTouch,
  354. dragViewport : this.dragViewport,
  355. hoverViewport: this.hoverViewport,
  356. // button: isTouch ? 0 : e.button,
  357. //intersectPoint:this.intersectPoint,
  358. hoveredElement: this.hoveredElements[0],
  359. intersect: this.intersect//this.getWholeIntersect() , //可能包含mesh上的,针对融合页面
  360. }
  361. if(e){
  362. o.isAtDomElement = e.target == this.domElement
  363. }
  364. if(isTouch){
  365. o.touches = this.touches
  366. }else if(e){
  367. o.button = e.button
  368. o.buttons = e.buttons
  369. }
  370. return o;
  371. }
  372. dealPointerUp(e,isTouch){
  373. if(!this.drag){// 在canvas外mousedown
  374. return
  375. }
  376. this.drag.end.copy(this.pointer)
  377. if(isTouch && e.touches.length >= 1){
  378. return
  379. }
  380. let now = Date.now()
  381. if (this.logMessages) console.log(this.constructor.name + ': onMouseUp');
  382. e.preventDefault();
  383. let pressDistance = this.mouseDownMouse.distanceTo(this.mouse);
  384. let pressTime = now - this.pointerDownTime;
  385. let noMovement = this.drag.pointerDelta.length() == 0//this.getNormalizedDrag().length() === 0;
  386. let consumed = false;
  387. let consume = () => { return consumed = true; };
  388. //if (this.hoveredElements.length === 0) {
  389. /* for (let inputListener of this.getSortedListeners()) {
  390. inputListener */this.viewer.dispatchEvent($.extend(
  391. this.getEventDesc(e,isTouch),
  392. {
  393. type: 'global_mouseup',
  394. pressDistance,
  395. consume,
  396. }
  397. ));
  398. /* if(consumed){//??
  399. break;
  400. } */
  401. //}
  402. //}
  403. if (this.hoveredElements.length > 0) {
  404. let hovered = this.hoveredElements
  405. .map(e => e.object)
  406. .find(e => (e._listeners && e._listeners['mouseup']));
  407. if(hovered){
  408. hovered.dispatchEvent({
  409. type: 'mouseup',
  410. viewer: this.viewer,
  411. consume: consume
  412. });
  413. }
  414. }
  415. if (this.drag) {
  416. //拖拽结束
  417. if (this.drag.object/* && e.button == THREE.MOUSE.LEFT */) {//add LEFT
  418. if (this.logMessages) console.log(`${this.constructor.name}: drop ${this.drag.object.name}`);
  419. this.drag.object.dispatchEvent($.extend(
  420. this.getEventDesc(e,isTouch),
  421. {
  422. type: 'drop',
  423. pressDistance,
  424. }
  425. ));
  426. } else {
  427. this.viewer.dispatchEvent($.extend(
  428. this.getEventDesc(e,isTouch),
  429. {
  430. type: 'global_drop',
  431. pressDistance
  432. }
  433. ));
  434. }
  435. // check for a click
  436. if(pressDistance < Potree.config.clickMaxDragDis && pressTime<Potree.config.clickMaxPressTime && !e.unableClick){
  437. let clickElement, consumed = false;
  438. if(this.hoveredElements){
  439. clickElement = this.hoveredElements.find(e=>e.object._listeners['click'])
  440. if(clickElement){
  441. //console.log('clickElement',clickElement)
  442. if (this.logMessages) console.log(`${this.constructor.name}: click ${clickElement.name}`);
  443. clickElement.object.dispatchEvent($.extend(
  444. this.getEventDesc(e,isTouch),
  445. {
  446. type: 'click',
  447. pressDistance
  448. }
  449. ));
  450. }
  451. }
  452. let selectable
  453. if(/* !consumed && */ !this.fixSelection){
  454. if (e.button === THREE.MOUSE.LEFT) {
  455. if (noMovement) {
  456. selectable = this.hoveredElements.find(el => el.object._listeners && el.object._listeners['select']);
  457. if (selectable) {
  458. selectable = selectable.object;
  459. if (this.isSelected(selectable)) {
  460. this.deselectAll();
  461. } else {
  462. this.deselectAll();
  463. this.toggleSelection(selectable);
  464. }
  465. consumed = true //add
  466. } else {
  467. if(this.selection.length>0)consumed = true //add 取消选择后,阻断后续
  468. this.deselectAll();
  469. }
  470. }
  471. } else if ((e.button === THREE.MOUSE.RIGHT) && noMovement) {
  472. this.deselectAll();
  473. }
  474. }
  475. let consume = () => { return consumed = true; };
  476. let desc = this.getEventDesc(e,isTouch)
  477. if(!consumed){
  478. this.viewer.dispatchEvent($.extend(
  479. desc,
  480. {
  481. type: 'global_click',
  482. pressDistance,
  483. clickElement:clickElement/* || selectable */,
  484. consume
  485. }
  486. ));
  487. }
  488. //增加 单击:
  489. this.needSingleClick = true;
  490. consumed || setTimeout(()=>{
  491. if(this.needSingleClick){
  492. this.viewer.dispatchEvent($.extend(
  493. desc,
  494. {
  495. type: 'global_single_click',
  496. pressDistance,
  497. clickElement
  498. }
  499. ));
  500. }
  501. }, Potree.config.doubleClickTime+1)
  502. //自行执行双击:
  503. if(now - this.lastClickTime < Potree.config.doubleClickTime){
  504. this.onDoubleClick(e)
  505. }
  506. this.lastClickTime = now
  507. }
  508. this.drag = null;
  509. }
  510. this.dragViewport = null
  511. }
  512. onMouseUp (e) {
  513. this.dealPointerUp( e )
  514. }
  515. getPointerInViewport(clientX, clientY, viewForceAt, pointer ){
  516. let rect = this.domElement.getBoundingClientRect();
  517. let x = clientX - rect.left;
  518. let y = clientY - rect.top;
  519. let camera
  520. let viewport
  521. pointer = pointer ||this.pointer
  522. //if(this.viewer.viewports || viewForceAt){
  523. var getDimension = (view)=>{
  524. var left = Math.ceil(this.domElement.clientWidth * view.left)
  525. , bottom = Math.ceil(this.domElement.clientHeight * view.bottom)
  526. , width = Math.ceil(this.domElement.clientWidth * view.width)
  527. , height = Math.ceil(this.domElement.clientHeight * view.height)
  528. , top = this.domElement.clientHeight - bottom - height
  529. return {left, bottom, width, height, top}
  530. }
  531. var getView = (view, left, bottom, width, height, top)=>{
  532. this.mouse.set(x-left, y - top )
  533. Utils.convertScreenPositionToNDC(pointer, this.mouse, width, height);
  534. //console.log('更新pointer2',this.pointer.toArray())
  535. camera = view.camera;
  536. viewport = view
  537. }
  538. if(viewForceAt){
  539. let {left, bottom, width, height, top} = getDimension(viewForceAt)
  540. getView(viewForceAt, left, bottom, width, height, top)
  541. }else{
  542. var length = this.viewer.viewports.length;
  543. //var getif = false
  544. for(var i=0;i<length;i++){
  545. var view = this.viewer.viewports[i];
  546. if(!view.active)continue
  547. var {left, bottom, width, height, top} = getDimension(view)
  548. if(x >= left && x <= left + width && y >= top && y <= top + height){
  549. getView(view, left, bottom, width, height, top)
  550. //getif = true
  551. break;
  552. }
  553. }
  554. }
  555. return {
  556. camera, viewport, pointer
  557. }
  558. }
  559. ifBlockedByIntersect({pos3d, margin=0, cameraPos, pickWindowSize, pano, useDepthTex}={}){//某点是否被遮挡(不允许camera修改位置, 因为depthTex不好置换)
  560. let intersect = this.getIntersect(this.hoverViewport, true, pickWindowSize, null, null, useDepthTex, {pos3d, cameraPos, pano})
  561. let cameraPos_ = (!cameraPos && pano) ? pano.position : (cameraPos||this.hoverViewport.view.position)
  562. if(intersect && intersect.distance+margin <= pos3d.distanceTo(cameraPos_)){
  563. return intersect //被遮挡
  564. }
  565. //点云模式,对没加载出的点云不准确。 尤其是需要修改相机位置时,因临时修改并不能使点云加载。
  566. }
  567. getIntersect(viewport, onlyGetIntersect, pickWindowSize, dontIntersect, usePointcloud, useDepthTex, prop={}){// usePointcloud:必须使用点云
  568. let intersectPoint
  569. let camera = viewport.camera
  570. let raycaster
  571. viewer.addTimeMark('getIntersect','start')
  572. let getByDepthTex = ()=>{
  573. let intersect
  574. if(prop.pos3d){
  575. let cameraPos = prop.pano ? prop.pano.position : camera.position
  576. let dir = new THREE.Vector3().subVectors(prop.pos3d, cameraPos).normalize();
  577. intersect = {dir}
  578. }else{
  579. intersect = Utils.getIntersect(camera, [viewer.images360.cube], this.pointer, raycaster)
  580. }
  581. intersectPoint = viewer.images360.depthSampler.sample(intersect, prop.pano, !!prop.pos3d) //可能不准确, 因pano可能未加载depthTex
  582. if(intersectPoint && Potree.settings.depTexLocBindDataset){
  583. intersectPoint.pointcloud = (prop.pano || viewer.images360.currentPano).pointcloud
  584. //在全景模式下,虽然深度图上的点可能对应别的pointcloud,但因为是在当前全景图处得到的,所以即使将原本对应的点云移走,该点也不移动是有道理的。它可以永远跟着该全景图。
  585. }
  586. }
  587. let getByCloud = ()=>{
  588. if(prop.pos3d){//指定了目标点,而非只是用pointer所在位置
  589. prop.cameraPos && camera.position.copy(prop.cameraPos)
  590. camera.lookAt(prop.pos3d)
  591. camera.updateMatrixWorld()
  592. prop.pointer = this.pointer.clone()
  593. prop.mouse = this.mouse.clone()
  594. this.pointer.set(0,0) //画布中心
  595. this.mouse.set(Math.round(viewport.resolution.x/2), Math.round(viewport.resolution.y/2))
  596. }
  597. intersectPoint = (viewport.noPointcloud || dontIntersect)? null : Utils.getMousePointCloudIntersection(
  598. viewport,
  599. this.mouse,
  600. this.pointer,
  601. camera,
  602. this.viewer,
  603. this.viewer.scene.pointclouds,
  604. {pickClipped: true, isMeasuring: this.isMeasuring, pickWindowSize, cameraChanged: !!prop.pos3d }
  605. );
  606. //恢复
  607. if(prop.pos3d){
  608. viewport.view.applyToCamera(camera)
  609. this.pointer.copy(prop.pointer)
  610. this.mouse.copy(prop.mouse)
  611. }
  612. }
  613. let canUseDepthTex = (Potree.settings.displayMode == 'showPanos' || useDepthTex)
  614. && viewer.images360.currentPano.pointcloud.hasDepthTex && viewport == viewer.mainViewport && !usePointcloud
  615. if(canUseDepthTex)getByDepthTex()
  616. else getByCloud()
  617. /* if(canUseDepthTex && !this.isMeasuring){
  618. getByDepthTex()
  619. }else{
  620. getByCloud()
  621. if(!intersectPoint && canUseDepthTex ){ //若在测量,先尝试点云,再用全景 //后来发现有深度图的点云全景visibleNode为空,pick不到的
  622. getByDepthTex()
  623. }
  624. } */
  625. //console.log(viewport.name , intersectPoint && intersectPoint.location )
  626. let intersect
  627. let intersectOnModel, allElements
  628. if(Potree.settings.intersectOnObjs && !dontIntersect){
  629. if(prop.point){
  630. raycaster = new THREE.Raycaster()
  631. var dir = new THREE.Vector3().subVectors(prop.point, camera.position).normalize()
  632. raycaster.set(camera.position, dir) //var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
  633. }
  634. allElements = this.getHoveredElements(viewer.objs.children, true, raycaster)
  635. if(allElements[0]){
  636. intersectOnModel = {//模拟点云的intersectPoint的结构写法
  637. hoveredElement : allElements[0] ,
  638. location: allElements[0].point,
  639. //point: {normal: allElements[0].face.normal },
  640. normal: allElements[0].face && allElements[0].face.normal,
  641. distance: allElements[0].distance,
  642. object: allElements[0].object
  643. }
  644. }
  645. }
  646. if(intersectPoint && intersectOnModel){
  647. if(intersectPoint.distance < intersectOnModel.distance){
  648. intersect = intersectPoint
  649. }else{
  650. intersect = intersectOnModel
  651. }
  652. }else{
  653. intersect = intersectOnModel || intersectPoint
  654. }
  655. if(viewport.camera.type == 'OrthographicCamera'/* == 'mapViewport' */){
  656. let pos3d = new THREE.Vector3(this.pointer.x,this.pointer.y,-1).unproject(viewport.camera); //z:-1朝外
  657. if(!intersect){
  658. intersect = {}
  659. }
  660. intersect.orthoIntersect = pos3d.clone()
  661. }
  662. //记录全部hover到的:
  663. if(intersect){
  664. intersect.allElements = allElements
  665. intersect.pointclouds = intersectPoint ? intersectPoint.pointclouds : []
  666. }
  667. viewer.addTimeMark('getIntersect','end')
  668. //点云费时:2-15ms
  669. //深度图费时: 0.1-0.2ms
  670. /*
  671. intersect && intersect.location && intersect.location.applyMatrix4(viewer.scene.scene.matrix)//add
  672. */
  673. if(onlyGetIntersect){
  674. return intersect
  675. }
  676. if (intersect) {
  677. if(viewer.showCoordType){ //显示坐标位置时
  678. let pos = intersect.point.position.toArray()
  679. if(viewer.showCoordType == "local"){
  680. }else if(viewer.showCoordType == "lonlat"){
  681. pos = viewer.transform.lonlatToLocal.inverse(pos)
  682. }else{
  683. pos = viewer.transform.lonlatToLocal.inverse(pos)
  684. pos = viewer.transform.lonlatTo4550.forward(pos)
  685. }
  686. viewer.dispatchEvent({
  687. type : "coordinateChange", pos
  688. })
  689. }
  690. }
  691. //console.log('getIntersect', !!intersectPoint)
  692. this.intersect = intersect
  693. intersect && (this.hoverViewport.lastIntersect = intersect)
  694. return intersect
  695. }
  696. onMouseMove (e) {
  697. return this.dealPointerMove( e )
  698. }
  699. dealPointerMove(e, isTouch){
  700. if(this.interactHistory.move) return //一帧只触发一次
  701. this.interactHistory.move = 1
  702. if(isTouch){
  703. var { camera, viewport } = this.updateTouchesInfo(e)
  704. }else {
  705. var { camera, viewport } = this.getPointerInViewport(e.clientX, e.clientY, this.dragViewport)
  706. }
  707. this.hoverViewport = viewport
  708. if(!viewport)return//刚变化viewport时会找不到
  709. let isFlying = this.viewer.viewports.some(e=>e.view.isFlying()) || viewer.scene.cameraAnimations.some(c=>c.onUpdate)
  710. let intersect
  711. if(e.onlyGetIntersect || (!this.drag || this.drag.object || viewport.alignment ) ){ //没有拖拽物体,但按下鼠标了的话,不intersect。触屏的就能直接避免intersect
  712. let dontIntersect = this.drag && viewport.alignment || isFlying || !Potree.settings.intersectWhenHover // flying 时可能卡顿
  713. //console.log('dontIntersectPointcloud',dontIntersectPointcloud)
  714. /* if(e.onlyGetIntersect ) */intersect = this.getIntersect(viewport, e.onlyGetIntersect, e.pickWindowSize, !!dontIntersect, e.whichPointcloud) //数据集多的时候卡顿
  715. /* else Potree.Common.intervalTool.isWaiting('getIntersect', ()=>{
  716. this.intersect = this.getIntersect(viewport, e.onlyGetIntersect, e.pickWindowSize, !!dontIntersect, e.whichPointcloud) //数据集多的时候卡顿
  717. }, 156); */
  718. //console.log('intersect', intersect)
  719. }
  720. if(e.onlyGetIntersect){
  721. /* if(Potree.settings.intersectOnObjs){
  722. let hoveredElements = this.getHoveredElements() //应该不用发送mouseover事件吧
  723. let intersect = this.getWholeIntersect(hoveredElements, intersectPoint)
  724. return intersect
  725. }
  726. return intersectPoint */
  727. return intersect
  728. }
  729. e.preventDefault();
  730. if (this.drag) {//有拖拽(不一定拖拽了物体, 也不一定按下了鼠标)
  731. this.drag.mouse = isTouch ? 1 : e.buttons;
  732. //add:
  733. //this.drag.pointer = this.pointer.clone();
  734. //this.drag.hoverViewport = this.hoverViewport
  735. this.drag.pointerDelta.subVectors(this.pointer, this.drag.end)
  736. this.drag.end.copy(this.pointer)
  737. if (this.drag.object && (e.buttons == Buttons.NONE || !this.drag.notPressMouse )){//如果是本不需要按鼠标的拖拽,但按下了鼠标,就不执行这段(改为拖拽场景,如添加测量时突然拖拽画面)
  738. if (this.logMessages) console.log(this.constructor.name + ': drag: ' + this.drag.object.name);
  739. this.drag.object.dispatchEvent($.extend(
  740. this.getEventDesc(e,isTouch),
  741. {
  742. type: 'drag', //拖拽物体
  743. }
  744. ))
  745. viewer.dispatchEvent('content_changed')
  746. } else {
  747. if (this.logMessages) console.log(this.constructor.name + ': drag: ');
  748. let dragConsumed = false;
  749. this.viewer.dispatchEvent($.extend(
  750. this.getEventDesc(e,isTouch),
  751. {
  752. type: 'global_drag', //拖拽画面
  753. consume: () => {dragConsumed = true;}
  754. }
  755. ))
  756. }
  757. }
  758. if(!isTouch || e.touches.length == 1){
  759. if((!this.drag || this.drag.notPressMouse || Potree.settings.intersectOnObjs && this.drag.object) && !isFlying){
  760. /* let blacklist = this.drag && this.drag */
  761. let hoveredElements = this.getHoveredElements( );
  762. if(hoveredElements.length > 0){
  763. let names = hoveredElements.map(h => h.object.name).join(", ");
  764. if (this.logMessages) console.log(`${this.constructor.name}: onMouseMove; hovered: '${names}'`);
  765. }
  766. let curr = hoveredElements.map(a => a.object).find(a => true);//只取第一个
  767. let prev = this.lastMouseoverElement //this.hoveredElements.map(a => a.object).find(a => true);
  768. if(curr !== prev){
  769. if(curr){
  770. if (this.logMessages) console.log(`${this.constructor.name}: mouseover: ${curr.name}`);
  771. curr.dispatchEvent({
  772. type: 'mouseover',
  773. object: curr,
  774. });
  775. }
  776. if(prev){
  777. if (this.logMessages) console.log(`${this.constructor.name}: mouseleave: ${prev.name}`);
  778. prev.dispatchEvent({
  779. type: 'mouseleave',
  780. object: prev,
  781. });
  782. }
  783. this.lastMouseoverElement = curr
  784. viewer.dispatchEvent('content_changed')
  785. }
  786. if(hoveredElements.length > 0){
  787. let object = hoveredElements
  788. .map(e => e.object)
  789. .find(e => (e._listeners && e._listeners['mousemove']));
  790. if(object){
  791. object.dispatchEvent({
  792. type: 'mousemove',
  793. object: object
  794. });
  795. }
  796. }
  797. this.hoveredElements = hoveredElements
  798. }
  799. //this.intersect = this.getWholeIntersect()
  800. this.viewer.dispatchEvent($.extend(
  801. this.getEventDesc(e,isTouch),
  802. {
  803. type: 'global_mousemove',
  804. }
  805. ))
  806. }
  807. }
  808. onMouseWheel(e){
  809. if(!this.enabled) return;
  810. if(this.logMessages) console.log(this.constructor.name + ": onMouseWheel");
  811. e.preventDefault();
  812. let delta = 0;
  813. if (e.wheelDelta !== undefined) { // WebKit / Opera / Explorer 9
  814. delta = e.wheelDelta;
  815. } else if (e.detail !== undefined) { // Firefox
  816. delta = -e.detail;
  817. }
  818. let ndelta = Math.sign(delta);
  819. // this.wheelDelta += Math.sign(delta);
  820. if(!this.hoverViewport){//调试手机版时会无
  821. var { viewport } = this.getPointerInViewport(e.clientX, e.clientY )
  822. this.hoverViewport = viewport
  823. }
  824. if (this.hoveredElement) {
  825. this.hoveredElement.object.dispatchEvent($.extend(
  826. this.getEventDesc(e,isTouch),
  827. {
  828. type: 'mousewheel',
  829. delta: ndelta,
  830. object: this.hoveredElement.object
  831. }
  832. ));
  833. } else {
  834. this.viewer.dispatchEvent($.extend(
  835. this.getEventDesc(e),
  836. {
  837. type: 'global_mousewheel',
  838. delta: ndelta,
  839. }
  840. ));
  841. }
  842. setTimeout(()=>{
  843. this.dealPointerMove(e )//add 在更新完view后重新获取intersect 和 drag
  844. },1)//只延迟1会崩溃吗
  845. }
  846. startDragging (object, args = null) {
  847. let name = object ? object.name : "no name";
  848. if (this.logMessages) console.log(`${this.constructor.name}: startDragging: '${name}'`);
  849. this.drag = {
  850. start: this.pointer.clone(),
  851. end: this.pointer.clone(),
  852. pointerDelta: new THREE.Vector2(0, 0),
  853. object: object,
  854. hoverViewport: this.hoverViewport, //会变化
  855. dragViewport: this.hoverViewport, //不变
  856. };
  857. if (args) {
  858. for (let key of Object.keys(args)) {
  859. this.drag[key] = args[key];
  860. }
  861. }
  862. if(object){
  863. object.dispatchEvent($.extend(
  864. this.getEventDesc(),
  865. {
  866. type: 'startDragging'
  867. }
  868. ));
  869. }
  870. }
  871. /* getMousePointCloudIntersection (mouse) {
  872. return Utils.getMousePointCloudIntersection(
  873. this.mouse,
  874. this.scene.getActiveCamera(),
  875. this.viewer,
  876. this.scene.pointclouds);
  877. } */
  878. toggleSelection (object) {
  879. let oldSelection = this.selection;
  880. let index = this.selection.indexOf(object);
  881. if (index === -1) {
  882. this.selection.push(object);
  883. object.dispatchEvent({
  884. type: 'select'
  885. });
  886. } else {
  887. this.selection.splice(index, 1);
  888. object.dispatchEvent({
  889. type: 'deselect'
  890. });
  891. }
  892. this.dispatchEvent({
  893. type: 'selection_changed',
  894. oldSelection: oldSelection,
  895. selection: this.selection
  896. });
  897. viewer.dispatchEvent('content_changed')
  898. }
  899. deselect(object){
  900. let oldSelection = this.selection;
  901. let index = this.selection.indexOf(object);
  902. if(index >= 0){
  903. this.selection.splice(index, 1);
  904. object.dispatchEvent({
  905. type: 'deselect'
  906. });
  907. this.dispatchEvent({
  908. type: 'selection_changed',
  909. oldSelection: oldSelection,
  910. selection: this.selection
  911. });
  912. }
  913. viewer.dispatchEvent('content_changed')
  914. }
  915. deselectAll () {
  916. for (let object of this.selection) {
  917. object.dispatchEvent({
  918. type: 'deselect'
  919. });
  920. }
  921. let oldSelection = this.selection;
  922. if (this.selection.length > 0) {
  923. this.selection = [];
  924. this.dispatchEvent({
  925. type: 'selection_changed',
  926. oldSelection: oldSelection,
  927. selection: this.selection
  928. });
  929. }
  930. viewer.dispatchEvent('content_changed')
  931. }
  932. isSelected (object) {
  933. let index = this.selection.indexOf(object);
  934. return index !== -1;
  935. }
  936. registerInteractiveObject(object){
  937. this.interactiveObjects.add(object);
  938. }
  939. removeInteractiveObject(object){
  940. this.interactiveObjects.delete(object);
  941. }
  942. registerInteractiveScene (scene) {
  943. let index = this.interactiveScenes.indexOf(scene);
  944. if (index === -1) {
  945. this.interactiveScenes.push(scene);
  946. }
  947. }
  948. unregisterInteractiveScene (scene) {
  949. let index = this.interactiveScenes.indexOf(scene);
  950. if (index > -1) {
  951. this.interactiveScenes.splice(index, 1);
  952. }
  953. }
  954. getHoveredElement () {
  955. let hoveredElements = this.getHoveredElements();
  956. if (hoveredElements.length > 0) {
  957. return hoveredElements[0];
  958. } else {
  959. return null;
  960. }
  961. }
  962. getHoveredElements (interactables, dontCheckDis, raycaster) {
  963. if(!interactables){
  964. let scenes = this.hoverViewport.interactiveScenes || this.interactiveScenes.concat(this.scene);
  965. let interactableListeners = ['mouseup', 'mousemove', 'mouseover', 'mouseleave', 'drag', 'drop', 'click', 'select', 'deselect'];
  966. interactables = []
  967. for (let scene of scenes) {
  968. scene.traverseVisible(node => {//检测加了侦听的object
  969. if (node._listeners && node.visible && !this.blacklist.has(node) ) {
  970. let hasInteractableListener = interactableListeners.filter((e) => {
  971. return node._listeners[e] !== undefined;
  972. }).length > 0;
  973. if (hasInteractableListener) {
  974. interactables.push(node);
  975. }
  976. }
  977. });
  978. }
  979. }
  980. let camera = this.hoverViewport.camera
  981. if(!raycaster){
  982. let ray = Utils.mouseToRay(this.pointer, camera );
  983. raycaster = new THREE.Raycaster();
  984. raycaster.ray.set(ray.origin, ray.direction);
  985. raycaster.camera = camera //add
  986. }
  987. if(camera.type == "OrthographicCamera"){//使无论多远,threshold区域都是一样宽的
  988. raycaster.params.Line.threshold = 20/camera.zoom
  989. }else{
  990. raycaster.params.Line.threshold = 0.04; //相对长度
  991. }
  992. raycaster.params.Line2 = {threshold :20 } //拓宽的lineWidth
  993. //raycaster.layers.enableAll()//add
  994. Potree.Utils.setCameraLayers(raycaster, //设置能识别到的layers(如空间模型里只有mapViewer能识别到marker)
  995. ['sceneObjects','mapObjects','measure', 'transformationTool', 'model'],
  996. this.hoverViewport && this.hoverViewport.extraEnableLayers
  997. )
  998. //this.hoverViewport.beforeRender && this.hoverViewport.beforeRender()
  999. viewer.dispatchEvent( {type:'raycaster', viewport: this.hoverViewport})//add
  1000. let intersections = raycaster.intersectObjects(interactables.filter(o => o.visible), true, null, true); //原本是false 检测不到children
  1001. let intersectionsCopy = intersections.slice()
  1002. if(this.intersect && this.intersect.distance != void 0 && !dontCheckDis){//add
  1003. intersections = intersections.filter(e=>{
  1004. let material = e.object.material
  1005. return e.object.pickDontCheckDis || ( material.depthTest == false || material.depthWrite == false) && !material.realUseDepth //!material.depthTestWhenPick
  1006. || ( material.useDepth ? e.distance < this.intersect.distance + material.uniforms.occlusionDistance.value : e.distance < this.intersect.distance )
  1007. })
  1008. }
  1009. intersections = intersections.map(e=>{//add 转化为interactables
  1010. var object = e.object;
  1011. do{
  1012. if(interactables.includes(object)) {
  1013. e.oriObject = e.object;
  1014. e.object = object;
  1015. break
  1016. }
  1017. object = object.parent
  1018. }while(object)
  1019. return e
  1020. })
  1021. //add for测量线,在检测到sphere时优先选中sphere而非线
  1022. //intersections = intersections.sort(function(a,b){return b.object.renderOrder-a.object.renderOrder}) // 降序
  1023. intersections = intersections.sort(function(a,b){
  1024. let order2 = b.object.pickOrder || 0
  1025. let order1 = a.object.pickOrder || 0
  1026. return order2-order1
  1027. }) // 降序
  1028. //console.log('getHoveredElement ', intersections)
  1029. return intersections;
  1030. }
  1031. /* setScene (scene) {
  1032. this.deselectAll();
  1033. this.scene = scene;
  1034. } */
  1035. update (delta) {
  1036. }
  1037. /*getNormalizedDrag () {
  1038. if (!this.drag) {
  1039. return new THREE.Vector2(0, 0);
  1040. }
  1041. let diff = new THREE.Vector2().subVectors(this.drag.end, this.drag.start);
  1042. diff.x = diff.x / this.domElement.clientWidth;
  1043. diff.y = diff.y / this.domElement.clientHeight;
  1044. return diff;
  1045. }
  1046. getNormalizedLastDrag () {
  1047. if (!this.drag) {
  1048. return new THREE.Vector2(0, 0);
  1049. }
  1050. let mouseDelta = this.drag.mouseDelta.clone();
  1051. mouseDelta.x = mouseDelta.x / this.domElement.clientWidth;
  1052. mouseDelta.y = mouseDelta.y / this.domElement.clientHeight;
  1053. return mouseDelta;
  1054. } */
  1055. getMouseDirection(pointer) {//add
  1056. pointer = pointer || this.pointer
  1057. let camera = this.hoverViewport.camera
  1058. var t = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
  1059. i = new THREE.Vector3(pointer.x, pointer.y, 1).unproject(camera);
  1060. return {origin: t, direction:i.clone().sub(t).normalize() }
  1061. }
  1062. }