index.js 82 KB

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