MergeEditor.js 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. import * as THREE from "../../../../libs/three.js/build/three.module.js";
  2. import cameraLight from '../../utils/cameraLight.js'
  3. import math from "../../utils/math.js"
  4. import Common from '../../utils/Common.js'
  5. import {LineDraw, MeshDraw} from "../../utils/DrawUtil.js";
  6. import {transitions, easing, lerp} from '../../utils/transitions.js'
  7. import SplitScreen from "../../utils/SplitScreen.js";
  8. import InfiniteGridHelper from '../../objects/InfiniteGridHelper.js'
  9. import Compass from "../../objects/tool/Compass.js";
  10. import {TransformControls} from "../../objects/tool/TransformControls.js";
  11. import History from "../../utils/History.js"
  12. const texLoader = new THREE.TextureLoader()
  13. texLoader.crossOrigin = "anonymous"
  14. const edgeStrengths = {
  15. pointcloud: 4,
  16. glb: 100
  17. }
  18. const viewportProps = [{
  19. left:0,
  20. bottom:0,
  21. width: 0.5,height:1,
  22. name : 'top',
  23. axis:["x","y"],
  24. direction : new THREE.Vector3(0,0,-1), //镜头朝向
  25. active: true,
  26. //相机位置在z轴正向
  27. limitBound: new THREE.Box3(new THREE.Vector3(-Infinity,-Infinity, 1),new THREE.Vector3(Infinity,Infinity,5000)), //在地面以上
  28. margin:{x:50, y:150} ,
  29. },
  30. {
  31. left:0.5,
  32. bottom:0,
  33. width: 0.5,height:1,
  34. name : 'right',
  35. axis:["y","z"],
  36. direction : new THREE.Vector3(1,0,0),
  37. active: true,
  38. //相机位置在x轴负向 右下角屏
  39. viewContainsPoints:[new THREE.Vector3(0,0,0)],
  40. margin:{x:300, y:250} ,
  41. } ]
  42. let cylinderSkyGeo, oldSkyGeo
  43. let MergeEditor = {
  44. bus:new THREE.EventDispatcher(),
  45. SplitScreen : new SplitScreen(),
  46. init(){
  47. this.history = new History({
  48. applyData: (data)=>{
  49. if(data.object.parent /* && data.object == this.selected */){
  50. data = Potree.Common.CloneObject(data) //避免使用后更改数据又被使用
  51. data.matrix.decompose( data.object.position, data.object.quaternion, data.object.scale );
  52. data.object.boundCenter.copy(data.boundCenter)
  53. data.object.dispatchEvent('changeByHistory')
  54. data.object.dispatchEvent('transformChanged')
  55. viewer.dispatchEvent('content_changed')
  56. return true
  57. }
  58. },
  59. getData:(object)=>{
  60. return {
  61. object,
  62. matrix: object.matrixWorld.clone(),
  63. boundCenter: object.boundCenter.clone()
  64. }
  65. }
  66. })
  67. {
  68. Potree.settings.notAdditiveBlending = true
  69. let ground = this.ground = new InfiniteGridHelper(1, 10000, new THREE.Color('#eee'), 10000, 0.2, 0.3)
  70. viewer.scene.scene.add(ground)
  71. //再加两条线否则在正侧边看不到
  72. let line1 = LineDraw.createLine([new THREE.Vector3(-10000, 0, 0),new THREE.Vector3(10000, 0, 0) ], {color:'#aaa', })
  73. let line2 = LineDraw.createLine([new THREE.Vector3(0, -10000, 0),new THREE.Vector3(0, 10000, 0) ], {mat:line1.material})
  74. ground.renderOrder = Potree.config.renderOrders.model + 1//line1.renderOrder + 1 //要比模型低,否则模型透明时效果不对
  75. ground.add(line1)
  76. ground.add(line2)
  77. ground.material.opacity = 0.9 //为了滞后渲染,否则被rt遮住
  78. ground.material.polygonOffset = true //多边形偏移(视觉上没有移动模型位置),防止闪烁
  79. ground.material.polygonOffsetFactor = 100 //多边形偏移因子
  80. ground.material.polygonOffsetUnits = 10 //多边形偏移单位
  81. ground.material.depthWrite = false
  82. //ground.material.depthTest = false
  83. line1.material.polygonOffset = true
  84. line1.material.polygonOffsetFactor = 130
  85. line1.material.polygonOffsetUnits = 10
  86. line1.material.depthWrite = false
  87. //见笔记:透明物体的材质设置
  88. }
  89. let oriEdgeStrength = viewer.outlinePass.edgeStrength
  90. {
  91. this.transformControls = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
  92. dontHideWhenFaceCamera: true,
  93. });
  94. //this.transformControls.space = 'local'//为了在当前方向上平移
  95. this.transformControls.setSize(1.5)
  96. viewer.scene.scene.add(this.transformControls)
  97. this.transformControls._gizmo.hideAxis = {rotate:['e']}
  98. this.transformControls.setRotateMethod(2)
  99. //右屏
  100. this.transformControls2 = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
  101. dontHideWhenFaceCamera: true,
  102. });
  103. this.transformControls2.setSize(1.5)
  104. viewer.scene.scene.add(this.transformControls2)
  105. Potree.Utils.setObjectLayers(this.transformControls2, 'layer2' )
  106. let mouseDown = (e)=>{
  107. viewer.outlinePass.edgeStrength = 0//暂时消失线
  108. }
  109. let mouseUp = (e)=>{
  110. //this.updateEdgeStrength()
  111. viewer.outlinePass.edgeStrength = oriEdgeStrength
  112. }
  113. this.transformControls.addEventListener('mouseDown',mouseDown)
  114. this.transformControls2.addEventListener('mouseDown',mouseDown)
  115. this.transformControls.addEventListener('mouseUp',mouseUp)
  116. this.transformControls2.addEventListener('mouseUp',mouseUp)
  117. this.transformControls.addEventListener('mouseDown', ()=>{ //dragstart
  118. this.history.beforeChange(this.selected)
  119. })
  120. this.transformControls.addEventListener('mouseUp',()=>{
  121. this.history.afterChange(this.selected)
  122. })
  123. }
  124. {
  125. this.secondCompass = new Compass(null)
  126. }
  127. viewer.setControls(viewer.orbitControls)
  128. //viewer.mainViewport.view.fixZWhenPan = true
  129. viewer.orbitControls.constantlyForward = true
  130. viewer.addEventListener('global_single_click',(e)=>{
  131. if(
  132. this.noNeedSelection //如模型查看页
  133. || viewer.scene.cameraAnimations.some(c=>c.onUpdate) //正在播放
  134. || e.drag && e.drag.notPressMouse //在加测量线
  135. || viewer.mainViewport.view.isFlying() //有其他校准
  136. || this.split //分屏中
  137. || e.clickElement //触发别的点击事件,如测量时click marker /* && e.clickElement != e.intersect.object */
  138. ){
  139. return
  140. }
  141. if(e.intersect){
  142. let object = e.intersect.object || e.intersect.pointcloud
  143. let objects = this.getAllObjects()
  144. if(objects.includes(object) && this.selected != object){
  145. this.selectModel(object)
  146. }else{
  147. //if(!viewer.inputHandler.selection[0]){//正在平移和旋转,不允许取消
  148. this.selectModel(null)
  149. //}
  150. }
  151. }else{
  152. //if(!viewer.inputHandler.selection[0]){
  153. this.selectModel(null)
  154. //}
  155. }
  156. })
  157. viewer.inputHandler.addEventListener('keydown', (e)=>{
  158. if((e.event.key).toLowerCase() == "h" ){
  159. this.fadeOutlineAuto = !this.fadeOutlineAuto
  160. this.showModelOutline(this.selected,!!this.selected)
  161. }
  162. })
  163. //viewer.fxaaPass.enabled = false//viewer.ssaaRenderPass.enabled = false
  164. viewer.outlinePass.enabled = true
  165. //Potree.settings.intersectWhenHover = false
  166. //Potree.Utils.updateVisible(viewer.reticule, 'force', false)
  167. viewer.composer.scaleRatio = 1
  168. viewer.composer.readTarget = false
  169. viewer.mainViewport.camera.near = 0.05; // too small will result in z-fighting
  170. viewer.addEventListener('updateModelBound', (e)=>{
  171. if(this.split){
  172. this.SplitScreen.updateCameraOutOfModel(/* this.selected && [this.selected] */)
  173. }
  174. })
  175. {//校准页面拖拽
  176. //左右屏都可以拖拽模型,旋转只能左屏
  177. let dragInfo
  178. let drag = (e)=>{
  179. if(this.split && this.selected && this.transformState && (e.dragViewport.name == 'top' || this.transformState == 'translate') ){
  180. if(e.type == 'global_mousedown' ){ //开始
  181. //if((e.intersect.object || e.intersect.pointcloud) == this.selected){
  182. if(e.intersect.pointclouds.includes(this.selected) || e.intersect.allElements.some(e=>e.object == this.selected)){
  183. dragInfo = {}
  184. //if(this.selected.isPointcloud){
  185. viewer.outlinePass.edgeStrength = 0//暂时消失线
  186. //}
  187. }
  188. }
  189. if(e.type == 'global_drag' && dragInfo ){
  190. if(this.transformState == 'translate'){
  191. let moveVec = Potree.Utils.getOrthoCameraMoveVec(e.drag.pointerDelta, e.dragViewport.camera )//最近一次移动向量
  192. this.selected.position.add(moveVec)
  193. this.selected.dispatchEvent("position_changed")
  194. }else if(this.transformState == 'rotate'){
  195. let vec = new THREE.Vector3().subVectors(e.intersect.orthoIntersect || e.intersect.location, this.selected.boundCenter).setZ(0)
  196. if(dragInfo.lastVec == void 0){//global_mousedown
  197. dragInfo.lastVec = vec
  198. return
  199. }
  200. let angle = math.getAngle(dragInfo.lastVec, vec, 'z')
  201. dragInfo.lastVec = vec
  202. //this.selected.rotation.z += angle //局部
  203. /* object.quaternion.copy( .setFromAxisAngle( new THREE.Vector3(0,0,1), angle ) );
  204. object.quaternion.multiply( quaternionStart ).normalize(); */
  205. let diffQua = new THREE.Quaternion().setFromAxisAngle( new THREE.Vector3(0,0,1), angle )
  206. this.selected.quaternion.premultiply(diffQua) //世界
  207. this.selected.dispatchEvent("rotation_changed")
  208. }
  209. return {stopContinue:true}
  210. }
  211. }
  212. }
  213. viewer.addEventListener('global_mousedown', drag)
  214. viewer.addEventListener('global_drag', drag, {importance:10})
  215. viewer.addEventListener('global_mousemove', (e)=>{
  216. if(this.split && this.transformState && !e.drag && (e.hoverViewport.name == 'top' || this.transformState == 'translate')){
  217. /* if(this.lastHoverViewport != e.hoverViewport){
  218. this.lastHoverViewport = e.hoverViewport
  219. this.transformControls.view = e.hoverViewport.view
  220. this.transformControls.camera = e.hoverViewport.camera
  221. this.transformControls.hideAxis( this.transformState, e.hoverViewport.name == 'top' ? [z] : [x,y]);
  222. } */
  223. let mouseover = e.intersect.pointclouds.includes(this.selected) || e.intersect.allElements.some(e=>e.object == this.selected)
  224. //let mouseover = (e.intersect.object || e.intersect.pointcloud) == this.selected
  225. if(mouseover){
  226. if(this.transformState == 'translate'){
  227. viewer.dispatchEvent({
  228. type : "CursorChange", action : "add", name:"movePointcloud"
  229. })
  230. }else{
  231. viewer.dispatchEvent({
  232. type : "CursorChange", action : "add", name:"rotatePointcloud"
  233. })
  234. }
  235. }else{
  236. this.clearTranCursor()
  237. }
  238. }
  239. })
  240. viewer.addEventListener('global_drop', (e)=>{
  241. dragInfo = null
  242. this.clearTranCursor()
  243. //this.updateEdgeStrength()
  244. viewer.outlinePass.edgeStrength = oriEdgeStrength
  245. })
  246. }
  247. /* viewer.addEventListener('background_changed',()=>{
  248. }) */
  249. viewer.addEventListener('camera_changed',()=>{
  250. Common.intervalTool.isWaiting('updateMemoryUsage', ()=>{
  251. this.updateMemoryUsage()
  252. }, 1000)
  253. })
  254. viewer.addEventListener('setDisplay',this.updateMemoryUsage.bind(this))
  255. },
  256. clearTranCursor(){
  257. viewer.dispatchEvent({
  258. type : "CursorChange", action : "remove", name:"movePointcloud"
  259. })
  260. viewer.dispatchEvent({
  261. type : "CursorChange", action : "remove", name:"rotatePointcloud"
  262. })
  263. },
  264. enterSplit(){
  265. this.split = true
  266. if(this.selected) this.SplitScreen.focusCenter = this.selected.boundCenter //旋转中心。注意 boundCenter不能直接赋值,否则改变后focusCenter也要改
  267. else this.SplitScreen.focusCenter = null
  268. this.SplitScreen.splitStart(viewportProps)
  269. this.beforeSplit = {
  270. pointDensity: Potree.settings.pointDensity,
  271. }
  272. Potree.settings.pointDensity = 'fourViewports' //强制降低点云质量
  273. viewer.setControls(viewer.fpControls)
  274. let rightViewport = viewer.viewports.find(e=>e.name == 'right')
  275. let topViewport = viewer.viewports.find(e=>e.name == 'top')
  276. topViewport.alignment = true
  277. rightViewport.rotateSide = true
  278. rightViewport.skyboxFixPos = true
  279. rightViewport.skyboxMinZoom = 10
  280. rightViewport.skyboxRenderFun = ()=>{// 使cube的一面永远正向镜头。 因侧视图的camera是ortho类型,需要平视mesh才不会拉伸
  281. viewer.skybox.scene.children[0].rotation.copy(rightViewport.camera.rotation)
  282. }
  283. topViewport.skyboxRenderFun = ()=>{
  284. viewer.skybox.scene.children[0].rotation.set(0,0,0)
  285. }
  286. viewer.viewports[1].layersAdd('layer2')
  287. viewer.viewports[0].layersAdd('layer1')
  288. Potree.Utils.setObjectLayers(this.transformControls, 'layer1' )
  289. this.transformControls.view = viewer.viewports[0].view
  290. this.transformControls.camera = viewer.viewports[0].camera
  291. this.transformControls._gizmo.hideAxis = {translate:['z'], rotate:['x','y','z'] }
  292. this.transformControls2.view = viewer.viewports[1].view
  293. this.transformControls2.camera = viewer.viewports[1].camera
  294. this.transformControls2._gizmo.hideAxis = {translate:['x','y'], rotate:['x','y','z'] }
  295. this.secondCompass.changeViewport(viewer.viewports[0])
  296. this.secondCompass.setDomPos()
  297. this.secondCompass.setDisplay(true)
  298. viewer.compass.changeViewport(viewer.viewports[1])
  299. viewer.compass.setDomPos()
  300. //this.changeSkyboxGeo(true)
  301. },
  302. leaveSplit(){
  303. this.split = false
  304. this.SplitScreen.unSplit()
  305. viewer.setControls(viewer.orbitControls)
  306. Potree.settings.pointDensity = this.beforeSplit.pointDensity
  307. /* if(this.selected && this.selected.isPointcloud){
  308. this.showModelOutline(this.selected, true)
  309. this.selected.material.activeAttributeName = "rgba"
  310. } */
  311. this.transformControls.camera = viewer.viewports[0].camera
  312. this.transformControls.view = viewer.viewports[0].view
  313. this.transformControls._gizmo.hideAxis = {rotate:['e']}
  314. Potree.Utils.setObjectLayers(this.transformControls, 'sceneObjects' ) //恢复
  315. viewer.compass.changeViewport(viewer.viewports[0]) //恢复
  316. viewer.compass.setDomPos()
  317. this.secondCompass.setDisplay(false)
  318. },
  319. rotateSideCamera(angle){
  320. this.SplitScreen.rotateSideCamera(viewer.viewports.find(e=>e.name == 'right'), angle)
  321. },
  322. setTransformState(state){//校准时
  323. this.transformState = state
  324. this.clearTranCursor()
  325. },
  326. //---------------------------
  327. getAllObjects(){
  328. return viewer.objs.children.concat(viewer.scene.pointclouds)
  329. },
  330. getModel(id){
  331. let models = this.getAllObjects()
  332. return models.find(e=>e.dataset_id == id)
  333. },
  334. removeModel(model){
  335. if(this.selected == model) this.selectModel(null)
  336. let dispose = (e)=>{
  337. e.geometry && e.geometry.dispose()
  338. e.material && e.material.dispose()
  339. }
  340. if(model.isPointcloud){
  341. dispose(model)
  342. viewer.scene.removePointCloud(model)
  343. }else{
  344. model.traverse(e=>{
  345. dispose(e)
  346. })
  347. viewer.objs.remove(model)
  348. this.updateMemoryUsage()
  349. }
  350. },
  351. selectModel(model, state=true, fitBound, by2d){
  352. if(!model) {
  353. model = this.selected
  354. state = false
  355. }
  356. if(state){
  357. if(this.selected){
  358. if(this.selected == model) return
  359. else{
  360. let transToolAttached = !!this.transformControls.object
  361. this.selectModel(this.selected, false, fitBound, by2d)
  362. transToolAttached && this.transformControls.attach(model)
  363. }
  364. }
  365. this.selected = model
  366. MergeEditor.focusOn(model, 500, !!fitBound) //通过在场景里点击模型的话,不focus
  367. this.showModelOutline(model)
  368. //this.updateEdgeStrength()
  369. //console.log('selectModel', model)
  370. }else{
  371. if(this.selected != model)return //model本来就没选中,不需要处理(防止2d先选中新的再取消旧的)
  372. this.showModelOutline(model, false)
  373. this.selected = null
  374. this.transformControls.detach() //viewer.transformObject(null);
  375. //console.log('selectModel', null)
  376. }
  377. if(!by2d && model){
  378. model.dispatchEvent({type:'changeSelect', selected : state})
  379. }
  380. },
  381. showModelOutline(model, state){
  382. if(this.fadeOutlineAuto){
  383. if(state === false){
  384. viewer.outlinePass.selectedObjects = []
  385. clearTimeout(this.timer)
  386. return
  387. }
  388. viewer.outlinePass.selectedObjects = [model]
  389. if(this.timer){
  390. clearTimeout(this.timer)
  391. }
  392. this.timer = setTimeout(()=>{
  393. viewer.outlinePass.selectedObjects = []
  394. viewer.dispatchEvent('content_changed')
  395. }, 1000)
  396. }else{
  397. if(state === false){
  398. viewer.outlinePass.selectedObjects = []
  399. }else{
  400. viewer.outlinePass.selectedObjects = [model]
  401. }
  402. }
  403. viewer.dispatchEvent('content_changed')
  404. },
  405. /*updateEdgeStrength(){
  406. if(!this.selected)return
  407. if(this.selected.isPointcloud){
  408. viewer.outlinePass.edgeStrength = edgeStrengths.pointcloud// / this.selected.material.opacity
  409. }else{
  410. viewer.outlinePass.edgeStrength = edgeStrengths.glb
  411. }
  412. },*/
  413. focusOn(objects, duration = 400, fitBound=true, dontLookUp){
  414. if(!(objects instanceof Array)){
  415. objects = [objects]
  416. }
  417. let boundingBox = new THREE.Box3
  418. objects.forEach(object=>{
  419. boundingBox.union(object.boundingBox.clone().applyMatrix4(object.matrixWorld))
  420. })
  421. if(fitBound){
  422. viewer.focusOnObject({boundingBox}, 'boundingBox', duration, {dontLookUp, dontChangeCamDir:true})
  423. }else{
  424. /*
  425. let position = viewer.inputHandler.intersect ? viewer.inputHandler.intersect.location : boundingBox.getCenter(new THREE.Vector3)
  426. position && viewer.focusOnObject({position}, 'point', duration, {dontChangePos: true})
  427. */
  428. let position = viewer.inputHandler.intersect ? viewer.inputHandler.intersect.location : boundingBox.getCenter(new THREE.Vector3)
  429. if(!position)return
  430. /* let targetOld = viewer.mainViewport.view.getPivot()
  431. let projected1 = targetOld.clone().project(viewer.mainViewport.camera);
  432. let projected2 = position.clone().project(viewer.mainViewport.camera); //使用其z
  433. let targetNew = projected1.clone().setZ(projected2.z).unproject(viewer.mainViewport.camera);
  434. viewer.mainViewport.view.lookAt(targetNew) */
  435. viewer.mainViewport.view.radius = viewer.mainViewport.camera.position.distanceTo(position)
  436. //为了不改画面,不调节方向了,只能调调radius,一定程度将target靠近model
  437. }
  438. },
  439. moveBoundCenterTo(model,pos){ //使boundCenter在所要的位置
  440. let diff = new THREE.Vector3().subVectors(pos, model.boundCenter)
  441. model.position.add(diff);
  442. },
  443. getBoundCenter(model){
  444. if(!model.boundCenter) model.boundCenter = new THREE.Vector3
  445. model.boundingBox.getCenter(model.boundCenter).applyMatrix4(model.matrixWorld)
  446. },
  447. setModelBtmHeight(model, z ){
  448. //无论模型怎么缩放、旋转,都使最低点为z
  449. if(z == void 0) z = model.btmHeight; //维持离地高度
  450. else model.btmHeight = z;
  451. if(model.btmHeight == void 0)return
  452. model.updateMatrixWorld()
  453. let boundingBox2 = model.boundingBox.clone().applyMatrix4(model.matrixWorld)
  454. let size = boundingBox2.getSize(new THREE.Vector3);
  455. let center = boundingBox2.getCenter(new THREE.Vector3);
  456. let hopeZ = z + size.z / 2
  457. //model.position.z = z + size.z / 2 - center.z
  458. model.position.z += (hopeZ - center.z)
  459. },
  460. computeBtmHeight(model){ //位移之后重新计算btmHeight
  461. model.updateMatrixWorld()
  462. let boundingBox2 = model.boundingBox.clone().applyMatrix4(model.matrixWorld)
  463. let size = boundingBox2.getSize(new THREE.Vector3);
  464. let center = boundingBox2.getCenter(new THREE.Vector3);
  465. model.btmHeight = center.z - size.z / 2
  466. },
  467. maintainBoundXY(model){ //在旋转和缩放后,立即执行这个函数,使boundCenter保持原位
  468. model.updateMatrixWorld()
  469. let center1 = model.boundCenter.clone();//还未更新的
  470. this.getBoundCenter(model)//更新
  471. let center2 = model.boundCenter.clone();
  472. let diff = new THREE.Vector2().subVectors(center1,center2);
  473. model.position.x += diff.x;
  474. model.position.y += diff.y;
  475. model.boundCenter.copy(center1)
  476. },
  477. maintainBoundCenter(model){
  478. model.updateMatrixWorld()
  479. let center1 = model.boundCenter.clone();//还未更新的
  480. this.getBoundCenter(model)//更新
  481. let center2 = model.boundCenter.clone();
  482. let diff = new THREE.Vector3().subVectors(center1,center2);
  483. model.position.add(diff)
  484. model.boundCenter.copy(center1)
  485. },
  486. modelTransformCallback(model){
  487. model.updateMatrixWorld()
  488. if(model.matrixWorld.equals(model.lastMatrixWorld))return
  489. viewer.scene.measurements.forEach(measure=>{
  490. let changed
  491. measure.points_datasets.forEach((dataset_id,i)=>{
  492. if(dataset_id == model.dataset_id){
  493. changed = true
  494. measure.points[i] = Potree.Utils.datasetPosTransform({fromDataset:true,datasetId:dataset_id, position:measure.dataset_points[i].clone()})
  495. measure.updateMarker(measure.markers[i], measure.points[i])
  496. }
  497. })
  498. if(changed){//仿transformByPointcloud
  499. measure.getPoint2dInfo(measure.points)
  500. measure.update()
  501. measure.setSelected(false)//隐藏edgelabel
  502. }
  503. })
  504. model.lastMatrixWorld = model.matrixWorld.clone()
  505. viewer.dispatchEvent('content_changed')
  506. viewer.mapViewer && Potree.settings.showObjectsOnMap && viewer.mapViewer.dispatchEvent('content_changed')
  507. },
  508. changeOpacity(model, opacity){
  509. let isRoot = model.dataset_id != void 0 //是否是最外层
  510. if(model.isPointcloud){
  511. model.changePointOpacity(opacity)
  512. //MergeEditor.updateEdgeStrength()
  513. }else{
  514. //model.traverse(e=>e.material && setOp(e, opacity))
  515. model.traverse(mesh=>{
  516. if(mesh.material){
  517. if(mesh.material.originOpacity == void 0 ){
  518. mesh.material.originOpacity = mesh.material.opacity
  519. }
  520. mesh.material.opacity = mesh.material.originOpacity * opacity
  521. if(mesh.material.opacity<1){
  522. mesh.material.transparent = true
  523. /* if(model.isPointcloud){
  524. mesh.changePointOpacity(realOpacity)
  525. }else{
  526. mesh.material.opacity = realOpacity
  527. } */
  528. mesh.renderOrder = Potree.config.renderOrders.model+1
  529. //mesh.material.depthWrite = false
  530. }else{
  531. mesh.material.transparent = false
  532. mesh.renderOrder = Potree.config.renderOrders.model
  533. //mesh.material.depthWrite = true
  534. }
  535. mesh.material.depthWrite = mesh.material.opacity>0.3
  536. }
  537. })
  538. }
  539. isRoot && (model.opacity = opacity)//记录在最外层
  540. viewer.dispatchEvent('content_changed')
  541. },
  542. modelAdded(model){
  543. model.addEventListener('isVisible',(e)=>{
  544. if(e.reason == "overlinePass")return
  545. //console.log(e)
  546. viewer.addEventListener('update',()=>{ //下一次更新结束后
  547. this.updateMemoryUsage()
  548. },{once:true})
  549. })
  550. this.updateMemoryUsage()
  551. },
  552. updateMemoryUsage(){
  553. //obj暂时不管其贴图大小, 因为顶点造成的不仅是内存还有卡顿所以先只看顶点
  554. const maxMemory = Potree.config.tiles3DMaxMemory + 100 //M 实际估计是这个的10倍
  555. const eachObjPosWeight = 100/1000/1000 //M 每个顶点pos是3*4个字节?法线3*4和uv2*4 其实还有贴图
  556. const eachCloudPointWeight = 12/1000/1000 //M 每个点 pos + 颜色 + 法线 大概
  557. const eachVisiCPointWeight = eachCloudPointWeight * 5 // 或 maxMemory / (6*1000*1000) 大概值接近 (再除以一个数是因为显示的要比内存中的耗更多资源
  558. const eachGltfPosWeight = 100/1000/1000 //M 每个顶点pos是3*4个字节?法线3*4和uv2*4 其实还有贴图
  559. let posCount=0
  560. viewer.objs.children.forEach(e=>{
  561. if(e.fileType == 'glb' || e.fileType == 'obj'){
  562. e.traverse((mesh)=>{
  563. if(mesh.geometry){
  564. posCount += mesh.geometry.attributes.position.count
  565. }
  566. })
  567. }else if(e.fileType == '3dTiles'){
  568. }
  569. })
  570. //获取点云的内存限制
  571. let objWeight = posCount*eachObjPosWeight
  572. let laserWeight = Potree.numVisiblePoints * eachCloudPointWeight //点云实际显示所占大小
  573. let laserMemoryWeight = Potree.lru.numPoints * eachCloudPointWeight //点云所使用内存大小
  574. let tiles3DWeight = viewer.tiles3dVisiVCount * eachGltfPosWeight //M 3dTiles所占内存大小
  575. let tiles3DMemoryWeight = viewer.tiles3dMemoryUsage / 1000 / 1000 //M 3dTiles显示的所占内存大小
  576. /* let min = 0.1, max = 6, minP = 100, maxP = 1000000;
  577. let ratio = Math.round(math.linearClamp(score, minP, maxP, max, min )); */
  578. let rest = maxMemory - objWeight - tiles3DWeight
  579. Potree.pointBudget = Math.max(30000, Math.round(rest/eachVisiCPointWeight))
  580. //获取3dTiles的内存限制
  581. let tiles3DMaxMemory = maxMemory - Math.round(objWeight + laserWeight)
  582. Potree.settings.tiles3DMaxMemory = THREE.Math.clamp(tiles3DMaxMemory , 30, Potree.config.tiles3DMaxMemory )
  583. //还存在的问题:仍然有隐患,因为没用到真实缓存的大小: tiles3DMemoryWeight laserMemoryWeight, 它们比真实可见的要多。不使用是因为它们无法反应出实际需要的内存量,缓存是只增不减
  584. //obj等普通mesh限制不了
  585. //console.log('objWeight',objWeight.toFixed(1), 'laserMemoryWeight',laserMemoryWeight.toFixed(1), 'tiles3DWeight',tiles3DWeight.toFixed(1), 'pointBudget',Potree.pointBudget, 'tiles3DMaxMemory',tiles3DMaxMemory)
  586. //总内存 = 内存占用空间+图片缓存 , obj的缓存比较多在图片中
  587. },
  588. setGroundPlaneImg(src,scale){//设置地面图
  589. this.goundScale = scale
  590. let oldSrc = this.curGroundImgSrc
  591. this.curGroundImgSrc = src
  592. const ratio = 0.04
  593. if(src){
  594. if(oldSrc == src && this.groundPlane.material.map.image){ //仅修改大小
  595. const s = ratio * this.goundScale
  596. let {width, height} = this.groundPlane.material.map.image
  597. this.groundPlane.scale.set(width*s, height*s)
  598. viewer.dispatchEvent('content_changed')
  599. return
  600. }
  601. let map = texLoader.load(src,(tex)=>{
  602. if(this.curGroundImgSrc == src){
  603. const s = ratio * this.goundScale
  604. this.groundPlane.scale.set(tex.image.width*s, tex.image.height*s)
  605. viewer.dispatchEvent('content_changed')
  606. }
  607. })
  608. Potree.Utils.makeTexDontResize(map)
  609. if(!this.groundPlane){
  610. this.groundPlane = new THREE.Mesh(new THREE.PlaneBufferGeometry(1,1,1), new THREE.MeshBasicMaterial({
  611. map,
  612. side : 2,
  613. }))
  614. viewer.scene.scene.add(this.groundPlane)
  615. this.groundPlane.position.z = -1
  616. }else{
  617. this.groundPlane.material.map = map
  618. }
  619. Potree.Utils.updateVisible(this.groundPlane,'show',true )
  620. }else{
  621. this.groundPlane && Potree.Utils.updateVisible(this.groundPlane,'show',false )
  622. }
  623. }
  624. }
  625. export default MergeEditor
  626. /*
  627. note:
  628. 要注意getHoveredElements只在getIntersect时才使interactables包含加载的model, 也就是model上不能有使之成为interactables的事件,否则在鼠标hover到模型上开始转动的一瞬间很卡。
  629. */