import parameter from "./parameter"; import mitt from "mitt"; import { CoordType } from "../../types"; import { Loading } from "@kankan/components/index"; import revision from "./REVISION"; import { ui18n } from "@/lang"; import libTransform from "coordtransform"; //交通版laser 主要适用设备:MatePad Pro 11英寸 const pointMeasureColor = "#3290ff" const CloneJson = function (data) { var str = JSON.stringify(data); return JSON.parse(str); }; var enter = ({ dom, mapDom, number, //datasetId, //初始数据集 webSite, //废弃,改为用dataset.webBin isLocal = false, basePath, isDebug = false, mapCompany, // 地图版本 'default' | 'google' default就跟现在一样 axios, version, //'V3''V4' 废弃,改为从getDataset获取 staticPrefix, cropArgs, getFileUrl, }) => { let isScreenshoting = false; let lastSiteModelData; let page; //所在页面 const sceneBus = mitt(); Potree.settings.isOfficial = true; //标记为正式、非测试版本 Potree.settings.isDebug = isDebug; //Potree.settings.originDatasetId = datasetId; /*if (isLocal) { //本地配置 Potree.settings.isLocal = isLocal; for (let i in Potree.settings.urls) { Potree.settings.urls[i] = basePath; //全部替换 } } webSite && (Potree.settings.webSite = webSite); //axios && (Potree.fileServer = axios); //暂时不用,比如vision那里 if (staticPrefix) { // "/dev/SS-t-4pMXagRDjk" Potree.settings.isLocal = true; Potree.settings.urls.prefix1 = Potree.settings.urls.prefix3 = staticPrefix; Potree.settings.webSite = "wwwroot"; } */ Potree.getFileUrl = getFileUrl //转化为另一种得到url的方法 Potree.start(dom, mapDom, number); parameter.dom = dom; parameter.number = number; parameter.viewer = viewer; parameter.sceneBus = sceneBus; //Potree.settings.rotAroundPoint = false; //试验 viewer.fixPoints = []//固定点 sceneBus.on("visible", (v) => { viewer.visible = v; /* if(v){ viewer.dispatchEvent('content_changed') //避免白屏 } */ //console.log('sceneBus visible', v) }); viewer.addEventListener("allLoaded", (e) => { //全部加载完,除了地图 console.log('emit allLoad') sceneBus.emit("allLoaded"); }); viewer.addEventListener("webglError", (e) => { console.error("viewer webglError: " + e); sceneBus.emit("webglError", { msg: e.msg }); }); viewer.addEventListener("viewChanged", (e) => { sceneBus.emit("viewChange", e.name) }); let cameraChange = (e) => { var camera = e.viewport.camera; var pos = camera.position; if (e.viewport.name == "MainView") { let meterPerPixel = viewer.mainViewport.camera.type == 'OrthographicCamera' ? 1 / viewer.mainViewport.camera.zoom : null//原本我设定的每像素代表1米, 然后再除以zoom //console.log('meterPerPixel', meterPerPixel) sceneBus.emit("posChange", { x: pos.x, y: pos.y, z: pos.z, rotate: camera.rotation, meterPerPixel, }); } viewer.fixPoints.forEach(point=>{ point.pos2d = Potree.Utils.getPos2d(point, e.viewport, viewer.renderArea ) point.pos2d.pos3d = point.clone() }) }; viewer.addEventListener("camera_changed", cameraChange); viewer.addEventListener("shelterComputed", () => { cameraChange({ viewport: viewer.mainViewport }); }); { Potree.loadingByTex = false; let delayShow = 400; let timer; viewer.addEventListener("loading", (e) => { //加载的等待页面 if (e.show) { if (!isScreenshoting) { //截图时不显示 Potree.loadingByTex = true; timer && clearTimeout(timer); timer = setTimeout(() => { if (Potree.loadingByTex) { Loading.show(); } }, delayShow); } } else { Potree.loadingByTex = false; timer && clearTimeout(timer); Loading.hide(); } }); } let info; const units = { 1: "metric", 2: "imperial" }; let getMeasureType = function (type, unit) { switch (type) { case 'BASE_LINE': info = { measureType: "Hor LINE with Text", //带有文字label的线 labelText : '基准线', isBaseLine : true, //暂时只有基准线是这种measureType }; break; case "LINE": info = { measureType: "Distance" }; break; case "SERIES": info = { measureType: "MulDistance" }; break; case "AREA": info = { measureType: "Area" }; break; case "L_LINE": info = { measureType: "Hor Distance" }; break; case "L_SERIES": info = { measureType: "Hor MulDistance" }; break; case "L_AREA": info = { measureType: "Hor Area" }; break; case "L_RECTANGLE": info = { measureType: "Hor Rect Area" }; break; case "V_LINE": info = { measureType: "Ver Distance" }; break; case "V_SERIES": info = { measureType: "Ver MulDistance" }; break; case "V_AREA": info = { measureType: "Ver Area" }; break; case "V_RECTANGLE": info = { measureType: "Ver Rect Area" }; break; default: console.error("无此 measure type", type); } info.unit = units[unit]; return info; }; let getMeasureFunction = function (measure, bus, isShape) { measure.addEventListener("marker_dropped", (e) => { //拖拽结束后发送changeCallBack if (measure.parent) { //未被删除 isShape ? bus.emit("graphChange", {path:measure.points, center:measure.getCenter()}) : bus.emit("update"); if(measure.isBaseLine){ viewer.dispatchEvent('baseLineChanged') } } }); /* measure.addEventListener("highlight", (e) => { bus.emit("highlight", e.state); }); */ measure.addEventListener("selected", (e) => { bus.emit(isShape ? "selectGraph":"selected", e.state) isShape && measure.mainPoint.ret.selected(e.state, true) }); return { quit: () => { Potree.Log("quit结束且删除: " + measure.id, { font: { color: "#00c7b2" }, }); viewer.dispatchEvent({ type: "cancel_insertions", remove: true, measure, }); }, //触发结束。退出测量模式,清除之前操作 clear: () => { //删除 Potree.Log("clear删除: " + measure.id, { font: { color: "#00c7b2" } }); viewer.dispatchEvent({ type: "cancel_insertions", remove: true, measure, }); viewer.scene.removeMeasurement(measure); if(measure.isBaseLine){ viewer.dispatchEvent('baseLineRemoved') } }, end: () => { //完成 相当于右键 measure.dispatchEvent({ type: "finish", measure }); }, getPoints: () => { return measure.points; }, getDatasetLocations: () => { return measure.dataset_points; }, getDatasets: () => { return [1]//measure.points_datasets; }, getDatasetId: () => { return 1//measure.datasetId; }, getArea: () => { return measure.area; //{value:area, string:..} }, getDistance: () => { if (measure.points.length < 2) return null; var value = measure.getTotalDistance(); //measure.points[0].distanceTo(measure.points[1]) return { value, //米 string: viewer.unitConvert.convert( value, "distance", Potree.settings.precision, measure.unitSystem, 0.01, true,true), }; }, changeUnit: (unit) => { //公制|英制 , 1 | 2 单位 measure.setUnitSystem(units[unit]); }, toDataURL: (width, height) => { //截图 isScreenshoting = true; var { getImagePromise, finishPromise } = viewer.startScreenshot({ type: "measure", measurement: measure, hideMarkers: true, ifGetPose: true, }, width, height); finishPromise.done(() => { isScreenshoting = false; }); return finishPromise; //getImagePromise.done时是可以getPose的, finishPromise.done时才开始截下一张图 }, //手动开启或关闭: show: () => { Potree.Utils.updateVisible(measure, "forceByUser", true); viewer.dispatchEvent('content_changed') }, hide: () => { Potree.Utils.updateVisible(measure, "forceByUser", false); viewer.dispatchEvent('content_changed') }, /* highlight: (isHight) => { measure.setSelected(isHight, "byList"); }, */ selected: (state, dontMoveCamera ) => { //measure.setSelected(state, "byList"); if(state){ measure.focus({dontMoveCamera}) }else{ measure.dispatchEvent('cancelSelect') } }, }; }; /* let getMeasurePointsInfo = (fixPoint, onlyMoveBasePoint)=>{ let baseLine = viewer.scene.measurements.find(e=>e.isBaseLine && e.points.length == 2) if(!baseLine){ return console.error('创建失败,因基准线不存在') } if(!fixPoint.basePoint){ return //console.log('no basePoint') } let fixPoint2d = new THREE.Vector2().copy(fixPoint) let baselineP12d = new THREE.Vector2().copy(baseLine.points[0]) let baselineP22d = new THREE.Vector2().copy(baseLine.points[1]) let foot1_2d = Potree.math.getFootPoint(fixPoint2d, baselineP12d, baselineP22d) let minZ = Math.min(fixPoint.basePoint.z, baseLine.points[0].z, fixPoint.z) let maxZ = Math.max(fixPoint.basePoint.z, baseLine.points[0].z, fixPoint.z) let foot1_P1 = new THREE.Vector3(foot1_2d.x, foot1_2d.y, fixPoint.z) let foot1_P2 = new THREE.Vector3(foot1_2d.x, foot1_2d.y, minZ) let foot1_P3 = new THREE.Vector3(foot1_2d.x, foot1_2d.y, maxZ) let info = { disMeasure1:{ points: [new THREE.Vector3().copy(fixPoint), foot1_P1], guideLinePoints : [foot1_P2, foot1_P3] //垂足上的垂线,从最低点到最高点(包含disMeasure2那一段) } } let basePoint2d = new THREE.Vector2().copy(fixPoint.basePoint) let anotherPoint2d = new THREE.Vector2().addVectors(basePoint2d, new THREE.Vector2().subVectors(baselineP12d,baselineP22d))//测量线方向上另一点 let foot2_2d = Potree.math.getFootPoint(fixPoint2d, basePoint2d, anotherPoint2d) let foot2_P1 = new THREE.Vector3(foot2_2d.x, foot2_2d.y, fixPoint.basePoint.z) let foot2_P2 = new THREE.Vector3(foot1_2d.x, foot1_2d.y, fixPoint.basePoint.z) info.disMeasure2 = { points : [new THREE.Vector3().copy(fixPoint.basePoint), foot2_P1], guideLinePoints : [foot2_P1, foot2_P2 ], } fixPoint.bus.emit('measureChange',[ {line: info.disMeasure1.points, dis: info.disMeasure1.points[0].distanceTo(info.disMeasure1.points[1])}, {line: info.disMeasure2.points, dis: info.disMeasure2.points[0].distanceTo(info.disMeasure2.points[1])} ]) return info } */ let getMeasurePointsInfo = (fixPoint, baseMeasurePoints )=>{ let baseLine = viewer.scene.measurements.find(e=>e.isBaseLine && e.points.length == 2) if(!baseLine){ return console.error('创建失败,因基准线不存在') } if(!fixPoint.basePoint){ return //console.log('no basePoint') } let fixPoint2d = new THREE.Vector2().copy(fixPoint) let baselineP12d = new THREE.Vector2().copy(baseLine.points[0]) let baselineP22d = new THREE.Vector2().copy(baseLine.points[1]) let foot1_2d = Potree.math.getFootPoint(fixPoint2d, baselineP12d, baselineP22d) let foot1_P1 = new THREE.Vector3(foot1_2d.x, foot1_2d.y, baseLine.points[0].z) let fixPointProj = fixPoint.clone().setZ(baseLine.points[0].z) let info = { disMeasure1:{ points: [fixPointProj, foot1_P1], guideLinePoints : [new THREE.Vector3().copy(fixPoint), fixPointProj] //垂足上的垂线,从最低点到最高点(包含disMeasure2那一段) } } let basePointProj = fixPoint.basePoint.clone().setZ(baseLine.points[0].z) if(baseMeasurePoints){//初始创建 info.disMeasure2 = { points : baseMeasurePoints, guideLinePoints:[fixPoint.basePoint.clone(), basePointProj, basePointProj, baseMeasurePoints[0].clone(), baseMeasurePoints[1].clone(), foot1_P1] } }else{ let basePoint2d = new THREE.Vector2().copy(fixPoint.basePoint) let anotherPoint2d = new THREE.Vector2().addVectors(basePoint2d, new THREE.Vector2().subVectors(baselineP12d,baselineP22d))//测量线方向上另一点 let foot2_2d = Potree.math.getFootPoint(fixPoint2d, basePoint2d, anotherPoint2d) let foot2_P1 = new THREE.Vector3(foot2_2d.x, foot2_2d.y, baseLine.points[0].z) info.disMeasure2 = { points : [basePointProj, foot2_P1 ], guideLinePoints : [fixPoint.basePoint.clone(), basePointProj, foot2_P1, foot1_P1], } } //fixPoint.emitLines() return info } //基准点处的测量线会重叠在一起,建议错开,向道路外移动。但是容易看起来很多线,为了整齐,让最长的在最里层;但需要每次排序更新所有的线…… let createMeasureForPoint = (fixPoint, baseMeasurePoints)=>{ let info = getMeasurePointsInfo(fixPoint, baseMeasurePoints) if(!info)return let info1 = {//垂直于基准线的水平测量线 measureType : 'Hor Distance', color : pointMeasureColor , unableDrag: true, points: info.disMeasure1.points, guideLinePoints : info.disMeasure1.guideLinePoints } let disMeasure1 = viewer.measuringTool.createMeasureFromData(info1); let info2 = {//平行于基准线的水平测量线 measureType : 'Hor Distance', color : pointMeasureColor , unableDrag: true, points: info.disMeasure2.points, guideLinePoints : info.disMeasure2.guideLinePoints } let disMeasure2 = viewer.measuringTool.createMeasureFromData(info2); //因多个measure在同一直线上,会重叠,所以使可拖拽 let mouseover = (e) => { viewer.dispatchEvent({ type : "CursorChange", action : "add", name:"markerMove" }) }; let mouseleave = (e) => { viewer.dispatchEvent({ type : "CursorChange", action : "remove", name:"markerMove" }) } disMeasure2.edges[0].addEventListener('mouseover', mouseover); disMeasure2.edges[0].addEventListener('mouseleave', mouseleave); let dragInfo = {} disMeasure2.edges[0].addEventListener('startDragging',(e)=>{ dragInfo = { startMeasurePoints : disMeasure2.points.map(e=>e.clone()), dragPoint : e.drag.location.clone(), normal : new THREE.Vector3().copy(Potree.math.getNormal2d({p1:disMeasure2.points[0], p2:disMeasure2.points[1]})).setZ(0), //measure的法线 plane: new THREE.Plane().setFromNormalAndCoplanarPoint(new THREE.Vector3(0,0,1), disMeasure2.points[0]), //水平面 } }) disMeasure2.edges[0].addEventListener('drag',(e)=>{ //平移 let ray = Potree.Utils.mouseToRay(e.pointer, e.drag.dragViewport.camera); let I = ray.intersectPlane(dragInfo.plane, new THREE.Vector3()) if(!I)return //向上了 let dragVec = new THREE.Vector3().subVectors(I, dragInfo.dragPoint); dragVec.projectOnVector(dragInfo.normal) dragDisMeasure2(fixPoint, dragVec, dragInfo.startMeasurePoints) fixPoint.emitLines() }) fixPoint.disMeasure1 = disMeasure1; fixPoint.disMeasure2 = disMeasure2; let selected ;[disMeasure1,disMeasure2].forEach(measure=>{ measure.addEventListener("selected", (e) => { let newState = disMeasure1.clickSelected || disMeasure2.clickSelected if(selected != newState){ selected = newState console.error('selectMeasure', selected, fixPoint.index11) fixPoint.bus.emit('selectMeasure', selected) } }) }) fixPoint.emitLines() } let dragDisMeasure2 = (fixPoint, dragVec, startMeasurePoints)=>{//将disMeasure2拖拽一定距离 let disMeasure1 = fixPoint.disMeasure1, disMeasure2 = fixPoint.disMeasure2 startMeasurePoints = startMeasurePoints || disMeasure2.points //开始拖拽时的点 disMeasure2.points = startMeasurePoints.map(e=>new THREE.Vector3().addVectors(e,dragVec)) let basePointProj = disMeasure2.guideLinePoints[1] let foot1_P1 = disMeasure2.guideLinePoints[disMeasure2.guideLinePoints.length-1] disMeasure2.guideLinePoints = [fixPoint.basePoint.clone(), basePointProj, //修改虚线 basePointProj, disMeasure2.points[0].clone(), disMeasure2.points[1].clone(), foot1_P1] disMeasure2.updateGuideLines() disMeasure2.update({ifUpdateMarkers:true}) viewer.dispatchEvent('content_changed') } let updateMeasureForPoint = (fixPoint, {onlyBasePoint,updateBaseLine}={})=>{ if(!fixPoint.disMeasure1)return let ps = fixPoint.disMeasure2.guideLinePoints let dragVec = ps.length == 6 && new THREE.Vector3().subVectors(ps[3],ps[2]) let info = getMeasurePointsInfo(fixPoint) if(!info)return if(!onlyBasePoint){ fixPoint.disMeasure1.points = info.disMeasure1.points fixPoint.disMeasure1.update({ifUpdateMarkers:true}) } fixPoint.disMeasure1.guideLinePoints = info.disMeasure1.guideLinePoints fixPoint.disMeasure1.updateGuideLines() fixPoint.disMeasure2.points = info.disMeasure2.points fixPoint.disMeasure2.update({ifUpdateMarkers:true}) fixPoint.disMeasure2.guideLinePoints = info.disMeasure2.guideLinePoints fixPoint.disMeasure2.updateGuideLines() if(dragVec){//基准点的那条垂线如果移动过 if(updateBaseLine){//移动基准线的话dragVec也改变方向了 let baseLine = viewer.scene.measurements.find(e=>e.isBaseLine && e.points.length == 2) let dragDir = dragVec.cross(baseLine.lineDir).z < 0 ? 1 : -1//相对于基准线向外or向内 ps = fixPoint.disMeasure2.guideLinePoints let newVec = new THREE.Vector3().subVectors(ps[ps.length-2],ps[ps.length-1]).normalize() let dis = dragVec.length() * dragDir newVec.multiplyScalar(dis) dragVec = newVec } dragDisMeasure2(fixPoint, dragVec)//恢复之前拖拽的距离 } fixPoint.emitLines() } let removeMeasureForPoint = (fixPoint)=>{ viewer.scene.removeMeasurement(fixPoint.disMeasure1); viewer.scene.removeMeasurement(fixPoint.disMeasure2); fixPoint.disMeasure1 = null fixPoint.disMeasure2 = null fixPoint.basePoint = null } var sdk = { temp: {}, //记录 debug: isDebug, scene: { getScreenByPoint(pos, canShelter) { //通过真实坐标获取DOM坐标 let pos3d = new THREE.Vector3().copy(pos); if (canShelter) { if (viewer.ifPointBlockedByIntersect(pos3d)) { //console.log('shelter') return { trueSide: false }; } } var viewport = viewer.mainViewport; var camera = viewport.camera; var dom = viewer.renderArea; //Potree.Log('getScreenByPoint scene' , pos3d.toArray(), {font:{toFixed:2,fontSize:10}}) return Potree.Utils.getPos2d(pos3d, viewport, dom ); }, getPointByScreen(pos2d) { //获取当前画面鼠标所在位置的三维点(必须是点云点) let position, /* datasetId, dataset_location, */ intersect; let Handler = viewer.inputHandler; let needReGet = !Potree.settings.depTexLocBindDataset && Potree.settings.useDepthTex && Handler.intersect && !Handler.intersect.pointcloud; //如果开启了depTexLocBindDataset,热点就可能使用深度图了,属于该漫游点。全景得到的位置更均匀 if ((pos2d && pos2d.inDrag) || needReGet) { //不使用当前鼠标所在位置的intersect,单独算 if (!pos2d) { // needReGet intersect = Handler.getIntersect({viewport:Handler.hoverViewport, onlyGetIntersect:true, usePointcloud: true}) //数据集多的时候卡顿 intersect = Handler.getIntersect( Handler.hoverViewport, true, null, null, true); //数据集多的时候卡顿 } else { pos2d.clientX = pos2d.x; pos2d.clientY = pos2d.y; pos2d.onlyGetIntersect = true; pos2d.whichPointcloud = !Potree.settings.depTexLocBindDataset; pos2d.usePointcloud = true // 深度图不准 intersect = Handler.onMouseMove(pos2d); } } else { intersect = Handler.intersect; } if (intersect && intersect.location) { position = intersect.location.clone(); /* datasetId = intersect.pointcloud.dataset_id; dataset_location = Potree.Utils.datasetPosTransform({ toDataset: true, pointcloud: intersect.pointcloud, position, }); */ } else return null; //console.log('getPointByScreen',position ) return { position, /* datasetId, dataset_location */ }; }, //全景模式一直获取会很卡 getPose2() { const camera = viewer.scene.getActiveCamera(); const target = viewer.scene.view.getPivot(); const position = viewer.scene.view.position; return { position, target }; }, currentCamera() { return viewer.scene.getActiveCamera().position.clone(); }, // 切换模式 1 点云 0 全景图 changeMode(v) { //Potree.settings.displayMode = Potree.settings.displayMode == 'showPointCloud' ? 'showPanos' : 'showPointCloud' Potree.settings.displayMode = v == 0 ? "showPanos" : "showPointCloud"; }, getCurrentMode() { return Potree.settings.displayMode == "showPanos" ? 0 : 1; }, comeToTag(tag) { let dontLookUp = page == "geoRegistration"; //防止相机在地面以下 return viewer.focusOnObject({ position: new THREE.Vector3().copy(tag) }, "tag", null, { dontLookUp, maxDis: Potree.config.panoFieldRadius, checkIntersect: true /*, sameFloor:true */, }).promise; }, comeToMeasure(measure) { let result = viewer.focusOnObject(measure.object, "measure", 1200); return result.msg ? result.msg : result.promise; //返回值 1 deferred 表示即将位移 2 'posNoChange' 表示已在最佳位置 3 'tooFar' 表示距离最佳位置太远 //后两种都代表停在原位 }, comeTo(o = {}) { //飞到某个点 暂时没写全景模式 let deferred = $.Deferred(); viewer.scene.view.setView( $.extend({}, o, { duration: o.dur, callback: () => { o.callback && o.callback(); deferred.resolve(true); }, })); return deferred.promise(); }, /** * 开始测量 */ startMeasure(type, unit, color) { const bus = mitt(); let info = getMeasureType(type, unit); //info.bus = bus info.color = color let measure = viewer.measuringTool.startInsertion( info, () => { //done: bus.emit("end", ret); //完成 }, () => { //cancel bus.emit("quit", ret); //删除 }); Potree.Log("startMeasure: " + measure.id, { font: { color: "#00c7b2" }, }); viewer.setPointStandardMat(true); const ret = { bus, type, object: measure, ...getMeasureFunction(measure, bus), }; measure.addEventListener("intersectNoPointcloud", () => { bus.emit("invalidPoint"); }); measure.addEventListener("firstClick", () => { bus.emit("firstClickMarker"); }); return ret; }, quitMeasure() { viewer.setPointStandardMat(false); }, /** * 绘画测量点 */ drawMeasure( type, unit, points, datasetId, dataset_points, points_datasets, sid, color) { const bus = mitt(); /* if(!viewer.scene.measurements.find(e=>e.isBaseLine)){ type = 'BASE_LINE' } */ let info = getMeasureType(type, unit); info.points = points; //info.datasetId = datasetId; info.dataset_points = dataset_points; info.points_datasets = points_datasets; info.sid = sid; info.bus = bus; info.color = color let measure = viewer.measuringTool.createMeasureFromData(info); Potree.Log("drawMeasure由数据新建: " + measure.id, { font: { color: "#00c7b2" }, }); //console.log(info) /* if(measure.isBaseLine && viewer.mainViewport.camera.type != 'OrthographicCamera'){ Potree.Utils.updateVisible(measure,'enterOrthoView',false)//基准线仅在正交视图可见 } */ const ret = { // 退出测量模式,清除之前操作 object: measure, bus, ...getMeasureFunction(measure, bus), }; viewer.dispatchEvent({type:'camera_changed', viewport:viewer.mainViewport, changeInfo:{}})//update sprite return ret; }, /* // 创建固定点对象,measure是否是测量模式, //graph 如果是形状则有形状路径点,如果不是形状则传入pos当前固定点的位置 sdk.scene.createFixPoint({ measure: boolean, graph: Array<{x,y,z}>, pos: {xyz} }) */ createFixPoint({measure, graph, pos, basePoint }, lines){//创建固定点或多线段 console.log('createFixPoint',measure, graph, pos, basePoint, lines) let ifDrawVerMeasure = measure//是否绘制垂线 let shape, measureFun, mainPoint = new THREE.Vector3(), bus = mitt(); basePoint && (mainPoint.basePoint = new THREE.Vector3().copy(basePoint)) mainPoint.bus = bus mainPoint.index11 = Math.random() let disMeasure2points = lines && lines[1].points.map(e=>new THREE.Vector3().copy(e)) const baseLineChanged = ()=>{ updateMeasureForPoint(mainPoint,{updateBaseLine:true}) } const setDisplay = (show)=>{ if(graph){ Potree.Utils.updateVisible(shape, "forceByUser", show); } if(ifDrawVerMeasure){ Potree.Utils.updateVisible(mainPoint.disMeasure1, "forceByUser", show); Potree.Utils.updateVisible(mainPoint.disMeasure2, "forceByUser", show); } viewer.dispatchEvent('content_changed') } mainPoint.emitLines = ()=>{ mainPoint.bus.emit('measureChange',[ {line: mainPoint.disMeasure1.points.map(e=>e.clone()), dis: mainPoint.disMeasure1.points[0].distanceTo(mainPoint.disMeasure1.points[1])}, {line: mainPoint.disMeasure2.points.map(e=>e.clone()), dis: mainPoint.disMeasure2.points[0].distanceTo(mainPoint.disMeasure2.points[1])} ]) } if(graph){ //多线段形状 let info = { measureType : 'MulDistance_shape', color : pointMeasureColor } let updateMeasure = ()=>{ if(!shape.isNew){//更新中心点和垂线 mainPoint.copy(shape.getCenter()) updateMeasureForPoint(mainPoint) } } if(graph.length == 0){//开始绘制 shape = viewer.measuringTool.startInsertion( info, () => { bus.emit("end", ret); //完成 shape.dispatchEvent('cancelSelect') ifDrawVerMeasure && (createMeasureForPoint(mainPoint) , updateMeasure()) }, () => { bus.emit("quit", ret); //删除 }); }else{//已经得到全部点 info.points = graph; info.sid = Math.random()//sid; info.bus = bus; shape = viewer.measuringTool.createMeasureFromData(info); ifDrawVerMeasure && (createMeasureForPoint(mainPoint, disMeasure2points) , updateMeasure()) } ifDrawVerMeasure && bus.on("graphChange",updateMeasure) measureFun = getMeasureFunction(shape, bus, true) shape.mainPoint = mainPoint //和普通MulDistance不同点:选中才能拖拽 非选中时不展示marker (clickSelected);选中后marker是非选中状态, 但是颜色一样 //https://lanhuapp.com/web/#/item/project/stage?tid=de3e5e3e-a489-4b19-862a-7c87ce113467&pid=fa4ff928-d61e-438a-b8ee-f848048b7f52 }else{//固定点 mainPoint.copy(pos) mainPoint.isFixPoint = true mainPoint.pos2d = Potree.Utils.getPos2d(mainPoint, viewer.mainViewport, viewer.renderArea ) if(ifDrawVerMeasure){ createMeasureForPoint(mainPoint, disMeasure2points) setTimeout(()=>{ mainPoint.emitLines() },10) } viewer.fixPoints.push(mainPoint) } ifDrawVerMeasure && viewer.addEventListener('baseLineChanged',baseLineChanged) const ret = { bus, destroy : ()=>{ console.log('destroy' ) ret.quitMeasure() if(graph){ measureFun.clear() }else{ let index = viewer.fixPoints.indexOf(mainPoint) index > -1 && viewer.fixPoints.splice(index,1) } }, quitMeasure(){//退出测量模式,删除测量线. 基准线被删时 console.log('quitMeasure' ) if(ifDrawVerMeasure){ ifDrawVerMeasure = false removeMeasureForPoint(mainPoint) viewer.removeEventListener('baseLineChanged',baseLineChanged) } }, changePos(pos){//固定点修改 console.log('changePos',pos) mainPoint.copy(pos) if(ifDrawVerMeasure){ updateMeasureForPoint(mainPoint) } }, changeBase(pos){//基准点修改 console.log('changeBase',pos) if(ifDrawVerMeasure){ mainPoint.basePoint.copy(pos) updateMeasureForPoint(mainPoint,{onlyBasePoint:true}) } }, graphDrawComplete: measureFun && measureFun.end, show:()=>{ setDisplay(true) }, hide:()=>{ setDisplay(false) }, selected(state, ignoreShape){ //console.error(mainPoint.index11, 'selected', state) if(graph){ ignoreShape || measureFun.selected(state) } if(ifDrawVerMeasure && mainPoint.disMeasure1){ if(state){ mainPoint.disMeasure1.focus({dontMoveCamera:true, dontEmit:true}) mainPoint.disMeasure2.focus({dontMoveCamera:true, dontEmit:true}) }else{ mainPoint.disMeasure1.dispatchEvent('cancelSelect') mainPoint.disMeasure2.dispatchEvent('cancelSelect') } } } }; mainPoint.ret = ret return ret }, // 开启放大镜 openMagnifier() { //console.error('开启放大镜') viewer.magnifier.dispatchEvent({ type: "setEnable", value: true }); }, // 关闭放大镜 closeMagnifier() { //console.error('关闭放大镜') viewer.magnifier.dispatchEvent({ type: "setEnable", value: false }); }, changePointDensity(levelType) { //点云密度:低中高 Potree.settings.UserPointDensity = levelType; return { percent: Potree.config.pointDensity[levelType].maxLevelPercent, }; //回调需要更改密度百分比滑动条 }, changeDensityPercent(percent) { //点云密度百分比(细节) percent : 0-1 //console.log('changeDensityPercent ', percent) //有出现过首次加载大于1的情况??? Potree.settings.UserDensityPercent = percent; viewer.setPointLevels(); }, // 设置far changeViewRange(num) { Potree.settings.cameraFar = num; }, // 设置色彩模式 0 彩色 1 海拔 2 半透明(透明色) changeColorMode: function (mode) { const modes = ["rgba", "elevation", "color"]; mode = modes[mode]; //console.log('设置色彩模式 ', mode) let otherChange = {}; switch (mode) { case "rgba": //每个点的颜色 otherChange.opacity = 1; otherChange.size = 0.4 / 4; break; case "elevation": otherChange.opacity = 0.3; otherChange.size = 0.4 / 4; break; case "color": //透明色 //otherChange.color = '' otherChange.opacity = 0.3; otherChange.size = 0.4 / 4; break; } viewer.scene.pointclouds.forEach((e) => { e.material.activeAttributeName = mode; }); sdk.scene.changePointSize(otherChange.size); sdk.scene.changePointOpacity(otherChange.opacity); delete otherChange.color; return otherChange; }, // 设置点大小 changePointSize(num) { viewer.scene.pointclouds.forEach((e) => { e.changePointSize(num); }); }, // 设置点透明度 changePointOpacity: function (num) { //num:0-1 navvis用的是亮度 viewer.scene.pointclouds.forEach((e) => { e.changePointOpacity(num); }); }, // 设置点形状 传入参数 1 矩形 2 圆形 changePointShape(shape) { viewer.scene.pointclouds.forEach((e) => { e.material.shape = Potree.PointShape[shape == 1 ? "SQUARE" : "CIRCLE"]; // and PARABOLOID }); }, // 设置是否强化边缘 changePointEdge(isStrong) { //console.log('强化边缘', isStrong) viewer.setEDLEnabled(isStrong); }, // 设置漫游点位显示 changePanoPoint(show) { Potree.settings.ifShowMarker = !!show; }, getDownloadInfo() { //获取直接下载点云的参数给后台 return viewer.modules.Clip.downloadNoCrop(); }, /* getDataSets() { //获取所有数据集对象 let datasets = CloneJson(Potree.datasetData); datasets.forEach((e) => { var pointcloud = viewer.scene.pointclouds.find( (p) => p.dataset_id == e.id); e.changeDisplay = function (show) { Potree.Utils.updateVisible(pointcloud, "datasetSelection", !!show); pointcloud.panos.forEach((pano) => { //数据集隐藏时漫游点也隐藏 //还是不隐藏了,仅隐藏点云 Potree.Utils.updateVisible(pano, "pointcloudVisi", show, 0); }); if ( viewer.modules.SiteModel.editing || viewer.modules.Alignment.editing) { viewer.updateFpVisiDatasets(); } }; e.changeColor = function (color) { pointcloud.material.color = color; }; e.getColor = function () { return pointcloud.material.color; }; e.focus = function () { viewer.modules.Alignment.SplitScreen.focusOnPointCloud(pointcloud); }; e.flyTo = function () { return viewer.flyToDataset({ pointcloud }) || false; }; e.getAttachPloygon = function () { //计算完后才会有 return ( pointcloud.belongToEntity && pointcloud.belongToEntity.polygon); }; }); return datasets; }, */ screenshot: (width, height, bgOpacity=1) => { //截图 let meterPerPixel, isScreenshoting = true; var { getImagePromise, finishPromise } = viewer.startScreenshot({ type: "default", hideMarkers:true, bgOpacity //hideMeasures:true, }, width, height); finishPromise.done(() => { isScreenshoting = false; }); if(viewer.mainViewport.camera.type == 'OrthographicCamera'){ meterPerPixel = 1 / viewer.mainViewport.camera.zoom } return {finishPromise, meterPerPixel}; }, canTurnToPanoMode(pos) { /* if(viewer.hasNoPanoDataset){ return } */ pos = pos ? new THREE.Vector3().copy(pos) : viewer.images360.position; let pano = viewer.images360.findNearestPano(pos); if ( pano && pano.position.distanceTo(pos) < Potree.config.panoFieldRadius) { return true; } //poschange后会调用这个,如果返回false会变为点云模式,且不会自动变回原先的模式 }, trackScenePos(){// 单击场景某个位置 返回当前三维坐标, 调用时场景不能漫游与选择直到获取完成 let deferred = $.Deferred(); let quit = ()=>{ //取消获取 viewer.removeEventListener('global_click',gotIntersect) Potree.settings.unableNavigate = false Potree.settings.unableUseDepTexPick = false viewer.controls.setEnable(true) } let gotIntersect = (e)=>{ if(e.intersect && e.intersect.location){ console.log('quit', e.intersect.location) quit() deferred.resolve(e.intersect.location) } } viewer.addEventListener('global_click',gotIntersect) Potree.settings.unableNavigate = true Potree.settings.unableUseDepTexPick = true viewer.controls.setEnable(false) viewer.scene.measurements.forEach(e=>e.dispatchEvent('cancelSelect')) //避免stopContinue return { promise: deferred.promise() , //获取的promise, 获取到了返回三维坐标,没获取到返回null quit } }, getSceneCropSetting(){ let boxData = viewer.modules.Clip.getBoxData() return { top : {value:boxData.scaleZ*100, minTop:0, maxTop:10}, scale : {value: boxData.scaleXY*100}, rotate : {value: THREE.Math.radToDeg(boxData.rotAngle)}, //rotByUser : {value:boxData.rotByUser} } }, //设置裁剪值 setSceneCropSetting({top,scale,rotate }){ viewer.modules.Clip.boxData = { scaleZ: top.value/100, scaleXY: scale.value/100, rotAngle: THREE.Math.degToRad(rotate.value), //rotByUser } viewer.modules.Clip.setBoxPose() }, enterCropSetting(){ let Clip = viewer.modules.Clip Clip.enter() return { quit(){ Clip.leave() }, enterSetScale(){ Clip.box.frameHorizon.visible = true }, leaveSetScale(){ Clip.box.frameHorizon.visible = false }, enterSetTop(){ Clip.box.frameVertical.visible = true }, leaveSetTop(){ Clip.box.frameVertical.visible = false }, enterSetRotate(){ Clip.box.frameHorizon.visible = true Clip.box.frameVertical.visible = true }, leaveSetRotate(){ Clip.box.frameHorizon.visible = false Clip.box.frameVertical.visible = false }, } }, ...parameter.sceneBus, }, transformPoint(point, datasetId, dataset_location) { /* //获取由dataset_location转出的position var r = datasetId != void 0 ? Potree.Utils.datasetPosTransform({ fromDataset: true, datasetId, position: dataset_location, }) : point; return r; */ return point }, // 坐标转换 coordTransform: (originType, pos, targetType, datasetId) => { // pos 坐标的类型, 当类型为SCREEN时为 { x, y } 其余为 {x, y, z} if (pos.z == void 0) pos.z = 0; //否则datasetPosTransform NAN 地理注册 let needMeshLocal; if (originType == targetType) return pos; if ( originType == CoordType.SCENE_SCREEN || originType == CoordType.MAP_SCREEN) { let tool = originType == CoordType.SCENE_SCREEN ? sdk.scene : sdk.map; let result = tool.getPointByScreen(pos) || {}; //{ position, datasetId, dataset_location } pos = result.position; if (!pos) return; datasetId = result.datasetId; originType = CoordType.LOCAL; } let pointcloud; if (datasetId != void 0) { pointcloud = viewer.scene.pointclouds.find( (p) => p.dataset_id == datasetId); } if (originType == CoordType.MESH_LOCAL) { pos = Potree.Utils.datasetPosTransform({ fromDataset: true, pointcloud, position: pos, }); originType = CoordType.LOCAL; } if (targetType == CoordType.MESH_LOCAL) { needMeshLocal = true; targetType = CoordType.LOCAL; //先转化为求CoordType.LOCAL } if (originType == targetType) { //for控制点,获取点云未移动前的坐标值。暂且这么写。 if (needMeshLocal) { //var invMatrix = new THREE.Matrix4().getInverse(viewer.scene.pointclouds[0].transformMatrix) pos = Potree.Utils.datasetPosTransform({ toDataset: true, pointcloud, position: pos, }); } return pos; } //先转成lonlat(高德) switch (originType) { //EPSG: 4550大地坐标 case CoordType.EPSE: pos = viewer.transform.lonlatTo4550.inverse(pos); break; //Wgs84 经纬度 case CoordType.WGS84: //84转高德 //pos = wgs84ToAMap(pos) break; // 本地坐标 case CoordType.LOCAL: pos = viewer.transform.lonlatToLocal.inverse(pos); } // 需要转换成什么类型的坐标 switch (targetType) { case CoordType.SCENE_SCREEN: // 场景屏幕坐标 pos = sdk.scene.getScreenByPoint(pos); break; case CoordType.MAP_SCREEN: // 地图屏幕坐标 pos = sdk.map.getScreenByPoint(pos); break; //EPSG: 4550大地坐标 case CoordType.EPSE: pos = viewer.transform.lonlatTo4550.forward(pos); break; //Wgs84 经纬度 case CoordType.WGS84: //pos = aMapToWgs84(pos) break; //本地坐标 case CoordType.LOCAL: pos = viewer.transform.lonlatToLocal.forward(pos); } if (needMeshLocal) { pos = Potree.Utils.datasetPosTransform({ toDataset: true, pointcloud, position: pos, }); } return pos; }, enterMeasurement() { //进入测量模块 viewer.setLimitFar(false); }, leaveMeasurement() { //退出测量模块 viewer.setLimitFar(true); }, loadModel(info) { info.moveWithPointcloud = true; viewer.loadModel(info); }, enterTopView(){ viewer.navCubeViewer.dispatchEvent('enterTopView') }, leaveTopView(){ viewer.navCubeViewer.dispatchEvent('leaveTopView') }, destroy(){//重新创建viewer,删了旧的 viewer.setDisplay(false) } }; Potree.sdk = sdk; return sdk; }; export default enter; /* 热点poi加载到的数据中,pos是错误的,只使用dataset_location 关于webgl context lost报错: 已知有一iphoneX在创建shadowMap后才报错。 所以报错的话很可能是代码中的某一句,去除后就会正常。 ======= 如果遇到点云只显示一部分,很可能是裁剪范围出错 */