index.js 20 KB

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