index.js 42 KB

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