index.js 70 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735
  1. import mitt from 'mitt'
  2. import libTransform from 'coordtransform';
  3. import axios from 'axios' //{ axios } from '@/api'
  4. let requestLoadCount = 0
  5. let maxLoadingCount = 2; //正在加载模型的最大数目
  6. //0看看,1看见,2深时,3用户上传三维模型,4深时mesh,5深光点云,6深光mesh
  7. const ModelTypes = {
  8. 0 : {name:'看看(八目)', panos4dkk:true},
  9. 1 : {name:'看见(双目转台)', panos4dkk:true, rot90:true},
  10. 2 : {name:'深时', },
  11. 3 : {name:'用户上传三维模型'},
  12. 4 : {name:'深时mesh(激光转台)',panos4dkk:true, rot90:true},//3dtiles or obj
  13. 5 : {name:'深光点云' },
  14. 6 : {name:'深光mesh',panos4dkk:true, rot90:true},//3dtiles
  15. 7 : {name:'圆周率相机' },//圆周率相机场景
  16. }
  17. let cesAspect
  18. /*
  19. const Id_noIntersect = -100 //path绘制在地图上的点,modelId传这个值,勿更改
  20. let isValidPoint = (modelId)=>{//所存的modelId没被删或者它本身不在模型上
  21. return modelId == Id_noIntersect || viewer.objs.children.concat(viewer.scene.pointclouds).some(e=>e.dataset_id == modelId )
  22. }
  23. let curSelectPath */
  24. {
  25. // 84坐标转高德 (国外地区用84,所以地理注册时填的是84,我这需要转成高德)
  26. const wgs84ToAMap = (pos ) => {
  27. const latlng = libTransform.wgs84togcj02(pos.x, pos.y)
  28. return {
  29. x: latlng[0],
  30. y: latlng[1]
  31. }
  32. }
  33. // 高德坐标转84
  34. const aMapToWgs84 = (pos ) => {
  35. const latlng = libTransform.gcj02towgs84(pos.x, pos.y)
  36. return {
  37. x: latlng[0],
  38. y: latlng[1]
  39. }
  40. }
  41. window.AMapWith84__ = { //在Potree里setLonlat时不管转不转效果都一样 很奇怪,所以这里改名。只在ces
  42. aMapToWgs84, wgs84ToAMap
  43. }
  44. }
  45. export const enter = ({ dom, mapDom, isLocal, lonlat, scenes }) => {
  46. console.warn('新的页面')
  47. Potree.settings.isOfficial = true //标记为正式、非测试版本
  48. //Potree.fileServer = axios
  49. Potree.settings.libsUrl = './lib/'
  50. let loadStartTime = Date.now()
  51. //正式环境(本地调试会打不开)
  52. if (location.host === 'mix3d.4dkankan.com') {
  53. Potree.settings.urls.prefix = Potree.settings.urls.prefix6
  54. Potree.settings.webSite = 'datav1'
  55. } else if (location.host === 'xfhd.4dkankan.com') {
  56. Potree.settings.urls.prefix = Potree.settings.urls.prefix7
  57. Potree.settings.webSite = 'datav1'
  58. }
  59. const mapBus = mitt(), sceneBus = mitt()
  60. const tagLimitDis = 8;
  61. /* if(isLocal2){//本地配置
  62. Potree.settings.isLocal = Potree.settings.tileOriginUrl = isLocal2
  63. } */
  64. Potree.settings.showCompass = true
  65. Potree.settings.compassDom = dom.querySelector('#direction')
  66. Potree.settings.mergeType2 = true //标识新版
  67. Potree.settings.modelSkybox = true //是否将全景图贴在模型上(会导致卡顿)。若不显示模型将不显示Reticule
  68. Potree.settings.tiles3DMaxMemory = 300 //稍微增加点
  69. Potree.settings.mergeTransCtlOnClick = true
  70. Potree.settings.canWalkThroughModel = true
  71. window.cesErrorWords = '由于GPU占用过大, 将关闭地图,请更换更好的显卡!'
  72. window.cesErrorCallback = ()=>{
  73. sdk.setBackdrop('none')
  74. }
  75. let { THREE } = Potree.mergeEditStart(dom, mapDom)
  76. let MergeEditor = viewer.modules.MergeEditor
  77. Potree.settings.unableNavigate = true
  78. lonlat && Potree.setLonlat(lonlat[0], lonlat[1])
  79. //因为getPose里用的是target,俯视的yaw不准,所以限制一下不要完全俯视
  80. viewer.mainViewport.view.maxPitch-=0.001
  81. viewer.mainViewport.view.minPitch+=0.001
  82. viewer.addEventListener('camera_changed', e => {
  83. var camera = e.viewport.camera
  84. var pos = camera.position
  85. if (e.viewport.name == 'MainView') {
  86. sceneBus.emit('cameraChange', { x: pos.x, y: pos.y, z: pos.z, rotate: camera.rotation })
  87. Potree.Common.intervalTool.isWaiting('updateCamNear', ()=>{
  88. updateCamNear()
  89. }, 1000)
  90. updateCamFar()
  91. }
  92. if (e.viewport.name == 'MainView' || e.viewport.name == 'top' ) {
  93. updateMap()
  94. }
  95. })
  96. //-------------------------------------
  97. let modelAinB = (A,B)=>{ //B的expand(5m) bound完全包含A
  98. let boundB = B.boundingBox.clone().expandByVector(new THREE.Vector3(5,5,5)).applyMatrix4(B.matrixWorld)
  99. let boundA = A.boundingBox.clone().applyMatrix4(A.matrixWorld)
  100. return boundB.containsBox(boundA)
  101. }
  102. let changeMeshVisi = (object, show) => {
  103. if(show == void 0) show = Potree.settings.displayMode == 'showPointCloud' || object == viewer.images360.currentPano.pointcloud && Potree.settings.modelSkybox || object.showInPano //showInPano: 装饰物,一直显示
  104. || !object.panos && modelAinB(object, viewer.images360.currentPano.pointcloud) //装饰物
  105. Potree.Utils.updateVisible(object, 'showPanos', show)
  106. }
  107. if(Potree.settings.canWalkThroughModel){
  108. let lastModel
  109. viewer.images360.addEventListener('flyToPano',(e)=>{//开始漫游 漫游到另一个模型就要选中这个模型?
  110. let model = e.toPano.pano.pointcloud
  111. if(lastModel != model){
  112. changeMeshVisi(model, true)
  113. //MergeEditor.selectModel(model)
  114. //model.result_.flyInPano(e.toPano.pano, {dontFly:true}) //切换模型显示,因为flyInPano有事件怕乱所以统一用这个函数
  115. updateCamNear()
  116. }
  117. })
  118. viewer.images360.addEventListener('flyToPanoDone',(e)=>{
  119. if(!e.makeIt)return
  120. let model = viewer.images360.currentPano.pointcloud
  121. if(lastModel != model){
  122. lastModel?.isModel && changeMeshVisi(lastModel, false)
  123. sceneBus.emit('panoModelChange', model.result_ )
  124. }
  125. lastModel = model
  126. })
  127. }
  128. viewer.images360.addEventListener('endChangeMode',(e)=>{
  129. sceneBus.emit('modeChange', {mode: e.mode == 'showPanos' ? 'pano' : 'fuse', model : e.mode == 'showPanos' && viewer.images360.currentPano.pointcloud.result_} )
  130. Potree.Utils.updateVisible(MergeEditor.transformControls, 'showPanos', e.mode == 'showPointCloud')
  131. Potree.Utils.updateVisible(MergeEditor.boxHelper, 'showPanos', e.mode == 'showPointCloud')
  132. if(e.mode == 'showPanos'){
  133. viewer.setControls( viewer.fpControls )
  134. viewer.removeEventListener('camera_changed', camera_changed)
  135. }else{
  136. viewer.addEventListener('camera_changed', camera_changed)
  137. }
  138. viewer.objs.children.forEach((e)=>{changeMeshVisi(e)})
  139. Potree.settings.canWalkThroughModel || viewer.images360.panos.forEach(pano => {
  140. pano.setEnable(e.mode == 'showPanos' ? pano.pointcloud == viewer.images360.currentPano.model : true)
  141. })
  142. Potree.settings.unableNavigate = e.mode == 'showPointCloud'
  143. updateCamNear()
  144. })
  145. let camera_changed = (e) => {
  146. if (e.viewport.name == 'MainView' && e.changeInfo.positionChanged) {
  147. //viewer.mainViewport.camera.position
  148. viewer.mainViewport.view.radius = 0.1 //使pivot在面前一丢丢距离
  149. viewer.setControls(viewer.orbitControls)
  150. viewer.removeEventListener('camera_changed', camera_changed)
  151. }
  152. }
  153. let requestInPano = false
  154. //-------------------------------------
  155. /* viewer.inputHandler.addEventListener('keydown', (e)=>{
  156. if(e.event.key == "e" ){
  157. MergeEditor.transformControls.mode = 'rotate'
  158. }else if(e.event.key == "w"){
  159. MergeEditor.transformControls.mode = 'translate'
  160. }else if(e.event.key == "s"){
  161. MergeEditor.transformControls.mode = 'scale'
  162. }
  163. }) */
  164. viewer.addEventListener('webglError', e => {
  165. console.error('viewer webglError: ' + e)
  166. let memory = '. \n jsHeapSizeLimit:'+ performance.memory.jsHeapSizeLimit/ 1e6 + ', usedJSHeapSize: '+performance.memory.usedJSHeapSize/ 1e6 + '(M)'
  167. sceneBus.emit('webglError', { msg: e.msg + memory })
  168. })
  169. viewer.compass.setAutoDisplay(true)
  170. /* mapBus.on('visible', v => {
  171. //console.log('mapBus visible', v)
  172. viewer.mapViewer.visible = v
  173. if (v) {
  174. viewer.mapViewer.mapLayer.needUpdate = true
  175. }
  176. viewer.mapViewer.dispatchEvent({type:'forceVisible',visible:v})
  177. }) */
  178. {
  179. let index = 1;
  180. //let setDisplay()
  181. if (!Potree.isIframeChild) {
  182. /* viewer.addEventListener('createIframe',(e)=>{//创建了子页面
  183. }) */
  184. window.winIndex = 0;
  185. window.iframeCreated = function (iframe) {
  186. let child = iframe.contentWindow
  187. child.winIndex = index++
  188. //案件里视图提取页面子页面覆盖了父级页面,父级的模型可以隐藏以释放内存
  189. console.error('createdIframe', child.winIndex, child.location.href)
  190. viewer.setDisplay(false)
  191. child.beforeDestroy = function () { //注:在前端仍会找不到beforeDestroy,可能contentWindow变更??所以手动调用setDisplay
  192. console.warn('beforeDestroy', child.winIndex)
  193. child.viewer && child.viewer.setDisplay(false)
  194. //如果是四维看看的场景,先不管了,页面被销毁应该就没了吧
  195. viewer.setDisplay(true)//恢复主页的模型显示
  196. if (!child.viewer) {
  197. try {
  198. let player = child.__sdk.core.get('Player')
  199. /* let runtime = player.model._3dTilesRuntime
  200. let tileset = runtime.getTileset()
  201. tileset._cache.trim(); //使下一次update时dispose所有不可见的tiles
  202. let sceneRenderer = child.__sdk.core.get('SceneRenderer')
  203. player.model.visible = false
  204. runtime.update(16, sceneRenderer.renderer, sceneRenderer.camera, true) //没用,为何_trimTiles的while无法进入
  205. */
  206. player.model.traverse(e => {
  207. e.geometry && e.geometry.dispose()
  208. if (e.material) {
  209. e.material.map && e.material.map.dispose()
  210. if (e.material.uniforms && e.material.uniforms.map && e.material.uniforms.map.value) {
  211. e.material.uniforms.map.value.dispose()
  212. }
  213. }
  214. }) //效果甚微
  215. /* let sceneRenderer = child.__sdk.core.get('SceneRenderer')
  216. sceneRenderer.renderer.render(sceneRenderer.scene, sceneRenderer.camera)
  217. */
  218. } catch (e) {
  219. console.log(e)
  220. }
  221. }
  222. }
  223. }
  224. //不知道删除iframe时是否那些模型还在内存里,需要释放吗? 如果要需要加一个事件
  225. } else {
  226. }
  227. }
  228. window.THREE = THREE
  229. //isLocal = false
  230. let autoLoads = /* window.autoLoads = */ []
  231. let readyToAddModel
  232. let mainBackground = viewer.background
  233. const units = { 1: 'metric', 2: 'imperial' }
  234. let getMeasureType = function (type, unit = 1) {
  235. let info
  236. switch (type) {
  237. case 'free':
  238. info = { measureType: 'Distance' }
  239. break
  240. case 'area':
  241. info = { measureType: 'Area' }
  242. break
  243. case 'vertical':
  244. info = { measureType: 'Ver Distance' }
  245. break
  246. default:
  247. console.error('无此 measure type')
  248. }
  249. info.unit = units[unit]
  250. return info
  251. }
  252. let getMeasureFunction = function (measure, bus) {
  253. measure.addEventListener('highlight', (e) => {
  254. //console.log('3d->2d highlight',e.state)
  255. bus.emit('highlight', e.state)
  256. })
  257. let update = (e)=>{ //拖拽结束后发送changeCallBack
  258. if (measure.parent) {
  259. //未被删除
  260. //console.warn('changePoints', measure.dataset_points.length )
  261. /* if(measure.type == 'Path'){
  262. bus.emit('changePoints', measure.dataset_points.map((p,i)=>{return {
  263. position: (p || measure.points[i]).clone(),
  264. modelId: measure.points_datasets[i] == void 0 ? Id_noIntersect : measure.points_datasets[i],
  265. name: measure.markerLabels[i].originText
  266. }}))
  267. }else{ */
  268. bus.emit('update', [
  269. measure.dataset_points.map(p => p.clone()),
  270. measure.points_datasets
  271. ])
  272. //}
  273. }
  274. }
  275. measure.addEventListener('marker_dropped', update)
  276. measure.addEventListener('changed', update)
  277. measure.addEventListener('createDone', update)
  278. measure.addEventListener('changeByHistory', update);
  279. return {
  280. /* quit: () => {
  281. Potree.Log('quit结束且删除: ' + measure.id, '#00c7b2')
  282. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true, measure })
  283. }, //触发结束。退出测量模式,清除之前操作 */
  284. destroy: () => {
  285. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true, measure })
  286. viewer.scene.removeMeasurement(measure)
  287. },
  288. /* getPoints: () => {
  289. return measure.points
  290. },
  291. getDatasetLocations: () => {
  292. return measure.dataset_points
  293. },
  294. getDatasets: () => {
  295. return measure.points_datasets
  296. },
  297. getDatasetId: () => {
  298. return measure.datasetId
  299. }, */
  300. getArea: () => {
  301. return measure.area //{value:area, string:..}
  302. },
  303. getDistance: () => {
  304. if (measure.points.length < 2) return 0
  305. var value = measure.points[0].distanceTo(measure.points[1])
  306. return {
  307. value, //米
  308. string: measure.getConvertString(value, 'distance')
  309. }
  310. },
  311. //手动开启或关闭:
  312. show: () => {
  313. Potree.Utils.updateVisible(measure, 'inListByUser', true)
  314. },
  315. hide: () => {
  316. Potree.Utils.updateVisible(measure, 'inListByUser', false)
  317. },
  318. fly() {
  319. let result = viewer.focusOnObject(measure, 'measure', 1200)
  320. return result.msg ? result.msg : result.promise
  321. //返回值 1 deferred 表示即将位移 2 'posNoChange' 表示已在最佳位置 3 'tooFar' 表示距离最佳位置太远
  322. },
  323. changeSelect(isHight) {
  324. //console.log('2d->3d isHight ', isHight)
  325. measure.setSelected(isHight, 'byList')
  326. },
  327. }
  328. }
  329. let sdk = {
  330. sceneBus, mapBus,
  331. canTurnToPanoMode(pos, far=Potree.config.panoFieldRadius) {
  332. pos = pos ? new THREE.Vector3().copy(pos) : viewer.images360.position
  333. let pano = viewer.images360.findNearestPano(pos)
  334. if (pano && pano.position.distanceTo(pos) < far * pano.pointcloud.scale.x) {
  335. return {model:pano.pointcloud.result_}
  336. }
  337. //poschange后会调用这个,如果返回false会变为点云模式,且不会自动变回原先的模式
  338. },
  339. getPositionByScreen(pos2d, hopeModelId) {//通过屏幕坐标获取真实坐标 . hopeModelId: 如果指定了模型,优先返回hopeModelId上的intersect
  340. //console.log('getPositionByScreen',hopeModelId)
  341. hopeModelId = null
  342. let worldPos, localPos, modelId, intersect/* , normal, localNormal */
  343. let Handler = viewer.inputHandler
  344. let reGet = () => {//不使用当前鼠标所在位置的intersect,单独算
  345. pos2d.clientX = pos2d.x
  346. pos2d.clientY = pos2d.y
  347. pos2d.onlyGetIntersect = true
  348. pos2d.whichPointcloud = true
  349. if (hopeModelId != void 0) {//隐藏其他的模型
  350. let models = MergeEditor.getAllObjects()
  351. models.forEach(model => {
  352. Potree.Utils.updateVisible(model, 'forPick', model.dataset_id == hopeModelId)
  353. })
  354. }
  355. let intersect2 = Handler.onMouseMove(pos2d)
  356. if (hopeModelId != void 0) {//恢复
  357. let models = MergeEditor.getAllObjects()
  358. models.forEach(model => {
  359. Potree.Utils.updateVisible(model, 'forPick', true)
  360. })
  361. }
  362. if (intersect2 && intersect2.location) {
  363. intersect = intersect2
  364. }
  365. }
  366. if (pos2d && pos2d.inDrag) {
  367. reGet()
  368. } else {
  369. intersect = Handler.intersect
  370. if (intersect) {
  371. modelId = intersect.pointcloud ? intersect.pointcloud.dataset_id : intersect.object.dataset_id
  372. if (hopeModelId != void 0 && modelId != hopeModelId) {
  373. reGet()
  374. }
  375. }
  376. }
  377. if (intersect && intersect.location) {
  378. modelId = intersect.pointcloud ? intersect.pointcloud.dataset_id : intersect.object.dataset_id
  379. /* if(hopeModelId != void 0 && modelId != hopeModelId){
  380. return null
  381. } */
  382. worldPos = intersect.location.clone()
  383. localPos = Potree.Utils.datasetPosTransform({ toDataset: true, datasetId: modelId, position: worldPos })
  384. /* normal = intersect.normal
  385. localNormal = intersect.localNormal */
  386. } else return null
  387. return { worldPos, modelId, localPos, /* normal, localNormal */ }
  388. },
  389. getScreenByPosition(pos3d, modelId, canShelter/* , disToCameraLimit */) {//通过模型局部坐标获取屏幕坐标
  390. //console.log('getScreenByPoint ')
  391. let isLocal = modelId != void 0
  392. pos3d = new THREE.Vector3().copy(pos3d)
  393. let worldPos = isLocal ? Potree.Utils.datasetPosTransform({ fromDataset: true, datasetId: modelId, position: pos3d }) : pos3d
  394. if (!worldPos) return
  395. if (canShelter) {
  396. if (viewer.inputHandler.ifBlockedByIntersect(worldPos, 0.1, true)) return { trueSide: false };
  397. }
  398. var viewport = viewer.mainViewport
  399. var camera = viewport.camera
  400. var dom = viewer.renderArea
  401. if (tagLimitDis != void 0) {
  402. if (camera.position.distanceToSquared(worldPos) > Math.pow(tagLimitDis, 2)) return false
  403. }
  404. //console.log('getScreenByPoint ' + pos3d.toArray())
  405. return Potree.Utils.getPos2d(worldPos, viewport, dom)
  406. },
  407. setCameraFov(fov) {
  408. viewer.setFOV(fov)
  409. },
  410. screenshot: (width, height/* , bgOpacity=0 */ ) => {//
  411. //截图
  412. let bgOpacity = Potree.settings.showCesium ? 0 : 1 /* viewer.background == 'skybox' */ //因为要画map底图所以上层只能透明。之后需要的话再改
  413. console.log('bgOpacity', bgOpacity)
  414. Potree.Utils.updateVisible(MergeEditor.boxHelper, 'screenshot', false)
  415. Potree.Utils.updateVisible(viewer.scene.overlayScene, 'screenshot', false) //hide all
  416. var { getImagePromise, finishPromise } = viewer.startScreenshot({ type: 'default', /* useRenderTarget:true, */bgOpacity }, width, height)
  417. var deferred = $.Deferred();
  418. finishPromise.done(({ dataUrl }) => {
  419. if(Potree.settings.displayMode != 'showPanos' && Potree.settings.showCesium){//need map background
  420. Potree.cesScreenshot(width, height).done((mapBGurl)=>{
  421. let img = new Image(); img.src = dataUrl
  422. let imgBG = new Image(); imgBG.src = mapBGurl
  423. let loadCount = 0
  424. img.onload = imgBG.onload = ()=>{
  425. loadCount++;
  426. if(loadCount == 2){
  427. let url = Potree.Common.imgAddLabel(imgBG,img,{leftRatioToImg:0,topRatioToImg:0})
  428. deferred.resolve(url)
  429. }
  430. }
  431. })
  432. }else{
  433. deferred.resolve(dataUrl)
  434. }
  435. Potree.Utils.updateVisible(MergeEditor.boxHelper, 'screenshot', true)
  436. Potree.Utils.updateVisible(viewer.scene.overlayScene, 'screenshot', true)
  437. })
  438. return deferred.promise()
  439. },
  440. getPose() {//获取当前点位和朝向
  441. const camera = viewer.scene.getActiveCamera()
  442. const target = viewer.scene.view.getPivot().clone()
  443. const position = viewer.scene.view.position.clone()
  444. const pose = { position, target, displayMode:Potree.settings.displayMode }
  445. if(Potree.settings.displayMode == 'showPanos'){
  446. let model = viewer.images360.currentPano.pointcloud
  447. pose.panoId = viewer.images360.currentPano.originID
  448. pose.model = model.result_
  449. pose.posInModel = Potree.Utils.datasetPosTransform({ toDataset: true, position: camera.position.clone(), object:model })
  450. pose.rotInModel = Potree.Utils.datasetRotTransform({ toDataset: true, quaternion: camera.quaternion.clone(), getQuaternion: true, pointcloud:model }).toArray() //拿第一个数据集
  451. }
  452. //console.log('getPose',position, target)
  453. return pose
  454. },
  455. comeTo(o = {}) {
  456. //console.log('comeTo',o.position, o.target)
  457. //飞到某个点
  458. let deferred = $.Deferred()
  459. if(o.panoId != void 0){
  460. let model = o.model.model
  461. let pano = model.panos.find(a=>a.originID == o.panoId)
  462. if(pano){
  463. o.rotInModel = new THREE.Quaternion().fromArray(o.rotInModel)
  464. let quaternion = Potree.Utils.datasetRotTransform({ fromDataset: true, quaternion: o.rotInModel, getQuaternion: true, object:model})
  465. o.model.flyInPano(pano, {quaternion, duration:0, callback(){
  466. o.callback && o.callback()
  467. deferred.resolve(true)
  468. }})
  469. return deferred.promise()
  470. }else{
  471. console.warn('没有找到漫游点',o)
  472. }
  473. }/* else if(requestInPano){
  474. requestInPano.result_.flyOutPano()
  475. }*/else {
  476. if (o.modelId != void 0) {
  477. ['position', 'target'].forEach(e => {
  478. if (o[e]) {
  479. o[e] = Potree.Utils.datasetPosTransform({ fromDataset: true, datasetId: o.modelId, position: o[e] })
  480. }
  481. })
  482. }
  483. }
  484. if (o.distance || o.maxDis) {
  485. //o.isFlyToTag = true
  486. let requestShowPano
  487. let position = o.target || o.position
  488. if(o.isFlyToTag){
  489. let r = sdk.canTurnToPanoMode(position, 5)//热点新需求:如果附近有漫游点就飞到全景模式
  490. if(r){
  491. requestShowPano = true
  492. }else{
  493. Potree.settings.displayMode = 'showPointCloud'
  494. }
  495. }
  496. let rusult = viewer.focusOnObject({ position }, 'tag', null, { distance: o.distance || 1, maxDis : o.maxDis, requestShowPano /* , checkIntersect:true */ })
  497. rusult.promise.then(()=>{
  498. if(o.isFlyToTag){
  499. Potree.settings.displayMode = requestShowPano ? 'showPanos' : 'showPointCloud'
  500. }
  501. })
  502. return rusult.promise
  503. }
  504. viewer.scene.view.setView($.extend({}, o, {
  505. duration: o.dur,
  506. callback: () => {
  507. o.callback && o.callback()
  508. deferred.resolve(true)
  509. }
  510. }))
  511. return deferred.promise()
  512. },
  513. setBackdrop(sky, type, { scale, rotate }={}) {//天空盒背景
  514. //console.log('天空盒背景', sky,type)
  515. let setGroundAndText = (color) => {
  516. MergeEditor.secondCompass.dom.find(".dirText").css({ 'color': color })
  517. viewer.compass.dom.find(".dirText").css({ 'color': color })
  518. MergeEditor.ground.material.uniforms.uColor.value.set(color)
  519. //MergeEditor.ground.children[0].material.color.set(color)
  520. }
  521. viewer.dispatchEvent('content_changed')
  522. if(type == 'map'){
  523. MergeEditor.setGroundPlaneImg(null)
  524. viewer.setBackground(mainBackground)
  525. Potree.settings.showCesium = true
  526. buildMap()
  527. viewer.backgroundOpacity = 0
  528. return
  529. }else{
  530. Potree.settings.showCesium = false
  531. }
  532. if (type == 'bimg') {//地面图
  533. MergeEditor.setGroundPlaneImg(sky, scale, rotate)
  534. setGroundAndText('#e0e0e0')
  535. viewer.setBackground(mainBackground)
  536. } else {
  537. MergeEditor.setGroundPlaneImg(null)
  538. if (sky == 'none') {
  539. viewer.setBackground(mainBackground)
  540. setGroundAndText('#eee')
  541. } else if (sky[0] == '#') {
  542. viewer.setBackground(new THREE.Color(sky))
  543. let color = sky == '#fff' ? '#666' : sky == '#333' ? '#eee' : '#bbb' //反相
  544. setGroundAndText(color)
  545. } else if (type == 'image-map' || type == 'vector-map') {//影像|矢量 地图
  546. } else {//环境
  547. viewer.setBackground('skybox', sky)
  548. setGroundAndText('#e0e0e0')
  549. }
  550. }
  551. },
  552. switchMapType(type) {
  553. let map = viewer.mapViewer.mapLayer.maps.find(e => e.name == 'map')
  554. map.switchStyle(type/* map.style == 'satellite' ? 'standard' : 'satellite' */)
  555. },
  556. enableMap(mapArea, latlng) {
  557. if (!viewer.mapViewer) {
  558. //--------------------------------
  559. viewer.mapViewer = new Potree.MapViewer(mapArea)
  560. viewer.mapViewer.initProjection()
  561. //focus
  562. let boundSize = new THREE.Vector3(200, 150, 1).max(viewer.bound.boundSize)
  563. viewer.mapViewer.addEventListener('viewerResize', () => {
  564. viewer.mapViewer.moveTo(viewer.bound.center, boundSize, 0)
  565. }, { once: true })
  566. }
  567. },
  568. enterSceneGuide(pathArr) {//导览 (不需要修改参数)
  569. let editor = viewer.modules.CamAniEditor
  570. console.log('pathArr', pathArr)
  571. //console.log('enterSceneGuide',pathArr)
  572. pathArr.forEach(e=>{
  573. if(e.panoId != void 0){
  574. e.model = e.model.model
  575. }
  576. })
  577. let data = {
  578. //duration: pathArr.slice(0, pathArr.length - 1).reduce(function (total, currentValue) { return total + currentValue.time }, 0), //总时长(要去掉最后一个,因为已到终点,该点time无意义)
  579. points: pathArr,
  580. useDurSlice: true
  581. }
  582. let ani = editor.createMulAnimation(data)
  583. //注:最多只存在一条导览
  584. let bus = mitt()
  585. //播放完成
  586. ani.event_.addEventListener('playDone', () => {
  587. bus.emit('playComplete')
  588. viewer.images360.panos.forEach(e=>e.marker && Potree.Utils.updateVisible(e, 'playAni', true))
  589. })
  590. //切换点
  591. ani.event_.addEventListener('updateCurrentIndex', e => {
  592. bus.emit('changePoint', e.currentIndex + 1)
  593. })
  594. return {
  595. bus,
  596. play() {
  597. MergeEditor.selectModel(null)
  598. viewer.images360.panos.forEach(e=>e.marker && Potree.Utils.updateVisible(e, 'playAni', false))
  599. ani.play()
  600. },
  601. pause() {
  602. viewer.images360.panos.forEach(e=>e.marker && Potree.Utils.updateVisible(e, 'playAni', true))
  603. ani.stop()
  604. },
  605. clear() {
  606. ani.remove()
  607. },
  608. }
  609. },
  610. //[path1, paht2], { time, speed }
  611. calcPathInfo(paths, info) { //传入的time, speed仅有一个。返回完整的 time, speed
  612. //这一版的control似乎无法在某个位置上改变角度,位置和角度一般都是一起变的,所以先不增加单位更换功能。
  613. let pos1 = new THREE.Vector3().copy(paths[0].position)
  614. let pos2 = new THREE.Vector3().copy(paths[1].position)
  615. let dis = pos1.distanceTo(pos2)
  616. if (info.time != void 0) {
  617. info.speed = dis / info.time
  618. } else {
  619. info.time = dis / info.speed
  620. }
  621. return info
  622. },
  623. addModel(props) {
  624. let model
  625. let bus = props.bus = mitt()
  626. //console.log('addModel',props)
  627. props.isFirstLoad = isLocal ? props.bottom == void 0 : (props.isDynamicAdded || props.mode == 'single') // 在编辑时用户添加的 或 展示单个模型 (props.mode='single'模型展示页, props.mode='many'融合页)
  628. if (props.opacity == void 0) props.opacity = 1
  629. //if (props.type == 'obj' ) props.type = 'glb'
  630. props.scale /= 100
  631. let getBaseRotation = () => {
  632. if(ModelTypes[props.fromType]?.rot90 && props.type != 'obj'){
  633. return new THREE.Euler(Math.PI / 2, 0, 0)
  634. } else return new THREE.Euler(0, 0, 0)
  635. }
  636. let getDefaultRotation = () => {
  637. if(model.lonLatRot){
  638. return model.lonLatRot
  639. }else{
  640. return getBaseRotation()
  641. }
  642. }
  643. if (props.rotation) {
  644. if (props.rotation._x == void 0 && props.rotation.x != void 0) {
  645. props.rotation = new THREE.Euler().setFromVector3(props.rotation)
  646. }
  647. }
  648. props.baseRotation = getBaseRotation()
  649. props.is4dkkModel = ModelTypes[props.fromType].panos4dkk
  650. if (!props.isFirstLoad) {
  651. if (autoLoads.length == 0) { //首次加载
  652. setTimeout(() => {
  653. let sizes = autoLoads.map(e => e.size || 0)
  654. console.log('需要请求加载的模型大小为', sizes, '总大小', sizes.reduce(function (total, currentValue) {
  655. let current = parseFloat(currentValue)
  656. return total + ((typeof currentValue == 'number' || currentValue.includes('M')) ? current : current / 1024)
  657. }, 0))
  658. readyToAddModel = true //准备开始加载
  659. loadNext()//startLoad(autoLoads[0])
  660. }, 30)
  661. }
  662. autoLoads.push(props)
  663. readyToAddModel = false
  664. } else {
  665. readyToAddModel = true
  666. }
  667. let done = (model_) => {
  668. model = model_
  669. model.result_ = result
  670. model.props = props
  671. result.model = model
  672. model.fromType = ModelTypes[props.fromType].name
  673. if (!props.isFirstLoad) {
  674. model.visible = false//先不显示,防止卡顿
  675. }
  676. model.showInPano = /* !model.is4dkkModel// */props.raw.showInPano //现在不用这个,所有模型都可见,非is4dkkModel的还显示原本的贴图
  677. props.opacity < 100 && result.changeOpacity(props.opacity)
  678. model.addEventListener('changeSelect', (e) => {
  679. bus.emit('changeSelect', e.selected)
  680. })
  681. let lastState = {}
  682. model.addEventListener('transformChanged', (e) => {
  683. let msg = {}
  684. if (!lastState.position || !model.position.equals(lastState.position)) {
  685. lastState.position = msg.position = model.position.clone()
  686. }
  687. if (!lastState.rotation || !model.rotation.equals(lastState.rotation)) {
  688. lastState.rotation = msg.rotation = model.rotation.clone()
  689. }
  690. if (lastState.scale == void 0 || model.scale.x * 100 != lastState.scale) {
  691. lastState.scale = msg.scale = model.scale.x * 100
  692. }
  693. msg = Potree.Common.CloneObject(msg)
  694. //console.log(msg)
  695. bus.emit('transformChanged', msg)
  696. })
  697. spliceFromArr(model, props, true)
  698. model.addEventListener('changeSelect', (e) => {
  699. MergeEditor.transformControls.visible && e.selected && MergeEditor.transformControls.attach(model, e.clickPos) //: MergeEditor.transformControls.detach()
  700. })
  701. MergeEditor.modelAdded(model)
  702. if (props.mode == 'single') {//模型查看页
  703. MergeEditor.noNeedSelection = true
  704. setTimeout(() => {
  705. MergeEditor.focusOn([model], 1000, true, true)
  706. }, 1)
  707. }
  708. if(ModelTypes[props.fromType].panos4dkk){
  709. Potree.load4dkkPanos(props.raw.num, model, getBaseRotation(), () => {
  710. bus.emit('loadDone')
  711. }, props.fromType == 0 ? '2k' : '4k' ) //看看场景是2k
  712. } else {
  713. bus.emit('loadDone')
  714. }
  715. //console.log('loadDone' )
  716. }
  717. let progressFun = (progress) => {
  718. bus.emit('loadProgress', progress)
  719. }
  720. let onError = function (xhr) {
  721. bus.emit('loadError', xhr)
  722. console.log('loadError!!!!!!!!!', Potree.Common.getNameFromURL(props.url), props.size, xhr)
  723. spliceFromArr(model, props, false)
  724. }
  725. try {
  726. props.url = JSON.parse(props.url) //去掉 '\'
  727. } catch (e) { }
  728. props.done = done; props.progressFun = progressFun; props.onError = onError
  729. if (readyToAddModel) {
  730. if (autoLoads.filter(e => e.loading).length < maxLoadingCount) {
  731. startLoad(props)
  732. }
  733. }
  734. let scaleMeasure
  735. let result = {
  736. bus,
  737. model,
  738. getDefaultRotation,
  739. supportPano() { //是否支持全景图
  740. return model?.panos?.length > 0
  741. },
  742. flyInPano(pano, {dontFly, quaternion, duration}={}) {// 飞入全景图
  743. requestInPano = model
  744. pano = pano || viewer.images360.findNearestPano(null, model.panos)
  745. if (pano) {
  746. dontFly || viewer.images360.flyToPano({ pano, canCancelLast: true, quaternion, duration})
  747. Potree.settings.displayMode = 'showPanos'
  748. }
  749. },
  750. flyOutPano() {// 飞出全景图(就是切换到正常融合视角)
  751. requestInPano = false
  752. Potree.settings.displayMode = 'showPointCloud'
  753. /* setTimeout(() => {//在下一帧再变,因为3dtiles需要更新一下才会显示tiles
  754. if (!requestInPano) {
  755. Potree.settings.displayMode = 'showPointCloud'
  756. Potree.Utils.updateVisible(MergeEditor.boxHelper, 'showPanos', true)
  757. }
  758. }, 50) */
  759. },
  760. changeShow(show) {
  761. props.show = show //for autoLoads show model
  762. if (model) {
  763. Potree.Utils.updateVisible(model, 'datasetSelection', show)
  764. if (model.panos) {
  765. model.panos.forEach(e => e.setEnable(show))
  766. }
  767. viewer.dispatchEvent('content_changed')
  768. }
  769. },
  770. changeSelect(state) {
  771. //console.error('select', state)
  772. if (model) {
  773. let fly = viewer.images360.latestRequestMode != 'showPanos'
  774. MergeEditor.selectModel(model, state, fly, true)
  775. updateCamNear()
  776. //console.log('changeSelect', props.id, state)
  777. }
  778. },
  779. changeScale(s) {
  780. if (model) {
  781. s /= 100
  782. if (model.scale.x == s) return
  783. //MergeEditor.history.beforeChange(model)//但不知道什么时候结束拖拽
  784. model.scale.set(s, s, s)
  785. model.isPointcloud && model.changePointSize(/* Potree.config.material.realPointSize * s */)
  786. model.dispatchEvent("scale_changed")
  787. }
  788. },
  789. changeOpacity(opacity) { //见笔记:透明物体的材质设置
  790. if (opacity == void 0) opacity = 100
  791. opacity /= 100
  792. MergeEditor.changeOpacity(model, opacity)
  793. },
  794. changeBottom(z) {
  795. /* model && MergeEditor.setModelBtmHeight(model,z)
  796. model.dispatchEvent('transformChanged') //改了position */
  797. },
  798. changePosition(pos) {//校准取消时执行
  799. //console.log('changePosition', model.name, pos.x, pos.y, pos.z)
  800. if(pos.x == 0 && pos.y == 0 && pos.z == 0 && model.lonLatPos ){
  801. model && model.position.copy(model.lonLatPos)
  802. console.log('changePosition 使用经纬度坐标', model.name )
  803. }else{
  804. model && model.position.copy(pos)
  805. }
  806. model.dispatchEvent({ type: 'position_changed' })
  807. },
  808. changeRotation(rot) {//校准取消时执行
  809. //console.log('changeRotation', model.name, rot.x, rot.y, rot.z)
  810. /* if(rot.x == 0 && rot.y == 0 && rot.z == 0 && model.lonLatRot ){
  811. model && model.rotation.copy(model.lonLatRot)
  812. console.log('changePosition 使用经纬度坐标', model.name )
  813. }else{ */
  814. model && model.rotation.setFromVector3(rot)
  815. //}
  816. model.dispatchEvent({ type: 'rotation_changed' , by2d:true})
  817. },
  818. enterRotateMode() {
  819. if (model) {
  820. if (MergeEditor.split) {//分屏校准
  821. MergeEditor.setTransformState('rotate')
  822. MergeEditor.transformControls2.attach(model)
  823. MergeEditor.transformControls2.mode = 'rotate'
  824. }
  825. MergeEditor.transformControls.attach(model)
  826. MergeEditor.transformControls.mode = 'rotate'
  827. }
  828. },
  829. enterMoveMode() {
  830. console.log('enterMoveMode')
  831. if (model) {
  832. if (MergeEditor.split) {//分屏校准
  833. MergeEditor.setTransformState('translate')
  834. MergeEditor.transformControls2.attach(model)
  835. MergeEditor.transformControls2.mode = 'translate'
  836. }
  837. MergeEditor.transformControls.attach(model)
  838. MergeEditor.transformControls.mode = 'translate'
  839. }
  840. },
  841. leaveTransform() {
  842. console.log('leaveTransform')
  843. if (MergeEditor.split) {//分屏校准
  844. MergeEditor.setTransformState(null)
  845. } else {
  846. MergeEditor.transformControls.detach()
  847. MergeEditor.transformControls2.detach()
  848. }
  849. MergeEditor.history.clear()
  850. },
  851. enterAlignment() {//开始校准
  852. result.leaveTransform()
  853. MergeEditor.enterSplit()
  854. if(Potree.settings.showCesium){
  855. cesiumViewer.scene.canvas.style.width = '50%'
  856. //cesiumViewer.resize()
  857. }
  858. let bus = new mitt()
  859. /* MergeEditor.transformControls.attach(model)
  860. MergeEditor.transformControls.mode = 'translate' */
  861. return {
  862. bus
  863. }
  864. },
  865. leaveAlignment() {
  866. //console.log('leaveAlignment',model.position, model.rotation)
  867. MergeEditor.leaveSplit()
  868. MergeEditor.transformControls.detach()
  869. MergeEditor.transformControls2.detach()
  870. if(Potree.settings.showCesium){
  871. cesiumViewer.scene.canvas.style.width = ''
  872. updateMap()
  873. }
  874. },
  875. enterScaleSet() {//设置比例
  876. let bus = new mitt()
  877. let length, measureBuilded;
  878. //viewer.outlinePass.selectedObjects = []
  879. if (!Potree.Utils.isInsideFrustum(model.boundingBox.clone().applyMatrix4(model.matrixWorld), viewer.scene.getActiveCamera())) {
  880. MergeEditor.focusOn(model, 600)
  881. }
  882. MergeEditor.getAllObjects().forEach(m => {//隐藏其他的模型
  883. if (m != model) Potree.Utils.updateVisible(m, 'enterScaleSet', false)
  884. })
  885. result.oldFar = Potree.settings.cameraFar
  886. model.enterScaleOldState_ = {
  887. //view: viewer.mainViewport.view.clone(),
  888. scale: model.scale.x,
  889. far: Potree.settings.cameraFar
  890. }
  891. let setScale = () => {
  892. if (length == void 0 || !measureBuilded) return
  893. let vec = new THREE.Vector3().subVectors(viewer.mainViewport.camera.position, scaleMeasure.points[1])
  894. let dis = scaleMeasure.points[0].distanceTo(scaleMeasure.points[1])
  895. let s = length / Math.max(dis,0.00001)
  896. result.changeScale(model.scale.x * s * 100)
  897. /* setTimeout(()=>{
  898. viewer.focusOnObject(scaleMeasure , 'measure', 500)
  899. },1) */
  900. let newCamPos = new THREE.Vector3().addVectors(scaleMeasure.points[1], vec.multiplyScalar(s))
  901. viewer.scene.view.setView({
  902. position: newCamPos, target: scaleMeasure.getCenter(), duration: 0, callback: () => {
  903. //更改target到measure中心的好处就是可以让相机绕measure中心转,坏处是每次更改都会变一下画面
  904. }
  905. })
  906. }
  907. return {
  908. bus,
  909. setLength(v) {
  910. if (!v) return
  911. length = v
  912. setScale()
  913. },
  914. startMeasure() {
  915. if (scaleMeasure) {
  916. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true, measure: scaleMeasure })
  917. viewer.scene.removeMeasurement(scaleMeasure)
  918. }
  919. measureBuilded = false
  920. scaleMeasure = viewer.measuringTool.startInsertion(
  921. { measureType: "Distance", unit: "metric" },
  922. () => {
  923. //done:
  924. //bus.emit('end' ) //完成
  925. measureBuilded = true
  926. setScale()
  927. },
  928. () => {
  929. //cancel
  930. //bus.emit('quit') //删除
  931. }
  932. )
  933. scaleMeasure.forbitRepeatPoint = true //两个点不能相同,否则长度是0
  934. scaleMeasure.addEventListener('marker_dropped', (e) => {//拖拽结束后发送changeCallBack
  935. if (scaleMeasure.parent) {
  936. //未被删除
  937. measureBuilded && setScale()
  938. }
  939. })
  940. }
  941. }
  942. },
  943. leaveScaleSet() {
  944. if (scaleMeasure) {
  945. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true, measure: scaleMeasure })
  946. viewer.scene.removeMeasurement(scaleMeasure)
  947. scaleMeasure = null
  948. }
  949. //viewer.outlinePass.selectedObjects = [model];
  950. MergeEditor.getAllObjects().forEach(m => {//恢复其他的模型
  951. if (m != model) Potree.Utils.updateVisible(m, 'enterScaleSet', true)
  952. })
  953. setTimeout(()=>{//可能还原了 相机位置移动回去
  954. if(model.scale.x == model.enterScaleOldState_.scale){
  955. MergeEditor.focusOn(model, 0) //reset orbitcontrol's minRadius //viewer.mainViewport.view.copy(model.enterScaleOldState_.view)
  956. //Potree.settings.cameraFar = model.enterScaleOldState_.far
  957. }
  958. },10)
  959. },
  960. destroy() {
  961. model && MergeEditor.removeModel(model)
  962. result.changeSelect(false)
  963. viewer.dispatchEvent('content_changed')
  964. }
  965. }
  966. return result
  967. },
  968. //测量线的点都附着于各个模型,当模型变化时,点跟着变化。
  969. // 新的测量创建方法,传入type 返回新测量对象
  970. startMeasure(type) {
  971. // 寻创建的测量对象有上面绘画测量对象的所有方法
  972. const bus = mitt()
  973. let info = getMeasureType(type)
  974. let measure = viewer.measuringTool.startInsertion(
  975. info,
  976. () => {
  977. //done:
  978. /* bus.emit('submit', {
  979. dataset_points: measure.dataset_points.map(p=>p.clone()) ,
  980. points_datasets: measure.points_datasets
  981. } ) //完成 */
  982. bus.emit('submit')
  983. /* bus.emit('update', [
  984. measure.dataset_points.map(p => p.clone()),
  985. measure.points_datasets
  986. ]) */
  987. },
  988. () => {
  989. //cancel
  990. bus.emit('cancel'/* , ret */) //删除
  991. }
  992. )
  993. Potree.Log('startMeasure: ' + measure.id, '#00c7b2')
  994. /* let cancel = ()=>{
  995. Potree.Log('clear删除: ' + measure.id, '#00c7b2')
  996. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true, measure })
  997. viewer.scene.removeMeasurement(measure)
  998. } */
  999. let result = {
  1000. bus,
  1001. ...getMeasureFunction(measure, bus),
  1002. }
  1003. /* StartMeasure = Measure & {
  1004. // 多了cancel 取消测量的事件,没有参数
  1005. // 多了invalidPoint 当用户测量了无效点时的事件,抛出无效原因
  1006. bus: Emitter<{ cancel: void; invalidPoint: string }>
  1007. } */
  1008. return result
  1009. },
  1010. // 绘画测量线(非新增使用)
  1011. // type = 'free' (自由) || 'vertical' (垂直) || 'area' (面积)
  1012. // positions 点数组 构成如下 [{ point: {x,y,z}, modelId: 1 }]
  1013. drawMeasure(type, dataset_points, points_datasets) {
  1014. // 返回测量对象有如下
  1015. const bus = mitt()
  1016. let info = getMeasureType(type /* , unit */)
  1017. //info.points = positions
  1018. info.dataset_points = dataset_points
  1019. info.points_datasets = points_datasets
  1020. //info.sid = sid
  1021. info.bus = bus
  1022. let measure = viewer.measuringTool.createMeasureFromData(info)
  1023. if (!measure) return { bus }
  1024. Potree.Log('drawMeasure由数据新建: ' + measure.id, '#00c7b2')
  1025. let result = {
  1026. bus,
  1027. setPositions(dataset_points, points_datasets) {//用于恢复measure的点,不会修改点的个数
  1028. measure.dataset_points = dataset_points.map(e => {
  1029. return e && new THREE.Vector3().copy(e)
  1030. })
  1031. measure.points_datasets = points_datasets
  1032. measure.points = measure.dataset_points.map((p, i) => {
  1033. return Potree.Utils.datasetPosTransform({ fromDataset: true, datasetId: measure.points_datasets[i], position: p })
  1034. })
  1035. measure.getPoint2dInfo(measure.points)
  1036. measure.update({ ifUpdateMarkers: true })
  1037. measure.setSelected(false)//隐藏edgelabel
  1038. },
  1039. ...getMeasureFunction(measure, bus),
  1040. }
  1041. return result
  1042. },
  1043. startAddSth(){//开始添加热点
  1044. Potree.settings.disableClick = true //禁止点击事件,尤其是全景模式下,否则会走到下一个点
  1045. viewer.dispatchEvent('start_inserting_tag')
  1046. },
  1047. endAddSth(){
  1048. Potree.settings.disableClick = false
  1049. viewer.dispatchEvent('endTagMove')
  1050. },
  1051. addTag(info) {//加标签
  1052. let bus = mitt()
  1053. let tag
  1054. let done = () => {
  1055. bus.emit('added')
  1056. bus.emit('update', { position: tag.position.clone(), normal: o.normal.clone(), modelId: tag.root.dataset_id })
  1057. tag = tag_
  1058. tag.spot.addEventListener('mouseover', () => {
  1059. bus.emit('hoverState', true)
  1060. })
  1061. tag.spot.addEventListener('mouseout', () => {
  1062. bus.emit('hoverState', false)
  1063. })
  1064. }
  1065. if (!info.position) {
  1066. viewer.tagTool.startInsertion().done(tag_ => {
  1067. done()
  1068. })
  1069. } else {
  1070. info.root = MergeEditor.getAllObjects().find(e => e.dataset_id == info.modelId)
  1071. if (!info.root) {
  1072. console.error('没有找到该modelId')
  1073. }
  1074. tag = viewer.tagTool.createTagFromData(info)
  1075. done()
  1076. }
  1077. let result = {
  1078. bus,
  1079. getScreenPos() {
  1080. let pos3d = new THREE.Vector3().setFromMatrixPosition(tag.matrixWorld)
  1081. return sdk.getScreenByPosition(pos3d)
  1082. },
  1083. show() {
  1084. Potree.Utils.updateVisible(tag, 'byList', true)
  1085. },
  1086. hide() {
  1087. Potree.Utils.updateVisible(tag, 'byList', false)
  1088. },
  1089. destroy() {
  1090. if (tag) {
  1091. tag.dispose()
  1092. }
  1093. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true })
  1094. },
  1095. changeTitle(title) {
  1096. tag.changeTitle(title)
  1097. }
  1098. }
  1099. return result
  1100. },
  1101. showGrid() {
  1102. Potree.Utils.updateVisible(viewer.modules.MergeEditor.ground, 'hideGrid', true)
  1103. viewer.dispatchEvent('content_changed')
  1104. },
  1105. hideGrid() {
  1106. Potree.Utils.updateVisible(viewer.modules.MergeEditor.ground, 'hideGrid', false)
  1107. viewer.dispatchEvent('content_changed')
  1108. }
  1109. }
  1110. function spliceFromArr(model, props, loaded){
  1111. //let autoLoads.find()
  1112. props.loadFinish = true
  1113. props.loading = false
  1114. if (loaded) {
  1115. props.loaded = true
  1116. props.model = model
  1117. } else {
  1118. props.error = true
  1119. }
  1120. /* let haventLoad = autoLoads.filter(e=>!e.loading && !e.loadFinish);
  1121. if( haventLoad[0]){
  1122. startLoad(haventLoad[0])
  1123. */
  1124. if (!loadNext()) {
  1125. if (autoLoads.filter(e => !e.loadFinish).length == 0 && autoLoads.filter(e => e.loaded).length > 0 && !props.isFirstLoad) {//设置相机位置:当自动开始加载第一个模型时(其余的也跟着自动加载),等这批加载完后;
  1126. let autoLoadsDone = autoLoads.filter(e => e.loaded).map(e => e.model)
  1127. let loadTimeCost = Date.now() - loadStartTime
  1128. console.log('所有模型加载完毕, 耗时', parseInt(loadTimeCost) )
  1129. autoLoads.filter(e => e.loaded && e.show).forEach(e => e.model.visible = true)
  1130. MergeEditor.focusOn(autoLoadsDone, 1000, true, true)
  1131. autoLoads.length = 0
  1132. }
  1133. }
  1134. }
  1135. function loadNext(){
  1136. let haventLoad = autoLoads.filter(e => !e.loading && !e.loadFinish);
  1137. let loading = autoLoads.filter(e => e.loading);
  1138. let needLoad = haventLoad.slice(0, maxLoadingCount - loading.length)
  1139. needLoad.forEach(e => startLoad(e))
  1140. return haventLoad.length > 0
  1141. }
  1142. function startLoad(prop){
  1143. /* if(prop.raw.visible !== 1){//用于临时隐藏
  1144. setTimeout(()=>{
  1145. spliceFromArr(null, prop, false)
  1146. prop.bus.emit('loadError' )
  1147. },1)
  1148. return
  1149. } */
  1150. if(prop.loading || prop.loadFinish)return
  1151. Potree.Log(`--开始加载--`, { font: { color: '#f68' } });
  1152. console.log('id:', prop.id, ', title:', prop.title, ', filename:', Potree.Common.getNameFromURL(prop.url), ', type:', prop.type, prop)
  1153. prop.unlit = prop.renderType != 'normal'
  1154. prop.maximumScreenSpaceError = 70
  1155. prop.prefix = prop.raw.prefix
  1156. Potree.addModel(prop, prop.done, prop.progressFun, prop.onError)
  1157. prop.loading = true
  1158. }
  1159. function buildMap(){
  1160. if (Potree.settings.showCesium && !window.cesiumViewer) {
  1161. viewer.backgroundOpacity = 0
  1162. Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI2ZGM2YzY0ZC1kNWE0LTRiYTgtYTkwNS1kYmJiODRjMWUwMmQiLCJpZCI6MjMzMTQ1LCJpYXQiOjE3MjI5OTUwNTB9.niqpkl6xOkQ2KeJjelyDDDydmSGqKXKb5cX2NyxSNAw'
  1163. class AmapMercatorTilingScheme extends Cesium.WebMercatorTilingScheme {
  1164. constructor(options) {
  1165. super(options)
  1166. let projection = new Cesium.WebMercatorProjection()
  1167. this._projection.project = function(cartographic, result) {
  1168. //WGS84转GCJ02坐标
  1169. /* result = gcoord.transform([
  1170. Cesium.Math.toDegrees(cartographic.longitude),
  1171. Cesium.Math.toDegrees(cartographic.latitude)
  1172. ], gcoord.WGS84, gcoord.GCJ02) */
  1173. result = AMapWith84__.wgs84ToAMap({
  1174. x: Cesium.Math.toDegrees(cartographic.longitude),
  1175. y: Cesium.Math.toDegrees(cartographic.latitude)
  1176. })
  1177. result = projection.project(new Cesium.Cartographic(Cesium.Math.toRadians(result.x),Cesium.Math.toRadians(result.y)))
  1178. return new Cesium.Cartesian2(result.x,result.y)
  1179. }
  1180. this._projection.unproject = function(cartesian, result) {
  1181. let cartographic = projection.unproject(cartesian)
  1182. //GCJ02转WGS84坐标
  1183. /* result = gcoord.transform([
  1184. Cesium.Math.toDegrees(cartographic.longitude),
  1185. Cesium.Math.toDegrees(cartographic.latitude)
  1186. ], gcoord.GCJ02, gcoord.WGS84) */
  1187. result = AMapWith84__.aMapToWgs84({
  1188. x: Cesium.Math.toDegrees(cartographic.longitude),
  1189. y: Cesium.Math.toDegrees(cartographic.latitude)
  1190. })
  1191. return new Cesium.Cartographic(Cesium.Math.toRadians(result.x),Cesium.Math.toRadians(result.y))
  1192. }
  1193. }
  1194. }//see : https://blog.csdn.net/hongxianqiang/article/details/140541555 cesium加载高德地图并纠偏
  1195. window.cesiumViewer = new Cesium.Viewer('app', {
  1196. useDefaultRenderLoop: true,
  1197. requestRenderMode: true, //add 只有需要render时才会render,如tile加载完后、镜头移动后
  1198. animation: false,
  1199. baseLayerPicker: false,
  1200. fullscreenButton: false,
  1201. geocoder: false,
  1202. homeButton: false,
  1203. infoBox: false,
  1204. sceneModePicker: false,
  1205. selectionIndicator: false,
  1206. timeline: false,
  1207. navigationHelpButton: false,
  1208. //高德秘钥版 imageryProvider: new Cesium.AmapImageryProvider({key, mapStyle: 'normal'})
  1209. //报错 401 (Unauthorized) 的方法 https://blog.csdn.net/LBY_XK/article/details/121992641
  1210. //terrainShadows: Cesium.ShadowMode.DISABLED, //terrain地形
  1211. });
  1212. let satellite = true
  1213. let gaoDeImageryProvider = /* cesImageryProvider || */new Cesium.UrlTemplateImageryProvider({
  1214. url: `//wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=${satellite?6:7}&x={x}&y={y}&z={z}&token=YOUR_API_KEY`, //style=6是卫星,7是标准
  1215. minimumLevel: 0,
  1216. maximumLevel: satellite?18:19,
  1217. credit: new Cesium.Credit('高德地图'),
  1218. tilingScheme: new AmapMercatorTilingScheme(), //修改投影,从84->高德
  1219. crossOrigin: 'anonymous',
  1220. })
  1221. cesiumViewer.imageryLayers.removeAll();
  1222. cesiumViewer.imageryLayers.addImageryProvider(gaoDeImageryProvider);
  1223. Potree.cesScreenshot = (w,h)=>{
  1224. console.log('cesScreenshot',w,h)
  1225. cesiumViewer.scene.canvas.style.width = w+'px'
  1226. cesiumViewer.scene.canvas.style.height = h+'px'
  1227. cesiumViewer.scene.canvas.style.visibility = 'hidden'
  1228. cesiumViewer.resize()
  1229. cesAspect = w/h
  1230. let deferred = $.Deferred();
  1231. updateMap(w/h)//hfov可能改变了需要update。
  1232. setTimeout(()=>{ //延迟是似乎还要做别的处理,否则立即截图的话可能得到绿色底图(俯视状态容易触发)
  1233. let oldMode = window.cesiumViewer._cesiumWidget._scene.requestRenderMode
  1234. window.cesiumViewer._cesiumWidget._scene.requestRenderMode = 0 //强制render,否则会黑屏
  1235. cesiumViewer.render();
  1236. let dataUrl = window.cesiumViewer.scene.canvas.toDataURL('image/png')
  1237. window.cesiumViewer._cesiumWidget._scene.requestRenderMode = oldMode
  1238. //Potree.Common.downloadFile(dataUrl, 'screenshot.png')
  1239. cesAspect = null
  1240. cesiumViewer.scene.canvas.style.width = ''
  1241. cesiumViewer.scene.canvas.style.height = ''
  1242. cesiumViewer.scene.canvas.style.visibility = ''
  1243. deferred.resolve(dataUrl)
  1244. },200) //时间短了容易黑屏
  1245. return deferred.promise()
  1246. }
  1247. }
  1248. updateMap()
  1249. }
  1250. function updateCamNear(type){// 有的漫游场景模型缩放的很小(0.1%),需要缩小near才能看见, 但会造成z-fighting, 离远了看大模型会闪烁
  1251. const min = 0.0001, max = 0.1
  1252. let near , bigScale = 0.2
  1253. if(Potree.settings.displayMode == 'showPanos'/* && type != 'cameraMove' */){
  1254. let currentModel = viewer.images360.currentPano.pointcloud
  1255. near = Potree.math.linearClamp(currentModel.scale.x, [0, 1], [min, max])
  1256. }else/* if(type == 'cameraMove') */{
  1257. //没有完美的解决方式,优先考虑选中的模型。否则优先考虑离得近的。 另外尽量用大的,因为缩很小的情况很少。
  1258. //虽然案例说应该看model.bound.size,但如果非场景模型,缩很小的话也不需要凑近看。
  1259. let allModels = viewer.objs.children.concat(viewer.scene.pointclouds)
  1260. if(allModels.length == 0)return
  1261. allModels.sort((a,b)=>{return a.scale.x - b.scale.x})
  1262. let minS = allModels[0].scale.x, maxS = allModels.pop().scale.x
  1263. let considerModel
  1264. if(minS>bigScale) near = max
  1265. else{
  1266. if(MergeEditor.selected){
  1267. considerModel = MergeEditor.selected
  1268. near = Potree.math.linearClamp(considerModel.scale.x, [0, bigScale], [min, max])
  1269. }else{
  1270. //allModels = allModels.filter() //写不下去了好难,就算了吧, 折中
  1271. near = Potree.math.linearClamp(minS, [0, bigScale], [max/4, max])
  1272. }
  1273. }
  1274. }
  1275. if(near != viewer.mainViewport.camera.near){
  1276. console.log('updateNear',near)
  1277. viewer.mainViewport.camera.near = near
  1278. viewer.mainViewport.camera.updateProjectionMatrix()
  1279. viewer.dispatchEvent('content_changed')
  1280. }
  1281. }
  1282. function updateCamFar(){
  1283. let expand = 1.1 //for label
  1284. Potree.settings.cameraFar = THREE.Math.clamp((viewer.bound.boundingBox.distanceToPoint(viewer.mainViewport.camera.position)+viewer.bound.boundSize.length() ) * expand , 10000, 100000000000)
  1285. }
  1286. function updateMap(){
  1287. if (Potree.settings.showCesium && Potree.settings.displayMode == 'showPointCloud') {
  1288. let camera = MergeEditor.split ? viewer.viewports.find(e=>e.name == 'top').camera : viewer.mainViewport.camera
  1289. let pPos = new THREE.Vector3(0, 0, 0).applyMatrix4(camera.matrixWorld);
  1290. let orientation
  1291. let toCes = (pos) => {
  1292. let xy = [pos.x, pos.y];
  1293. let height = pos.z;
  1294. let deg = viewer.transform.lonlatToLocal.inverse(xy) // toMap.forward(xy);
  1295. let cPos = Cesium.Cartesian3.fromDegrees(...deg, height);
  1296. //console.log('toCes',cPos,height) //数字过大如e35会崩溃
  1297. return cPos;
  1298. };
  1299. let cPos = toCes(pPos);
  1300. if(MergeEditor.split){
  1301. orientation = {
  1302. heading: Cesium.Math.toRadians(0.0), // 方向角
  1303. pitch: Cesium.Math.toRadians(-90.0), // 俯仰角
  1304. roll: 0.0 // 翻滚角
  1305. }
  1306. if(!cesiumViewer.camera.perpFrustum_){
  1307. cesiumViewer.camera.perpFrustum_ = cesiumViewer.camera.frustum
  1308. cesiumViewer.camera.frustum = new Cesium.OrthographicOffCenterFrustum({//OrthographicFrustum OrthographicOffCenterFrustum
  1309. left: -10000, // 左边界
  1310. right: 10000, // 右边界
  1311. bottom: -10000, // 下边界
  1312. top: 10000, // 上边界
  1313. near: 1.0, // 近裁剪面距离
  1314. far: 100000000.0, // 远裁剪面距离
  1315. })
  1316. }
  1317. cesiumViewer.camera.frustum.left = camera.left / camera.zoom
  1318. cesiumViewer.camera.frustum.right = camera.right / camera.zoom
  1319. cesiumViewer.camera.frustum.top = camera.top / camera.zoom
  1320. cesiumViewer.camera.frustum.bottom = camera.bottom / camera.zoom
  1321. }else{
  1322. cesiumViewer.camera.perpFrustum_ && (cesiumViewer.camera.frustum = cesiumViewer.camera.perpFrustum_, cesiumViewer.camera.perpFrustum_ = null) //恢复
  1323. //let pRight = new THREE.Vector3(600, 0, 0).applyMatrix4(camera.matrixWorld);
  1324. let pUp = new THREE.Vector3(0, 600, 0).applyMatrix4(camera.matrixWorld);
  1325. let pTarget = viewer.scene.view.getPivot();
  1326. let cUpTarget = toCes(pUp);
  1327. let cTarget = toCes(pTarget);
  1328. let cDir = Cesium.Cartesian3.subtract(cTarget, cPos, new Cesium.Cartesian3());
  1329. let cUp = Cesium.Cartesian3.subtract(cUpTarget, cPos, new Cesium.Cartesian3());
  1330. cDir = Cesium.Cartesian3.normalize(cDir, new Cesium.Cartesian3());
  1331. cUp = Cesium.Cartesian3.normalize(cUp, new Cesium.Cartesian3());
  1332. //console.log('ces', 'cPos', cPos, 'cDir',cDir, 'cUp', cUp)
  1333. orientation = {
  1334. direction: cDir,
  1335. up: cUp
  1336. }
  1337. let aspect = cesAspect || camera.aspect;
  1338. //console.log('updateMap', aspect)
  1339. if (aspect < 1) {
  1340. let fovy = Math.PI * (viewer.scene.getActiveCamera().fov / 180);
  1341. cesiumViewer.camera.frustum.fov = fovy;
  1342. } else {
  1343. let fovy = Math.PI * (viewer.scene.getActiveCamera().fov / 180);
  1344. let fovx = Math.atan(Math.tan(0.5 * fovy) * aspect) * 2
  1345. cesiumViewer.camera.frustum.fov = fovx;
  1346. }
  1347. }
  1348. cesiumViewer.camera.setView({
  1349. destination: cPos,
  1350. orientation
  1351. });
  1352. cesiumViewer.scene.globe.show = camera.position.z > 0 //在地面之下地球会闪烁,故隐藏
  1353. cesiumViewer.render(); //立即render,否则会和点云render不同步而错位
  1354. }//cesium测试沙盒 https://sandcastle.cesium.com/
  1355. }
  1356. return sdk
  1357. }
  1358. /*
  1359. 暂定不同场景间的漫游点不能互通。虽然它们可能是摆放正确的,如果是组成一整个场景的话还是要打通……
  1360. 不互通的方法是设置pano.enable
  1361. 现在需要互通了。但是还需要设置neibgbours, 有点麻烦,暂时没写。
  1362. */
  1363. export default enter