index.js 114 KB

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