import * as THREE from "../../libs/three.js/build/three.module.js"; import {Measure} from "./Measure.js"; import {Utils} from "../utils.js"; import math from "./math.js"; import {CameraMode,MOUSE} from "../defines.js"; import { EventDispatcher } from "../EventDispatcher.js"; function updateAzimuth(viewer, measure){ if(!measure.showAzimuth)return const azimuth = measure.azimuth; const isOkay = measure.points.length === 2; azimuth.node.visible = isOkay if(!azimuth.node.visible){ return; } const camera = viewer.scene.getActiveCamera(); const renderAreaSize = viewer.renderer.getSize(new THREE.Vector2()); const width = renderAreaSize.width; const height = renderAreaSize.height; const [p0, p1] = measure.points; const r = p0.position.distanceTo(p1.position); const northVec = Utils.getNorthVec(p0.position, r, viewer.getProjection()); const northPos = p0.position.clone().add(northVec); azimuth.center.position.copy(p0.position); azimuth.center.scale.set(2, 2, 2); azimuth.center.visible = false; // azimuth.target.visible = false; { // north azimuth.north.position.copy(northPos); azimuth.north.scale.set(2, 2, 2); let distance = azimuth.north.position.distanceTo(camera.position); let pr = Utils.projectedRadius(1, camera, distance, width, height); let scale = (5 / pr); azimuth.north.scale.set(scale, scale, scale); } { // target azimuth.target.position.copy(p1.position); azimuth.target.position.z = azimuth.north.position.z; let distance = azimuth.target.position.distanceTo(camera.position); let pr = Utils.projectedRadius(1, camera, distance, width, height); let scale = (5 / pr); azimuth.target.scale.set(scale, scale, scale); } azimuth.circle.position.copy(p0.position); azimuth.circle.scale.set(r, r, r); azimuth.circle.material.resolution.set(width, height); // to target azimuth.centerToTarget.geometry.setPositions([ 0, 0, 0, ...p1.position.clone().sub(p0.position).toArray(), ]); azimuth.centerToTarget.position.copy(p0.position); azimuth.centerToTarget.geometry.verticesNeedUpdate = true; azimuth.centerToTarget.geometry.computeBoundingSphere(); azimuth.centerToTarget.computeLineDistances(); azimuth.centerToTarget.material.resolution.set(width, height); // to target ground azimuth.centerToTargetground.geometry.setPositions([ 0, 0, 0, p1.position.x - p0.position.x, p1.position.y - p0.position.y, 0, ]); azimuth.centerToTargetground.position.copy(p0.position); azimuth.centerToTargetground.geometry.verticesNeedUpdate = true; azimuth.centerToTargetground.geometry.computeBoundingSphere(); azimuth.centerToTargetground.computeLineDistances(); azimuth.centerToTargetground.material.resolution.set(width, height); // to north azimuth.centerToNorth.geometry.setPositions([ 0, 0, 0, northPos.x - p0.position.x, northPos.y - p0.position.y, 0, ]); azimuth.centerToNorth.position.copy(p0.position); azimuth.centerToNorth.geometry.verticesNeedUpdate = true; azimuth.centerToNorth.geometry.computeBoundingSphere(); azimuth.centerToNorth.computeLineDistances(); azimuth.centerToNorth.material.resolution.set(width, height); // label const radians = Utils.computeAzimuth(p0.position, p1.position, viewer.getProjection()); let degrees = THREE.Math.radToDeg(radians); if(degrees < 0){ degrees = 360 + degrees; } const txtDegrees = `${degrees.toFixed(2)}°`; const labelDir = northPos.clone().add(p1.position).multiplyScalar(0.5).sub(p0.position); if(labelDir.length() > 0){ labelDir.z = 0; labelDir.normalize(); const labelVec = labelDir.clone().multiplyScalar(r); const labelPos = p0.position.clone().add(labelVec); azimuth.label.position.copy(labelPos); } azimuth.label.setText(txtDegrees); let distance = azimuth.label.position.distanceTo(camera.position); let pr = Utils.projectedRadius(1, camera, distance, width, height); let scale = (70 / pr); azimuth.label.scale.set(scale, scale, scale); } export class MeasuringTool extends EventDispatcher{ constructor (viewer) { super(); this.viewer = viewer; this.renderer = viewer.renderer; this.viewer.addEventListener('start_inserting_measurement', e => { this.viewer.dispatchEvent({ type: 'cancel_insertions' }); }); this.showLabels = true; this.scene = new THREE.Scene(); this.scene.name = 'scene_measurement'; //this.light = new THREE.PointLight(0xffffff, 1.0); //this.scene.add(this.light); this.viewer.inputHandler.registerInteractiveScene(this.scene); //this.scene = viewer.overlay// this.onRemove = (e) => { e.measurement.dispose()/* this.scene.remove(e.measurement); */}; this.onAdd = e => {this.scene.add(e.measurement);}; for(let measurement of viewer.scene.measurements){ this.onAdd({measurement: measurement}); } viewer.addEventListener('camera_changed',(e)=>{ if(e.viewport == viewer.mainViewport ) this.update() }) //viewer.addEventListener("update", this.update.bind(this)); viewer.addEventListener("render.pass.perspective_overlay", this.render.bind(this)); viewer.addEventListener("scene_changed", this.onSceneChange.bind(this)); viewer.scene.addEventListener('measurement_added', this.onAdd); viewer.scene.addEventListener('measurement_removed', this.onRemove); viewer.addEventListener('resize',this.setSize.bind(this)) } onSceneChange(e){ if(e.oldScene){ e.oldScene.removeEventListener('measurement_added', this.onAdd); e.oldScene.removeEventListener('measurement_removed', this.onRemove); } e.scene.addEventListener('measurement_added', this.onAdd); e.scene.addEventListener('measurement_removed', this.onRemove); } startInsertion (args = {}, callback, cancelFun) { let domElement = this.viewer.renderer.domElement; const pick = (defaul, alternative) => { if(defaul != null){ return defaul; }else{ return alternative; } }; args.showDistances = (args.showDistances === null) ? true : args.showDistances; args.showArea = pick(args.showArea, false); args.showAngles = pick(args.showAngles, false); args.showCoordinates = pick(args.showCoordinates, false); args.showHeight = pick(args.showHeight, false); args.showCircle = pick(args.showCircle, false); args.showAzimuth = pick(args.showAzimuth, false); args.showEdges = pick(args.showEdges, true); args.closed = pick(args.closed, false); args.maxMarkers = pick(args.maxMarkers, Infinity); args.direction = args.direction//add args.type = args.type /* || 'Measurement'; */ args.showGuideLine = pick(args.showGuideLine, false); args.isRect = pick(args.isRect, false); let measure = new Measure(args); this.scene.add(measure); measure.isNew = true this.viewer.dispatchEvent({ type: 'start_inserting_measurement', measure: measure }); measure.editStateChange(true) let timer; let continueDrag = (marker)=>{ timer = setTimeout(()=>{//等 drag=null之后 //右键拖拽结束后需要重新得到drag this.viewer.inputHandler.startDragging(marker, {endDragFun} ); },1) } let endDragFun = (e) => { if (e.button == THREE.MOUSE.LEFT /* e.drag.mouse == MOUSE.LEFT */) { if (measure.points.length >= measure.maxMarkers) { end({complete:true}); }else{ if(measure.points.length == 1){//点击第一下,恢复可见 measure.markers[0].visible = true; /* if(e.drag.hoverViewport.name == 'mapViewport'){//如果在地图点击,直接使用地图上的 let pos2d = e.drag.hoverViewport.end; let newPos = new THREE.Vector3(pos2d.x,pos2d.y,-1).unproject(e.drag.hoverViewport.camera); //z:-1朝外 } */ } var marker = measure.addMarker(measure.points[measure.points.length - 1].clone()) if(args.isRect && measure.markers.length == 3){ measure.addMarker(measure.points[0].clone()) } measure.editStateChange(true) //重新激活reticule状态 continueDrag(marker) } } else if (e.button === THREE.MOUSE.RIGHT /* e.drag.mouse === MOUSE.RIGHT */) { if(e.pressDistance < 2 )end(e);//非拖拽的话 else continueDrag(e.drag.object) } }; let end = (e={}) => {//确定、结束 if(args.minMarkers != void 0){ if(!e.complete && measure.markers.length<=args.minMarkers){//右键 当个数不够时取消 this.viewer.scene.removeMeasurement(measure) cancelFun && cancelFun() return /* if(!Potree.settings.isOfficial) this.viewer.scene.removeMeasurement(measure) else if(e.drag){ //正式版本不允许右键退出, 继续 continueDrag(e.drag.object) measure.editStateChange(true) return } */ } } if (!e.complete && measure.markers.length > 3) { measure.removeMarker(measure.points.length - 1); } measure.isNew = false clearTimeout(timer) this.viewer.removeEventListener('cancel_insertions', Exit); pressExit && this.viewer.inputHandler.removeEventListener('keydown', pressExit); callback && callback() /* this.viewer.dispatchEvent({ type: 'finish_inserting_measurement', measure: measure }); */ }; let Exit = (e)=>{//模拟右键点击 if(this.viewer.inputHandler.drag){//还未触发drop的话 this.viewer.inputHandler.drag.object.dispatchEvent({ type: 'drop', drag: this.viewer.inputHandler.drag, viewer: this.viewer, pressDistance:0, button : THREE.MOUSE.RIGHT }); this.viewer.inputHandler.drag = null }else{ end() //未结束时添加新的measure时会触发 } } this.viewer.addEventListener('cancel_insertions', Exit); let pressExit if(!Potree.settings.isOfficial){ pressExit = (e)=>{ if(e.keyCode == 27){//Esc Exit() } } this.viewer.inputHandler.addEventListener('keydown', pressExit) } var marker = measure.addMarker(new THREE.Vector3(0, 0, 0)) this.viewer.inputHandler.startDragging(marker , {endDragFun}); if(measure.maxMarkers > 1){ marker.visible = false } this.viewer.scene.addMeasurement(measure); return measure; } createMeasureFromData(data){//add const measure = new Measure(data); viewer.scene.addMeasurement(measure); if(measure.guideLine)measure.guideLine.visible = false return measure } update(){ let camera = this.viewer.scene.getActiveCamera(); let domElement = this.renderer.domElement; let measurements = this.viewer.scene.measurements; // make size independant of distance let mainLabels = [], subLabels = []; for (let measure of measurements) { measure.lengthUnit = this.viewer.lengthUnit; measure.lengthUnitDisplay = this.viewer.lengthUnitDisplay; //measure.update(); updateAzimuth(this.viewer, measure); /* [...measure.markers, ...measure.edgeLabels, measure.areaLabel].forEach(e=>{ e && e.update() }); */ // labels /* let labels = measure.edgeLabels.concat(measure.angleLabels); for(let label of labels){ label.update() if(label.elem.hasClass('sub')){ subLabels.push(label) }else{ mainLabels.push(label) } } // coordinate labels for (let j = 0; j < measure.coordinateLabels.length; j++) { let label = measure.coordinateLabels[j]; label.update() mainLabels.push(label) } if(measure.showArea){ // area label let label = measure.areaLabel; label.update() mainLabels.push(label) } */ /* if(measure.showCircle){ // radius label let label = measure.circleRadiusLabel; let distance = label.position.distanceTo(camera.position); let pr = Utils.projectedRadius(1, camera, distance, clientWidth, clientHeight); let scale = (70 / pr); label.scale.set(scale, scale, scale); } */ if(!this.showLabels){ const labels = [ ...measure.sphereLabels, ...measure.angleLabels, measure.circleRadiusLabel, ]; for(const label of labels){ label.visible = false; } } } //this.updateLabelZIndex([{labels:subLabels},{labels:mainLabels}]) } setSize(e){ //e.resolution /* if(Measure.lineMats){ for(var m in Measure.lineMats){ Measure.lineMats[m].resolution.set(e.canvasWidth, e.canvasHeight); } } if(Measure.sphereMats){ for(var s in Measure.sphereMats){ Measure.sphereMats[s].uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight); } } for (let measure of this.viewer.scene.measurements) { measure.edgeLabels.concat(measure.areaLabel).forEach(label=>{ label.sprite.material.uniforms.resolution.value.set(e.canvasWidth, e.canvasHeight); }) } */ } updateLabelZIndex(group){//[{labels:[]},{}] 顺序按照z-index低到高 group.forEach((e,i)=>{ e.base = group[i-1] ? group[i-1].base + group[i-1].labels.length : 0 var labels = e.labels.sort((a,b)=>{ return b.pos2d.z - a.pos2d.z }) labels.forEach((label,index)=>{ $(label.elem).css('z-index', e.base+index) }) }) } render(o={}){ viewer.setCameraLayers(o.camera, ['measure']) this.viewer.renderer.render(this.scene, o.camera/* this.viewer.scene.getActiveCamera() */); } };