index.js 40 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  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. if(location.host === 'mix3d.4dkankan.com' ){//正式环境
  8. Potree.settings.urls.prefix = Potree.settings.urls.prefix6
  9. Potree.settings.webSite = 'datav1'
  10. }
  11. Potree.settings.notAdditiveBlending = true
  12. const tagLimitDis = 8;
  13. Potree.settings.showCompass = true
  14. Potree.settings.compassDom = dom.querySelector('#direction')
  15. let {THREE} = Potree.mergeEditStart(dom)
  16. let MergeEditor = viewer.modules.MergeEditor
  17. let sceneBus = mitt()
  18. viewer.addEventListener('camera_changed', e => {
  19. var camera = e.viewport.camera
  20. var pos = camera.position
  21. if (e.viewport.name == 'MainView') {
  22. sceneBus.emit('cameraChange', { x: pos.x, y: pos.y, z: pos.z, rotate: camera.rotation })
  23. }
  24. })
  25. viewer.addEventListener('webglError', e => {
  26. console.error('viewer webglError: ' + e)
  27. sceneBus.emit('webglError', { msg: e.msg })
  28. })
  29. window.THREE = THREE
  30. //isLocal = false
  31. let autoLoads = []
  32. let readyToAddModel
  33. let maxLoadingCount = /* isLocal ? 1 : */2; //正在加载模型的最大数目
  34. const units = { 1: 'metric', 2: 'imperial' }
  35. let getMeasureType = function (type, unit=1) {
  36. let info
  37. switch (type) {
  38. case 'free':
  39. info = { measureType: 'Distance' }
  40. break
  41. case 'area':
  42. info = { measureType: 'Area' }
  43. break
  44. case 'vertical':
  45. info = { measureType: 'Ver Distance' }
  46. break
  47. default:
  48. console.error('无此 measure type')
  49. }
  50. info.unit = units[unit]
  51. return info
  52. }
  53. let getMeasureFunction = function (measure, bus) {
  54. measure.addEventListener('highlight',(e)=>{
  55. //console.log('3d->2d highlight',e.state)
  56. bus.emit('highlight', e.state)
  57. })
  58. measure.addEventListener('marker_dropped',(e)=>{//拖拽结束后发送changeCallBack
  59. if (measure.parent) {
  60. //未被删除
  61. bus.emit('update',[
  62. measure.dataset_points.map(p=>p.clone()) ,
  63. measure.points_datasets
  64. ])
  65. }
  66. })
  67. return {
  68. /* quit: () => {
  69. Potree.Log('quit结束且删除: ' + measure.id, '#00c7b2')
  70. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true, measure })
  71. }, //触发结束。退出测量模式,清除之前操作 */
  72. destroy: () => {
  73. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true, measure })
  74. viewer.scene.removeMeasurement(measure)
  75. },
  76. /* getPoints: () => {
  77. return measure.points
  78. },
  79. getDatasetLocations: () => {
  80. return measure.dataset_points
  81. },
  82. getDatasets: () => {
  83. return measure.points_datasets
  84. },
  85. getDatasetId: () => {
  86. return measure.datasetId
  87. }, */
  88. getArea: () => {
  89. return measure.area //{value:area, string:..}
  90. },
  91. getDistance: () => {
  92. if (measure.points.length < 2) return 0
  93. var value = measure.points[0].distanceTo(measure.points[1])
  94. return {
  95. value, //米
  96. string: viewer.unitConvert.convert(value, 'distance', void 0, measure.unitSystem, 0.1, true),
  97. }
  98. },
  99. /* changeUnit: unit => {
  100. //公制|英制 , 1 | 2 单位
  101. measure.setUnitSystem(units[unit])
  102. },
  103. toDataURL: (width, height) => {
  104. //截图
  105. isScreenshoting = true
  106. var promise = viewer.startScreenshot({ type: 'measure', measurement: measure, hideMarkers: true }, width, height)
  107. promise.done(() => {
  108. isScreenshoting = false
  109. })
  110. return promise
  111. }, */
  112. //手动开启或关闭:
  113. show: () => {
  114. viewer.updateVisible(measure, 'inListByUser', true)
  115. },
  116. hide: () => {
  117. viewer.updateVisible(measure, 'inListByUser', false)
  118. },
  119. fly(){
  120. let result = viewer.focusOnObject(measure , 'measure', 1200 )
  121. return result.msg ? result.msg : result.promise
  122. //返回值 1 deferred 表示即将位移 2 'posNoChange' 表示已在最佳位置 3 'tooFar' 表示距离最佳位置太远
  123. },
  124. changeSelect(isHight){
  125. console.log('2d->3d isHight ',isHight)
  126. measure.setSelected(isHight, 'byList')
  127. },
  128. }
  129. }
  130. let sdk = {
  131. sceneBus,
  132. getPositionByScreen(pos2d, hopeModelId ){//通过屏幕坐标获取真实坐标 . hopeModelId: 如果指定了模型,优先返回hopeModelId上的intersect
  133. console.log('getPositionByScreen',hopeModelId)
  134. hopeModelId = null
  135. let worldPos, localPos, modelId, intersect
  136. let Handler = viewer.inputHandler
  137. let reGet = ()=>{//不使用当前鼠标所在位置的intersect,单独算
  138. pos2d.clientX = pos2d.x
  139. pos2d.clientY = pos2d.y
  140. pos2d.onlyGetIntersect = true
  141. pos2d.whichPointcloud = true
  142. if(hopeModelId != void 0){//隐藏其他的模型
  143. let models = MergeEditor.getAllObjects()
  144. models.forEach(model=>{
  145. viewer.updateVisible(model, 'forPick', model.dataset_id == hopeModelId)
  146. })
  147. }
  148. let intersect2 = Handler.onMouseMove(pos2d)
  149. if(hopeModelId != void 0){//恢复
  150. let models = MergeEditor.getAllObjects()
  151. models.forEach(model=>{
  152. viewer.updateVisible(model, 'forPick', true)
  153. })
  154. }
  155. if(intersect2 && intersect2.location){
  156. intersect = intersect2
  157. }
  158. }
  159. if (pos2d && pos2d.inDrag) {
  160. reGet()
  161. } else {
  162. intersect = Handler.intersect
  163. if(intersect){
  164. modelId = intersect.pointcloud ? intersect.pointcloud.dataset_id : intersect.object.dataset_id
  165. if(hopeModelId != void 0 && modelId != hopeModelId){
  166. reGet()
  167. }
  168. }
  169. }
  170. if (intersect && intersect.location) {
  171. modelId = intersect.pointcloud ? intersect.pointcloud.dataset_id : intersect.object.dataset_id
  172. /* if(hopeModelId != void 0 && modelId != hopeModelId){
  173. return null
  174. } */
  175. worldPos = intersect.location.clone()
  176. localPos = Potree.Utils.datasetPosTransform({ toDataset: true, datasetId:modelId, position:worldPos })
  177. } else return null
  178. return { worldPos, modelId, localPos }
  179. },
  180. getScreenByPosition(pos3d, modelId, canShelter/* , disToCameraLimit */){//通过模型局部坐标获取屏幕坐标
  181. let isLocal = modelId != void 0
  182. pos3d = new THREE.Vector3().copy(pos3d)
  183. let worldPos = isLocal ? Potree.Utils.datasetPosTransform({ fromDataset: true, datasetId: modelId, position:pos3d}) : pos3d
  184. if(!worldPos)return
  185. if(canShelter){
  186. if(viewer.inputHandler.ifBlockedByIntersect(worldPos, 0.1, true)) return {trueSide:false};
  187. }
  188. var viewport = viewer.mainViewport
  189. var camera = viewport.camera
  190. var dom = viewer.renderArea
  191. if(tagLimitDis != void 0){
  192. if(camera.position.distanceTo(worldPos) > tagLimitDis)return false
  193. }
  194. //console.log('getScreenByPoint ' + pos3d.toArray())
  195. return Potree.Utils.getPos2d(worldPos, camera, dom, viewport)
  196. },
  197. screenshot: (width, height) => {
  198. //截图
  199. var promise = viewer.startScreenshot({ type: 'default' }, width, height)
  200. promise.done(() => {
  201. })
  202. return promise
  203. },
  204. getPose() {//获取当前点位和朝向
  205. const camera = viewer.scene.getActiveCamera()
  206. const target = viewer.scene.view.getPivot().clone()
  207. const position = viewer.scene.view.position.clone()
  208. //console.log('getPose',position, target)
  209. return { position, target }
  210. },
  211. comeTo(o = {}) {
  212. //console.log('comeTo',o.position, o.target)
  213. //飞到某个点
  214. if(o.modelId){
  215. ['position','target'].forEach(e=>{
  216. if(o[e]){
  217. o[e] = Potree.Utils.datasetPosTransform({ fromDataset: true, datasetId: o.modelId, position:o[e]})
  218. }
  219. })
  220. }
  221. if(o.distance){
  222. let position = o.target || o.position
  223. return viewer.focusOnObject({ position}, 'tag', null,{distance:o.distance} ).promise
  224. }
  225. let deferred = $.Deferred()
  226. viewer.scene.view.setView($.extend({},o, {
  227. duration: o.dur,
  228. callback:()=>{
  229. o.callback && o.callback()
  230. deferred.resolve(true)
  231. }
  232. }))
  233. return deferred.promise()
  234. },
  235. /* getPose(o={}) {
  236. //获取相对于第一个数据集的初始画面。(当数据集校准后,如果初始画面设置在被修改的数据集上,且该数据集非初始数据集的话,还是会偏移的)
  237. var deferred = o.deferred || $.Deferred();
  238. console.log('getPose')
  239. if(viewer.mainViewport.view.isFlying()){
  240. let f = ()=>{
  241. this.getPose(o)
  242. viewer.mainViewport.view.removeEventListener('flyingDone', f)
  243. }
  244. viewer.mainViewport.view.addEventListener('flyingDone', f) //once
  245. o.deferred = deferred
  246. return deferred.promise()
  247. }
  248. var camera = viewer.scene.getActiveCamera()
  249. var rotation = camera.rotation
  250. var pos_In_dataset = Potree.Utils.datasetPosTransform({ toDataset: true, position: camera.position.clone(), datasetId: Potree.settings.originDatasetId })
  251. var rot_In_dataset = Potree.Utils.datasetRotTransform({ toDataset: true, rotation, getRotation: true, datasetId: Potree.settings.originDatasetId }) //拿第一个数据集
  252. var view = viewer.scene.view.clone()
  253. view.rotation = rot_In_dataset //获取yaw pitch
  254. var pose = {
  255. //displayMode: Potree.settings.displayMode,
  256. position: pos_In_dataset,
  257. yaw: view.yaw,
  258. pitch: view.pitch,
  259. displayMode : Potree.settings.displayMode,
  260. panoSid: viewer.images360.currentPano.sid
  261. }
  262. //return pose
  263. setTimeout(()=>{
  264. deferred.resolve(pose)
  265. console.log('getPose resolve',pose)
  266. },1)
  267. return deferred.promise()
  268. },
  269. setPose(o = {}, duration=0) {
  270. //设置相机位置和朝向
  271. var deferred = o.deferred || $.Deferred();
  272. console.warn('setPose 初始画面', o)
  273. var quaternion
  274. let view = viewer.scene.view.clone()
  275. if(viewer.mainViewport.view.isFlying()){
  276. let f = ()=>{
  277. this.setPose(o, duration)
  278. viewer.mainViewport.view.removeEventListener('flyingDone', f)
  279. }
  280. viewer.mainViewport.view.addEventListener('flyingDone', f) //once
  281. o.deferred = deferred
  282. return deferred.promise()
  283. }
  284. var getQuaternion = ()=>{
  285. view.pitch = o.pitch
  286. view.yaw = o.yaw
  287. quaternion = Potree.Utils.datasetRotTransform({ fromDataset: true, rotation: view.rotation, getQuaternion: true, datasetId: Potree.settings.originDatasetId }) //拿第一个数据集
  288. }
  289. viewer.images360.cancelFlyToPano()//防止旧的在之后继续执行
  290. let pano
  291. if(o.panoSid != void 0){//好像都不存这个
  292. pano = viewer.images360.panos.find(e=>e.sid == o.panoSid)
  293. if(pano == void 0)return deferred.reject('没有找到该panoSid').promise()
  294. getQuaternion()
  295. viewer.images360.flyToPano({pano, duration, quaternion},()=>{
  296. deferred.resolve()
  297. })
  298. }else{
  299. if(Potree.settings.displayMode == 'showPanos'){
  300. return deferred.reject('全景模式下不允许设置位置').promise()
  301. }
  302. let position = Potree.Utils.datasetPosTransform({ fromDataset: true, position: o.position, datasetId: Potree.settings.originDatasetId })
  303. //view.position.copy(position)
  304. getQuaternion()
  305. pano = viewer.images360.panos.find(e=>Potree.math.closeTo(e.position, position))
  306. if(pano){//如果原来在某pano上最好也使currentPano为此pano,否则isAtPano会返回false
  307. viewer.images360.flyToPano({pano, duration, quaternion},()=>{
  308. deferred.resolve()
  309. })
  310. }else{
  311. viewer.scene.view.setView({position,quaternion,duration, callback:()=>{
  312. //setTimeout(()=>{
  313. deferred.resolve()
  314. console.log('setPose resolve')
  315. //},1)
  316. } })
  317. viewer.mapViewer.moveTo(position, null, duration) //初始位置在地图居中
  318. }
  319. }
  320. return deferred.promise()
  321. },
  322. */
  323. enterSceneGuide(pathArr){//导览 (不需要修改参数)
  324. let editor = viewer.modules.CamAniEditor
  325. console.log('pathArr',pathArr)
  326. /* type SceneGuidec = {
  327. position: {x,y,z}
  328. target: {x,y,z}
  329. time: number
  330. speed: number //没用到
  331. }
  332. */
  333. //console.log('enterSceneGuide',pathArr)
  334. let data = {
  335. duration: pathArr.slice(0,pathArr.length-1).reduce(function(total, currentValue ){return total+currentValue.time}, 0), //总时长(要去掉最后一个,因为已到终点,该点time无意义)
  336. points: pathArr,
  337. useDurSlice:true
  338. }
  339. let animation = editor.createAnimation(data)
  340. //注:最多只存在一条导览
  341. let bus = mitt()
  342. //播放完成
  343. animation.addEventListener('playDone', () => {
  344. bus.emit('playComplete')
  345. })
  346. //切换点
  347. animation.addEventListener('updateCurrentIndex', e => {
  348. bus.emit('changePoint', e.currentIndex + 1)
  349. })
  350. return {
  351. bus,
  352. play() {
  353. MergeEditor.selectModel(null)
  354. animation.play()
  355. },
  356. pause() {
  357. animation.pause()
  358. },
  359. clear() {
  360. //删除
  361. editor.removeAnimation(animation)
  362. },
  363. }
  364. },
  365. //[path1, paht2], { time, speed }
  366. calcPathInfo(paths, info){ //传入的time, speed仅有一个。返回完整的 time, speed
  367. //这一版的control似乎无法在某个位置上改变角度,位置和角度一般都是一起变的,所以先不增加单位更换功能。
  368. let pos1 = new THREE.Vector3().copy(paths[0].position)
  369. let pos2 = new THREE.Vector3().copy(paths[1].position)
  370. let dis = pos1.distanceTo(pos2)
  371. if(info.time != void 0){
  372. info.speed = dis / info.time
  373. }else{
  374. info.time = dis / info.speed
  375. }
  376. return info
  377. },
  378. //scaleRange: { min, max }, opacityRange: { min, max }, bottomRange: { min, max } })
  379. addModel(props){
  380. //console.log(props.isDynamicAdded, props.mode)
  381. let bus = mitt()
  382. //console.log('addModel',props)
  383. props.isFirstLoad = isLocal ? props.bottom == void 0 : (props.isDynamicAdded || props.mode == 'single') // 在编辑时用户添加的 或 展示单个模型 (props.mode='single'模型展示页, props.mode='many'融合页)
  384. if(props.opacity == void 0) props.opacity = 1
  385. if(props.type == 'obj') props.type = 'glb'
  386. props.scale /= 100
  387. if(!props.isFirstLoad){
  388. if(autoLoads.length == 0){ //首次加载
  389. setTimeout(()=>{
  390. let sizes = autoLoads.map(e=>e.size|| 0 )
  391. console.log('需要请求加载的模型大小为', sizes, '总大小', sizes.reduce(function(total, currentValue ){
  392. let current = parseFloat(currentValue)
  393. return total + ((typeof currentValue == 'number' || currentValue.includes('M')) ? current : current / 1024)
  394. }, 0))
  395. readyToAddModel = true //准备开始加载
  396. startLoad(autoLoads[0])
  397. },30)
  398. }
  399. autoLoads.push(props)
  400. readyToAddModel = false
  401. }else{
  402. readyToAddModel = true
  403. }
  404. let startLoad = (prop)=>{
  405. //if(autoLoads.filter(e=>e.loaded).length>1)return console.log('取消加载', prop), prop.onError()
  406. //return prop.onError()
  407. Potree.addModel(prop, prop.done , prop.progressFun, prop.onError)
  408. prop.loading = true
  409. console.log('-------开始加载 id:', prop.id, 'title:', prop.title, ', filename:',getName(prop.url), prop )
  410. }
  411. let spliceFromArr = (model,loaded)=>{
  412. //let autoLoads.find()
  413. props.loadFinish = true
  414. props.loading = false
  415. if(loaded){
  416. props.loaded = true
  417. props.model = model
  418. }else{
  419. props.error = true
  420. }
  421. let haventLoad = autoLoads.filter(e=>!e.loading && !e.loadFinish);
  422. if( haventLoad[0]){
  423. startLoad(haventLoad[0])
  424. //this.addModel(autoLoads[0])
  425. }else if(autoLoads.filter(e=>!e.loadFinish).length == 0 && autoLoads.filter(e=>e.loaded).length>0 && !props.isFirstLoad){//设置相机位置:当自动开始加载第一个模型时(其余的也跟着自动加载),等这批加载完后;
  426. let autoLoadsDone = autoLoads.filter(e=>e.loaded).map(e=>e.model)
  427. console.log('所有模型加载完毕')
  428. autoLoads.filter(e=>e.loaded && e.show).forEach(e=>e.model.visible = true)
  429. MergeEditor.focusOn(autoLoadsDone, 1000, true, true)
  430. autoLoads.length = 0
  431. }
  432. }
  433. let model
  434. let done = (model_)=>{
  435. model = model_
  436. if(!props.isFirstLoad){
  437. model.visible = false//先不显示,防止卡顿
  438. }
  439. props.opacity < 100 && result.changeOpacity(props.opacity)
  440. model.addEventListener('changeSelect',(e)=>{
  441. bus.emit('changeSelect',e.selected)
  442. })
  443. model.addEventListener('transformChanged',(e)=>{
  444. bus.emit('transformChanged', {
  445. position : model.position.clone(),
  446. scale: model.scale.x * 100,
  447. rotation: model.rotation.clone(),
  448. //bottom: model.btmHeight
  449. })
  450. })
  451. spliceFromArr(model,true)
  452. if(props.mode == 'single'){//模型查看页
  453. MergeEditor.noNeedSelection = true
  454. setTimeout(()=>{
  455. MergeEditor.focusOn([model], 1000, true, true)
  456. },1)
  457. }
  458. bus.emit('loadDone')
  459. //console.log('loadDone' )
  460. }
  461. let progressFun = (progress)=>{
  462. bus.emit('loadProgress',progress)
  463. }
  464. let onError = function ( xhr ) {
  465. bus.emit('loadError', xhr)
  466. console.log('loadError!!!!!!!!!', getName(props.url), props.size, xhr)
  467. spliceFromArr(model,false)
  468. }
  469. if(props.type == "glb"){////////////////////////////test
  470. if(props.url.includes('coffeemat')){
  471. props.url = '/lib/potree/resources/models/glb/coffeemat.glb'
  472. }
  473. //props.url += '5'
  474. //props.url = 'http://localhost:5173/api/profile/datav1/1537680519838306304/data/glb/cloud_glb_24.glb'
  475. }
  476. props.done = done; props.progressFun = progressFun; props.onError = onError
  477. if(readyToAddModel){
  478. if(autoLoads.filter(e=>e.loading).length<maxLoadingCount ){
  479. startLoad(props)
  480. }
  481. }
  482. let scaleMeasure
  483. let result = {
  484. bus,
  485. changeShow(show){
  486. props.show = show //for autoLoads show model
  487. if(model){
  488. viewer.updateVisible(model, 'changeShow', show)
  489. }
  490. },
  491. changeSelect(state){
  492. if(model){
  493. MergeEditor.selectModel(model, state, true, true)
  494. if(state && viewer.inputHandler.selection[0]){
  495. MergeEditor.transformControls.attach(model) //viewer.transformObject(model); //交换
  496. }
  497. //console.log('changeSelect', props.id, state)
  498. }
  499. },
  500. changeScale(s){
  501. if(model){
  502. s /= 100
  503. model.scale.set(s,s,s)
  504. model.isPointcloud && model.changePointSize(Potree.config.material.realPointSize * s)
  505. model.dispatchEvent("scale_changed")
  506. }
  507. },
  508. changeOpacity(opacity){ //见笔记:透明物体的材质设置
  509. if(opacity == void 0)opacity = 100
  510. opacity/=100
  511. if(model){
  512. if(model.isPointcloud){
  513. model.changePointOpacity(opacity)
  514. //MergeEditor.updateEdgeStrength()
  515. }else{
  516. //model.traverse(e=>e.material && setOp(e, opacity))
  517. model.traverse(mesh=>{
  518. if(mesh.material){
  519. mesh.material.opacity = opacity
  520. if(opacity<1){
  521. mesh.material.transparent = true
  522. if(model.isPointcloud){
  523. mesh.changePointOpacity(opacity)
  524. }else{
  525. mesh.material.opacity = opacity
  526. }
  527. mesh.renderOrder = Potree.config.renderOrders.model+1
  528. mesh.material.depthWrite = false
  529. }else{
  530. mesh.material.transparent = false
  531. mesh.renderOrder = Potree.config.renderOrders.model
  532. mesh.material.depthWrite = true
  533. }
  534. }
  535. })
  536. }
  537. model.opacity = opacity//记录在最外层
  538. }
  539. },
  540. changeBottom(z){
  541. /* model && MergeEditor.setModelBtmHeight(model,z)
  542. model.dispatchEvent('transformChanged') //改了position */
  543. },
  544. changePosition(pos){//校准取消时执行
  545. //if(MergeEditor.selected == model){
  546. //console.log('pos',pos.x, pos.y, pos.z)
  547. //}
  548. model && model.position.copy(pos)
  549. model.dispatchEvent({type:'position_changed'})
  550. },
  551. changeRotation(rot){//校准取消时执行
  552. //if(MergeEditor.selected == model){
  553. //console.log('rot', rot.x, rot.y, rot.z)
  554. //}
  555. model && model.rotation.setFromVector3(rot)
  556. model.dispatchEvent({type:'rotation_changed'})
  557. },
  558. enterRotateMode(){
  559. if(model){
  560. if(MergeEditor.split){//分屏校准
  561. MergeEditor.setTransformState('rotate')
  562. MergeEditor.transformControls2.attach(model)
  563. MergeEditor.transformControls2.mode = 'rotate'
  564. }
  565. MergeEditor.transformControls.attach(model)
  566. MergeEditor.transformControls.mode = 'rotate'
  567. }
  568. },
  569. enterMoveMode(){
  570. if(model){
  571. if(MergeEditor.split){//分屏校准
  572. MergeEditor.setTransformState('translate')
  573. MergeEditor.transformControls2.attach(model)
  574. MergeEditor.transformControls2.mode = 'translate'
  575. }
  576. MergeEditor.transformControls.attach(model)
  577. MergeEditor.transformControls.mode = 'translate'
  578. }
  579. },
  580. leaveTransform(){
  581. if(MergeEditor.split){//分屏校准
  582. MergeEditor.setTransformState(null)
  583. }else{
  584. MergeEditor.transformControls.detach()
  585. MergeEditor.transformControls2.detach()
  586. }
  587. },
  588. enterAlignment(){//开始校准
  589. result.leaveTransform()
  590. MergeEditor.enterSplit()
  591. //console.log('enterAlignment',model.position, model.rotation)
  592. let bus = new mitt()
  593. /* MergeEditor.transformControls.attach(model)
  594. MergeEditor.transformControls.mode = 'translate' */
  595. return {
  596. bus
  597. }
  598. },
  599. leaveAlignment(){
  600. //console.log('leaveAlignment',model.position, model.rotation)
  601. MergeEditor.leaveSplit()
  602. MergeEditor.transformControls.detach()
  603. MergeEditor.transformControls2.detach()
  604. },
  605. enterScaleSet(){//设置比例
  606. let bus = new mitt()
  607. let length , measureBuilded ;
  608. viewer.outlinePass.selectedObjects = []
  609. if(!Potree.Utils.isInsideFrustum(model.boundingBox.clone().applyMatrix4(model.matrixWorld), viewer.scene.getActiveCamera())){
  610. MergeEditor.focusOn(model, 600 )
  611. }
  612. MergeEditor.getAllObjects().forEach(m=>{//隐藏其他的模型
  613. if(m!=model) viewer.updateVisible(m, 'enterScaleSet', false)
  614. })
  615. let setScale = ()=>{
  616. if(length == void 0 || !measureBuilded )return
  617. let vec = new THREE.Vector3().subVectors(viewer.mainViewport.camera.position, scaleMeasure.points[1])
  618. let s = length / (scaleMeasure.points[0].distanceTo(scaleMeasure.points[1]))
  619. result.changeScale(model.scale.x * s*100)
  620. /* setTimeout(()=>{
  621. viewer.focusOnObject(scaleMeasure , 'measure', 500)
  622. },1) */
  623. let newCamPos = new THREE.Vector3().addVectors(scaleMeasure.points[1], vec.multiplyScalar(s))
  624. viewer.scene.view.setView({position:newCamPos, target:scaleMeasure.getCenter(), duration:0, callback:()=>{
  625. //更改target到measure中心的好处就是可以让相机绕measure中心转,坏处是每次更改都会变一下画面
  626. }
  627. })
  628. }
  629. return {
  630. bus,
  631. setLength(v){
  632. if(!v)return
  633. length = v
  634. setScale()
  635. },
  636. startMeasure(){
  637. if(scaleMeasure){
  638. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true, measure:scaleMeasure })
  639. viewer.scene.removeMeasurement(scaleMeasure)
  640. }
  641. measureBuilded = false
  642. scaleMeasure = viewer.measuringTool.startInsertion(
  643. {measureType: "Distance", unit: "metric"},
  644. () => {
  645. //done:
  646. //bus.emit('end' ) //完成
  647. measureBuilded = true
  648. setScale()
  649. },
  650. () => {
  651. //cancel
  652. //bus.emit('quit') //删除
  653. }
  654. )
  655. scaleMeasure.addEventListener('marker_dropped',(e)=>{//拖拽结束后发送changeCallBack
  656. if (scaleMeasure.parent) {
  657. //未被删除
  658. measureBuilded && setScale()
  659. }
  660. })
  661. }
  662. }
  663. },
  664. leaveScaleSet(){
  665. if(scaleMeasure){
  666. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true, measure:scaleMeasure })
  667. viewer.scene.removeMeasurement(scaleMeasure)
  668. scaleMeasure = null
  669. }
  670. viewer.outlinePass.selectedObjects = [model];
  671. MergeEditor.getAllObjects().forEach(m=>{//恢复其他的模型
  672. if(m!=model) viewer.updateVisible(m, 'enterScaleSet', true)
  673. })
  674. },
  675. destroy(){
  676. model && MergeEditor.removeModel(model)
  677. }
  678. }
  679. return result
  680. },
  681. //测量线的点都附着于各个模型,当模型变化时,点跟着变化。
  682. // 新的测量创建方法,传入type 返回新测量对象
  683. startMeasure(type){
  684. // 寻创建的测量对象有上面绘画测量对象的所有方法
  685. const bus = mitt()
  686. let info = getMeasureType(type)
  687. let measure = viewer.measuringTool.startInsertion(
  688. info,
  689. () => {
  690. //done:
  691. /* bus.emit('submit', {
  692. dataset_points: measure.dataset_points.map(p=>p.clone()) ,
  693. points_datasets: measure.points_datasets
  694. } ) //完成 */
  695. bus.emit('submit')
  696. bus.emit('update',[
  697. measure.dataset_points.map(p=>p.clone()) ,
  698. measure.points_datasets
  699. ])
  700. },
  701. () => {
  702. //cancel
  703. bus.emit('cancel'/* , ret */) //删除
  704. }
  705. )
  706. Potree.Log('startMeasure: ' + measure.id, '#00c7b2')
  707. /* let cancel = ()=>{
  708. Potree.Log('clear删除: ' + measure.id, '#00c7b2')
  709. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true, measure })
  710. viewer.scene.removeMeasurement(measure)
  711. } */
  712. let result = {
  713. bus,
  714. ...getMeasureFunction(measure, bus),
  715. }
  716. /* StartMeasure = Measure & {
  717. // 多了cancel 取消测量的事件,没有参数
  718. // 多了invalidPoint 当用户测量了无效点时的事件,抛出无效原因
  719. bus: Emitter<{ cancel: void; invalidPoint: string }>
  720. } */
  721. return result
  722. },
  723. // 绘画测量线(非新增使用)
  724. // type = 'free' (自由) || 'vertical' (垂直) || 'area' (面积)
  725. // positions 点数组 构成如下 [{ point: {x,y,z}, modelId: 1 }]
  726. drawMeasure(type, dataset_points, points_datasets){
  727. // 返回测量对象有如下
  728. const bus = mitt()
  729. let info = getMeasureType(type /* , unit */)
  730. //info.points = positions
  731. info.dataset_points = dataset_points
  732. info.points_datasets = points_datasets
  733. //info.sid = sid
  734. info.bus = bus
  735. let measure = viewer.measuringTool.createMeasureFromData(info)
  736. if(!measure)return {bus}
  737. Potree.Log('drawMeasure由数据新建: ' + measure.id, '#00c7b2')
  738. let result = {
  739. bus,
  740. setPositions(dataset_points, points_datasets){//用于恢复measure的点,不会修改点的个数
  741. measure.dataset_points = dataset_points.map(e=>{
  742. return e && new THREE.Vector3().copy(e)
  743. })
  744. measure.points_datasets = points_datasets
  745. measure.points = measure.dataset_points.map((p,i)=>{
  746. return Potree.Utils.datasetPosTransform({fromDataset:true, datasetId:measure.points_datasets[i], position: p})
  747. })
  748. measure.getPoint2dInfo(measure.points)
  749. measure.update({ifUpdateMarkers:true})
  750. measure.setSelected(false)//隐藏edgelabel
  751. },
  752. ...getMeasureFunction(measure, bus),
  753. }
  754. return result
  755. },
  756. addTag(info){//加热点
  757. let bus = mitt()
  758. let tag
  759. let done = ()=>{
  760. bus.emit('added')
  761. bus.emit('update', {position: tag.position.clone(), normal:o.normal.clone(), modelId:tag.root.dataset_id } )
  762. tag = tag_
  763. tag.spot.addEventListener('mouseover',()=>{
  764. bus.emit('hoverState',true)
  765. })
  766. tag.spot.addEventListener('mouseout',()=>{
  767. bus.emit('hoverState',false)
  768. })
  769. }
  770. if(!info.position){
  771. viewer.tagTool.startInsertion().done(tag_=>{
  772. done()
  773. })
  774. }else{
  775. info.root = MergeEditor.getAllObjects().find(e=>e.dataset_id == info.modelId)
  776. if(!info.root){
  777. console.error('没有找到该modelId')
  778. }
  779. tag = viewer.tagTool.createTagFromData(info)
  780. done()
  781. }
  782. let result = {
  783. bus,
  784. getScreenPos(){
  785. let pos3d = new THREE.Vector3().setFromMatrixPosition( tag.matrixWorld )
  786. return sdk.getScreenByPosition(pos3d)
  787. },
  788. show(){
  789. viewer.updateVisible(tag, 'byList', true)
  790. },
  791. hide(){
  792. viewer.updateVisible(tag, 'byList', false)
  793. },
  794. destroy(){
  795. if(tag){
  796. tag.dispose()
  797. }
  798. viewer.dispatchEvent({ type: 'cancel_insertions', remove: true })
  799. },
  800. changeTitle(title){
  801. tag.changeTitle(title)
  802. }
  803. }
  804. return result
  805. }
  806. }
  807. function getName(url){
  808. return url.split('/').pop()
  809. }
  810. console.log('版本: 2022.9.20-1')
  811. return sdk
  812. }
  813. export default enter