index.js 90 KB

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