index.js 23 KB

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