index.js 41 KB

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