SplitScreen.js 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. import {ExtendView} from "../../viewer/ExtendView.js";
  2. import Viewport from "../viewer/Viewport.js";
  3. import * as THREE from "../../../libs/three.js/build/three.module.js";
  4. class SplitScreen extends THREE.EventDispatcher{
  5. constructor (args = {}) {
  6. super();
  7. this.noRotSide = args.noRotSide
  8. }
  9. /*
  10. viewport.targetPlane // bound中心点处的plane,朝向view的方向
  11. viewport.shiftTarget // camera的位置project在targetPlane上的位置
  12. 这两个参数的主要目的是为了getPosOutOfModel,以及rotateSideCamera时保持相对位置
  13. */
  14. splitStart(cameraProps){//创建viewport
  15. this.splited = true
  16. let viewports = []
  17. let subViewports = [viewer.mainViewport] //已有项
  18. if(viewer.mapViewer){
  19. subViewports.push(viewer.mapViewer.viewports[0])
  20. }
  21. let length = cameraProps.length
  22. for(let i=0;i<length;i++){
  23. let prop = cameraProps[i];
  24. let viewport;
  25. let v = subViewports.find(e=>e.name == (prop.name2||prop.name))
  26. if(v){
  27. viewport = v
  28. viewport.left = prop.left; viewport.bottom = prop.bottom; viewport.width = prop.width; viewport.height = prop.height;
  29. }
  30. if(!viewport){
  31. let view = new ExtendView()
  32. if(prop.limitBound)view.limitBound = prop.limitBound
  33. prop.direction && (view.direction = prop.direction)
  34. viewport = new Viewport(view , this.getOrthoCamera(), prop )
  35. if(prop.viewContainsPoints)viewport.viewContainsPoints = prop.viewContainsPoints
  36. //viewport.unableDepth = true //depthBasicMaterial等在此viewport中不开启depth
  37. }
  38. if(viewport.camera.type == 'OrthographicCamera' ){
  39. viewport.targetPlane = new THREE.Plane()
  40. viewport.shiftTarget = new THREE.Vector3 //project在targetPlane上的位置
  41. }
  42. viewport.fitMargin = prop.margin
  43. viewports.push(viewport)
  44. }
  45. viewer.viewports = viewports;
  46. viewer.updateScreenSize({forceUpdateSize:true})
  47. viewports.forEach(viewport=>{
  48. if(viewport.name == 'MainView')return
  49. this.viewportFitBound(viewport, viewer.bound.boundingBox , viewer.bound.center , 0, viewport.fitMargin)
  50. })
  51. return viewports
  52. }
  53. unSplit(){
  54. this.splited = false
  55. this.unfocusViewport()
  56. viewer.inputHandler.hoverViewport = null //清空
  57. viewer.viewports = [viewer.mainViewport]
  58. viewer.mainViewport.width = 1;
  59. viewer.mainViewport.height = 1;
  60. viewer.mainViewport.left = 0
  61. viewer.mainViewport.bottom = 0;
  62. viewer.updateScreenSize({forceUpdateSize:true})
  63. }
  64. viewportFitBound(viewport, bound, center, duration=0, margin){
  65. let view = viewport.view
  66. let info = {bound}
  67. let {boundSize, boundCenter} = this.getViewBound(viewport/* , bound */ )// 去掉bound是因为需要在所有点云的一侧才能都看到
  68. //this.setShiftTarget(viewport, boundCenter)
  69. viewport.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), boundCenter )
  70. viewport.targetPlane.projectPoint(center, viewport.shiftTarget) //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
  71. info.endPosition = this.getPosOutOfModel(viewport, boundSize)
  72. //if(viewport.name == 'mapViewport')info.endPosition.z = Math.max(Potree.config.map.cameraHeight, info.endPosition.z)
  73. info.margin = margin || {x:30, y:30}
  74. view.moveOrthoCamera(viewport, info , duration )
  75. }
  76. getViewBound(viewport, boundingBox){
  77. if(boundingBox){
  78. boundSize = boundingBox.getSize(new THREE.Vector3)
  79. center = boundingBox.getCenter(new THREE.Vector3)
  80. }else{
  81. var {boundSize, center, boundingBox} = viewer.bound
  82. }
  83. let containsPoints = []
  84. this.focusCenter && containsPoints.push(this.focusCenter)
  85. viewport.viewContainsPoints && containsPoints.push(...viewport.viewContainsPoints)
  86. if(containsPoints.length){//视野范围内必须要包含的点,直接算入模型区域。这时候得到的boundCenter和模型中心不重合
  87. boundingBox = boundingBox.clone()
  88. containsPoints.forEach(point=>{
  89. boundingBox.expandByPoint(point)
  90. })
  91. boundSize = boundingBox.getSize(new THREE.Vector3)
  92. center = boundingBox.getCenter(new THREE.Vector3)
  93. }
  94. return {boundSize, boundCenter:center }
  95. }
  96. getPosOutOfModel(viewport, boundSize){
  97. //let {boundSize, center} = viewer.bound
  98. boundSize = boundSize || this.getViewBound(viewport).boundSize
  99. let expand = 10;
  100. let radius = (this.noRotSide ? boundSize.clone().projectOnVector(viewport.view.direction).length() : boundSize.length() ) * 2
  101. let position = viewport.shiftTarget.clone().sub(viewport.view.direction.clone().multiplyScalar(radius + expand))
  102. return position
  103. }
  104. updateCameraOutOfModel(){//因为移动模型导致模型超出相机外,所以更新位置
  105. viewer.viewports.forEach((viewport, i )=>{
  106. if(viewport.camera.isOrthographicCamera){ //or if(viewport.targetPlane)
  107. let {boundSize, boundCenter} = this.getViewBound(viewport)
  108. /* viewport.targetPlane.setFromNormalAndCoplanarPoint( viewport.view.direction.clone(), boundCenter)
  109. viewport.targetPlane.projectPoint(viewport.view.position, viewport.shiftTarget) //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
  110. */
  111. this.setShiftTarget(viewport, boundCenter)
  112. let endPosition = this.getPosOutOfModel(viewport, boundSize)
  113. //if(viewport.name == 'mapViewport')endPosition.z = Math.max(Potree.config.map.cameraHeight, endPosition.z)
  114. viewport.view.position.copy(endPosition)
  115. }
  116. })
  117. }
  118. setShiftTarget(viewport, center){
  119. if(!viewport.targetPlane ){
  120. viewport.targetPlane = new THREE.Plane()
  121. viewport.shiftTarget = new THREE.Vector3 //project在targetPlane上的位置
  122. }
  123. viewport.targetPlane.setFromNormalAndCoplanarPoint(viewport.view.direction, center )
  124. viewport.targetPlane.projectPoint(viewport.view.position, viewport.shiftTarget ) //target转换到过模型中心的平面,以保证镜头一定在模型外
  125. }
  126. rotateSideCamera(viewport, angle, axis=new THREE.Vector3(0,0,1)){//侧视图或俯视图绕模型中心水平旋转
  127. this.rotateCamera(viewport, angle, axis)
  128. }
  129. rotateCamera(viewport, angle, axis, endQua){//旋转前后保持shiftTarget在镜头的相对位置不变
  130. //let {boundSize, center} = viewer.bound
  131. let {boundSize, boundCenter } = this.getViewBound(viewport)
  132. let center = this.focusCenter || boundCenter //旋转中心,一般是所有模型的中心,除非想指定中心点
  133. this.setShiftTarget(viewport, center)
  134. //找到平移向量
  135. let vec = new THREE.Vector3().subVectors(center, viewport.shiftTarget)//相对于中心的偏移值,旋转后偏移值也旋转
  136. var rotMatrix
  137. if(endQua){
  138. let qua = new THREE.Quaternion().multiplyQuaternions(endQua, viewport.view.quaternion.invert())
  139. rotMatrix = new THREE.Matrix4().makeRotationFromQuaternion(qua)
  140. viewport.view.quaternion = endQua
  141. }else{
  142. rotMatrix = new THREE.Matrix4().makeRotationAxis(axis, angle)
  143. //viewport.view.direction = viewport.view.direction.applyMatrix4(rotMatrix)
  144. let qua = new THREE.Quaternion().setFromRotationMatrix(rotMatrix)
  145. viewport.view.quaternion = viewport.view.quaternion.premultiply(qua)
  146. }
  147. vec.applyMatrix4(rotMatrix)
  148. viewport.shiftTarget.subVectors(center,vec) //新的
  149. viewport.view.position = this.getPosOutOfModel(viewport, boundSize)
  150. }
  151. getOrthoCamera(){
  152. let camera = new THREE.OrthographicCamera(-100, 100, 100, 100, 0.01, 10000)
  153. camera.up.set(0,0,1)
  154. return camera
  155. }
  156. focusOnViewport(name){//全屏
  157. if(this.focusInfo){
  158. this.unfocusViewport()
  159. }
  160. viewer.viewports.forEach((viewport, i )=>{
  161. if(viewport.name == name){
  162. this.focusInfo = {
  163. name,
  164. left : viewport.left, bottom : viewport.bottom, height : viewport.height, width : viewport.width
  165. }
  166. viewport.left = 0; viewport.bottom = 0; viewport.height = 1; viewport.width = 1
  167. }else{
  168. viewport.active = false
  169. }
  170. })
  171. viewer.updateScreenSize({forceUpdateSize:true})
  172. }
  173. unfocusViewport(){
  174. if(!this.focusInfo)return
  175. viewer.viewports.forEach((viewport, i )=>{
  176. if(this.focusInfo.name == viewport.name){//全屏的恢复
  177. viewport.left = this.focusInfo.left;
  178. viewport.bottom = this.focusInfo.bottom;
  179. viewport.height = this.focusInfo.height;
  180. viewport.width = this.focusInfo.width;
  181. }
  182. viewport.active = true
  183. })
  184. viewer.updateScreenSize({forceUpdateSize:true})
  185. this.focusInfo = null
  186. }
  187. }
  188. export default SplitScreen