index.js 107 KB

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