MeasuringTool.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  2. import {Measure} from "./Measure.js";
  3. import {Utils} from "../../../utils.js";
  4. import math from "../../utils/math.js";
  5. import {CameraMode} from "../../../defines.js";
  6. import {TextSprite} from '../TextSprite.js'
  7. function updateAzimuth(viewer, measure){
  8. if(!measure.showAzimuth)return
  9. const azimuth = measure.azimuth;
  10. const isOkay = measure.points.length === 2;
  11. azimuth.node.visible = isOkay
  12. if(!azimuth.node.visible){
  13. return;
  14. }
  15. const camera = viewer.scene.getActiveCamera();
  16. const renderAreaSize = viewer.renderer.getSize(new THREE.Vector2());
  17. const width = renderAreaSize.width;
  18. const height = renderAreaSize.height;
  19. const [p0, p1] = measure.points;
  20. const r = p0.position.distanceTo(p1.position);
  21. const northVec = Utils.getNorthVec(p0.position, r, viewer.getProjection());
  22. const northPos = p0.position.clone().add(northVec);
  23. azimuth.center.position.copy(p0.position);
  24. azimuth.center.scale.set(2, 2, 2);
  25. azimuth.center.visible = false;
  26. // azimuth.target.visible = false;
  27. { // north
  28. azimuth.north.position.copy(northPos);
  29. azimuth.north.scale.set(2, 2, 2);
  30. let distance = azimuth.north.position.distanceTo(camera.position);
  31. let pr = Utils.projectedRadius(1, camera, distance, width, height);
  32. let scale = (5 / pr);
  33. azimuth.north.scale.set(scale, scale, scale);
  34. }
  35. { // target
  36. azimuth.target.position.copy(p1.position);
  37. azimuth.target.position.z = azimuth.north.position.z;
  38. let distance = azimuth.target.position.distanceTo(camera.position);
  39. let pr = Utils.projectedRadius(1, camera, distance, width, height);
  40. let scale = (5 / pr);
  41. azimuth.target.scale.set(scale, scale, scale);
  42. }
  43. azimuth.circle.position.copy(p0.position);
  44. azimuth.circle.scale.set(r, r, r);
  45. azimuth.circle.material.resolution.set(width, height);
  46. // to target
  47. azimuth.centerToTarget.geometry.setPositions([
  48. 0, 0, 0,
  49. ...p1.position.clone().sub(p0.position).toArray(),
  50. ]);
  51. azimuth.centerToTarget.position.copy(p0.position);
  52. azimuth.centerToTarget.geometry.verticesNeedUpdate = true;
  53. azimuth.centerToTarget.geometry.computeBoundingSphere();
  54. azimuth.centerToTarget.computeLineDistances();
  55. azimuth.centerToTarget.material.resolution.set(width, height);
  56. // to target ground
  57. azimuth.centerToTargetground.geometry.setPositions([
  58. 0, 0, 0,
  59. p1.position.x - p0.position.x,
  60. p1.position.y - p0.position.y,
  61. 0,
  62. ]);
  63. azimuth.centerToTargetground.position.copy(p0.position);
  64. azimuth.centerToTargetground.geometry.verticesNeedUpdate = true;
  65. azimuth.centerToTargetground.geometry.computeBoundingSphere();
  66. azimuth.centerToTargetground.computeLineDistances();
  67. azimuth.centerToTargetground.material.resolution.set(width, height);
  68. // to north
  69. azimuth.centerToNorth.geometry.setPositions([
  70. 0, 0, 0,
  71. northPos.x - p0.position.x,
  72. northPos.y - p0.position.y,
  73. 0,
  74. ]);
  75. azimuth.centerToNorth.position.copy(p0.position);
  76. azimuth.centerToNorth.geometry.verticesNeedUpdate = true;
  77. azimuth.centerToNorth.geometry.computeBoundingSphere();
  78. azimuth.centerToNorth.computeLineDistances();
  79. azimuth.centerToNorth.material.resolution.set(width, height);
  80. // label
  81. const radians = Utils.computeAzimuth(p0.position, p1.position, viewer.getProjection());
  82. let degrees = THREE.Math.radToDeg(radians);
  83. if(degrees < 0){
  84. degrees = 360 + degrees;
  85. }
  86. const txtDegrees = `${degrees.toFixed(2)}°`;
  87. const labelDir = northPos.clone().add(p1.position).multiplyScalar(0.5).sub(p0.position);
  88. if(labelDir.length() > 0){
  89. labelDir.z = 0;
  90. labelDir.normalize();
  91. const labelVec = labelDir.clone().multiplyScalar(r);
  92. const labelPos = p0.position.clone().add(labelVec);
  93. azimuth.label.position.copy(labelPos);
  94. }
  95. azimuth.label.setText(txtDegrees);
  96. let distance = azimuth.label.position.distanceTo(camera.position);
  97. let pr = Utils.projectedRadius(1, camera, distance, width, height);
  98. let scale = (70 / pr);
  99. azimuth.label.scale.set(scale, scale, scale);
  100. }
  101. export class MeasuringTool extends THREE.EventDispatcher{
  102. constructor (viewer) {
  103. super();
  104. this.viewer = viewer;
  105. this.renderer = viewer.renderer;
  106. this.viewer.addEventListener('start_inserting_measurement', e => {
  107. this.viewer.dispatchEvent({
  108. type: 'cancel_insertions'
  109. });
  110. });
  111. this.showLabels = true;
  112. this.scene = new THREE.Scene();
  113. this.scene.name = 'scene_measurement';
  114. //this.light = new THREE.PointLight(0xffffff, 1.0);
  115. //this.scene.add(this.light);
  116. this.viewer.inputHandler.registerInteractiveScene(this.scene);
  117. //this.scene = viewer.overlay//
  118. this.onRemove = (e) => { e.measurement.dispose()/* this.scene.remove(e.measurement); */};
  119. this.onAdd = e => {this.scene.add(e.measurement);};
  120. for(let measurement of viewer.scene.measurements){
  121. this.onAdd({measurement: measurement});
  122. }
  123. viewer.addEventListener('camera_changed',(e)=>{
  124. if(e.viewport == viewer.mainViewport ) this.update()
  125. })
  126. //viewer.addEventListener("update", this.update.bind(this));
  127. viewer.addEventListener("render.pass.perspective_overlay", this.render.bind(this));
  128. viewer.addEventListener("scene_changed", this.onSceneChange.bind(this));
  129. viewer.scene.addEventListener('measurement_added', this.onAdd);
  130. viewer.scene.addEventListener('measurement_removed', this.onRemove);
  131. viewer.addEventListener('resize',this.setSize.bind(this))
  132. }
  133. onSceneChange(e){
  134. if(e.oldScene){
  135. e.oldScene.removeEventListener('measurement_added', this.onAdd);
  136. e.oldScene.removeEventListener('measurement_removed', this.onRemove);
  137. }
  138. e.scene.addEventListener('measurement_added', this.onAdd);
  139. e.scene.addEventListener('measurement_removed', this.onRemove);
  140. }
  141. createMeasureFromData(data){//add
  142. const measure = new Measure(data);
  143. if(measure.failBuilded){
  144. return
  145. }
  146. viewer.scene.addMeasurement(measure);
  147. if(measure.guideLine)measure.guideLine.visible = false
  148. return measure
  149. }
  150. update(){
  151. return;
  152. let camera = this.viewer.scene.getActiveCamera();
  153. let domElement = this.renderer.domElement;
  154. let measurements = this.viewer.scene.measurements;
  155. // make size independant of distance
  156. let mainLabels = [], subLabels = [];
  157. for (let measure of measurements) {
  158. measure.lengthUnit = this.viewer.lengthUnit;
  159. measure.lengthUnitDisplay = this.viewer.lengthUnitDisplay;
  160. //measure.update();
  161. updateAzimuth(this.viewer, measure);
  162. /* [...measure.markers, ...measure.edgeLabels, measure.areaLabel].forEach(e=>{
  163. e && e.update()
  164. }); */
  165. // labels
  166. /* let labels = measure.edgeLabels.concat(measure.angleLabels);
  167. for(let label of labels){
  168. label.update()
  169. if(label.elem.hasClass('sub')){
  170. subLabels.push(label)
  171. }else{
  172. mainLabels.push(label)
  173. }
  174. }
  175. // coordinate labels
  176. for (let j = 0; j < measure.coordinateLabels.length; j++) {
  177. let label = measure.coordinateLabels[j];
  178. label.update()
  179. mainLabels.push(label)
  180. }
  181. if(measure.showArea){ // area label
  182. let label = measure.areaLabel;
  183. label.update()
  184. mainLabels.push(label)
  185. } */
  186. /* if(measure.showCircle){ // radius label
  187. let label = measure.circleRadiusLabel;
  188. let distance = label.position.distanceTo(camera.position);
  189. let pr = Utils.projectedRadius(1, camera, distance, clientWidth, clientHeight);
  190. let scale = (70 / pr);
  191. label.scale.set(scale, scale, scale);
  192. } */
  193. if(!this.showLabels){
  194. const labels = [
  195. ...measure.sphereLabels,
  196. ...measure.angleLabels,
  197. measure.circleRadiusLabel,
  198. ];
  199. for(const label of labels){
  200. label.visible = false;
  201. }
  202. }
  203. }
  204. //this.updateLabelZIndex([{labels:subLabels},{labels:mainLabels}])
  205. }
  206. setSize(e){ //e.resolution
  207. /* if(Measure.lineMats){
  208. for(var m in Measure.lineMats){
  209. Measure.lineMats[m].resolution.set(e.canvasWidth, e.canvasHeight);
  210. }
  211. }
  212. if(Measure.sphereMats){
  213. for(var s in Measure.sphereMats){
  214. Measure.sphereMats[s].uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
  215. }
  216. }
  217. for (let measure of this.viewer.scene.measurements) {
  218. measure.edgeLabels.concat(measure.areaLabel).forEach(label=>{
  219. label.sprite.material.uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
  220. })
  221. } */
  222. }
  223. updateLabelZIndex(group){//[{labels:[]},{}] 顺序按照z-index低到高
  224. group.forEach((e,i)=>{
  225. e.base = group[i-1] ? group[i-1].base + group[i-1].labels.length : 0
  226. var labels = e.labels.sort((a,b)=>{
  227. return b.pos2d.z - a.pos2d.z
  228. })
  229. labels.forEach((label,index)=>{
  230. $(label.elem).css('z-index', e.base+index)
  231. })
  232. })
  233. }
  234. editStateChange(e){
  235. //console.log("editStateChange" , e.state)
  236. let state = e.state
  237. if(!state){
  238. state = viewer.scene.measurements.some(e=>e.isEditing)
  239. }
  240. if(state){
  241. viewer.dispatchEvent({type:"measureMovePoint"})
  242. }else{
  243. viewer.dispatchEvent({type:"endMeasureMove"})
  244. }
  245. //this.editing =
  246. }
  247. startInsertion (args = {}, callback, cancelFun) {
  248. let domElement = this.viewer.renderer.domElement;
  249. let measure = new Measure(args);
  250. this.scene.add(measure);
  251. measure.isNew = true
  252. this.viewer.dispatchEvent({
  253. type: 'start_inserting_measurement',
  254. measure: measure
  255. });
  256. measure.addEventListener('editStateChange', this.editStateChange.bind(this))
  257. measure.editStateChange(true)
  258. let timer;
  259. let endDragFun = (e) => {
  260. let length = measure.points.length
  261. if (e.button == THREE.MOUSE.LEFT || e.isTouch) {
  262. if (length >= measure.maxMarkers) {
  263. end({finish:true});
  264. }else{
  265. var marker = measure.addMarker({point:measure.points[length - 1].clone()})
  266. if(args.isRect && measure.markers.length == 3){//marker全可见
  267. measure.addMarker({point:measure.points[0].clone()})
  268. }else{
  269. measure.markers[length].visible = false
  270. measure.edges[length].visible = false
  271. }
  272. measure.edges[length-1].visible = true
  273. measure.markers[length-1].visible = true;
  274. measure.editStateChange(true) //重新激活reticule状态
  275. marker.isDragging = true
  276. measure.continueDrag(marker, e)
  277. }
  278. } else if (e.button === THREE.MOUSE.RIGHT ) { //触屏怎么取消?
  279. if(e.pressDistance < Potree.config.clickMaxDragDis )end(e);//非拖拽的话
  280. else measure.continueDrag(null, e)
  281. }
  282. };
  283. let end = (e={}) => {//确定、结束
  284. if(!measure.isNew || measure.markers.length == 0)return
  285. if(args.minMarkers != void 0 ){
  286. if(!e.finish && measure.markers.length<=args.minMarkers ){//右键 当个数不够时取消
  287. //this.viewer.scene.removeMeasurement(measure)
  288. //cancelFun && cancelFun()
  289. //重新开始画
  290. measure.markers[0].removeEventListener('mousedown',end)
  291. measure.reDraw()
  292. this.viewer.addEventListener('global_click', click, 10)
  293. measure.editStateChange(true)
  294. return
  295. /* if(!Potree.settings.isOfficial) this.viewer.scene.removeMeasurement(measure)
  296. else if(e.drag){ //正式版本不允许右键退出, 继续
  297. continueDrag(e.drag.object)
  298. measure.editStateChange(true)
  299. return
  300. } */
  301. }
  302. }
  303. if (/* !e.finish&& */ measure.markers.length > args.minMarkers) {
  304. measure.removeMarker(measure.points.length - 1);
  305. measure.markers[0].removeEventListener('mouseover', mouseover);
  306. measure.markers[0].removeEventListener('mouseleave', mouseleave);
  307. measure.markers[0].removeEventListener('click'/* 'mousedown' */,Exit)
  308. if(e.byClickMarker && measure.markers.length > args.minMarkers){//通过点击第一个marker而结束的话,会多一个marker
  309. measure.removeMarker(measure.points.length - 1);
  310. }
  311. }
  312. measure.isNew = false
  313. let length = measure.points.length
  314. if(length){
  315. measure.markers[length-1].visible = true;
  316. measure.edges[length-1].visible = !!measure.closed
  317. measure.markers.forEach(marker=>{marker.dispatchEvent('addHoverEvent') })
  318. measure.edges.forEach(edge=>{edge.dispatchEvent('addHoverEvent') })
  319. measure.update();//update last edgeLabel
  320. }
  321. clearTimeout(timer)
  322. this.viewer.removeEventListener('cancel_insertions', Exit);
  323. //pressExit && this.viewer.inputHandler.removeEventListener('keydown', pressExit);
  324. this.viewer.removeEventListener('global_click', click)
  325. this.viewer.removeEventListener('global_mousemove', ifAtWrongPlace)
  326. viewer.dispatchEvent({
  327. type : "CursorChange", action : "remove", name:"polygon_AtWrongPlace"
  328. });
  329. viewer.inputHandler.dispatchEvent({type:'isMeasuring', v:false, cause:'stopInsertion'} )
  330. e.remove || callback && callback()
  331. /* this.viewer.dispatchEvent({
  332. type: 'finish_inserting_measurement',
  333. measure: measure
  334. }); */
  335. };
  336. measure.addEventListener('finish', end) //完成
  337. let Exit = (e)=>{//强制退出
  338. if(e.measure && e.measure != measure){
  339. return;//若指定了退出的measure但和该measure不一致,就返回
  340. }
  341. console.log('Exit: ' + measure.id)
  342. if(e.remove){
  343. viewer.scene.removeMeasurement(measure)
  344. }
  345. measure.editStateChange(false)
  346. measure.cannotConfirmNormal = false //一些dropMarker中的句子
  347. measure.guideLine &&(measure.guideLine.visible = false)
  348. /*
  349. if(this.viewer.inputHandler.drag && !e.remove ){//还未触发drop的话
  350. this.viewer.inputHandler.drag.object.dispatchEvent({ //这句会导致又增一个marker
  351. type: 'drop',
  352. drag: this.viewer.inputHandler.drag,
  353. viewer: this.viewer,
  354. pressDistance:0,
  355. button : THREE.MOUSE.RIGHT
  356. });
  357. } else {*///未结束时添加新的measure时会触发
  358. end({finish:true, remove:e.remove, byClickMarker: e.type == 'click'})
  359. //}
  360. this.viewer.inputHandler.drag && (this.viewer.inputHandler.drag.object = null)
  361. }
  362. this.viewer.addEventListener('cancel_insertions', Exit);
  363. /*let pressExit
  364. if(!Potree.settings.isOfficial){
  365. pressExit = (e)=>{
  366. if(e.keyCode == 27){//Esc
  367. //Exit()
  368. //怎么模拟右键???//现由前端发出
  369. }
  370. }
  371. this.viewer.inputHandler.addEventListener('keydown', pressExit)
  372. } */
  373. let mouseover = (e) => {
  374. measure.setMarkerSelected(e.object, 'hover', 'single');
  375. };
  376. let mouseleave = (e) => {
  377. measure.setMarkerSelected(e.object, 'unhover', 'single');
  378. }
  379. let click = (e)=>{//一旦点击就立刻增加两marker
  380. if(ifAtWrongPlace(e))return
  381. if(e.clickElement)return //如点击label时focusOnObject
  382. if(e.button === THREE.MOUSE.RIGHT)return
  383. //console.log('measure clicked33', !!e.intersectPoint)
  384. //var I = e.intersectPoint && (e.intersectPoint.orthoIntersect || e.intersectPoint.location)
  385. var I = e.intersect && (e.intersect.orthoIntersect || e.intersect.location)
  386. if(!I){
  387. return measure.dispatchEvent('intersectNoPointcloud')
  388. }
  389. var atMap = e.drag.dragViewport.name == 'mapViewport'
  390. //在地图上测量的首个点按楼层高度(暂时先只按mainViewport相机高度吧,但navvis是按楼层,画在楼层的地面上,可能因为平面图显示的是楼层近地面),
  391. if(atMap){
  392. I = I.clone().setZ(viewer.mainViewport.camera.position.z )
  393. }
  394. var marker = measure.addMarker({point:I})
  395. marker.isDragging = true
  396. this.viewer.inputHandler.startDragging(marker , {endDragFun, notPressMouse:true} ); //notPressMouse代表不是通过按下鼠标来拖拽
  397. e.drag = this.viewer.inputHandler.drag
  398. e.drag.endDragFun = endDragFun
  399. e.drag.notPressMouse = true
  400. //if(!measure.dragMarker(e) || !measure.dropMarker(e))return
  401. measure.dragMarker(e)
  402. measure.dropMarker(e)
  403. if(measure.maxMarkers > 1 ){
  404. measure.markers[1].visible = false
  405. measure.edges[1].visible = false
  406. }
  407. if(measure.closed && !measure.isRect){
  408. measure.markers[0].addEventListener('mouseover', mouseover);
  409. measure.markers[0].addEventListener('mouseleave', mouseleave);
  410. measure.markers[0].addEventListener('click'/* 'mousedown' */,Exit) //点击到第一个marker就结束
  411. }
  412. this.viewer.removeEventListener('global_click', click)///* global_drop */
  413. //console.log('measure clicked')
  414. e.consume && e.consume()
  415. return {stopContinue:true}//防止继续执行别的侦听,如flytopano
  416. }
  417. //点击第n下拥有n+1个marker, n>0
  418. viewer.inputHandler.dispatchEvent({type: 'isMeasuring', v: true, cause:'startInsertion'})
  419. this.viewer.addEventListener('global_click', click, 10)//add importance:10
  420. let ifAtWrongPlace = (e)=>{
  421. if(measure.unableDragAtMap && e.hoverViewport.name == 'mapViewport' ){
  422. if(e.isTouch){
  423. viewer.dispatchEvent({type:'reticule_forbit', v:true})
  424. }else{
  425. viewer.dispatchEvent({
  426. type : "CursorChange", action : "add", name:"polygon_AtWrongPlace"
  427. });
  428. }
  429. return true
  430. }else{
  431. if(e.isTouch){
  432. viewer.dispatchEvent({type:'reticule_forbit',v:false})
  433. }else{
  434. viewer.dispatchEvent({
  435. type : "CursorChange", action : "remove", name:"polygon_AtWrongPlace"
  436. });
  437. }
  438. }
  439. }
  440. if(measure.unableDragAtMap){
  441. this.viewer.addEventListener('global_mousemove', ifAtWrongPlace)
  442. }
  443. this.viewer.scene.addMeasurement(measure);
  444. return measure;
  445. }
  446. render(o={}){
  447. if(this.scene.children.length == 0)return
  448. viewer.setCameraLayers(o.camera, ['measure'])
  449. if(o.screenshot && this.viewer.ssaaRenderPass.enabled){ //抗锯齿
  450. this.viewer.ssaaRenderPass.sampleLevel = 4
  451. this.viewer.composer.render(this.scene, o.camera );
  452. /* viewer.scene.measurements.forEach(e=>{ //隐藏除了label以外的
  453. e.children.forEach((c)=>{
  454. if(!(c instanceof TextSprite)){
  455. c.visible = false
  456. }
  457. })
  458. }) */
  459. }else{
  460. this.viewer.renderer.render(this.scene, o.camera );
  461. }
  462. }
  463. };