start.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522
  1. import * as THREE from "../libs/three.js/build/three.module.js";
  2. import {settings, config} from './settings.js'
  3. import math from './utils/math.js'
  4. import browser from './utils/browser.js'
  5. import './extensions/three.shim.js'
  6. import {Utils} from "./utils.js"
  7. var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
  8. /* {
  9. let obj = JSON.parse(localStorage.getItem('setting'))
  10. for(let i in obj){
  11. console.log(i + ': ' + obj[i])
  12. }
  13. }
  14. */
  15. Potree.settings.number = number || 't-o5YMR13'// 't-iksBApb'// 写在viewer前
  16. Potree.fileServer = fileServer
  17. webSite && (Potree.settings.webSite = webSite)
  18. let viewer = new Potree.Viewer(dom , mapDom);
  19. let Alignment = viewer.modules.Alignment
  20. //let pointDensity = config.pointDensity.middle
  21. viewer.setEDLEnabled(false);
  22. viewer.setFOV(config.view.fov);
  23. //viewer.setPointBudget(pointDensity.pointBudget);
  24. viewer.loadSettingsFromURL();
  25. if(!Potree.settings.isOfficial){
  26. viewer.loadGUI(() => {
  27. viewer.setLanguage('en');
  28. //$("#menu_appearance").next().show();
  29. $("#menu_tools").next().show();
  30. $("#menu_scene").next().show();
  31. $("#siteModel").show();
  32. //$("#alignment").show();
  33. viewer.toggleSidebar();
  34. });
  35. Potree.settings.sizeFitToLevel = true//当type为衰减模式时自动根据level调节大小。每长一级,大小就除以2
  36. }
  37. Potree.loadDatasetsCallback = function(data, ifReload){
  38. if(!data || data.length == 0)return console.error('getDataSet加载的数据为空')
  39. Potree.datasetData = data
  40. viewer.transform = null
  41. var datasetLength = data.length
  42. var pointcloudLoaded = 0
  43. var panosLoaded = 0
  44. var pointcloudLoadDone = function(){//点云cloud.js加载完毕后
  45. viewer.updateModelBound()
  46. let {boundSize, center} = viewer.bound
  47. Potree.Log(`中心点: ${math.toPrecision(center.toArray(),2)}, boundSize: ${math.toPrecision(boundSize.toArray(),2)} ` , null, 12)
  48. if(!Potree.settings.isOfficial){
  49. Potree.loadMapEntity('all') //加载floorplan
  50. }
  51. if(!ifReload){
  52. viewer.scene.view.setView({
  53. position: center.clone().add(new THREE.Vector3(10,5,10)),
  54. target: center
  55. })
  56. viewer.dispatchEvent({type:'loadPointCloudDone'})
  57. if(!Potree.settings.UserPointDensity){
  58. Potree.settings.UserPointDensity = 'high'//'middle'
  59. }
  60. Potree.Log('loadPointCloudDone 点云加载完毕', null, 10)
  61. }
  62. }
  63. var panosLoadDone = function(){
  64. viewer.images360.loadDone()
  65. viewer.scene.add360Images(viewer.images360);
  66. viewer.mapViewer.addListener(viewer.images360)
  67. {//初始位置
  68. var urlFirstView = false
  69. var panoId = browser.urlHasValue('pano',true);
  70. if(panoId !== ''){
  71. var pos
  72. var pano = viewer.images360.panos.find(e=>e.id==panoId);
  73. if(pano){
  74. viewer.images360.focusPano({
  75. pano,
  76. duration:0,
  77. callback:()=>{/* Potree.settings.displayMode = 'showPanos' */}
  78. })
  79. }
  80. }else{//考虑到多数据集距离很远,或者像隧道那种场景,要使视野范围内一定能看到点云,最好初始点设置在漫游点上
  81. let {boundSize, center} = viewer.bound
  82. let pano = viewer.images360.findNearestPano(center)
  83. /* pano && viewer.scene.view.setView({
  84. position: pano.position.clone().add(new THREE.Vector3(10,10,10)),
  85. target: pano.position
  86. }) */
  87. pano && viewer.images360.flyToPano({
  88. pano, duration:0,
  89. target : viewer.images360.bound.center
  90. })
  91. }
  92. }
  93. viewer.addVideo()//addFire()
  94. console.log('allLoaded')
  95. viewer.dispatchEvent('allLoaded')
  96. }
  97. var transformPointcloud = (pointcloud, dataset)=>{
  98. var locationLonLat = dataset.location.slice(0,2)
  99. //当只有一个dataset时,无论如何transform 点云和漫游点都能对应上。
  100. var location = viewer.transform.lonlatToLocal.forward(locationLonLat) //transform.inverse()
  101. //初始化位置
  102. viewer.sidebar && viewer.sidebar.addAlignmentButton(pointcloud)
  103. //dataset.orientation = 0
  104. Alignment.rotate(pointcloud, null, dataset.orientation)
  105. Alignment.translate(pointcloud, new THREE.Vector3(location[0], location[1], dataset.location[2]))
  106. pointcloud.updateMatrixWorld()
  107. Potree.Log(`点云${pointcloud.dataset_id}旋转值:${pointcloud.orientationUser}, 位置${math.toPrecision(pointcloud.translateUser.toArray(),3)}, 经纬度 ${locationLonLat}, spacing ${pointcloud.material.spacing}`, null, 17 )
  108. //-------------------
  109. //viewer.mapView.showSources(false);
  110. }
  111. if(!Potree.settings.originDatasetId)Potree.settings.originDatasetId = data[0].id
  112. var originDataset = data.find(e=>e.id == Potree.settings.originDatasetId)
  113. {//拿初始数据集作为基准。它的位置是000
  114. var locationLonLat = originDataset.location.slice(0,2)
  115. proj4.defs("NAVVIS:TMERC", "+proj=tmerc +ellps=WGS84 +lon_0=" + locationLonLat[0].toPrecision(15) + " +lat_0=" + locationLonLat[1].toPrecision(15));
  116. proj4.defs("WGS84", "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs");
  117. let transform1 = proj4("WGS84", "NAVVIS:TMERC"); //这个ok TMERC是展开的平面投影
  118. let transform2 = proj4("+proj=tmerc +lat_0=0 +lon_0=123 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs;");
  119. viewer.transform = {
  120. lonlatToLocal : transform1,
  121. lonlatTo4550 : transform2 // 转大地坐标EPSG:4550
  122. }
  123. viewer.mapViewer && viewer.mapViewer.mapLayer.maps[0].updateProjection()
  124. }
  125. data.forEach((dataset,index)=>{
  126. if(!ifReload){
  127. var datasetCode = dataset.sceneCode || dataset.name //对应4dkk的场景码
  128. var cloudPath = `${Potree.settings.urls.prefix}/${Potree.settings.webSite}/${datasetCode}/data/${datasetCode}/webcloud/cloud.js`
  129. var timeStamp = dataset.createTime ? dataset.createTime.replace(/[^0-9]/ig,'') : ''; //每重算一次后缀随createTime更新一次
  130. //console.warn(dataset.name, 'timeStamp', timeStamp)
  131. Potree.loadPointCloud(cloudPath, dataset.name ,datasetCode, timeStamp, e => {
  132. let scene = viewer.scene;
  133. let pointcloud = e.pointcloud;
  134. let config = Potree.config.material
  135. let material = pointcloud.material;
  136. pointcloud.hasDepthTex = Potree.settings.hasDepthTex && (!!dataset.has_depth || Potree.settings.isLocalhost && Potree.settings.number == 'SS-t-7DUfWAUZ3V') //test
  137. material.minSize = config.minSize
  138. material.maxSize = config.maxSize
  139. material.pointSizeType = config.pointSizeType //Potree.PointSizeType[config.pointSizeType]//Potree.PointSizeType.ADAPTIVE;//FIXED
  140. pointcloud.changePointSize(config.realPointSize) //material.size = config.pointSize;
  141. pointcloud.changePointOpacity(1)
  142. material.shape = Potree.PointShape.SQUARE;
  143. pointcloud.color = pointcloud.material.color = dataset.color
  144. pointcloud.dataset_id = dataset.id;//供漫游点找到属于的dataset点云
  145. pointcloud.timeStamp = timeStamp
  146. transformPointcloud(pointcloud,dataset)
  147. scene.addPointCloud(pointcloud);
  148. pointcloudLoaded ++;
  149. if(pointcloudLoaded == datasetLength)pointcloudLoadDone()
  150. Potree.loadPanos(dataset.id, (data) => {
  151. //console.log('loadPanos',dataset.sceneCode, dataset.id, data)
  152. viewer.images360.addPanoData(data, dataset.id )
  153. panosLoaded ++;
  154. if(panosLoaded == datasetLength){
  155. panosLoadDone()
  156. }
  157. })
  158. })
  159. }else{
  160. let pointcloud = viewer.scene.pointclouds.find(p => p.dataset_id == dataset.id)
  161. if(!pointcloud){
  162. Potree.Log('数据集id变了,自动使用第一个','#500')
  163. pointcloud = viewer.scene.pointclouds[0]
  164. }
  165. //先归零
  166. Alignment.translate(pointcloud, pointcloud.translateUser.clone().negate())
  167. Alignment.rotate(pointcloud, null, - pointcloud.orientationUser)
  168. transformPointcloud(pointcloud, dataset)
  169. }
  170. })
  171. if(ifReload){
  172. //loadDone()
  173. }
  174. }
  175. Potree.loadDatasets(Potree.loadDatasetsCallback)
  176. window.testTransform = function(locationLonLat, location1, location2){
  177. proj4.defs("NAVVIS:test", "+proj=tmerc +ellps=WGS84 +lon_0=" + locationLonLat[0].toPrecision(15) + " +lat_0=" + locationLonLat[1].toPrecision(15));
  178. let transform = proj4("WGS84", "NAVVIS:test"); //这个ok navvis里也是这两种转换 见proj4Factory
  179. if(location1){//经纬度
  180. return transform.forward(location1)
  181. }else{
  182. return transform.inverse(location2)
  183. }
  184. }
  185. window.THREE = THREE
  186. window.buttonFunction = function(){
  187. viewer.scene.pointclouds.forEach(e=>e.predictNodeMaxLevel())
  188. /*
  189. viewer.startScreenshot({type:'measure', measurement:viewer.scene.measurements[0]})
  190. viewer.modules.RouteGuider.routeStart = new THREE.Vector3(0,0,-1.3)
  191. viewer.modules.RouteGuider.routeEnd = new THREE.Vector3(-10,0,-1.3)
  192. */
  193. }
  194. if(Potree.settings.isLocalhost){
  195. let before = {}
  196. viewer.inputHandler.addEventListener('keydown',e=>{ //测试的代码
  197. if(e.event.key == 't'){
  198. viewer.images360.cube.visible = true
  199. viewer.images360.cube.material.wireframe = true
  200. }else if(e.event.key == 'y'){
  201. viewer.images360.cube.material.wireframe = false
  202. viewer.images360.cube.visible = Potree.settings.displayMode == 'showPanos'
  203. }
  204. })
  205. }
  206. }
  207. //=======================================================================
  208. /*
  209. 漫游点编辑
  210. */
  211. //=======================================================================
  212. var panoEditStart = function(dom, number, fileServer, webSite){
  213. Potree.settings.editType = 'pano'
  214. Potree.settings.number = number
  215. Potree.settings.unableNavigate = true
  216. let viewer = new Potree.Viewer(dom);
  217. let Alignment = viewer.modules.Alignment
  218. viewer.setEDLEnabled(false);
  219. viewer.setFOV(config.view.fov);
  220. viewer.loadSettingsFromURL();
  221. let datasetLoaded = 0;
  222. if(!Potree.settings.isOfficial){
  223. viewer.loadGUI(() => {
  224. viewer.setLanguage('en');
  225. $("#menu_tools").next().show();
  226. $("#panos").show();
  227. $("#alignment").show();
  228. viewer.toggleSidebar();
  229. });
  230. Potree.settings.sizeFitToLevel = true
  231. }
  232. var pointcloudLoadDone = function( ){//所有点云cloud.js加载完毕后
  233. viewer.scene.pointclouds.forEach(c=>{
  234. transformPointcloud(c)
  235. })
  236. viewer.images360.loadDone()
  237. viewer.scene.add360Images(viewer.images360);
  238. viewer.updateModelBound()
  239. let {boundSize, center} = viewer.bound
  240. Potree.Log(`中心点: ${math.toPrecision(center.toArray(),2)}, boundSize: ${math.toPrecision(boundSize.toArray(),2)} ` , null, 12)
  241. viewer.scene.view.setView({
  242. position: center.clone().add(new THREE.Vector3(10,5,10)),
  243. target: center
  244. })
  245. viewer.dispatchEvent({type:'loadPointCloudDone'})
  246. if(!Potree.settings.UserPointDensity){
  247. Potree.settings.UserPointDensity = 'panoEdit'//'middle'
  248. }
  249. Potree.Log('loadPointCloudDone 点云加载完毕', null, 10)
  250. viewer.dispatchEvent('allLoaded');
  251. }
  252. var transformPointcloud = (pointcloud )=>{ //初始化位置
  253. viewer.sidebar && viewer.sidebar.addAlignmentButton(pointcloud)
  254. let orientation = pointcloud.panos[0].dataRotation.z
  255. let location = pointcloud.panos[0].dataPosition.clone().negate()
  256. Alignment.rotate(pointcloud, null, orientation )
  257. Alignment.translate(pointcloud, location )
  258. pointcloud.updateMatrixWorld()
  259. }
  260. let loadPanosDone = Potree.loadPanosDone = (datasetId, panoData)=>{ //一个数据集获取到它的panos后
  261. Potree.settings.datasetsPanos[datasetId] = {panoData, panos:[]}
  262. console.log('panoData', datasetId, panoData)
  263. let panoCount = panoData.length
  264. let pointcloudLoaded = 0
  265. let datasetsCount = Object.keys(Potree.settings.datasetsPanos).length
  266. panoData.forEach((pano, index)=>{
  267. //let cloudPath = `${Potree.scriptPath}/data/panoEdit/uuidcloud/${pano.uuid}/cloud.js`
  268. let cloudPath = `https://laser-oss.4dkankan.com/testdata/${Potree.settings.number}/data/bundle_${Potree.settings.number}/building/uuidcloud/${pano.uuid}/cloud.js`
  269. let name = datasetId + '-'+pano.uuid
  270. let timeStamp = 0
  271. pano.index = index //注意:index不等于uuid,因为有的uuid缺失。但是visibles中存的是下标!
  272. Potree.loadPointCloud(cloudPath, name , name, timeStamp, e => { //开始加载点云
  273. let scene = viewer.scene;
  274. let pointcloud = e.pointcloud;
  275. let config = Potree.config.material
  276. let material = pointcloud.material;
  277. material.minSize = config.minSize
  278. material.maxSize = config.maxSize
  279. material.pointSizeType = /* 'ADAPTIVE'// */config.pointSizeType //Potree.PointSizeType[config.pointSizeType]//Potree.PointSizeType.ADAPTIVE;//FIXED
  280. pointcloud.changePointSize( 0.2 /* config.realPointSize */ ) //material.size = config.pointSize;
  281. pointcloud.changePointOpacity(1)
  282. material.shape = Potree.PointShape.SQUARE;
  283. pointcloud.color = config.pointColor
  284. pointcloud.dataset_id = datasetId; //多个点云指向一个datasetId
  285. pointcloud.panoUuid = pano.uuid
  286. pointcloud.timeStamp = timeStamp
  287. //transformPointcloud(pointcloud, pano)
  288. scene.addPointCloud(pointcloud);
  289. pointcloudLoaded ++;
  290. if(pointcloudLoaded == panoCount ){
  291. datasetLoaded ++
  292. viewer.images360.addPanoData(panoData , datasetId )
  293. if(datasetLoaded == datasetsCount){
  294. pointcloudLoadDone()
  295. }
  296. }
  297. })
  298. })
  299. }
  300. if(!Potree.settings.isOfficial){
  301. Potree.settings.datasetsPano = {'testDataset':null}
  302. Potree.loadPanosInfo( data=>{loadPanosDone('testDataset', data.sweepLocations)} )
  303. }
  304. }
  305. /* var changeLog = ()=>{ //如果移动端加了test反而出不来bug的话,用这个
  306. var textarea = document.createElement('textarea');
  307. textarea.id = "consoleLog";
  308. textarea.style.width = '160px';
  309. textarea.style.height = '200px'
  310. textarea.style.position = 'fixed'
  311. textarea.style.right = 0
  312. textarea.style.bottom = '0'
  313. textarea.style['z-index'] = 9999;
  314. textarea.style.color = 'black';
  315. textarea.style.opacity = 0.9;
  316. textarea.style['font-size'] = '12px';
  317. textarea.style['backgroundColor'] = '#ffffff'
  318. document.getElementsByTagName("body")[0].appendChild(textarea);
  319. var list = ["log", "error", "warn", "debug", "info", "time", "timeEnd"]
  320. var exchange = function (o) {
  321. console["old" + o] = console[o];
  322. console[o] = function () {
  323. var args = Array.from(arguments)
  324. console["old" + o].apply(this, arguments)
  325. var t = document.getElementById("consoleLog").innerHTML;
  326. var str = ''
  327. args.forEach(a=>{
  328. str += a + ' '
  329. })
  330. document.getElementById("consoleLog").innerHTML = str + "\n\n" + t;
  331. }
  332. }
  333. for (var i = 0; i < list.length; i++) {
  334. exchange(list[i])
  335. }
  336. }
  337. changeLog() */
  338. export {start, panoEditStart}
  339. /*
  340. 坐标转换问题:
  341. 由于控制点可以随便输入,所以本地和地理位置的转换也是可拉伸的。而navvis的转换是等比由中心展开,
  342. 所以对比两种转化方式时误差较大。
  343. 另外地理注册控制点是有参考数据集的,若参考数据集和我放置在0,0,0的数据集一致,就可直接使用,否则要转换。
  344. */