MeasuringTool.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  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 "./math.js";
  5. import {CameraMode,MOUSE} from "../defines.js";
  6. import { EventDispatcher } from "../EventDispatcher.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 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. startInsertion (args = {}, callback, cancelFun) {
  142. let domElement = this.viewer.renderer.domElement;
  143. const pick = (defaul, alternative) => {
  144. if(defaul != null){
  145. return defaul;
  146. }else{
  147. return alternative;
  148. }
  149. };
  150. args.showDistances = (args.showDistances === null) ? true : args.showDistances;
  151. args.showArea = pick(args.showArea, false);
  152. args.showAngles = pick(args.showAngles, false);
  153. args.showCoordinates = pick(args.showCoordinates, false);
  154. args.showHeight = pick(args.showHeight, false);
  155. args.showCircle = pick(args.showCircle, false);
  156. args.showAzimuth = pick(args.showAzimuth, false);
  157. args.showEdges = pick(args.showEdges, true);
  158. args.closed = pick(args.closed, false);
  159. args.maxMarkers = pick(args.maxMarkers, Infinity);
  160. args.direction = args.direction//add
  161. args.type = args.type /* || 'Measurement'; */
  162. args.showGuideLine = pick(args.showGuideLine, false);
  163. args.isRect = pick(args.isRect, false);
  164. let measure = new Measure(args);
  165. this.scene.add(measure);
  166. measure.isNew = true
  167. this.viewer.dispatchEvent({
  168. type: 'start_inserting_measurement',
  169. measure: measure
  170. });
  171. measure.editStateChange(true)
  172. let timer;
  173. let continueDrag = (marker)=>{
  174. timer = setTimeout(()=>{//等 drag=null之后 //右键拖拽结束后需要重新得到drag
  175. this.viewer.inputHandler.startDragging(marker,
  176. {endDragFun}
  177. );
  178. },1)
  179. }
  180. let endDragFun = (e) => {
  181. if (e.button == THREE.MOUSE.LEFT /* e.drag.mouse == MOUSE.LEFT */) {
  182. if (measure.points.length >= measure.maxMarkers) {
  183. end({complete:true});
  184. }else{
  185. if(measure.points.length == 1){//点击第一下,恢复可见
  186. measure.markers[0].visible = true;
  187. /* if(e.drag.hoverViewport.name == 'mapViewport'){//如果在地图点击,直接使用地图上的
  188. let pos2d = e.drag.hoverViewport.end;
  189. let newPos = new THREE.Vector3(pos2d.x,pos2d.y,-1).unproject(e.drag.hoverViewport.camera); //z:-1朝外
  190. } */
  191. }
  192. var marker = measure.addMarker(measure.points[measure.points.length - 1].clone())
  193. if(args.isRect && measure.markers.length == 3){
  194. measure.addMarker(measure.points[0].clone())
  195. }
  196. measure.editStateChange(true) //重新激活reticule状态
  197. continueDrag(marker)
  198. }
  199. } else if (e.button === THREE.MOUSE.RIGHT /* e.drag.mouse === MOUSE.RIGHT */) {
  200. if(e.pressDistance < 2 )end(e);//非拖拽的话
  201. else continueDrag(e.drag.object)
  202. }
  203. };
  204. let end = (e={}) => {//确定、结束
  205. if(args.minMarkers != void 0){
  206. if(!e.complete && measure.markers.length<=args.minMarkers){//右键 当个数不够时取消
  207. this.viewer.scene.removeMeasurement(measure)
  208. cancelFun && cancelFun()
  209. return
  210. /* if(!Potree.settings.isOfficial) this.viewer.scene.removeMeasurement(measure)
  211. else if(e.drag){ //正式版本不允许右键退出, 继续
  212. continueDrag(e.drag.object)
  213. measure.editStateChange(true)
  214. return
  215. } */
  216. }
  217. }
  218. if (!e.complete && measure.markers.length > 3) {
  219. measure.removeMarker(measure.points.length - 1);
  220. }
  221. measure.isNew = false
  222. clearTimeout(timer)
  223. this.viewer.removeEventListener('cancel_insertions', Exit);
  224. pressExit && this.viewer.inputHandler.removeEventListener('keydown', pressExit);
  225. callback && callback()
  226. /* this.viewer.dispatchEvent({
  227. type: 'finish_inserting_measurement',
  228. measure: measure
  229. }); */
  230. };
  231. let Exit = (e)=>{//模拟右键点击
  232. if(this.viewer.inputHandler.drag){//还未触发drop的话
  233. this.viewer.inputHandler.drag.object.dispatchEvent({
  234. type: 'drop',
  235. drag: this.viewer.inputHandler.drag,
  236. viewer: this.viewer,
  237. pressDistance:0,
  238. button : THREE.MOUSE.RIGHT
  239. });
  240. this.viewer.inputHandler.drag = null
  241. }else{
  242. end() //未结束时添加新的measure时会触发
  243. }
  244. }
  245. this.viewer.addEventListener('cancel_insertions', Exit);
  246. let pressExit
  247. if(!Potree.settings.isOfficial){
  248. pressExit = (e)=>{
  249. if(e.keyCode == 27){//Esc
  250. Exit()
  251. }
  252. }
  253. this.viewer.inputHandler.addEventListener('keydown', pressExit)
  254. }
  255. var marker = measure.addMarker(new THREE.Vector3(0, 0, 0))
  256. this.viewer.inputHandler.startDragging(marker , {endDragFun});
  257. if(measure.maxMarkers > 1){
  258. marker.visible = false
  259. }
  260. this.viewer.scene.addMeasurement(measure);
  261. return measure;
  262. }
  263. createMeasureFromData(data){//add
  264. const measure = new Measure(data);
  265. viewer.scene.addMeasurement(measure);
  266. if(measure.guideLine)measure.guideLine.visible = false
  267. return measure
  268. }
  269. update(){
  270. let camera = this.viewer.scene.getActiveCamera();
  271. let domElement = this.renderer.domElement;
  272. let measurements = this.viewer.scene.measurements;
  273. // make size independant of distance
  274. let mainLabels = [], subLabels = [];
  275. for (let measure of measurements) {
  276. measure.lengthUnit = this.viewer.lengthUnit;
  277. measure.lengthUnitDisplay = this.viewer.lengthUnitDisplay;
  278. //measure.update();
  279. updateAzimuth(this.viewer, measure);
  280. /* [...measure.markers, ...measure.edgeLabels, measure.areaLabel].forEach(e=>{
  281. e && e.update()
  282. }); */
  283. // labels
  284. /* let labels = measure.edgeLabels.concat(measure.angleLabels);
  285. for(let label of labels){
  286. label.update()
  287. if(label.elem.hasClass('sub')){
  288. subLabels.push(label)
  289. }else{
  290. mainLabels.push(label)
  291. }
  292. }
  293. // coordinate labels
  294. for (let j = 0; j < measure.coordinateLabels.length; j++) {
  295. let label = measure.coordinateLabels[j];
  296. label.update()
  297. mainLabels.push(label)
  298. }
  299. if(measure.showArea){ // area label
  300. let label = measure.areaLabel;
  301. label.update()
  302. mainLabels.push(label)
  303. } */
  304. /* if(measure.showCircle){ // radius label
  305. let label = measure.circleRadiusLabel;
  306. let distance = label.position.distanceTo(camera.position);
  307. let pr = Utils.projectedRadius(1, camera, distance, clientWidth, clientHeight);
  308. let scale = (70 / pr);
  309. label.scale.set(scale, scale, scale);
  310. } */
  311. if(!this.showLabels){
  312. const labels = [
  313. ...measure.sphereLabels,
  314. ...measure.angleLabels,
  315. measure.circleRadiusLabel,
  316. ];
  317. for(const label of labels){
  318. label.visible = false;
  319. }
  320. }
  321. }
  322. //this.updateLabelZIndex([{labels:subLabels},{labels:mainLabels}])
  323. }
  324. setSize(e){ //e.resolution
  325. /* if(Measure.lineMats){
  326. for(var m in Measure.lineMats){
  327. Measure.lineMats[m].resolution.set(e.canvasWidth, e.canvasHeight);
  328. }
  329. }
  330. if(Measure.sphereMats){
  331. for(var s in Measure.sphereMats){
  332. Measure.sphereMats[s].uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
  333. }
  334. }
  335. for (let measure of this.viewer.scene.measurements) {
  336. measure.edgeLabels.concat(measure.areaLabel).forEach(label=>{
  337. label.sprite.material.uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight);
  338. })
  339. } */
  340. }
  341. updateLabelZIndex(group){//[{labels:[]},{}] 顺序按照z-index低到高
  342. group.forEach((e,i)=>{
  343. e.base = group[i-1] ? group[i-1].base + group[i-1].labels.length : 0
  344. var labels = e.labels.sort((a,b)=>{
  345. return b.pos2d.z - a.pos2d.z
  346. })
  347. labels.forEach((label,index)=>{
  348. $(label.elem).css('z-index', e.base+index)
  349. })
  350. })
  351. }
  352. render(o={}){
  353. viewer.setCameraLayers(o.camera, ['measure'])
  354. this.viewer.renderer.render(this.scene, o.camera/* this.viewer.scene.getActiveCamera() */);
  355. }
  356. };