index.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. import mitt from 'mitt'
  2. import axios from 'axios' //{ axios } from '@/api'
  3. export const enter = (dom, isLocal) => {
  4. Potree.settings.isOfficial = true //标记为正式、非测试版本
  5. //Potree.fileServer = axios
  6. Potree.settings.libsUrl = '../lib/'
  7. let {THREE} = Potree.mergeEditStart(dom)
  8. let MergeEditor = viewer.modules.MergeEditor
  9. let sceneBus = mitt()
  10. viewer.addEventListener('camera_changed', e => {
  11. var camera = e.viewport.camera
  12. var pos = camera.position
  13. if (e.viewport.name == 'MainView') {
  14. sceneBus.emit('cameraChange', { x: pos.x, y: pos.y, z: pos.z, rotate: camera.rotation })
  15. }
  16. })
  17. window.THREE = THREE
  18. //isLocal = false
  19. let autoLoads = []
  20. let readyToAddModel
  21. let maxLoadingCount = isLocal ? 1 : 2; //正在加载模型的最大数目
  22. let sdk = {
  23. sceneBus,
  24. getPositionByScreen(pos2d, mustModelId ){//通过屏幕坐标获取真实坐标 . mustModelId: 如果指定了模型,modelId必须为mustModelId才有效
  25. let worldPos, localPos, modelId, intersect
  26. let Handler = viewer.inputHandler
  27. let reGet = ()=>{//不使用当前鼠标所在位置的intersect,单独算
  28. pos2d.clientX = pos2d.x
  29. pos2d.clientY = pos2d.y
  30. pos2d.onlyGetIntersect = true
  31. pos2d.whichPointcloud = true
  32. if(mustModelId != void 0){//隐藏其他的模型
  33. let models = MergeEditor.getAllObjects()
  34. models.forEach(model=>{
  35. viewer.updateVisible(model, 'forPick', model.dataset_id == mustModelId)
  36. })
  37. }
  38. intersect = Handler.onMouseMove(pos2d)
  39. if(mustModelId != void 0){//恢复
  40. let models = MergeEditor.getAllObjects()
  41. models.forEach(model=>{
  42. viewer.updateVisible(model, 'forPick', true)
  43. })
  44. }
  45. }
  46. if (pos2d && pos2d.inDrag) {
  47. reGet()
  48. } else {
  49. intersect = Handler.intersect
  50. if(intersect){
  51. modelId = intersect.pointcloud ? intersect.pointcloud.dataset_id : intersect.object.dataset_id
  52. if(mustModelId != void 0 && modelId != mustModelId){
  53. reGet()
  54. }
  55. }
  56. }
  57. if (intersect && intersect.location) {
  58. modelId = intersect.pointcloud ? intersect.pointcloud.dataset_id : intersect.object.dataset_id
  59. if(mustModelId != void 0 && modelId != mustModelId){
  60. return null
  61. }
  62. worldPos = intersect.location.clone()
  63. localPos = Potree.Utils.datasetPosTransform({ toDataset: true, datasetId:modelId, position:worldPos })
  64. } else return null
  65. return { worldPos, modelId, localPos }
  66. },
  67. getScreenByPosition(pos3d, modelId){//通过模型局部坐标获取屏幕坐标
  68. let isLocal = modelId != void 0
  69. pos3d = new THREE.Vector3().copy(pos3d)
  70. let worldPos = isLocal ? Potree.Utils.datasetPosTransform({ fromDataset: true, datasetId: modelId, position:pos3d}) : pos3d
  71. if(!worldPos)return
  72. var viewport = viewer.mainViewport
  73. var camera = viewport.camera
  74. var dom = viewer.renderArea
  75. //console.log('getScreenByPoint ' + pos3d.toArray())
  76. return Potree.Utils.getPos2d(worldPos, camera, dom, viewport)
  77. },
  78. screenshot: (width, height) => {
  79. //截图
  80. var promise = viewer.startScreenshot({ type: 'default' }, width, height)
  81. promise.done(() => {
  82. })
  83. return promise
  84. },
  85. getPose() {//获取当前点位和朝向
  86. const camera = viewer.scene.getActiveCamera()
  87. const target = viewer.scene.view.getPivot().clone()
  88. const position = viewer.scene.view.position.clone()
  89. console.log('getPose',position, target)
  90. return { position, target }
  91. },
  92. comeTo(o = {}) {
  93. console.log('comeTo',o.position, o.target)
  94. //飞到某个点
  95. if(o.modelId){
  96. ['position','target'].forEach(e=>{
  97. if(o[e]){
  98. o[e] = Potree.Utils.datasetPosTransform({ fromDataset: true, datasetId: o.modelId, position:o[e]})
  99. }
  100. })
  101. }
  102. if(o.distance){
  103. let position = o.target || o.position
  104. return viewer.focusOnObject({ position}, 'tag', null,{distance:o.distance} ).promise
  105. }
  106. let deferred = $.Deferred()
  107. viewer.scene.view.setView($.extend({},o, {
  108. duration: o.dur,
  109. callback:()=>{
  110. o.callback && o.callback()
  111. deferred.resolve(true)
  112. }
  113. }))
  114. return deferred.promise()
  115. },
  116. /* getPose(o={}) {
  117. //获取相对于第一个数据集的初始画面。(当数据集校准后,如果初始画面设置在被修改的数据集上,且该数据集非初始数据集的话,还是会偏移的)
  118. var deferred = o.deferred || $.Deferred();
  119. console.log('getPose')
  120. if(viewer.mainViewport.view.isFlying()){
  121. let f = ()=>{
  122. this.getPose(o)
  123. viewer.mainViewport.view.removeEventListener('flyingDone', f)
  124. }
  125. viewer.mainViewport.view.addEventListener('flyingDone', f) //once
  126. o.deferred = deferred
  127. return deferred.promise()
  128. }
  129. var camera = viewer.scene.getActiveCamera()
  130. var rotation = camera.rotation
  131. var pos_In_dataset = Potree.Utils.datasetPosTransform({ toDataset: true, position: camera.position.clone(), datasetId: Potree.settings.originDatasetId })
  132. var rot_In_dataset = Potree.Utils.datasetRotTransform({ toDataset: true, rotation, getRotation: true, datasetId: Potree.settings.originDatasetId }) //拿第一个数据集
  133. var view = viewer.scene.view.clone()
  134. view.rotation = rot_In_dataset //获取yaw pitch
  135. var pose = {
  136. //displayMode: Potree.settings.displayMode,
  137. position: pos_In_dataset,
  138. yaw: view.yaw,
  139. pitch: view.pitch,
  140. displayMode : Potree.settings.displayMode,
  141. panoSid: viewer.images360.currentPano.sid
  142. }
  143. //return pose
  144. setTimeout(()=>{
  145. deferred.resolve(pose)
  146. console.log('getPose resolve',pose)
  147. },1)
  148. return deferred.promise()
  149. },
  150. setPose(o = {}, duration=0) {
  151. //设置相机位置和朝向
  152. var deferred = o.deferred || $.Deferred();
  153. console.warn('setPose 初始画面', o)
  154. var quaternion
  155. let view = viewer.scene.view.clone()
  156. if(viewer.mainViewport.view.isFlying()){
  157. let f = ()=>{
  158. this.setPose(o, duration)
  159. viewer.mainViewport.view.removeEventListener('flyingDone', f)
  160. }
  161. viewer.mainViewport.view.addEventListener('flyingDone', f) //once
  162. o.deferred = deferred
  163. return deferred.promise()
  164. }
  165. var getQuaternion = ()=>{
  166. view.pitch = o.pitch
  167. view.yaw = o.yaw
  168. quaternion = Potree.Utils.datasetRotTransform({ fromDataset: true, rotation: view.rotation, getQuaternion: true, datasetId: Potree.settings.originDatasetId }) //拿第一个数据集
  169. }
  170. viewer.images360.cancelFlyToPano()//防止旧的在之后继续执行
  171. let pano
  172. if(o.panoSid != void 0){//好像都不存这个
  173. pano = viewer.images360.panos.find(e=>e.sid == o.panoSid)
  174. if(pano == void 0)return deferred.reject('没有找到该panoSid').promise()
  175. getQuaternion()
  176. viewer.images360.flyToPano({pano, duration, quaternion},()=>{
  177. deferred.resolve()
  178. })
  179. }else{
  180. if(Potree.settings.displayMode == 'showPanos'){
  181. return deferred.reject('全景模式下不允许设置位置').promise()
  182. }
  183. let position = Potree.Utils.datasetPosTransform({ fromDataset: true, position: o.position, datasetId: Potree.settings.originDatasetId })
  184. //view.position.copy(position)
  185. getQuaternion()
  186. pano = viewer.images360.panos.find(e=>Potree.math.closeTo(e.position, position))
  187. if(pano){//如果原来在某pano上最好也使currentPano为此pano,否则isAtPano会返回false
  188. viewer.images360.flyToPano({pano, duration, quaternion},()=>{
  189. deferred.resolve()
  190. })
  191. }else{
  192. viewer.scene.view.setView({position,quaternion,duration, callback:()=>{
  193. //setTimeout(()=>{
  194. deferred.resolve()
  195. console.log('setPose resolve')
  196. //},1)
  197. } })
  198. viewer.mapViewer.moveTo(position, null, duration) //初始位置在地图居中
  199. }
  200. }
  201. return deferred.promise()
  202. },
  203. */
  204. enterSceneGuide(pathArr){//导览 (不需要修改参数)
  205. let editor = viewer.modules.CamAniEditor
  206. console.log('pathArr',pathArr)
  207. /* type SceneGuidec = {
  208. position: {x,y,z}
  209. target: {x,y,z}
  210. time: number
  211. speed: number //没用到
  212. }
  213. */
  214. console.log('enterSceneGuide',pathArr)
  215. let data = {
  216. duration: pathArr.slice(0,pathArr.length-1).reduce(function(total, currentValue ){return total+currentValue.time}, 0), //总时长(要去掉最后一个,因为已到终点,该点time无意义)
  217. points: pathArr,
  218. useDurSlice:true
  219. }
  220. let animation = editor.createAnimation(data)
  221. //注:最多只存在一条导览
  222. let bus = mitt()
  223. //播放完成
  224. animation.addEventListener('playDone', () => {
  225. bus.emit('playComplete')
  226. })
  227. //切换点
  228. animation.addEventListener('updateCurrentIndex', e => {
  229. bus.emit('changePoint', e.currentIndex + 1)
  230. })
  231. return {
  232. bus,
  233. play() {
  234. MergeEditor.selectModel(null)
  235. animation.play()
  236. },
  237. pause() {
  238. animation.pause()
  239. },
  240. clear() {
  241. //删除
  242. editor.removeAnimation(animation)
  243. },
  244. }
  245. },
  246. //[path1, paht2], { time, speed }
  247. calcPathInfo(paths, info){ //传入的time, speed仅有一个。返回完整的 time, speed
  248. //这一版的control似乎无法在某个位置上改变角度,位置和角度一般都是一起变的,所以先不增加单位更换功能。
  249. let pos1 = new THREE.Vector3().copy(paths[0].position)
  250. let pos2 = new THREE.Vector3().copy(paths[1].position)
  251. let dis = pos1.distanceTo(pos2)
  252. if(info.time != void 0){
  253. info.speed = dis / info.time
  254. }else{
  255. info.time = dis / info.speed
  256. }
  257. return info
  258. },
  259. //scaleRange: { min, max }, opacityRange: { min, max }, bottomRange: { min, max } })
  260. addModel(props){
  261. let bus = mitt()
  262. //console.log('addModel',props)
  263. props.isFirstLoad = props.bottom == void 0 //在编辑时用户添加的
  264. if(props.opacity == void 0) props.opacity = 1
  265. props.scale /= 100
  266. if(!props.isFirstLoad){
  267. if(autoLoads.length == 0){ //首次加载
  268. setTimeout(()=>{
  269. let sizes = autoLoads.map(e=>e.size)
  270. console.log('需要请求加载的模型大小为', sizes, '总大小', sizes.reduce(function(total, currentValue ){
  271. let current = parseFloat(currentValue)
  272. return total + (currentValue.includes('M') ? current : current / 1024)
  273. }, 0))
  274. readyToAddModel = true //准备开始加载
  275. startLoad(autoLoads[0])
  276. },30)
  277. }
  278. autoLoads.push(props)
  279. }else{
  280. readyToAddModel = true
  281. }
  282. let startLoad = (prop)=>{
  283. //if(autoLoads.filter(e=>e.loaded).length>1)return console.log('取消加载', prop), prop.onError()
  284. Potree.addModel(prop, prop.done , prop.progressFun, prop.onError)
  285. prop.loading = true
  286. console.log('startLoad', prop)
  287. }
  288. let spliceFromArr = (model,loaded)=>{
  289. //let autoLoads.find()
  290. props.loadFinish = true
  291. props.loading = false
  292. if(loaded){
  293. props.loaded = true
  294. props.model = model
  295. }else{
  296. props.error = true
  297. }
  298. let haventLoad = autoLoads.filter(e=>!e.loading && !e.loadFinish);
  299. if( haventLoad[0]){
  300. startLoad(haventLoad[0])
  301. //this.addModel(autoLoads[0])
  302. }else if(autoLoads.filter(e=>!e.loadFinish).length == 0 && autoLoads.filter(e=>e.loaded).length>0){//设置相机位置:当自动开始加载第一个模型时(其余的也跟着自动加载),等这批加载完后;
  303. let autoLoadsDone = autoLoads.filter(e=>e.loaded).map(e=>e.model)
  304. console.log('所有模型加载完毕')
  305. MergeEditor.focusOn(autoLoadsDone, 1000)
  306. }
  307. }
  308. let model
  309. let done = (model_)=>{
  310. model = model_
  311. props.opacity < 100 && result.changeOpacity(props.opacity)
  312. model.addEventListener('changeSelect',(e)=>{
  313. bus.emit('changeSelect',e.selected)
  314. })
  315. model.addEventListener('transformChanged',(e)=>{
  316. bus.emit('transformChanged', {
  317. position : model.position.clone(),
  318. scale: model.scale.x * 100,
  319. rotation: model.rotation.clone(),
  320. bottom: model.btmHeight
  321. })
  322. })
  323. spliceFromArr(model,true)
  324. bus.emit('loadDone')
  325. //console.log('loadDone' )
  326. }
  327. let progressFun = (progress)=>{
  328. bus.emit('loadProgress',progress)
  329. }
  330. let onError = function ( xhr ) {
  331. bus.emit('loadError', xhr)
  332. spliceFromArr(model,false)
  333. console.log('loadError!!!!!!!!!', props.url, props.size, xhr)
  334. }
  335. if(props.type == "glb"){////////////////////////////test
  336. if(props.url.includes('coffeemat')){
  337. props.url = '/lib/potree/resources/models/glb/coffeemat.glb'
  338. }
  339. //props.url += '5'
  340. //props.url = 'http://localhost:5173/api/profile/datav1/1537680519838306304/data/glb/cloud_glb_24.glb'
  341. }
  342. props.done = done; props.progressFun = progressFun; props.onError = onError
  343. if(readyToAddModel){
  344. if(autoLoads.filter(e=>e.loading).length<maxLoadingCount ){
  345. startLoad(props)
  346. }
  347. }
  348. let result = {
  349. bus,
  350. changeShow(show){
  351. if(model){
  352. viewer.updateVisible(model, 'changeShow', show)
  353. }
  354. },
  355. changeSelect(state){
  356. if(model){
  357. MergeEditor.selectModel(model, state, true, true)
  358. if(state && viewer.inputHandler.selection[0]){
  359. viewer.transformObject(model); //交换
  360. }
  361. }
  362. },
  363. changeScale(s){
  364. if(model){
  365. s /= 100
  366. model.scale.set(s,s,s)
  367. model.dispatchEvent("scale_changed")
  368. }
  369. },
  370. changeOpacity(opacity){
  371. if(opacity == void 0)opacity = 100
  372. opacity/=100
  373. if(model){
  374. if(model.isPointcloud){
  375. model.material.opacity = opacity
  376. }else{
  377. model.traverse(e=>e.material && (e.material.opacity = opacity))
  378. }
  379. }
  380. },
  381. changeBottom(z){
  382. model && MergeEditor.setModelBtmHeight(model,z)
  383. },
  384. enterRotateMode(){
  385. if(model){
  386. viewer.transformObject(model);
  387. viewer.transformationTool.setModeEnable('rotation',true)
  388. viewer.transformationTool.setModeEnable('translation',false)
  389. }
  390. },
  391. enterMoveMode(){
  392. if(model){
  393. viewer.transformObject(model);
  394. viewer.transformationTool.setModeEnable('rotation',false)
  395. viewer.transformationTool.setModeEnable('translation',true)
  396. }
  397. },
  398. leaveTransform(){
  399. viewer.transformObject(null);
  400. },
  401. destroy(){
  402. MergeEditor.removeModel(model)
  403. }
  404. }
  405. return result
  406. },
  407. }
  408. return sdk
  409. }
  410. export default enter