index.js 83 KB

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