potree.shim.js 84 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262
  1. import * as THREE from "../../libs/three.js/build/three.module.js";
  2. import math from "./utils/math.js";
  3. import browser from "./utils/browser.js";
  4. import cameraLight from "./utils/cameraLight.js";
  5. import {Utils} from "../utils.js";
  6. import Common from "./utils/Common.js";
  7. import {BinaryLoader} from "../loader/BinaryLoader.js";
  8. import {Features} from "../Features.js";
  9. import {PointAttribute,PointAttributeTypes} from "../loader/PointAttributes.js";
  10. import {ProfileWindow} from "../viewer/profile.js";
  11. import {XHRFactory} from "../XHRFactory.js";
  12. import {ClipTask, ClipMethod} from "../defines.js";
  13. import {VolumeTool} from "../utils/VolumeTool.js";
  14. import {Box3Helper} from "../utils/Box3Helper.js";
  15. import {KeyCodes} from "../KeyCodes.js";
  16. import {HQSplatRenderer} from "../viewer/HQSplatRenderer.js";
  17. import {LRU} from "../LRU.js";
  18. import {ExtendPointCloudMaterial} from '../materials/ExtendPointCloudMaterial.js'
  19. import {PointCloudOctreeGeometry, PointCloudOctreeGeometryNode} from '../PointCloudOctreeGeometry.js'
  20. import {Shaders} from "../../build/shaders/shaders.js";
  21. import {LineSegmentsGeometry} from '../../libs/three.js/lines/LineSegmentsGeometry.js'
  22. import {LineGeometry} from '../../libs/three.js/lines/LineGeometry.js'
  23. import {ExtendView} from '../viewer/ExtendView.js'
  24. import {ExtendScene} from '../viewer/ExtendScene.js'
  25. KeyCodes.BACKSPACE = 8
  26. //注意,这时候Potree.js中export的内容还不在Potree变量中
  27. var texLoader = new THREE.TextureLoader()
  28. texLoader.crossOrigin = "anonymous"
  29. {//defines:
  30. Potree.defines = {}
  31. Potree.defines.Buttons = {// MouseEvent.buttons
  32. //buttons,设置按下了鼠标哪些键,是一个3个比特位的二进制值,默认为0。1表示按下主键(通常是左键),2表示按下次要键(通常是右键),4表示按下辅助键(通常是中间的键)。
  33. NONE:0,//add
  34. LEFT: 0b0001,
  35. RIGHT: 0b0010,
  36. MIDDLE: 0b0100
  37. };
  38. /* 如果访问的是button, 用THREE.MOUSE来判断:
  39. button,设置按下了哪一个鼠标按键,默认为0。-1表示没有按键,0表示按下主键(通常是左键),1表示按下辅助键(通常是中间的键),2表示按下次要键(通常是右键)
  40. */
  41. Potree.browser = browser
  42. /////////// add //////////////////////////////////
  43. Potree.defines.GLCubeFaces = {
  44. GL_TEXTURE_CUBE_MAP_POSITIVE_X: 0,
  45. GL_TEXTURE_CUBE_MAP_NEGATIVE_X: 1,
  46. GL_TEXTURE_CUBE_MAP_POSITIVE_Y: 2,
  47. GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: 3,
  48. GL_TEXTURE_CUBE_MAP_POSITIVE_Z: 4,
  49. GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: 5
  50. };
  51. Potree.defines.PanoSizeClass = {
  52. BASE: 1,
  53. STANDARD: 2,
  54. HIGH: 3,
  55. ULTRAHIGH: 4
  56. };
  57. Potree.defines.PanoRendererEvents = {
  58. PanoRenderComplete: "panorama.render.complete",
  59. TileRenderFailure: "panorama.tile.render.failed",
  60. TileRenderSuccess: "panorama.tile.render.success",
  61. TileUploadAttempted: "panorama.tile.upload.attempted",
  62. UploadAttemptedForAllTiles: "panorama.upload.attempted.all.tiles",
  63. ZoomLevelRenderStarted: "panorama.zoom.render.started"
  64. };
  65. Potree.defines.SceneRendererEvents = {
  66. ContextCreated: "scene-renderer-context-created",
  67. AfterRender: "after-render",
  68. MemoryUsageUpdated: "scene-renderer-memory-usage-updated"
  69. };
  70. Potree.defines.TileDownloaderEvents = {
  71. TileDownloadSuccess: "tiledownloader.download.success",
  72. TileDownloadFailure: "tiledownloader.download.failure",
  73. PanoDownloadComplete: "tiledownloader.pano.download.complete"
  74. };
  75. Potree.defines.Vectors = {
  76. UP: new THREE.Vector3(0,1,0),
  77. DOWN: new THREE.Vector3(0,-1,0),
  78. LEFT: new THREE.Vector3(-1,0,0),
  79. RIGHT: new THREE.Vector3(1,0,0),
  80. FORWARD: new THREE.Vector3(0,0,-1),
  81. BACK: new THREE.Vector3(0,0,1)
  82. };
  83. Potree.defines.gs3d = {
  84. DepthMapRange : 1 << 16,
  85. MemoryPageSize : 65536,
  86. BytesPerFloat : 4,
  87. BytesPerInt : 4,
  88. MaxScenes : 32,
  89. ProgressiveLoadSectionSize : 262144,
  90. ProgressiveLoadSectionDelayDuration : 15,
  91. SphericalHarmonics8BitCompressionRange : 3
  92. }
  93. Potree.defines.DownloadStatus = Object.freeze({
  94. None: 0,
  95. Queued: 1,
  96. ForceQueued: 2,
  97. Downloading: 3,
  98. Downloaded: 4,
  99. DownloadFailed: 5
  100. });
  101. Potree.defines.ModelManagerEvents = {
  102. ModelAdded: "model-added",
  103. ActiveModelChanged: "active-model-changed"
  104. };
  105. Potree.defines.PanoramaEvents = {
  106. Enter: 'panorama.enter',
  107. Exit: 'panorama.exit',
  108. LoadComplete: "panorama.load.complete",
  109. LoadFailed: "panorama.load.failed",
  110. TileLoaded: "panorama.tile.loaded",
  111. VideoRendered: "panorama.video.rendered"
  112. };
  113. ClipTask.SHOW_INSIDE_Big = 4
  114. }
  115. {//Features
  116. let gl_, webgl2Support
  117. Features.EXT_DEPTH = {
  118. isSupported: function (gl) {
  119. gl = gl || gl_
  120. gl_ = gl
  121. if(browser.detectIOS()){
  122. let {major,minor,patch} = browser.iosVersion()
  123. //console.warn('iosVersion',major,minor,patch)
  124. if(major == 15 && minor == 4 && patch == 1){
  125. console.warn('检测到是ios15.4.1, 关闭EXT_frag_depth')//该版本ext_depth有问题,导致clear错乱。没有解决办法先关闭。
  126. return false
  127. }
  128. }
  129. return (typeof WebGL2RenderingContext != 'undefined' && gl instanceof WebGL2RenderingContext) || gl.getExtension('EXT_frag_depth'); //shader中的GL_EXT_frag_depth需要判断一下detectIOS吗。。
  130. }
  131. }
  132. /* Features.getMaxMapSize = (gl)=>{
  133. // 查询最大立方体贴图纹理尺寸
  134. gl = gl || gl_
  135. gl_ = gl
  136. let info = {
  137. cubeMap: gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE),
  138. tex: gl.getParameter( gl.MAX_TEXTURE_SIZE )
  139. }
  140. if(info.cubeMap < 4096){
  141. console.warn('cubeMap最大仅支持', info.cubeMap)
  142. }
  143. return info
  144. } */
  145. Features.webgl2RealSupport = ()=>{
  146. if(webgl2Support != void 0){
  147. return webgl2Support
  148. }
  149. let gl
  150. try {
  151. var canvas = document.createElement('canvas')
  152. if(window.WebGL2RenderingContext){ //遇到有设备(iphone8 plus ios14.1 型号MQ8F2CH/A)直接获取webgl2后会点云和全景图闪烁,WebGL2RenderingContext和得到的context是undefined。但是为何4dkk不会闪烁
  153. gl = canvas.getContext('webgl2') //麒麟系统chromium 128 到这一步才获取失败 如果直接对最终的canvas获取webgl2,会造成多viewport无法单独渲染以及clearAlpha透明失败
  154. }
  155. }catch (e) {
  156. console.log(e)
  157. }
  158. webgl2Support = !!gl
  159. return webgl2Support
  160. }
  161. }
  162. Utils.loadSkybox = function(path, oldSky, callback ) {
  163. let camera, scene, parent , cameraOrtho
  164. if(!oldSky){
  165. parent = new THREE.Object3D("skybox_root");
  166. camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 1, 100000);
  167. cameraOrtho = new THREE.OrthographicCamera(-1, 1, 1, -1, Potree.config.view.near, Potree.settings.cameraFar);
  168. if(!window.axisYup) camera.up.set(0, 0, 1);//add
  169. scene = new THREE.Scene();
  170. let skyboxBgWidth = Potree.config.skyboxBgWidth
  171. let skyGeometry = new THREE.BoxBufferGeometry(skyboxBgWidth,skyboxBgWidth,skyboxBgWidth)
  172. let skybox = new THREE.Mesh(skyGeometry, new THREE.ShaderMaterial({
  173. vertexShader: Shaders['skybox.vs'],
  174. fragmentShader: Shaders['skybox.fs'],
  175. side: THREE.BackSide,
  176. uniforms:{
  177. tDiffuse: {
  178. type: "t",
  179. value: null
  180. },
  181. matrix:{
  182. type: "m4",
  183. value: new THREE.Matrix4
  184. }
  185. },
  186. depthTest:false,
  187. depthWrite:false
  188. }) );
  189. scene.add(skybox);
  190. scene.traverse(n => n.frustumCulled = false);
  191. // z up
  192. //scene.rotation.x = Math.PI / 2;
  193. parent.children.push(camera);
  194. camera.parent = parent;
  195. }else{
  196. camera = oldSky.camera,
  197. scene = oldSky.scene
  198. parent = oldSky.parent
  199. cameraOrtho = oldSky.cameraOrtho
  200. }
  201. let texture = texLoader.load( path, ()=>{
  202. console.log('loadSkybox成功',path)
  203. texture.wrapS = THREE.RepeatWrapping;
  204. texture.flipY = false
  205. texture.magFilter = THREE.LinearFilter
  206. texture.minFilter = THREE.LinearFilter
  207. scene.children[0].material.uniforms.tDiffuse.value = texture
  208. callback && callback()
  209. viewer.dispatchEvent('content_changed')
  210. },null,(e)=>{//error
  211. console.error('loadSkybox失败',path)
  212. });
  213. return {camera, scene, parent, cameraOrtho};
  214. };
  215. Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera, viewer, pointclouds, pickParams = {} ) {
  216. //getIntersectByDepthTex
  217. /* let result = viewer.edlRenderer.depthTexSampler.sample(viewport, mouse)//add
  218. if(result != 'unsupport')return result
  219. */
  220. if(!pointclouds || pointclouds.filter(e=>Potree.Utils.getObjVisiByReason(e, 'datasetSelection')).length == 0)return
  221. //console.log('getMousePointCloudIntersection')
  222. let renderer = viewer.renderer;
  223. let resolution = pickParams.resolution || viewport?.resolution || renderer.getSize(new THREE.Vector2)
  224. if(pickParams.ifCenter){
  225. pickParams.x = Math.round(resolution.x / 2)
  226. pickParams.y = Math.round(resolution.y / 2)
  227. }else{
  228. /* if(viewport){ //转换到类似整个画面时
  229. pickParams.x = mouse.x;
  230. pickParams.y = viewport.resolution.y - mouse.y;
  231. }else{
  232. pickParams.x = mouse.x;
  233. pickParams.y = renderer.domElement.clientHeight - mouse.y;
  234. } */
  235. pickParams.x = mouse.x;
  236. pickParams.y = resolution.y - mouse.y;
  237. }
  238. //console.log('getMousePointCloudIntersection')
  239. /* if(!raycaster){
  240. raycaster = new THREE.Raycaster();
  241. raycaster.setFromCamera(pointer, camera);
  242. } */
  243. let raycaster = new THREE.Raycaster();
  244. raycaster.setFromCamera(pointer, camera);
  245. let ray = raycaster.ray;
  246. let selectedPointcloud = null;
  247. let closestDistance = Infinity;
  248. let closestIntersection = null;
  249. let closestPoint = null;
  250. //-----------add--------------------
  251. let old_clipBoxes_in = new Map()
  252. let old_clipBoxes_out = new Map()
  253. let old_bigClipInBox = new Map()
  254. let old_highlightBoxes = new Map()
  255. let old_visibleNodes = new Map()
  256. //bigClipInBox 最好也写下
  257. let density
  258. let sizeType
  259. let size = new Map()
  260. let visiMap = new Map()
  261. let needsUpdate = false;
  262. if(pickParams.measuring || Potree.settings.displayMode == 'showPanos') { //测量或无深度图时的全景模式提高精准度. (全景模式有深度图时不会执行到这)
  263. density = Potree.settings.pointDensity
  264. Potree.settings.pointDensity = 'magnifier' //加载最高level
  265. pointclouds.forEach(e=>{//因为全景模式的pointSizeType是fixed所以要还原下
  266. visiMap.set(e,e.visible)
  267. e.visible = Potree.Utils.getObjVisiByReason(e, 'datasetSelection'); //先将隐藏的点云显示
  268. if(!e.visible)return
  269. size.set(e, e.temp.pointSize)
  270. sizeType = e.material.pointSizeType
  271. e.material.pointSizeType = Potree.config.material.pointSizeType
  272. //e.changePointSize(Potree.config.material.realPointSize*2, true)//更改点云大小到能铺满为止,否则容易识别不到
  273. })
  274. needsUpdate = true
  275. }else{
  276. if(viewer.viewports.filter(e=>!e.noPointcloud && e.active).length>1 || pickParams.cameraChanged){//在pick时相机和渲染时不一样的话
  277. viewport.beforeRender && viewport.beforeRender()
  278. needsUpdate = true //不updatePointClouds的话hover久了会不准 因node是错的
  279. //但依旧需要camera真的移动到那个位置才能加载出点云
  280. }
  281. }
  282. if(!pickParams.pickClipped){// 无视clipBoxes
  283. for(let pointcloud of pointclouds){
  284. old_clipBoxes_in.set(pointcloud, pointcloud.clipBoxes_in)
  285. old_clipBoxes_out.set(pointcloud, pointcloud.clipBoxes_out)
  286. old_bigClipInBox.set(pointcloud, pointcloud.bigClipInBox)
  287. old_highlightBoxes.set(pointcloud, pointcloud.highlightBoxes)
  288. pointcloud.material.setClipBoxes(null, [],[],[])
  289. }
  290. needsUpdate = true
  291. }
  292. if(needsUpdate) {
  293. for(let pointcloud of pointclouds){
  294. old_visibleNodes.set(pointcloud, pointcloud.visibleNodes)
  295. }
  296. if(window.notViewOffset){
  297. Potree.updatePointClouds(pointclouds, camera, viewport.resolution );
  298. }else{
  299. //尽量减少点云加载的范围,集中在pick的空间(这部分以外还是会加载一些散点的)
  300. let viewWidth = Math.max(pickParams.pickWindowSize||80, 80) //viewer.magnifier ? viewer.magnifier.viewport.resolution.x : 200
  301. let camera_ = camera.clone()
  302. camera_.setViewOffset( resolution.x, resolution.y, pickParams.x-viewWidth/2, ( resolution.y - pickParams.y)-viewWidth/2, viewWidth, viewWidth ); //注意offsetY是从上到下,和一般的不同
  303. Potree.updatePointClouds(pointclouds, camera_, resolution );
  304. }
  305. }
  306. //------------------------------------------------
  307. let allPointclouds = []
  308. for(let pointcloud of pointclouds){
  309. let point = pointcloud.pick(viewer, viewport, camera, ray, pickParams );
  310. if(!point){
  311. continue;
  312. }
  313. allPointclouds.push(pointcloud)
  314. let distance = camera.position.distanceTo(point.position);
  315. if (distance < closestDistance) {
  316. closestDistance = distance;
  317. selectedPointcloud = pointcloud;
  318. closestIntersection = point.position;
  319. closestPoint = point;
  320. }
  321. }
  322. //恢复
  323. if(pickParams.measuring || Potree.settings.displayMode == 'showPanos'){
  324. Potree.settings.pointDensity = density
  325. pointclouds.forEach(e=>{
  326. if(e.visible){
  327. e.material.pointSizeType = sizeType
  328. //e.changePointSize(size.get(e))
  329. }
  330. e.visible = visiMap.get(e)
  331. })
  332. }else{
  333. /* if(viewer.viewports.filter(e=>!e.noPointcloud).length>1){
  334. viewport.afterRender && viewport.afterRender()
  335. } */
  336. }
  337. if(!pickParams.pickClipped){//add
  338. for(let pointcloud of pointclouds){
  339. pointcloud.material.setClipBoxes(old_bigClipInBox.get(pointcloud), old_clipBoxes_in.get(pointcloud), old_clipBoxes_out.get(pointcloud), old_highlightBoxes.get(pointcloud))
  340. }
  341. }
  342. if(needsUpdate){
  343. for(let pointcloud of pointclouds){ //不恢复的话(尤其cameraChanged时),在下次render前,再次pick可能是错的。表现为多数据集刚开始reticule消失了,直到ifPointBlockedByIntersect停止
  344. pointcloud.visibleNodes = old_visibleNodes.get(pointcloud)
  345. }
  346. }
  347. if (selectedPointcloud) {
  348. let localNormal = closestPoint.normal && new THREE.Vector3().fromArray(closestPoint.normal)
  349. return {
  350. location: closestIntersection,
  351. distance: closestDistance,
  352. pointcloud: selectedPointcloud,
  353. point: closestPoint,
  354. pointclouds: allPointclouds, //add
  355. localNormal: localNormal,
  356. normal: localNormal?.clone().applyMatrix4(selectedPointcloud.rotateMatrix)//add
  357. };
  358. } else {
  359. return null;
  360. }
  361. };
  362. Utils.pixelsArrayToDataUrl = function(pixels, width, height, compressRatio = 0.7) {
  363. let canvas = document.createElement('canvas');
  364. canvas.width = width;
  365. canvas.height = height;
  366. let context = canvas.getContext('2d');
  367. pixels = new pixels.constructor(pixels);
  368. /* for (let i = 0; i < pixels.length; i++) {
  369. pixels[i * 4 + 3] = 255;
  370. } */
  371. // flip vertically
  372. let bytesPerLine = width * 4;
  373. for(let i = 0; i < parseInt(height / 2); i++){
  374. let j = height - i - 1;
  375. let lineI = pixels.slice(i * bytesPerLine, i * bytesPerLine + bytesPerLine);
  376. let lineJ = pixels.slice(j * bytesPerLine, j * bytesPerLine + bytesPerLine);
  377. pixels.set(lineJ, i * bytesPerLine);
  378. pixels.set(lineI, j * bytesPerLine);
  379. }
  380. let imageData = context.createImageData(width, height);
  381. imageData.data.set(pixels);
  382. context.putImageData(imageData, 0, 0);
  383. let dataURL = canvas.toDataURL(compressRatio);
  384. return dataURL;
  385. }
  386. Utils.renderTargetToDataUrl = function(renderTarget, width, height, renderer, compressRatio = 0.7){
  387. let pixelCount = width * height;
  388. let buffer = new Uint8Array(4 * pixelCount);
  389. renderer.readRenderTargetPixels(renderTarget, 0, 0, width, height, buffer);
  390. var dataUrl = Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio)
  391. return dataUrl
  392. }
  393. Utils.mouseToRay = function(pointer, camera ){
  394. let vector = new THREE.Vector3(pointer.x, pointer.y, 1);
  395. let origin = new THREE.Vector3(pointer.x, pointer.y, -1); //不能用camera.position,在orbitCamera时不准
  396. vector.unproject(camera);
  397. origin.unproject(camera);
  398. let direction = new THREE.Vector3().subVectors(vector, origin).normalize();
  399. let ray = new THREE.Ray(origin, direction);
  400. return ray;
  401. }
  402. Utils.getPos2d = function(point, viewport , dom, renderer ){//获取一个三维坐标对应屏幕中的二维坐标
  403. var pos
  404. if(math.closeTo(viewport.camera.position, point, 1e-5) ){ //和相机位置重合时显示会四处飘,看是要改成一直显示中间还是隐藏?
  405. pos = new THREE.Vector3(0,0,1.5); //1.5是为了不可见
  406. }else{
  407. pos = point.clone().project(viewport.camera) //比之前hotspot的计算方式写得简单 project用于3转2(求法同shader); unproject用于2转3 :new r.Vector3(e.x, e.y, -1).unproject(this.camera);
  408. }
  409. let size = renderer && renderer.getSize(new THREE.Vector2) //如果是渲染到renderTarget上,resolution和dom的大小不一致。如果输出的结果给前端2d用,就使用clinetWidth,如果自己场景用,用renderer.size
  410. let w = renderer ? size.x : dom.clientWidth
  411. let h = renderer ? size.y : dom.clientHeight
  412. var x,y,left,top;
  413. x = (pos.x + 1) / 2 * w * viewport.width;
  414. y = (1 - (pos.y + 1) / 2) * h * viewport.height;
  415. left = viewport.left * w;
  416. top = (1- viewport.bottom - viewport.height) * h;
  417. var inSight = pos.x <= 1 && pos.x >= -1 //是否在屏幕中
  418. && pos.x <= 1 && pos.y >= -1
  419. return {
  420. pos: new THREE.Vector2(left+x,top+y) ,// 屏幕像素坐标
  421. vector: pos, //(范围 -1 ~ 1)
  422. trueSide : pos.z<1, //trueSide为false时,即使在屏幕范围内可见,也是反方向的另一个不可以被渲染的点 参见Tag.update
  423. inSight : inSight, //在屏幕范围内可见,
  424. posInViewport: new THREE.Vector2(x,y),
  425. };
  426. }
  427. Utils.getPointerPosAtHeight = function(planeZ=0, pointer, camera=viewer.mainViewport.camera){
  428. var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
  429. end = new THREE.Vector3(pointer.x, pointer.y, 1).unproject(camera)
  430. var dir = end.sub(origin)
  431. let r = (planeZ - origin.z)/dir.z
  432. let x = r * dir.x + origin.x
  433. let y = r * dir.y + origin.y
  434. return {x,y}
  435. }
  436. Utils.screenPass = new function () {
  437. this.screenScene = new THREE.Scene();
  438. this.screenQuad = new THREE.Mesh(new THREE.PlaneBufferGeometry(2, 2, 1));
  439. this.screenQuad.material.depthTest = true;
  440. this.screenQuad.material.depthWrite = true;
  441. this.screenQuad.material.transparent = true;
  442. this.screenScene.add(this.screenQuad);
  443. this.camera = new THREE.Camera();
  444. this.render = function (renderer, material, target, composer) {
  445. this.screenQuad.material = material;
  446. if (typeof target === 'undefined') {
  447. (composer || renderer).render(this.screenScene, this.camera);
  448. } else {
  449. let oldTarget = renderer.getRenderTarget()
  450. renderer.setRenderTarget(target);
  451. //renderer.clear(); //有时候不能clear,如renderBG后再
  452. (composer || renderer).render(this.screenScene, this.camera);
  453. renderer.setRenderTarget(oldTarget)
  454. }
  455. };
  456. }();
  457. //add
  458. Utils.computePointcloudsBound = function(pointclouds){
  459. var boundingBox = new THREE.Box3();
  460. pointclouds.forEach(pointcloud=>{
  461. pointcloud.updateBound()
  462. boundingBox.union(pointcloud.bound2)
  463. })
  464. var boundSize = boundingBox.getSize(new THREE.Vector3)
  465. var center = boundingBox.getCenter(new THREE.Vector3)
  466. return {boundSize, center, boundingBox}
  467. }
  468. Utils.convertScreenPositionToNDC = function(pointer, mouse, width, height) {
  469. return pointer = pointer || new THREE.Vector2,
  470. pointer.x = mouse.x / width * 2 - 1,
  471. pointer.y = 2 * -(mouse.y / height) + 1,
  472. pointer
  473. }
  474. Utils.convertNDCToScreenPosition = function(pointer, mouse, width, height) {
  475. return mouse = mouse || new THREE.Vector2,
  476. mouse.x = Math.round((pointer.x + 1 ) / 2 * width),
  477. mouse.y = Math.round(-(pointer.y - 1 ) / 2 * height),
  478. mouse
  479. }
  480. Utils.getOrthoCameraMoveVec = function(pointerDelta, camera ){//获取当camera为Ortho型时 屏幕点1 到 屏幕点2 的三维距离
  481. let cameraViewWidth = camera.right / camera.zoom
  482. let cameraViewHeight = camera.top / camera.zoom
  483. let moveVec = new THREE.Vector3;
  484. moveVec.set( pointerDelta.x * cameraViewWidth , pointerDelta.y * cameraViewHeight , 0).applyQuaternion(camera.quaternion)
  485. return moveVec
  486. }
  487. Utils.VectorFactory = {
  488. fromArray : function(t) {
  489. if (t) {
  490. if (t.length < 2 || t.length > 3)
  491. console.error("Wrong number of ordinates for a point!");
  492. return 3 === t.length ? (new THREE.Vector3).fromArray(t) : (new THREE.Vector2).fromArray(t)
  493. }
  494. },
  495. fromArray3 : function(t) {
  496. if (t) {
  497. if (3 !== t.length)
  498. console.error("Wrong number of ordinates for a point!");
  499. return (new THREE.Vector3).fromArray(t)
  500. }
  501. },
  502. fromArray2 : function(t) {
  503. if (t) {
  504. if (2 !== t.length)
  505. console.error("Wrong number of ordinates for a point!");
  506. return (new THREE.Vector2).fromArray(t)
  507. }
  508. },
  509. toString : function(t) {
  510. return t.x.toFixed(8) + "," + t.y.toFixed(8) + "," + t.z.toFixed(3)
  511. }
  512. }
  513. Utils.QuaternionFactory = {
  514. rot90 : (new THREE.Quaternion).setFromAxisAngle(new THREE.Vector3(0,0,1), THREE.Math.degToRad(-90)),
  515. fromArray : function(t) {
  516. if (t) {
  517. if (4 !== t.length)
  518. console.error("Wrong number of ordinates for a quaternion!");
  519. return new THREE.Quaternion(t[1],t[2],t[3],t[0]).multiply(this.rot90)
  520. }
  521. }
  522. ,
  523. toArray : function(t) {
  524. if (t) {
  525. var e = t.clone().multiply(a).toArray();
  526. return [e[3], e[0], e[1], e[2]]
  527. }
  528. }
  529. ,
  530. fromLonLat : function(t) {
  531. if (t)
  532. return (new THREE.Quaternion).setFromEuler(new THREE.Euler(t.lon,t.lat,0))
  533. }
  534. ,
  535. toLonLat : function(t) {
  536. if (t) {
  537. var e = (new THREE.Euler).setFromQuaternion(t);
  538. return {
  539. lon: e.x,
  540. lat: e.y
  541. }
  542. }
  543. }
  544. }
  545. Utils.datasetPosTransform = function(o={}){
  546. let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
  547. let tranMatrix
  548. if(pointcloud){
  549. if(Potree.settings.editType == 'merge'){
  550. tranMatrix = o.fromDataset ? pointcloud.matrixWorld : new THREE.Matrix4().copy(pointcloud.matrixWorld).invert()
  551. }else{
  552. tranMatrix = o.fromDataset ? pointcloud.transformMatrix : pointcloud.transformInvMatrix
  553. }
  554. }else{
  555. if(Potree.settings.intersectOnObjs){
  556. let object = o.object || viewer.objs.children.find(e=>e.dataset_id == o.datasetId)
  557. if(object){
  558. tranMatrix = o.fromDataset ? object.matrixWorld : new THREE.Matrix4().copy(object.matrixWorld).invert()
  559. }
  560. }
  561. }
  562. if(tranMatrix){
  563. return (new THREE.Vector3).copy(o.position).applyMatrix4(tranMatrix)
  564. }else{
  565. if(o.datasetId != void 0){
  566. console.error(`datasetPosTransform找不到datasetId为${o.datasetId}的数据集或模型,请检查数据, 模型未创建或删除`)
  567. //很可能是旧的热点,需要删除
  568. }
  569. }
  570. }
  571. Utils.datasetRotTransform = function(o={}){
  572. let object = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
  573. || o.object || viewer.objs.children.find(e=>e.dataset_id == o.datasetId)
  574. if(object){
  575. var matrix, newMatrix, result
  576. if(o.rotation){
  577. matrix = new THREE.Matrix4().makeRotationFromEuler(o.rotation)
  578. }else if(o.quaternion){
  579. matrix = new THREE.Matrix4().makeRotationFromQuaternion(o.quaternion)
  580. }else if(o.matrix){
  581. matrix = o.matrix.clone()
  582. }else{
  583. return
  584. }
  585. let rotateMatrix = o.fromDataset ? object.rotateMatrix : object.rotateInvMatrix
  586. if(!rotateMatrix){
  587. rotateMatrix = new THREE.Matrix4().makeRotationFromEuler(object.rotation) //如果是没有漫游点的模型,在此临时获取一个,但和有漫游点的比会有所不同,因为没有初始旋转(如转90度)
  588. if(o.toDataset){
  589. rotateMatrix.invert()
  590. }
  591. }
  592. newMatrix = new THREE.Matrix4().multiplyMatrices(rotateMatrix, matrix )
  593. if(o.getRotation){
  594. result = new THREE.Euler().setFromRotationMatrix(newMatrix)
  595. }else if(o.getQuaternion){
  596. result = new THREE.Quaternion().setFromRotationMatrix(newMatrix)
  597. }else if(o.getMatrix){
  598. result = newMatrix
  599. }
  600. return result
  601. }
  602. }
  603. Utils.isInsideFrustum = function(bounding, camera){// bounding是否在视野范围内有可见部分(视野就是一个锥状box)
  604. let frustumMatrix = new THREE.Matrix4
  605. frustumMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
  606. let frustum = new THREE.Frustum();
  607. frustum.setFromProjectionMatrix(frustumMatrix)
  608. if(bounding instanceof THREE.Sphere){
  609. return frustum.intersectsSphere(bounding)
  610. }else{
  611. return frustum.intersectsBox(bounding)
  612. }
  613. }
  614. Utils.isIntersectBox = function(object, boxMatrix){//object是否有在box中的部分。 object可以是点或者bounding, box原为1*1*1,但可能形变
  615. //let frustum = new THREE.Frustum();
  616. //frustum.setFromProjectionMatrix(boxMatrixInverse) --错
  617. let px = new THREE.Vector3(+0.5, 0, 0).applyMatrix4(boxMatrix);
  618. let nx = new THREE.Vector3(-0.5, 0, 0).applyMatrix4(boxMatrix);
  619. let py = new THREE.Vector3(0, +0.5, 0).applyMatrix4(boxMatrix);
  620. let ny = new THREE.Vector3(0, -0.5, 0).applyMatrix4(boxMatrix);
  621. let pz = new THREE.Vector3(0, 0, +0.5).applyMatrix4(boxMatrix);
  622. let nz = new THREE.Vector3(0, 0, -0.5).applyMatrix4(boxMatrix);
  623. let pxN = new THREE.Vector3().subVectors(nx, px).normalize();
  624. let nxN = pxN.clone().multiplyScalar(-1);
  625. let pyN = new THREE.Vector3().subVectors(ny, py).normalize();
  626. let nyN = pyN.clone().multiplyScalar(-1);
  627. let pzN = new THREE.Vector3().subVectors(nz, pz).normalize();
  628. let nzN = pzN.clone().multiplyScalar(-1);
  629. let pxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pxN, px);
  630. let nxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nxN, nx);
  631. let pyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pyN, py);
  632. let nyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nyN, ny);
  633. let pzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pzN, pz);
  634. let nzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nzN, nz);
  635. let frustum = new THREE.Frustum(pxPlane, nxPlane, pyPlane, nyPlane, pzPlane, nzPlane);
  636. if(object instanceof THREE.Box3){
  637. var boxBound = new THREE.Box3(
  638. new THREE.Vector3(-0.5,-0.5,-0.5), new THREE.Vector3(0.5,0.5,0.5),
  639. ).applyMatrix4(boxMatrix) //large boundingbox
  640. if(!object.intersectsBox(boxBound))return
  641. return frustum.intersectsBox(object) //根据该函数, 若存在某个plane在box上的对应点都在plane背面,则不相交. 可得知在box构成的frustum倾斜时不准确,不相交也判断为相交,甚至不如bound相交准确。所以前面加步骤排除下,但仍不完全准确。(可在裁剪中将box放置到数据集上方旋转下校验)
  642. }else if(object instanceof Array){//点合集, 只能粗略计算下
  643. let sphere = new THREE.Sphere()
  644. sphere.setFromPoints(object)
  645. return this.isIntersectBox(sphere, boxMatrix)
  646. }else if(object instanceof THREE.Sphere){
  647. return frustum.intersectsSphere(object)
  648. }else if(object instanceof THREE.Vector3){
  649. return frustum.containsPoint(object)
  650. }else if(object instanceof THREE.Matrix4){//第一个参数如果和第二个参数一样都是box的worldMatrix
  651. }
  652. /* containsPoint: ƒ containsPoint( point )
  653. intersectsBox: ƒ intersectsBox( box )
  654. intersectsObject: ƒ intersectsObject( object )//geo
  655. intersectsSphere: ƒ intersectsSphere( sphere )
  656. intersectsSprite: ƒ intersectsSprite( sprite )
  657. */
  658. }
  659. Utils.getIntersect = function (camera, meshes, pointer, raycaster) {
  660. //获取鼠标和meshes交点
  661. if(!raycaster){//getMouseIntersect
  662. camera.updateMatrixWorld()
  663. raycaster = new THREE.Raycaster()
  664. var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
  665. end = new THREE.Vector3(pointer.x, pointer.y, 1).unproject(camera)
  666. var dir = end.sub(origin).normalize()
  667. raycaster.set(origin, dir)
  668. }
  669. meshes.forEach(e=>{
  670. raycaster.layers.enable(math.getBaseLog(2,e.layers.mask))
  671. })
  672. var n = raycaster.intersectObjects(meshes)
  673. if (0 === n.length) return null
  674. return n[0]
  675. }
  676. Utils.addOrRemoveDefine = function(material, defineName, type, value=''){
  677. let defines = material.defines
  678. if(type == 'add'){
  679. if(defines[defineName] != void 0 && defines[defineName] == value)return
  680. defines[defineName] = value
  681. }else{
  682. if(defines[defineName] == void 0)return;
  683. delete defines[defineName]
  684. }
  685. material.needsUpdate = true;
  686. }
  687. Utils.makeTexDontResize = function(map){//避免贴图因非2的次方而缩小。小心使用
  688. if(!map || !map.image){
  689. return console.log('!map || !map.image', map, map&&map.image)
  690. }
  691. if(THREE.Math.isPowerOfTwo(map.image.width ) && THREE.Math.isPowerOfTwo(map.image.height ))return
  692. map.wrapS = map.wrapT = THREE.ClampToEdgeWrapping; //原默认 RepeatWrapping
  693. map.minFilter = THREE.LinearFilter; // or THREE.NearestFilter 原默认 LinearMipmapLinearFilter
  694. map.generateMipmaps = false
  695. map.needsUpdate = true
  696. }
  697. Utils.updateVisible = function(object, reason, ifShow, level=0, type, needRender=true){//当所有加入的条件都不为false时才显示. reason='force'一般是强制、临时的
  698. if(!object.unvisibleReasons) object.unvisibleReasons = []; //如果length>0代表不可见
  699. if(!object.visibleReasons) object.visibleReasons = []; //在同级时,优先可见
  700. var update = function(){
  701. //先按从高到低的level排列
  702. object.unvisibleReasons = object.unvisibleReasons.sort((a,b)=>b.level-a.level)
  703. object.visibleReasons = object.visibleReasons.sort((a,b)=>b.level-a.level)
  704. var maxVisiLevel = object.visibleReasons[0] ? object.visibleReasons[0].level : -1
  705. var maxunVisiLevel = object.unvisibleReasons[0] ? object.unvisibleReasons[0].level : -1
  706. var shouldVisi = maxVisiLevel >= maxunVisiLevel
  707. var visiBefore = object.visible
  708. if(visiBefore != shouldVisi){
  709. object.visible = shouldVisi
  710. object.dispatchEvent({
  711. type: 'isVisible',
  712. visible: shouldVisi,
  713. reason,
  714. })
  715. needRender && viewer.dispatchEvent('content_changed')
  716. }
  717. }
  718. if(ifShow){
  719. var index = object.unvisibleReasons.findIndex(e=>e.reason == reason)
  720. if(index > -1){
  721. type = 'cancel'
  722. object.unvisibleReasons.splice(index, 1);
  723. }
  724. if(type == 'add' ){
  725. if(!object.visibleReasons.some(e=>e.reason == reason)){
  726. object.visibleReasons.push({reason,level})
  727. }
  728. }
  729. }else{
  730. var index = object.visibleReasons.findIndex(e=>e.reason == reason)
  731. if(index > -1){
  732. type = 'cancel'
  733. object.visibleReasons.splice(index, 1);
  734. }
  735. if(type != 'cancel' ){
  736. if(!object.unvisibleReasons.some(e=>e.reason == reason)){
  737. object.unvisibleReasons.push({reason,level})
  738. }
  739. }
  740. }
  741. update()
  742. }
  743. /*
  744. 复杂案例: 如果物体默认隐藏, 当符合任何一个其他条件时可见,则可:
  745. Potree.Utils.updateVisible(this, "default", false, 0 ) //默认隐藏
  746. Potree.Utils.updateVisible(this, 条件名, ifShow, 1, ifShow?'add':'cancel' ) //其他的条件
  747. */
  748. Utils.getObjVisiByReason = function(object,reason){//获取在某条件下是否可见. 注: 用户在数据集选择可不可见为"datasetSelection"
  749. if(object.visible)return true
  750. else{
  751. return !object.unvisibleReasons || !object.unvisibleReasons.some(e=>e.reason == reason)
  752. }
  753. }
  754. Utils.setCameraLayers = function(camera, enableLayers, extraEnableLayers=[]){//add
  755. camera.layers.disableAll()
  756. enableLayers.concat(extraEnableLayers).forEach(e=>{
  757. let layer = Potree.config.renderLayers[e]
  758. if(layer == void 0){
  759. console.error('setCameraLayer没找到layer!', e);
  760. return
  761. }
  762. camera.layers.enable(layer)
  763. })
  764. }
  765. Utils.setObjectLayers = function(object, layerName){//add
  766. let layer = Potree.config.renderLayers[layerName]
  767. if(layer == void 0){
  768. console.error('setObjectLayers没找到layer!',layerName);
  769. return
  770. }
  771. object.traverse(e=>{
  772. e.layers.set(layer)
  773. })
  774. }
  775. Utils.imgAddText = async (img, text, labelInfo)=>{
  776. let label = new Potree.TextSprite(Object.assign({//如果直接在canvas里写字,要另外写很多和canvas.drawText有关的,所以还是借助textSprite吧
  777. backgroundColor: { r: 0, g: 0, b: 0, a: 0 },
  778. textColor: { r: 255, g: 255, b: 255, a: 1 },
  779. margin:{x:3,y:3},
  780. renderOrder: 50, fontsize : 20,
  781. text,
  782. },labelInfo))
  783. let labelImg = new Image
  784. labelImg.src = label.sprite.material.map.image.toDataURL('image/png')
  785. return new Promise((resolve,reject)=>{
  786. labelImg.onload = ()=>{
  787. if(labelInfo.horizonCenter){//水平居中(对img来说)
  788. labelInfo.leftRatioToImg = 0.5 - (labelImg.width / img.width)/2
  789. }
  790. let result = Common.imgAddLabel(img,labelImg,labelInfo)
  791. label.dispose()
  792. resolve(result)
  793. }
  794. })
  795. }
  796. Utils.combineImgs = async (imgs, compressRatio, width, height)=>{//拼合图片,顺序从上到下从左到右, 每张图大小不一定一致,但同列的宽一致,同行宽一致
  797. return new Promise((resolve,reject)=>{
  798. let item = imgs[0][0]
  799. let wc=imgs.length, hc=imgs[0].length, loadCount = 0, amount = wc * hc
  800. width = width || imgs.reduce((w,c)=>w + c[0].width, 0), //相加得到的可能比想要得到的大几个像素,之后会重叠
  801. height = height || imgs[0].reduce((w,c)=>w + c.height, 0)
  802. let canvas = document.createElement('canvas')
  803. canvas.width = width
  804. canvas.height = height
  805. let context = canvas.getContext('2d')
  806. for(let i=0;i<wc;i++){
  807. for(let j=0;j<hc;j++){
  808. let img = new Image
  809. img.src = imgs[i][j].dataUrl
  810. img.index = {i,j}
  811. img.onload = ()=>{
  812. loadCount++
  813. context.drawImage(img, img.index.i * img.width, img.index.j * img.height, img.width, img.height)
  814. if(loadCount == amount){
  815. var dataUrl = canvas.toDataURL('image/png',compressRatio)
  816. context.clearRect(0,0,width,height)
  817. resolve(dataUrl)
  818. }
  819. }
  820. }
  821. }
  822. })
  823. }
  824. BinaryLoader.prototype.load = function(node, callback){//解析点云
  825. if (node.loaded) {
  826. return;
  827. }
  828. let url = node.getURL();
  829. if (this.version.equalOrHigher('1.4')) {
  830. url += '.bin';
  831. }
  832. url += '?m='+node.pcoGeometry.timeStamp //add
  833. let xhr = XHRFactory.createXMLHttpRequest();
  834. xhr.open('GET', url, true);
  835. xhr.responseType = 'arraybuffer';
  836. xhr.overrideMimeType('text/plain; charset=x-user-defined');
  837. xhr.onreadystatechange = () => {
  838. if (xhr.readyState === 4) {
  839. if((xhr.status === 200 || xhr.status === 0) && xhr.response !== null){
  840. let buffer = xhr.response;
  841. this.parse(node, buffer, callback);
  842. } else {
  843. node.loadFailed = 'status:'+xhr.status+",url:"+url
  844. Potree.numNodesLoading--;
  845. //console.error(`Failed to load file! HTTP status: ${xhr.status}, file: ${url}`);
  846. throw new Error(`Failed to load file! HTTP status: ${xhr.status}, file: ${url}`);
  847. }
  848. }
  849. };
  850. try {
  851. xhr.send(null);
  852. } catch (e) {
  853. node.loadFailed = 'catchError'
  854. Potree.numNodesLoading--;
  855. console.error('加载点云node出错 ', url, e );
  856. }
  857. }
  858. PointAttribute.RGBA_PACKED = new PointAttribute("rgba", PointAttributeTypes.DATA_TYPE_INT8, 4);
  859. PointAttribute.COLOR_PACKED = PointAttribute.RGBA_PACKED;
  860. PointAttribute.INTENSITY = new PointAttribute("intensity", PointAttributeTypes.DATA_TYPE_UINT16, 1);
  861. PointAttribute.CLASSIFICATION = new PointAttribute("classification", PointAttributeTypes.DATA_TYPE_UINT8, 1);
  862. PointAttribute.GPS_TIME = new PointAttribute("gps-time", PointAttributeTypes.DATA_TYPE_DOUBLE, 1);
  863. ProfileWindow.prototype.initTHREE = function(){
  864. this.renderer = new THREE.WebGLRenderer({alpha: true, premultipliedAlpha: false});
  865. this.renderer.setClearColor(0x000000, 0);
  866. this.renderer.setSize(10, 10);
  867. this.renderer.autoClear = false;
  868. this.renderArea.append($(this.renderer.domElement));
  869. this.renderer.domElement.tabIndex = '2222';
  870. $(this.renderer.domElement).css('width', '100%');
  871. $(this.renderer.domElement).css('height', '100%');
  872. {
  873. let gl = this.renderer.getContext();
  874. if(gl.createVertexArray == null){
  875. let extVAO = gl.getExtension('OES_vertex_array_object');
  876. if(!extVAO){
  877. throw new Error("OES_vertex_array_object extension not supported");
  878. }
  879. gl.createVertexArray = extVAO.createVertexArrayOES.bind(extVAO);
  880. gl.bindVertexArray = extVAO.bindVertexArrayOES.bind(extVAO);
  881. }
  882. }
  883. this.camera = new THREE.OrthographicCamera(-1000, 1000, 1000, -1000, -1000, 1000);
  884. this.camera.up.set(0, 0, 1);
  885. this.camera.rotation.order = "ZXY";
  886. this.camera.rotation.x = Math.PI / 2.0;
  887. this.scene = new THREE.Scene();
  888. this.profileScene = new THREE.Scene();
  889. let sg = new THREE.SphereGeometry(1, 16, 16);
  890. let sm = new THREE.MeshNormalMaterial();
  891. this.pickSphere = new THREE.Mesh(sg, sm);
  892. this.scene.add(this.pickSphere);
  893. this.viewerPickSphere = new THREE.Mesh(sg, sm);
  894. }
  895. //Potree_update_visibility
  896. Potree.updatePointClouds = function(pointclouds,camera, areaSize ){
  897. viewer.addTimeMark('updateClouds','start')
  898. for (let pointcloud of pointclouds) {
  899. let start = performance.now();
  900. for (let profileRequest of pointcloud.profileRequests) {
  901. profileRequest.update();
  902. let duration = performance.now() - start;
  903. if(duration > 5){
  904. break;
  905. }
  906. }
  907. let duration = performance.now() - start;
  908. }
  909. let result = Potree.updateVisibility(pointclouds, camera, areaSize );
  910. for (let pointcloud of pointclouds) {
  911. //pointcloud.updateMaterial(pointcloud.material, pointcloud.visibleNodes, camera, renderer);//转移到渲染时
  912. pointcloud.updateVisibleBounds();
  913. }
  914. Potree.lru.freeMemory();//即Potree.lru 能看到所有在加载的node
  915. viewer.addTimeMark('updateClouds','end')
  916. return result;
  917. };
  918. Potree.updateVisibilityStructures = function(pointclouds, camera, areaSize) {
  919. let frustums = {};
  920. let camObjPositions = {}
  921. let camObjDirs = {} //add
  922. let priorityQueue = new BinaryHeap(function (x) { return -x.weight /* 1 / x.weight; */ });//二叉堆。 改,之前的weight不支持负数
  923. viewer.addTimeMark('visiStructure','start')
  924. //camera.updateMatrixWorld();
  925. let viewI = camera.matrixWorldInverse;
  926. let proj = camera.projectionMatrix;
  927. let view = camera.matrixWorld;
  928. let projViewI = new THREE.Matrix4().multiply(proj).multiply(viewI)
  929. /* let list = pointclouds // stopWhenAllUsed = !viewer.lastFrameChanged
  930. let min = 5, max = Math.max(20 , Math.round(list.length / 10 ))
  931. let result = Common.batchHandling.getSlice('pcGetFrustum', list, { min,max, durBound1: 3, durBound2: 10} ) //iphonex稳定后大概在7-10。
  932. */
  933. for (let i = 0; i < pointclouds.length; i++) {
  934. let pointcloud = pointclouds[i];
  935. if (!pointcloud.initialized()) {
  936. continue;
  937. }
  938. /* let info = history.get(pointcloud)
  939. if() */
  940. pointcloud.numVisibleNodes = 0;
  941. pointcloud.numVisiblePoints = 0;
  942. pointcloud.deepestVisibleLevel = 0;
  943. pointcloud.visibleNodes = [];
  944. pointcloud.visibleGeometry = [];
  945. // 因漫游模式而隐藏的话 依旧需要加入visibleNodes,因为pick需要
  946. /* if (pointcloud.visible && pointcloud.root !== null) {
  947. priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
  948. } */
  949. if (pointcloud.visible || !pointcloud.hasDepthTex && pointcloud.unvisibleReasons && pointcloud.unvisibleReasons.length == 1 && pointcloud.unvisibleReasons[0].reason == 'displayMode' && pointcloud.root !== null) {//改 visible ->
  950. priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
  951. }else{
  952. continue
  953. }
  954. // frustum in object space
  955. let frustum = new THREE.Frustum();
  956. let world = pointcloud.matrixWorld;
  957. // use close near plane for frustum intersection
  958. /* let frustumCam = camera.clone();
  959. frustumCam.zoom = camera.zoom //add
  960. frustumCam.near = Math.min(camera.near, 0.1);
  961. frustumCam.updateProjectionMatrix(); */ //----没用到frustumCam,删了
  962. let fm = new THREE.Matrix4().multiply(projViewI).multiply(world);
  963. frustum.setFromProjectionMatrix(fm);
  964. frustums[i] = frustum //frustums.push(frustum);
  965. // camera position in object space
  966. let worldI = pointcloud.matrixWorldInverse
  967. let camMatrixObject = new THREE.Matrix4().multiply(worldI).multiply(view);//假设点云无变换的话,相机相对于点云的变换矩阵
  968. let camObjPos = new THREE.Vector3().setFromMatrixPosition(camMatrixObject);
  969. camObjPositions[i] = camObjPos//camObjPositions.push(camObjPos);
  970. let quaternion = new THREE.Quaternion().setFromRotationMatrix(camMatrixObject)
  971. let camDir = (new THREE.Vector3(0,0,-1)).applyQuaternion(quaternion)
  972. camObjDirs[i] = camDir
  973. // hide all previously visible nodes
  974. // if(pointcloud.root instanceof PointCloudOctreeNode){
  975. // pointcloud.hideDescendants(pointcloud.root.sceneNode);
  976. // }
  977. if (pointcloud.root.isTreeNode()) {
  978. pointcloud.hideDescendants(pointcloud.root.sceneNode);
  979. }
  980. for (let j = 0; j < pointcloud.boundingBoxNodes.length; j++) {
  981. pointcloud.boundingBoxNodes[j].visible = false;
  982. }
  983. }
  984. viewer.addTimeMark('visiStructure','end')
  985. return {
  986. 'frustums': frustums,
  987. 'camObjPositions': camObjPositions,
  988. 'priorityQueue': priorityQueue,
  989. camObjDirs
  990. };
  991. };
  992. Potree.updateVisibility = function(pointclouds, camera, areaSize){
  993. let numVisibleNodes = 0;
  994. let numVisiblePoints = 0;
  995. let numVisiblePointsInPointclouds = new Map(pointclouds.map(pc => [pc, 0]));
  996. let visibleNodes = [];
  997. let visibleGeometry = [];
  998. let unloadedGeometry = [];
  999. let lowestSpacing = Infinity;
  1000. // calculate object space frustum and cam pos and setup priority queue
  1001. let s = Potree.updateVisibilityStructures(pointclouds, camera, areaSize);//得到相机可见范围
  1002. let frustums = s.frustums;
  1003. let camObjPositions = s.camObjPositions;
  1004. let priorityQueue = s.priorityQueue;
  1005. let camObjDirs = s.camObjDirs
  1006. let loadedToGPUThisFrame = 0;
  1007. let domWidth = areaSize.x; //renderer.domElement.clientWidth;
  1008. let domHeight = areaSize.y;//renderer.domElement.clientHeight;
  1009. let fov = (camera.fov * Math.PI) / 180;
  1010. let slope = Math.tan(fov / 2);
  1011. let projFactor0 = (0.5 * domHeight) / slope ;
  1012. // check if pointcloud has been transformed
  1013. // some code will only be executed if changes have been detected
  1014. if(!Potree._pointcloudTransformVersion){
  1015. Potree._pointcloudTransformVersion = new Map();
  1016. }
  1017. let pointcloudTransformVersion = Potree._pointcloudTransformVersion;
  1018. for(let pointcloud of pointclouds){
  1019. if(pointcloud.hasDepthTex ? !pointcloud.visible : !Potree.Utils.getObjVisiByReason(pointcloud, 'datasetSelection')){//改 visible ->
  1020. continue;
  1021. }
  1022. //if(!pointcloud.visible) continue
  1023. pointcloud.updateMatrixWorld();
  1024. if(!pointcloudTransformVersion.has(pointcloud)){
  1025. pointcloudTransformVersion.set(pointcloud, {number: 0, transform: pointcloud.matrixWorld.clone()});
  1026. }else{
  1027. let version = pointcloudTransformVersion.get(pointcloud);
  1028. if(!version.transform.equals(pointcloud.matrixWorld)){
  1029. version.number++;
  1030. version.transform.copy(pointcloud.matrixWorld);
  1031. pointcloud.dispatchEvent({
  1032. type: "transformation_changed",
  1033. target: pointcloud
  1034. });
  1035. }
  1036. }
  1037. }
  1038. while (priorityQueue.size() > 0) {
  1039. let element = priorityQueue.pop(); //取出权重最大的一个
  1040. let node = element.node;
  1041. let parent = element.parent;
  1042. let pointcloud = pointclouds[element.pointcloud];
  1043. // { // restrict to certain nodes for debugging
  1044. // let allowedNodes = ["r", "r0", "r4"];
  1045. // if(!allowedNodes.includes(node.name)){
  1046. // continue;
  1047. // }
  1048. // }
  1049. let box = node.getBoundingBox();
  1050. let frustum = frustums[element.pointcloud];
  1051. let camObjPos = camObjPositions[element.pointcloud];
  1052. if(!frustum) continue //add
  1053. let camObjDir = camObjDirs[element.pointcloud];
  1054. let insideFrustum = frustum.intersectsBox(box);
  1055. let maxLevel = pointcloud.maxLevel == void 0 ? Infinity : pointcloud.maxLevel;
  1056. let minLevel = pointcloud.minLevel == void 0 ? 0 : pointcloud.minLevel; //add
  1057. let level = node.getLevel();
  1058. let visible = insideFrustum;
  1059. visible = visible && !(numVisiblePoints + node.getNumPoints() > Potree.pointBudget);
  1060. visible = visible && !(numVisiblePointsInPointclouds.get(pointcloud) + node.getNumPoints() > pointcloud.pointBudget); // pointcloud.pointBudget一直是Infinity
  1061. visible = visible && level <= maxLevel /* && level >= minLevel */ ; //< 改为 <=
  1062. //visible = visible || node.getLevel() <= 2;
  1063. let pcWorldInverse = pointcloud.matrixWorld.clone().invert();
  1064. /* let m = pcWorldInverse.elements
  1065. let pcWorldInvM3 = new THREE.Matrix3().set(m[0],m[4],m[12],m[1],m[5],m[13],m[3],m[7],m[15]) //去掉z的
  1066. */
  1067. //pointcloud.pcMatrix3 = new THREE.Matrix3().set(m[0],m[4],m[12],m[1],m[5],m[13],m[3],m[7],m[15]) //去掉z的
  1068. let intersectBox = (clipBox)=>{
  1069. let toPCObject = pcWorldInverse.clone().multiply(clipBox.box.matrixWorld); //box乘上点云逆矩阵
  1070. return Potree.Utils.isIntersectBox(box, toPCObject)
  1071. }
  1072. //改 总共两种box : 可见和不可见(都是并集)
  1073. let clipBoxes_in = pointcloud.material.clipBoxes_in;
  1074. let clipBoxes_out = pointcloud.material.clipBoxes_out;
  1075. let bigClipInBox = pointcloud.material.bigClipInBox
  1076. if(visible && bigClipInBox){//不在剪裁下载的框内
  1077. if(!intersectBox(bigClipInBox)){
  1078. visible = false;
  1079. }
  1080. }
  1081. if(visible && clipBoxes_in.length > 0){//当有可见box时,需要在任一可见box内才可见
  1082. let visi = false;
  1083. for(let i = 0, length=clipBoxes_in.length; i < length; i++){
  1084. if(intersectBox(clipBoxes_in[i])){
  1085. visi = true;
  1086. break;
  1087. }
  1088. }
  1089. if(!visi){
  1090. visible = false
  1091. }
  1092. }
  1093. //outside不做处理。因为node必须完全在clipBox内才能完全隐藏,而这里的intersect只能识别出部分在clipBox内。因而只能说明不在任意一个box内绝对可见,没有意义,这里需要找出不可见的。
  1094. if(visible){
  1095. let prism = pointcloud.material.activeAttributeName == 'prismHeight' && pointcloud.material.prisms && pointcloud.material.prisms.find(e=>e.computing)
  1096. if(prism){
  1097. let bound = box.clone().applyMatrix4(pointcloud.matrixWorld)
  1098. if(bound.intersectsBox(prism.prismBound)){
  1099. /* //node box是否包含points中的一个点
  1100. let box2 = new THREE.Box2().copy(box)
  1101. let points2d = prisms.points.map(e=>new THREE.Vector2().copy(e).applyMatrix3(pcWorldInvM3))
  1102. let intersect = points2d.some(e=>{
  1103. return box2.containsPoint(e)
  1104. })
  1105. if(!intersect){
  1106. //或者多边形中是否包含node box中的一个点
  1107. intersect = [
  1108. new THREE.Vector2(box.min.x, box.min.y),
  1109. new THREE.Vector2(box.max.x, box.max.y),
  1110. new THREE.Vector2(box.min.x, box.max.y),
  1111. new THREE.Vector2(box.max.x, box.min.y),
  1112. ].some(e=>{
  1113. if(math.isPointInArea(points2d, null, e) ){
  1114. return true
  1115. }
  1116. })
  1117. //z是不是在外层已经判断好了?
  1118. if(!intersect){
  1119. visible = false
  1120. }
  1121. } */
  1122. //会有两个互不包含点但是交叉了的情况,所以就不仔细判断了(如横竖两个矩形构成十字架)
  1123. }else visible = false
  1124. }
  1125. }
  1126. if (node.spacing) {
  1127. lowestSpacing = Math.min(lowestSpacing, node.spacing);
  1128. } else if (node.geometryNode && node.geometryNode.spacing) {
  1129. lowestSpacing = Math.min(lowestSpacing, node.geometryNode.spacing);
  1130. }
  1131. if (numVisiblePoints + node.getNumPoints() > Potree.pointBudget) {
  1132. viewer.dispatchEvent({type:'overPointBudget', restQueueSize: priorityQueue.size(), numVisiblePoints} )
  1133. break;
  1134. }
  1135. if (!visible) {
  1136. continue;
  1137. }
  1138. // TODO: not used, same as the declaration?
  1139. // numVisibleNodes++;
  1140. numVisiblePoints += node.getNumPoints();
  1141. let numVisiblePointsInPointcloud = numVisiblePointsInPointclouds.get(pointcloud);
  1142. numVisiblePointsInPointclouds.set(pointcloud, numVisiblePointsInPointcloud + node.getNumPoints());
  1143. pointcloud.numVisibleNodes++;
  1144. pointcloud.numVisiblePoints += node.getNumPoints();
  1145. if (node.isGeometryNode() && (!parent || parent.isTreeNode())) {
  1146. if (node.isLoaded() && loadedToGPUThisFrame < 2) {
  1147. node = pointcloud.toTreeNode(node, parent);
  1148. loadedToGPUThisFrame++;
  1149. } else {
  1150. //console.log('unloadedGeometry',node)
  1151. unloadedGeometry.push({pointcloud,node}); //加载点云。虽然还没加载,但也计入了visibleNodes,只是无children,numPoints=0
  1152. visibleGeometry.push(node);
  1153. }
  1154. }
  1155. if (node.isTreeNode()) {
  1156. Potree.lru.touch(node.geometryNode);//在缓存中计入点云
  1157. node.sceneNode.visible = true;
  1158. node.sceneNode.material = pointcloud.material;
  1159. /* level >= minLevel && */visibleNodes.push(node);
  1160. /* level >= minLevel && */pointcloud.visibleNodes.push(node);
  1161. //if(Potree.settings.sortNodesDis){//add
  1162. if(pointcloud.material.opacity < 1 && Potree.settings.notAdditiveBlending ){
  1163. let nodePos = node.getBoundingSphere().center;
  1164. let toCam = new THREE.Vector3().subVectors(nodePos, camObjPos)
  1165. toCam.projectOnVector(camObjDir)
  1166. node.disSqToCamZ_ = toCam.lengthSq()
  1167. }
  1168. if(node._transformVersion === undefined){
  1169. node._transformVersion = -1;
  1170. }
  1171. let transformVersion = pointcloudTransformVersion.get(pointcloud);
  1172. if(node._transformVersion !== transformVersion.number){
  1173. node.sceneNode.updateMatrix();
  1174. //node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);
  1175. node.sceneNode.matrixWorld.multiplyMatrices(pointcloud.matrixWorld, node.sceneNode.matrix);
  1176. node._transformVersion = transformVersion.number;
  1177. }
  1178. if (pointcloud.showBoundingBox && !node.boundingBoxNode && node.getBoundingBox) {
  1179. let colorHue = level / (maxLevel+1)
  1180. let s = 0.1 + level / (maxLevel+1)
  1181. let color = (new THREE.Color()).setHSL(colorHue, s, s)
  1182. let boxHelper = new Box3Helper(node.getBoundingBox(),color);
  1183. boxHelper.matrixAutoUpdate = false;
  1184. pointcloud.boundingBoxNodes.push(boxHelper);
  1185. node.boundingBoxNode = boxHelper;
  1186. node.boundingBoxNode.matrix.copy(pointcloud.matrixWorld);
  1187. } else if (pointcloud.showBoundingBox) {
  1188. node.boundingBoxNode.visible = true;
  1189. node.boundingBoxNode.matrix.copy(pointcloud.matrixWorld);
  1190. } else if (!pointcloud.showBoundingBox && node.boundingBoxNode) {
  1191. node.boundingBoxNode.visible = false;
  1192. }
  1193. // if(node.boundingBoxNode !== undefined && exports.debug.allowedNodes !== undefined){
  1194. // if(!exports.debug.allowedNodes.includes(node.name)){
  1195. // node.boundingBoxNode.visible = false;
  1196. // }
  1197. // }
  1198. }
  1199. // add child nodes to priorityQueue 由近及远、由大及小逐渐加载
  1200. let children = node.getChildren();
  1201. for (let i = 0; i < children.length; i++) {
  1202. let child = children[i];
  1203. let weight = 0;
  1204. if(camera.isPerspectiveCamera){
  1205. let sphere = child.getBoundingSphere();
  1206. let center = sphere.center;
  1207. let dd = sphere.center.distanceToSquared(camObjPos);
  1208. let addPow = 0.2//viewer.mainViewport.view.isFlying() ? 0 : 0.5 //0-0.5,正常原本是0. 数字越大近处加载越快。但会造成远处加载慢甚至因pointBudge限制不加载。 isFlying:漫游时需要尽量加载一下远处的点云
  1209. //addPow *= window.devicePixelRatio //devicePixelRatio高的手机需要优先加载最近的高级点云,减少远处的中高级点云。
  1210. let distance = Math.pow(dd,0.5+addPow)//Math.sqrt(dd); //提高距离权重,为了提高近处加载速度。 某些场景近处加载慢优化明显,如SS-t-cqCAL6rJ5i
  1211. //let attenuateDis = 10;//add
  1212. let radius = sphere.radius;
  1213. let projFactor = projFactor0 / distance
  1214. let screenPixelRadius = radius * projFactor;
  1215. /* if(distance > attenuateDis){
  1216. screenPixelRadius -= (distance - attenuateDis) * Math.sqrt(radius) * projFactor0 * 0.002
  1217. } */
  1218. //screenPixelRadius 和 domHeight 成正比,所以手机横屏后screenPixelRadius会变小。这是正常的,因为vhov不变,相同物体高度在横屏后高度变小,所需要的密度不需要那么高了。但hfov横屏后扩大,所以可见的node范围变大,又增加了一些可见node;只是总体的可见node还是减少了。
  1219. //使用hfov和domWidth计算结果相同。
  1220. if(screenPixelRadius < pointcloud.minimumNodePixelSize / Math.pow(dd,addPow)){ //理论上因手机像素小,更不容易堆叠铺满,minimumNodePixelSize应该除以window.deviceRatio 但会造成加载过多,而内存小
  1221. continue;
  1222. }
  1223. weight = screenPixelRadius;
  1224. if( !sphere.containsPoint(camObjPos) ){ //add 优先加载屏幕中央的点云(手机端缩小离远效果明显,不会那么稀疏)
  1225. let dir = new THREE.Vector3().subVectors(center, camObjPos).normalize()
  1226. let cos = 1+dir.dot(camObjDir) //0-2
  1227. weight *= cos/2//Math.pow(cos,0.5) //幂越高,旁边的容易加载不到,出现缺块 如SS-t-7DUfWAUZ3V
  1228. }
  1229. if(distance - radius < 0){
  1230. weight = Number.MAX_VALUE;
  1231. }
  1232. //如果能得到每个方向上的密度,也就是node数量,密度大的远处少加载,因为被遮挡了显示也没有意义,就好了。
  1233. } else {
  1234. // TODO ortho visibility
  1235. //let bb = child.getBoundingBox();
  1236. let sphere = child.getBoundingSphere();
  1237. //let diagonal = bb.max.clone().sub(bb.min).length();
  1238. const reduce = 0 //0-0.5,正常原本是0.
  1239. if( sphere.radius * /* Math.pow( */camera.zoom/* ,1-reduce) */ < pointcloud.minimumNodePixelSize ){
  1240. continue;
  1241. }
  1242. let distance = sphere.center.distanceToSquared(camObjPos); //先加载中间然后四周
  1243. weight = sphere.radius / distance
  1244. /* let vec = new THREE.Vector3().subVectors(sphere.center, camObjPos)
  1245. let disOnCamDir = vec.dot(camObjDir)
  1246. let vecOnCamDir = camObjDir.clone().multiplyScalar(disOnCamDir)
  1247. let vecSide = new THREE.Vector3().subVectors(vec, vecOnCamDir) //在屏幕上从中心到该node的向量
  1248. let disSide = vecSide.length()
  1249. //weight = sphere.radius / disSide * camera.zoom - disOnCamDir * 2; //如果用除的,ortho的camera离远了的话dis的影响就小了
  1250. weight = sphere.radius / ( disSide * 0.1 + disOnCamDir * 14 )
  1251. */
  1252. //weight = diagonal;
  1253. }
  1254. priorityQueue.push({pointcloud: element.pointcloud, node: child, parent: node, weight: weight}); //貌似好像二叉堆中子节点和父节点没什么关系,就只是为了方便排序层层遍历
  1255. }
  1256. //手机上像素点更小,所以远处感觉会更稀疏
  1257. }// end priority queue loop
  1258. { // update DEM 这是什么
  1259. let maxDEMLevel = 4;
  1260. let candidates = pointclouds.filter(p => (p.generateDEM && p.dem instanceof Potree.DEM));
  1261. for (let pointcloud of candidates) {
  1262. let updatingNodes = pointcloud.visibleNodes.filter(n => n.getLevel() <= maxDEMLevel);
  1263. pointcloud.dem.update(updatingNodes);
  1264. }
  1265. }
  1266. unloadedGeometry = unloadedGeometry.filter(e=>!e.loadFailed) //过滤加载失败的,否则有失败的就无法发送加载完成
  1267. if(unloadedGeometry.length){//加载点云
  1268. let idleCount = Common.getBestCountFPS('unloadedGeometry', false, 1, 3) //即使静止,因为加载不仅影响这一帧,所以低fps还是加载少一些
  1269. let maxNodesLoading = Common.getBestCount('unloadedGeometry', viewer.lastFrameChanged?1:idleCount, idleCount+4, 3, 14 /* , true */ )//dur在iphoneX中静止有7,pc是2 //!lastFrameChanged静止时加速下载
  1270. //THREE.Math.clamp(Math.round(9 - dur), 1, 6 )
  1271. //console.log('unloadedGeometry', unloadedGeometry.length)
  1272. //主要在手机端有效果。不改之前在展示的点云较多时前进会卡。
  1273. for (let i = 0; i < Math.min(maxNodesLoading, unloadedGeometry.length); i++) {
  1274. unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry);
  1275. }
  1276. if(!Potree.pointsLoading){
  1277. Potree.pointsLoading = true
  1278. //console.log('startLoad')
  1279. viewer.dispatchEvent('startLoadPoints')
  1280. }
  1281. }else{
  1282. if(Potree.pointsLoading){
  1283. Potree.pointsLoading = false
  1284. //console.log('load done!')
  1285. setTimeout(()=>{
  1286. Potree.pointsLoading || viewer.dispatchEvent('pointsLoaded')
  1287. },document.hidden ? 3000 : 50) //hidden时可能好几秒才更新一次,所以这个并不准
  1288. }
  1289. }
  1290. Potree.unloadedGeometry = unloadedGeometry
  1291. //add:
  1292. Potree.numVisiblePoints = numVisiblePoints
  1293. Potree.visibleNodes = visibleNodes
  1294. //if(Potree.settings.sortNodesDis){
  1295. //let s = performance.now()
  1296. for(let pointcloud of pointclouds){
  1297. if(pointcloud.material.opacity < 1 && Potree.settings.notAdditiveBlending ){//排序。如果能所有点云一起排序更好,这样遮挡更正确
  1298. pointcloud.visibleNodes.sort((a,b)=>{return b.disSqToCamZ_ - a.disSqToCamZ_})
  1299. }
  1300. }
  1301. //console.log(performance.now() - s)
  1302. //}
  1303. return {
  1304. visibleNodes: visibleNodes,
  1305. numVisiblePoints: numVisiblePoints,
  1306. lowestSpacing: lowestSpacing
  1307. };
  1308. };
  1309. Potree.numVisiblePoints = 0
  1310. /*
  1311. note:
  1312. 缓存中的点数 Potree.lru.numPoints 一般会 大于 每个点云显示点总数的numVisiblePoints
  1313. 当超出缓冲区最大点云数时,加载的点云节点会被dispose彻底消除;否则,隐藏的节点就会等待再次被使用显示
  1314. 由于加载按照由近及远、由大及小的顺序,要降低卡顿,就只需要降低Potree.pointBudget即可。但目前只设置了三个层次;另外提供maxLevel细节调节,能显示更均匀. 最好多一个调节pointBudge的滑动条
  1315. Potree.lru.numPoints
  1316. Potree.numVisiblePoints
  1317. viewer.scene.pointclouds[0].visibleNodes.length
  1318. */
  1319. {//HQSplatRenderer
  1320. let oldInit = HQSplatRenderer.prototype.init;
  1321. HQSplatRenderer.prototype.init = function(){
  1322. oldInit()
  1323. viewer.addEventListener('resize',this.resize.bind(this))
  1324. }
  1325. HQSplatRenderer.prototype.resize = function(e){
  1326. this.rtDepth.setSize(e.canvasWidth, e.canvasHeight);
  1327. this.rtAttribute.setSize(e.canvasWidth, e.canvasHeight);
  1328. }
  1329. HQSplatRenderer.prototype.clear = function(params={}){
  1330. this.init();
  1331. const {renderer, background} = this.viewer;
  1332. if(background === "skybox"){
  1333. renderer.setClearColor(0x000000, 0);
  1334. } else if (background === 'gradient') {
  1335. renderer.setClearColor(0x000000, 0);
  1336. } else if (background === 'black') {
  1337. renderer.setClearColor(0x000000, 1);
  1338. } else if (background === 'white') {
  1339. renderer.setClearColor(0xFFFFFF, 1);
  1340. } else {
  1341. renderer.setClearColor(0x000000, 0);
  1342. }
  1343. params.target || renderer.clear();
  1344. this.clearTargets(params);
  1345. }
  1346. HQSplatRenderer.prototype.render = function(params={}) {
  1347. this.init();
  1348. const viewer = this.viewer;
  1349. const camera = params.camera ? params.camera : viewer.scene.getActiveCamera();
  1350. const {width, height} = params.width ? params : this.viewer.renderer.getSize(new THREE.Vector2());
  1351. viewer.renderer.setRenderTarget(params.target||null);
  1352. viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
  1353. //params.target || this.resize(width, height);
  1354. const visiblePointClouds = viewer.scene.pointclouds.filter(pc => pc.visible);
  1355. const originalMaterials = new Map();
  1356. for(let pointcloud of visiblePointClouds){
  1357. originalMaterials.set(pointcloud, pointcloud.material);
  1358. if(!this.attributeMaterials.has(pointcloud)){
  1359. let attributeMaterial = new ExtendPointCloudMaterial();
  1360. this.attributeMaterials.set(pointcloud, attributeMaterial);
  1361. }
  1362. if(!this.depthMaterials.has(pointcloud)){
  1363. let depthMaterial = new ExtendPointCloudMaterial();
  1364. depthMaterial.setDefine("depth_pass", "#define hq_depth_pass");
  1365. depthMaterial.setDefine("use_edl", "#define use_edl");
  1366. this.depthMaterials.set(pointcloud, depthMaterial);
  1367. }
  1368. }
  1369. { // DEPTH PASS
  1370. for (let pointcloud of visiblePointClouds) {
  1371. let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
  1372. let material = originalMaterials.get(pointcloud);
  1373. let depthMaterial = this.depthMaterials.get(pointcloud);
  1374. depthMaterial.size = material.size;
  1375. depthMaterial.minSize = material.minSize;
  1376. depthMaterial.maxSize = material.maxSize;
  1377. depthMaterial.pointSizeType = material.pointSizeType;
  1378. depthMaterial.visibleNodesTexture = material.visibleNodesTexture;
  1379. depthMaterial.weighted = false;
  1380. depthMaterial.screenWidth = width;
  1381. depthMaterial.shape = PointShape.CIRCLE;
  1382. depthMaterial.screenHeight = height;
  1383. depthMaterial.uniforms.visibleNodes.value = material.visibleNodesTexture;
  1384. depthMaterial.uniforms.octreeSize.value = octreeSize;
  1385. depthMaterial.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(...pointcloud.scale.toArray());
  1386. depthMaterial.classification = material.classification;
  1387. depthMaterial.uniforms.classificationLUT.value.image.data = material.uniforms.classificationLUT.value.image.data;
  1388. depthMaterial.classificationTexture.needsUpdate = true;
  1389. depthMaterial.uniforms.uFilterReturnNumberRange.value = material.uniforms.uFilterReturnNumberRange.value;
  1390. depthMaterial.uniforms.uFilterNumberOfReturnsRange.value = material.uniforms.uFilterNumberOfReturnsRange.value;
  1391. depthMaterial.uniforms.uFilterGPSTimeClipRange.value = material.uniforms.uFilterGPSTimeClipRange.value;
  1392. depthMaterial.uniforms.uFilterPointSourceIDClipRange.value = material.uniforms.uFilterPointSourceIDClipRange.value;
  1393. depthMaterial.clipTask = material.clipTask;
  1394. depthMaterial.clipMethod = material.clipMethod;
  1395. depthMaterial.setClipBoxes(material.clipBoxes);
  1396. depthMaterial.setClipPolygons(material.clipPolygons);
  1397. pointcloud.material = depthMaterial;
  1398. }
  1399. viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, (params.rtEDL || this.rtDepth), {
  1400. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
  1401. });
  1402. }
  1403. { // ATTRIBUTE PASS
  1404. for (let pointcloud of visiblePointClouds) {
  1405. let octreeSize = pointcloud.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
  1406. let material = originalMaterials.get(pointcloud);
  1407. let attributeMaterial = this.attributeMaterials.get(pointcloud);
  1408. attributeMaterial.size = material.size;
  1409. attributeMaterial.minSize = material.minSize;
  1410. attributeMaterial.maxSize = material.maxSize;
  1411. attributeMaterial.pointSizeType = material.pointSizeType;
  1412. attributeMaterial.activeAttributeName = material.activeAttributeName;
  1413. attributeMaterial.visibleNodesTexture = material.visibleNodesTexture;
  1414. attributeMaterial.weighted = true;
  1415. attributeMaterial.screenWidth = width;
  1416. attributeMaterial.screenHeight = height;
  1417. attributeMaterial.shape = PointShape.CIRCLE;
  1418. attributeMaterial.uniforms.visibleNodes.value = material.visibleNodesTexture;
  1419. attributeMaterial.uniforms.octreeSize.value = octreeSize;
  1420. attributeMaterial.spacing = pointcloud.pcoGeometry.spacing; // * Math.max(...pointcloud.scale.toArray());
  1421. attributeMaterial.classification = material.classification;
  1422. attributeMaterial.uniforms.classificationLUT.value.image.data = material.uniforms.classificationLUT.value.image.data;
  1423. attributeMaterial.classificationTexture.needsUpdate = true;
  1424. attributeMaterial.uniforms.uFilterReturnNumberRange.value = material.uniforms.uFilterReturnNumberRange.value;
  1425. attributeMaterial.uniforms.uFilterNumberOfReturnsRange.value = material.uniforms.uFilterNumberOfReturnsRange.value;
  1426. attributeMaterial.uniforms.uFilterGPSTimeClipRange.value = material.uniforms.uFilterGPSTimeClipRange.value;
  1427. attributeMaterial.uniforms.uFilterPointSourceIDClipRange.value = material.uniforms.uFilterPointSourceIDClipRange.value;
  1428. attributeMaterial.elevationGradientRepeat = material.elevationGradientRepeat;
  1429. attributeMaterial.elevationRange = material.elevationRange;
  1430. attributeMaterial.gradient = material.gradient;
  1431. attributeMaterial.matcap = material.matcap;
  1432. attributeMaterial.intensityRange = material.intensityRange;
  1433. attributeMaterial.intensityGamma = material.intensityGamma;
  1434. attributeMaterial.intensityContrast = material.intensityContrast;
  1435. attributeMaterial.intensityBrightness = material.intensityBrightness;
  1436. attributeMaterial.rgbGamma = material.rgbGamma;
  1437. attributeMaterial.rgbContrast = material.rgbContrast;
  1438. attributeMaterial.rgbBrightness = material.rgbBrightness;
  1439. attributeMaterial.weightRGB = material.weightRGB;
  1440. attributeMaterial.weightIntensity = material.weightIntensity;
  1441. attributeMaterial.weightElevation = material.weightElevation;
  1442. attributeMaterial.weightRGB = material.weightRGB;
  1443. attributeMaterial.weightClassification = material.weightClassification;
  1444. attributeMaterial.weightReturnNumber = material.weightReturnNumber;
  1445. attributeMaterial.weightSourceID = material.weightSourceID;
  1446. attributeMaterial.color = material.color;
  1447. attributeMaterial.clipTask = material.clipTask;
  1448. attributeMaterial.clipMethod = material.clipMethod;
  1449. attributeMaterial.setClipBoxes(material.clipBoxes);
  1450. attributeMaterial.setClipPolygons(material.clipPolygons);
  1451. pointcloud.material = attributeMaterial;
  1452. }
  1453. let gl = this.gl;
  1454. //viewer.renderer.setRenderTarget(null);
  1455. viewer.pRenderer.render(viewer.scene.scenePointCloud, camera, this.rtAttribute, {
  1456. clipSpheres: viewer.scene.volumes.filter(v => (v instanceof SphereVolume)),
  1457. //material: this.attributeMaterial,
  1458. blendFunc: [gl.SRC_ALPHA, gl.ONE],
  1459. //depthTest: false,
  1460. depthWrite: false
  1461. });
  1462. }
  1463. for(let [pointcloud, material] of originalMaterials){
  1464. pointcloud.material = material;
  1465. }
  1466. if(viewer.background === "skybox"){
  1467. viewer.renderer.setClearColor(0x000000, 0);
  1468. viewer.renderer.clear();
  1469. viewer.skybox.camera.rotation.copy(viewer.scene.cameraP.rotation);
  1470. viewer.skybox.camera.fov = viewer.scene.cameraP.fov;
  1471. viewer.skybox.camera.aspect = viewer.scene.cameraP.aspect;
  1472. viewer.skybox.parent.rotation.x = 0;
  1473. viewer.skybox.parent.updateMatrixWorld();
  1474. viewer.skybox.camera.updateProjectionMatrix();
  1475. viewer.renderer.render(viewer.skybox.scene, viewer.skybox.camera);
  1476. } else if (viewer.background === 'gradient') {
  1477. viewer.renderer.setClearColor(0x000000, 0);
  1478. viewer.renderer.clear();
  1479. viewer.renderer.render(viewer.scene.sceneBG, viewer.scene.cameraBG);
  1480. } else if (viewer.background === 'black') {
  1481. viewer.renderer.setClearColor(0x000000, 1);
  1482. viewer.renderer.clear();
  1483. } else if (viewer.background === 'white') {
  1484. viewer.renderer.setClearColor(0xFFFFFF, 1);
  1485. viewer.renderer.clear();
  1486. } else {
  1487. viewer.renderer.setClearColor(0x000000, 0);
  1488. viewer.renderer.clear();
  1489. }
  1490. { // NORMALIZATION PASS
  1491. let normalizationMaterial = this.useEDL ? this.normalizationEDLMaterial : this.normalizationMaterial;
  1492. if(this.useEDL){
  1493. normalizationMaterial.uniforms.edlStrength.value = viewer.edlStrength;
  1494. normalizationMaterial.uniforms.radius.value = viewer.edlRadius;
  1495. normalizationMaterial.uniforms.screenWidth.value = width;
  1496. normalizationMaterial.uniforms.screenHeight.value = height;
  1497. normalizationMaterial.uniforms.uEDLMap.value = (params.rtEDL || this.rtDepth).texture;
  1498. }
  1499. normalizationMaterial.uniforms.uWeightMap.value = this.rtAttribute.texture;
  1500. normalizationMaterial.uniforms.uDepthMap.value = this.rtAttribute.depthTexture;
  1501. Utils.screenPass.render(viewer.renderer, normalizationMaterial);
  1502. }
  1503. viewer.renderer.render(viewer.scene.scene, camera);
  1504. viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer});
  1505. viewer.renderer.render(viewer.scene.sceneOverlay, camera);// add 透明贴图层
  1506. viewer.renderer.clearDepth();
  1507. viewer.transformationTool.update();
  1508. if(!params.target){
  1509. //测量线
  1510. viewer.dispatchEvent({type: "render.pass.perspective_overlay",viewer: viewer, camera});
  1511. viewer.renderer.render(viewer.overlay, camera);//从 viewer.renderDefault搬过来,为了reticule不遮住测量线
  1512. }
  1513. viewer.renderer.render(viewer.controls.sceneControls, camera);
  1514. viewer.renderer.render(viewer.clippingTool.sceneVolume, camera);
  1515. viewer.renderer.render(viewer.transformationTool.scene, camera);
  1516. viewer.renderer.setViewport(width - viewer.navigationCube.width,
  1517. height - viewer.navigationCube.width,
  1518. viewer.navigationCube.width, viewer.navigationCube.width);
  1519. viewer.renderer.render(viewer.navigationCube, viewer.navigationCube.camera);
  1520. viewer.renderer.setViewport(0, 0, width, height);
  1521. viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
  1522. viewer.renderer.setRenderTarget(null)
  1523. }
  1524. }
  1525. //PointCloudOctreeGeometry.js
  1526. PointCloudOctreeGeometryNode.prototype.loadHierachyThenPoints = function(pointcloud){
  1527. let node = this;
  1528. // load hierarchy
  1529. let callback = function (node, hbuffer) {
  1530. let tStart = performance.now();
  1531. let view = new DataView(hbuffer);
  1532. let stack = [];
  1533. let children = view.getUint8(0);
  1534. let numPoints = view.getUint32(1, true);
  1535. node.numPoints = numPoints;
  1536. stack.push({children: children, numPoints: numPoints, name: node.name});
  1537. let decoded = [];
  1538. let offset = 5;
  1539. while (stack.length > 0) {
  1540. let snode = stack.shift();
  1541. let mask = 1;
  1542. for (let i = 0; i < 8; i++) {
  1543. if ((snode.children & mask) !== 0) {
  1544. let childName = snode.name + i;
  1545. let childChildren = view.getUint8(offset);
  1546. let childNumPoints = view.getUint32(offset + 1, true);
  1547. stack.push({children: childChildren, numPoints: childNumPoints, name: childName});
  1548. decoded.push({children: childChildren, numPoints: childNumPoints, name: childName});
  1549. offset += 5;
  1550. }
  1551. mask = mask * 2;
  1552. }
  1553. if (offset === hbuffer.byteLength) {
  1554. break;
  1555. }
  1556. }
  1557. // console.log(decoded);
  1558. let nodes = {};
  1559. nodes[node.name] = node;
  1560. let pco = node.pcoGeometry;
  1561. let maxLevel_ = 0
  1562. for (let i = 0; i < decoded.length; i++) {
  1563. let name = decoded[i].name;
  1564. let decodedNumPoints = decoded[i].numPoints;
  1565. let index = parseInt(name.charAt(name.length - 1));
  1566. let parentName = name.substring(0, name.length - 1);
  1567. let parentNode = nodes[parentName];
  1568. let level = name.length - 1;
  1569. maxLevel_ = Math.max(maxLevel_,level)//add
  1570. let boundingBox = Utils.createChildAABB(parentNode.boundingBox, index);
  1571. let currentNode = new PointCloudOctreeGeometryNode(name, pco, boundingBox);
  1572. currentNode.level = level;
  1573. currentNode.numPoints = decodedNumPoints;
  1574. currentNode.hasChildren = decoded[i].children > 0;
  1575. currentNode.spacing = pco.spacing / Math.pow(2, level);
  1576. parentNode.addChild(currentNode);
  1577. nodes[name] = currentNode;
  1578. }
  1579. pco.dispatchEvent({type:'updateNodeMaxLevel',level:maxLevel_});//add
  1580. let duration = performance.now() - tStart;
  1581. if(duration > 5){
  1582. /* let msg = `duration: ${duration}ms, numNodes: ${decoded.length}`;
  1583. console.log(msg); */
  1584. }
  1585. node.loadPoints();
  1586. };
  1587. if ((node.level % node.pcoGeometry.hierarchyStepSize) === 0) {
  1588. // let hurl = node.pcoGeometry.octreeDir + "/../hierarchy/" + node.name + ".hrc";
  1589. let hurl = node.pcoGeometry.octreeDir + '/' + node.getHierarchyPath() + '/' + node.name + '.hrc';
  1590. hurl += '?m='+node.pcoGeometry.timeStamp //add
  1591. let xhr = XHRFactory.createXMLHttpRequest();
  1592. xhr.open('GET', hurl, true);
  1593. xhr.responseType = 'arraybuffer';
  1594. xhr.overrideMimeType('text/plain; charset=x-user-defined');
  1595. xhr.onreadystatechange = () => {
  1596. if (xhr.readyState === 4) {
  1597. if (xhr.status === 200 || xhr.status === 0) {
  1598. let hbuffer = xhr.response;
  1599. callback(node, hbuffer);
  1600. } else {
  1601. console.log('Failed to load file! HTTP status: ' + xhr.status + ', file: ' + hurl);
  1602. Potree.numNodesLoading--;
  1603. }
  1604. }
  1605. };
  1606. try {
  1607. xhr.send(null);
  1608. } catch (e) {
  1609. console.log('fehler beim laden der punktwolke: ' + e);
  1610. }
  1611. }
  1612. }
  1613. PointCloudOctreeGeometryNode.prototype.loadPoints = function(){
  1614. let name = this.name
  1615. this.pcoGeometry.loader.load(this, ()=>{//callback
  1616. viewer.dispatchEvent('pointcloud_changed' )
  1617. //console.log('loadPoints success ', name)
  1618. });
  1619. }
  1620. //加载点云成功->准备渲染画面->更新点云可见性updateVisibility->请求加载新的点云
  1621. PointCloudOctreeGeometryNode.prototype.traverse = function(t, e){//add from navvis 25.js
  1622. void 0 === e && (e = !0);
  1623. for (var n, i = e ? [this] : []; void 0 !== (n = i.pop()); ) {
  1624. t(n);
  1625. for (var o = 0, r = n.children; o < r.length; o++) {
  1626. var a = r[o];
  1627. null !== a && i.push(a)
  1628. }
  1629. }
  1630. }
  1631. Object.assign( PointCloudOctreeGeometry.prototype, THREE.EventDispatcher.prototype );
  1632. LRU.prototype.freeMemory = function(){
  1633. if (this.elements <= 1) {
  1634. return;
  1635. }
  1636. let memoryRatio = browser.isMobile() ? 2 : 5;
  1637. //改成navvis的,使用pointBudget,否则四屏点云闪烁。 (似乎要比updateVisiblede的node时限制要宽些,作为缓存继续存着。否则会闪烁)
  1638. let max = THREE.Math.clamp( viewer.viewports.length * memoryRatio * Potree.pointBudget, 0, Potree.settings.maxLRUPoints)
  1639. for (; this.numPoints > max; ) {
  1640. var node = this.getLRUItem();
  1641. node && this.disposeDescendants(node);
  1642. }
  1643. }
  1644. VolumeTool.prototype.update = function(){}
  1645. VolumeTool.prototype.startInsertion = function(args = {}){
  1646. let volume;
  1647. if(args.type){
  1648. volume = new args.type();
  1649. }else{
  1650. volume = new Potree.BoxVolume(Object.assign(args,{clip:true}) );
  1651. }
  1652. volume.highlight = true
  1653. volume.name = args.name || 'Volume-'+args.clipTask;
  1654. volume.isNew = true
  1655. viewer.transformObject(null)//先清空
  1656. //console.log('startInsertion',volume.uuid)
  1657. let oldVisiBoxes
  1658. if(args.clipTask == Potree.ClipTask.SHOW_INSIDE){ //如果是显示类型,需要将所有同类型的解除效果,否则看不到效果。 (或者可以在添加非第一个时去除highlight效果,会更自然,但看不清全貌)
  1659. oldVisiBoxes = viewer.scene.volumes.filter(v => v.clipTask == Potree.ClipTask.SHOW_INSIDE && !v.highlight )
  1660. oldVisiBoxes.forEach(box=>box.highlight = true)
  1661. }
  1662. let updatePose = ()=>{ //保证在视野中的大小一致:
  1663. let camera = this.viewer.scene.getActiveCamera();
  1664. let w = math.getScaleForConstantSize({
  1665. width2d: 300,
  1666. camera , position:volume.getWorldPosition(new THREE.Vector3()) ,
  1667. resolution: viewer.mainViewport.resolution//2
  1668. })
  1669. /* let wp = volume.getWorldPosition(new THREE.Vector3()).applyMatrix4(camera.matrixWorldInverse);
  1670. // let pp = new THREE.Vector4(wp.x, wp.y, wp.z).applyMatrix4(camera.projectionMatrix);
  1671. let w = Math.abs((wp.z / 3));*/
  1672. if(!isNaN(w))volume.scale.set(w, w, w);
  1673. {//使水平朝向与camera一致
  1674. let direction = viewer.mainViewport.view.direction.setZ(0)
  1675. volume.quaternion.copy(math.getQuaByAim(direction))
  1676. }
  1677. }
  1678. this.dispatchEvent({
  1679. type: 'start_inserting_volume',
  1680. volume: volume
  1681. });
  1682. updatePose()
  1683. this.viewer.scene.addVolume(volume);
  1684. this.scene.add(volume);
  1685. let drag = e => {
  1686. if(e.hoverViewport.name == 'mapViewport')return
  1687. let I = Utils.getMousePointCloudIntersection(
  1688. viewer.mainViewport,
  1689. viewer.inputHandler.mouse,
  1690. viewer.inputHandler.pointer,
  1691. this.viewer.scene.getActiveCamera(),
  1692. this.viewer,
  1693. this.viewer.scene.pointclouds,
  1694. {pickClipped: args.clipTask == Potree.ClipTask.SHOW_OUTSIDE } //无视clip状态
  1695. );
  1696. var worldPos = I && I.location
  1697. if(!worldPos){
  1698. return
  1699. }
  1700. volume.position.copy(worldPos);
  1701. updatePose()
  1702. };
  1703. let cancel = ()=>{
  1704. end('remove')
  1705. }
  1706. let end = (e) => {
  1707. if(e.button == THREE.MOUSE.RIGHT && e.pressDistance<=Potree.config.clickMaxDragDis) {//remove
  1708. e = 'remove'
  1709. }
  1710. //console.log('end',volume.uuid, e)
  1711. if(e != 'remove' && (!e.isAtDomElement || e.pressDistance>Potree.config.clickMaxDragDis))return continueDrag()
  1712. volume.removeEventListener('drag', drag);
  1713. volume.removeEventListener('drop', end);
  1714. this.viewer.removeEventListener('cancel_insertions', cancel);
  1715. volume.isNew = false
  1716. viewer.removeEventListener('camera_changed', updatePose)
  1717. if(e == 'remove'){
  1718. viewer.scene.removeVolume(volume); //删除没完成的
  1719. }else{
  1720. viewer.transformObject(volume)
  1721. volume.highlight = false
  1722. }
  1723. volume.dispatchEvent({type:'createFinish', success:e != 'remove' })
  1724. oldVisiBoxes && oldVisiBoxes.forEach(box=>box.highlight = false)
  1725. };
  1726. let continueDrag = ( )=>{
  1727. //console.log('continueDrag',volume.uuid )
  1728. var timer = setTimeout(()=>{//等 drag=null之后 //右键拖拽结束后需要重新得到drag
  1729. if(volume.parent && volume.isNew){
  1730. viewer.inputHandler.startDragging( volume , {notPressMouse:true}
  1731. /* {endDragFun: e.drag.endDragFun, notPressMouse:e.drag.notPressMouse, dragViewport:e.drag.dragViewport} */
  1732. )
  1733. }
  1734. },1)
  1735. return timer
  1736. }
  1737. volume.addEventListener('drag', drag);
  1738. volume.addEventListener('drop', end);
  1739. this.viewer.addEventListener('cancel_insertions', cancel);
  1740. viewer.addEventListener('camera_changed', updatePose)
  1741. this.viewer.inputHandler.startDragging(volume, {notPressMouse:true});
  1742. return volume;
  1743. }
  1744. LineGeometry.prototype.setPositions = function( array ) { //xzw改成类似LineSegments的多段线 (第二个点和第三个点之间是没有线段的, 所以不用在意线段顺序)
  1745. const points = new Float32Array( array );
  1746. LineSegmentsGeometry.prototype.setPositions.call(this, points );
  1747. return this;
  1748. }
  1749. Object.assign(ExtendView.prototype, THREE.EventDispatcher.prototype)
  1750. Object.assign(ExtendScene.prototype, THREE.EventDispatcher.prototype );