index.js 130 KB

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