index.js 42 KB

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