PointCloudOctree.js 73 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173
  1. import * as THREE from "../libs/three.js/build/three.module.js";
  2. import {PointCloudTree, PointCloudTreeNode} from "./PointCloudTree.js";
  3. import {PointCloudOctreeGeometryNode} from "./PointCloudOctreeGeometry.js";
  4. import {Utils} from "./utils.js";
  5. import {PointCloudMaterial} from "./materials/PointCloudMaterial.js";
  6. import math from "./utils/math.js";
  7. import Common from './utils/Common.js'
  8. import {MeshDraw} from "./utils/DrawUtil.js";
  9. import searchRings from "./utils/searchRings.js";
  10. import {TextSprite} from './objects/TextSprite.js'
  11. import {PointSizeType } from "./defines.js";
  12. const planeGeo = new THREE.PlaneBufferGeometry(1,1);
  13. const planeMats = new Map()
  14. let getPlaneMat = (group, removed)=>{
  15. let mat = planeMats.get(group)
  16. if(mat)return mat
  17. var planeMat = new THREE.MeshBasicMaterial({
  18. //color: level == 'removed' ? "#f00" : new THREE.Color(1 - level*0.2, 1,1),
  19. color: (new THREE.Color()).setHSL(Math.random(), 0.5, 0.9) ,
  20. //color: (new THREE.Color()).setHSL(removed ? 0 : 0.6, Math.random(), 0.9/* Math.random() */) ,
  21. transparent:true,
  22. side:2,
  23. opacity: removed ? 0.3 : 0.9,
  24. })
  25. planeMats.set(group, planeMat)
  26. return planeMat
  27. }
  28. export class PointCloudOctreeNode extends PointCloudTreeNode {
  29. constructor () {
  30. super();
  31. //this.children = {};
  32. this.children = [];
  33. this.sceneNode = null;
  34. this.octree = null;
  35. }
  36. getNumPoints () {
  37. return this.geometryNode.numPoints;
  38. }
  39. isLoaded () {
  40. return true;
  41. }
  42. isTreeNode () {
  43. return true;
  44. }
  45. isGeometryNode () {
  46. return false;
  47. }
  48. getLevel () {
  49. return this.geometryNode.level;
  50. }
  51. getBoundingSphere () {
  52. return this.geometryNode.boundingSphere;
  53. }
  54. getBoundingBox () {
  55. return this.geometryNode.boundingBox;
  56. }
  57. getChildren () {
  58. let children = [];
  59. for (let i = 0; i < 8; i++) {
  60. if (this.children[i]) {
  61. children.push(this.children[i]);
  62. }
  63. }
  64. return children;
  65. }
  66. getPointsInBox(boxNode){
  67. if(!this.sceneNode){
  68. return null;
  69. }
  70. let buffer = this.geometryNode.buffer;
  71. let posOffset = buffer.offset("position");
  72. let stride = buffer.stride;
  73. let view = new DataView(buffer.data);
  74. let worldToBox = boxNode.matrixWorld.clone().invert();
  75. let objectToBox = new THREE.Matrix4().multiplyMatrices(worldToBox, this.sceneNode.matrixWorld);
  76. let inBox = [];
  77. let pos = new THREE.Vector4();
  78. for(let i = 0; i < buffer.numElements; i++){
  79. let x = view.getFloat32(i * stride + posOffset + 0, true);
  80. let y = view.getFloat32(i * stride + posOffset + 4, true);
  81. let z = view.getFloat32(i * stride + posOffset + 8, true);
  82. pos.set(x, y, z, 1);
  83. pos.applyMatrix4(objectToBox);
  84. if(-0.5 < pos.x && pos.x < 0.5){
  85. if(-0.5 < pos.y && pos.y < 0.5){
  86. if(-0.5 < pos.z && pos.z < 0.5){
  87. pos.set(x, y, z, 1).applyMatrix4(this.sceneNode.matrixWorld);
  88. inBox.push(new THREE.Vector3(pos.x, pos.y, pos.z));
  89. }
  90. }
  91. }
  92. }
  93. return inBox;
  94. }
  95. get name () {
  96. return this.geometryNode.name;
  97. }
  98. };
  99. export class PointCloudOctree extends PointCloudTree {
  100. constructor (geometry, material) {
  101. super();
  102. //this.pointBudget = Infinity;
  103. this.pcoGeometry = geometry;
  104. this.boundingBox = this.pcoGeometry.tightBoundingBox//this.pcoGeometry.boundingBox; //boundingBox是正方体,所以换掉
  105. this.boundingSphere = this.boundingBox.getBoundingSphere(new THREE.Sphere());
  106. this.material = material || new PointCloudMaterial();
  107. this.visiblePointsTarget = 2 * 1000 * 1000;
  108. this.minimumNodePixelSize = 150;
  109. this.level = 0;
  110. this.position.copy(geometry.offset);
  111. this.updateMatrix();
  112. this.nodeMaxLevel = 0;//add
  113. this.maxLevel = Infinity;
  114. this.temp = { sizeFitToLevel:{}, opacity:{}}//add
  115. //add
  116. this.panos = []
  117. this.matrixAutoUpdate = false //最好禁止updateMatrix 直接使用matrixWorld
  118. this.orientationUser = 0
  119. this.translateUser = new THREE.Vector3;
  120. this.rotateMatrix = new THREE.Matrix4;
  121. this.transformMatrix = new THREE.Matrix4;// 数据集的变化矩阵
  122. this.transformInvMatrix = new THREE.Matrix4;
  123. this.rotateInvMatrix = new THREE.Matrix4;
  124. this.nodeMaxLevelPredict = this.predictNodeMaxLevel()//预测maxNodeLevel
  125. this.testMaxNodeCount = this.testMaxNodeCount2 = 0
  126. this.material.spacing = this.pcoGeometry.spacing;//初始化一下 以便于设置pointsize
  127. {
  128. let priorityQueue = ["rgba", "rgb", "intensity", "classification"];
  129. let selected = "rgba";
  130. for(let attributeName of priorityQueue){
  131. let attribute = this.pcoGeometry.pointAttributes.attributes.find(a => a.name === attributeName);
  132. if(!attribute){
  133. continue;
  134. }
  135. let min = attribute.range[0].constructor.name === "Array" ? attribute.range[0] : [attribute.range[0]];
  136. let max = attribute.range[1].constructor.name === "Array" ? attribute.range[1] : [attribute.range[1]];
  137. let range_min = new THREE.Vector3(...min);
  138. let range_max = new THREE.Vector3(...max);
  139. let range = range_min.distanceTo(range_max);
  140. if(range === 0){
  141. continue;
  142. }
  143. selected = attributeName;
  144. break;
  145. }
  146. this.material.activeAttributeName = selected;
  147. }
  148. this.showBoundingBox = false;
  149. this.boundingBoxNodes = [];
  150. this.loadQueue = [];
  151. this.visibleBounds = new THREE.Box3();
  152. this.visibleNodes = [];
  153. this.visibleGeometry = [];
  154. this.generateDEM = false;
  155. this.profileRequests = [];
  156. this.name = '';
  157. this._visible = true;
  158. //this._isVisible = true//add
  159. //this.unvisibleReasons = []
  160. {
  161. let box = [this.pcoGeometry.tightBoundingBox, this.getBoundingBoxWorld()]
  162. .find(v => v !== undefined);
  163. this.updateMatrixWorld(true);
  164. box = Utils.computeTransformedBoundingBox(box, this.matrixWorld);
  165. let bMin = box.min.z;
  166. let bMax = box.max.z;
  167. this.material.heightMin = bMin;
  168. this.material.heightMax = bMax;
  169. }
  170. // TODO read projection from file instead
  171. this.projection = geometry.projection;
  172. this.fallbackProjection = geometry.fallbackProjection;
  173. this.root = this.pcoGeometry.root;
  174. this.pcoGeometry.addEventListener('updateNodeMaxLevel', this.updateNodeMaxLevel.bind(this))
  175. this.isPointcloud = true //add
  176. }
  177. /*
  178. 注释:node的level从最大的box 0开始。
  179. 且加载任意一个node必定也会加载它的所有祖先。(如visibleNodes中有一个level为4,则一定有3,2,1,0)
  180. visibleNodes就是所有可见的node,比如:
  181. 如果相机在0这个位置朝下,这时候的visibleNodes中只有一个level为0的node;
  182. 而如果朝上看,上方的几个node如果在视野中占据足够大的位置的话,就会加载。
  183. 如果相机在2这个位置朝上,这时候的visibleNodes中所包含的level为: 0,1,2
  184. ________________
  185. | | | |
  186. |__2| | |
  187. | 1 | 1 |
  188. |_______|_______|
  189. | |
  190. | |
  191. | 0 |
  192. |_______________|
  193. 查看box可在potree中开启
  194. */
  195. updateNodeMaxLevel(e){//目前点云包含node的最高level
  196. var level = Math.max(e.level, this.nodeMaxLevel)
  197. if(level != this.nodeMaxLevel){
  198. this.nodeMaxLevel = level
  199. //viewer.dispatchEvent({type:'updateNodeMaxLevel', pointcloud: this, nodeMaxLevel:level})
  200. //console.log('updateNodeMaxLevel ' + this.dataset_id + " : "+ this.nodeMaxLevel)
  201. this.setPointLevel()//重新计算
  202. if(!Potree.settings.sizeFitToLevel){
  203. this.changePointSize()
  204. }
  205. }
  206. }//注:在没有加载到真实的 nodeMaxLevel之前,点云会显示得偏大
  207. //panoEdit时比预测值小很多?
  208. testMaxNodeLevel(){//手动使maxLevel达到最高,从而迫使updateNodeMaxLevel。 因为Potree.settings.pointDensity 不为 'high'时,maxLevel不是所加载的最高,就很容易加载不出下一个层级,导致无法知道nodeMaxLevel
  209. if(this.testMaxNodeLevelDone ) return
  210. //if(this.nodeMaxLevel > this.nodeMaxLevelPredict.min )return
  211. if( this.nodeMaxLevel==0 )return true
  212. if( !viewer.atDatasets.includes(this))return true //否则老远就count++
  213. let levels = this.visibleNodes.map(e=>e.getLevel())
  214. let actMaxLevel = Math.max.apply(null, levels) //实际加载到的最高的node level
  215. if(actMaxLevel < this.maxLevel)return true// 还没加载到能加载到的最高。 但在细节设置较低时,排除作用微弱。
  216. //尝试加载出更高级的level
  217. let old = this.maxLevel
  218. this.maxLevel = 12;
  219. //var visibleNodes1 = this.visibleNodes.map(e=>e.getLevel())
  220. //console.log('visibleNodes1',visibleNodes1)
  221. Potree.updatePointClouds([this], viewer.scene.getActiveCamera(), viewer.mainViewport.resolution );
  222. //不在camera可视范围内还是加载不出来。即使临时修改位置
  223. var visibleNodes2 = this.visibleNodes.map(e=>e.getLevel())
  224. //console.log('visibleNodes2',visibleNodes2)
  225. this.maxLevel = old;
  226. this.testMaxNodeCount ++
  227. if(this.testMaxNodeCount > 500){
  228. console.log('testMaxNodeLevel次数超出,强制结束:',this.dataset_id, this.nodeMaxLevel, this.nodeMaxLevelPredict.min)
  229. this.testMaxNodeLevelDone = 'moreThanMaxCount'
  230. return; //在可以看见点云的情况下,超时,有可能是预测的max是错的
  231. }
  232. if(this.nodeMaxLevel < this.nodeMaxLevelPredict.min) return true //仍需要继续testMaxNodeLevel
  233. this.testMaxNodeCount2 ++; // 已经> this.nodeMaxLevelPredict.min 后,开始计数。因为min可能低于真实nodeMaxLevel所以要再试几次
  234. /* if(this.name == 'SS-t-CWmVgzP4XU'){
  235. console.log('SS-t-CWmVgzP4XU count++')
  236. } */
  237. if(this.testMaxNodeCount2 < 50) return true //再试几次 ( 主要是细节调得低时需要多测几次才加载到
  238. this.testMaxNodeLevelDone = true
  239. }
  240. setPointLevel(){
  241. var pointDensity = Potree.settings.pointDensity
  242. var config = Potree.config.pointDensity[pointDensity];
  243. if(!config)return
  244. /* if(this.testingMaxLevel){
  245. this.maxLevel = 12;//先加载到最大的直到测试完毕。由于5个level为一组来加载,所以如果写4最高能加载到5,如果写5最高能加载到下一个级别的最高也就是10
  246. //console.log('maxLevel: '+e.maxLevel + ' testingMaxLevel中 ' )
  247. }else{ */
  248. let percent = config.percentByUser && Potree.settings.UserDensityPercent != void 0 ? Potree.settings.UserDensityPercent : config.maxLevelPercent
  249. this.maxLevel = Math.round( percent * this.nodeMaxLevel);
  250. //console.log('maxLevel: '+e.maxLevel + ', density : '+Potree.settings.pointDensity, ", percent :"+percent);
  251. if(Potree.settings.sizeFitToLevel){
  252. this.changePointSize()
  253. }
  254. this.changePointOpacity()
  255. //}
  256. }
  257. //预测可能的nodeMaxLevel:
  258. predictNodeMaxLevel(){//预测maxNodeLevel。 可能只适用于我们相机拍的点云
  259. let spacing = {min:0.005, max:0.014};//最小节的两点间的距离 ,获得方法:spacing / Math.pow(2, nodeMaxLevel)。 目前观测的我们自己拍的这个数值的范围大概是这样
  260. let min = Math.log2(this.material.spacing / spacing.max); //有见过最大是0.01368
  261. let max = Math.log2(this.material.spacing / spacing.min); //大部分是 0.006
  262. //console.log('predictNodeMaxLevel:', this.name , min, max )
  263. return {min, max}
  264. }
  265. getHighestNodeSpacing(){
  266. return this.material.spacing / Math.pow(2, this.nodeMaxLevel) //前提是这个nodeMaxLevel是准确的
  267. }
  268. setName (name) {
  269. if (this.name !== name) {
  270. this.name = name;
  271. this.dispatchEvent({type: 'name_changed', name: name, pointcloud: this});
  272. }
  273. }
  274. getName () {
  275. return this.name;
  276. }
  277. getAttribute(name){
  278. const attribute = this.pcoGeometry.pointAttributes.attributes.find(a => a.name === name);
  279. if(attribute){
  280. return attribute;
  281. }else{
  282. return null;
  283. }
  284. }
  285. getAttributes(){
  286. return this.pcoGeometry.pointAttributes;
  287. }
  288. toTreeNode (geometryNode, parent) {
  289. let node = new PointCloudOctreeNode();
  290. // if(geometryNode.name === "r40206"){
  291. // console.log("creating node for r40206");
  292. // }
  293. let sceneNode = new THREE.Points(geometryNode.geometry, this.material); //好像没什么用
  294. sceneNode.name = geometryNode.name;
  295. sceneNode.position.copy(geometryNode.boundingBox.min);
  296. sceneNode.frustumCulled = false;
  297. sceneNode.onBeforeRender = (_this, scene, camera, geometry, material, group) => {
  298. if (material.program) {
  299. _this.getContext().useProgram(material.program.program);
  300. if (material.program.getUniforms().map.level) {
  301. let level = geometryNode.getLevel();
  302. material.uniforms.level.value = level;
  303. material.program.getUniforms().map.level.setValue(_this.getContext(), level);
  304. }
  305. if (this.visibleNodeTextureOffsets && material.program.getUniforms().map.vnStart) {
  306. let vnStart = this.visibleNodeTextureOffsets.get(node);
  307. material.uniforms.vnStart.value = vnStart;
  308. material.program.getUniforms().map.vnStart.setValue(_this.getContext(), vnStart);
  309. }
  310. if (material.program.getUniforms().map.pcIndex) {
  311. let i = node.pcIndex ? node.pcIndex : this.visibleNodes.indexOf(node);
  312. material.uniforms.pcIndex.value = i;
  313. material.program.getUniforms().map.pcIndex.setValue(_this.getContext(), i);
  314. }
  315. }
  316. };
  317. // { // DEBUG
  318. // let sg = new THREE.SphereGeometry(1, 16, 16);
  319. // let sm = new THREE.MeshNormalMaterial();
  320. // let s = new THREE.Mesh(sg, sm);
  321. // s.scale.set(5, 5, 5);
  322. // s.position.copy(geometryNode.mean)
  323. // .add(this.position)
  324. // .add(geometryNode.boundingBox.min);
  325. //
  326. // viewer.scene.scene.add(s);
  327. // }
  328. node.geometryNode = geometryNode;
  329. node.sceneNode = sceneNode;
  330. node.pointcloud = this;
  331. node.children = [];
  332. //for (let key in geometryNode.children) {
  333. // node.children[key] = geometryNode.children[key];
  334. //}
  335. for(let i = 0; i < 8; i++){
  336. node.children[i] = geometryNode.children[i];
  337. }
  338. if (!parent) {
  339. this.root = node;
  340. this.add(sceneNode);
  341. } else {
  342. let childIndex = parseInt(geometryNode.name[geometryNode.name.length - 1]);
  343. parent.sceneNode.add(sceneNode);
  344. parent.children[childIndex] = node;
  345. }
  346. let disposeListener = function () {
  347. let childIndex = parseInt(geometryNode.name[geometryNode.name.length - 1]);
  348. parent.sceneNode.remove(node.sceneNode);
  349. parent.children[childIndex] = geometryNode;
  350. };
  351. geometryNode.oneTimeDisposeHandlers.push(disposeListener);
  352. //this.buildTexMesh(geometryNode,sceneNode)
  353. return node;
  354. }
  355. buildTexMesh11(geometryNode,sceneNode){
  356. // viewer.scene.pointclouds.forEach(a=>a.areaPlanes.forEach(e=>e.material = viewer.images360.cube.material))
  357. //还是无法避免不在同一个平面的点被识别到同一个面上,然后法向都算错了。 另外还有就是破面太多。虽然能算出地板也不错。或者只去算水平面和垂直面。
  358. let startTime = Date.now()
  359. if(!this.splitSprites){
  360. let splitSprites = new THREE.Object3D
  361. splitSprites.name = 'splitSprites_'+this.name
  362. splitSprites.matrixAutoUpdate = false //同pointcloud一样不自动更新,直接使用
  363. splitSprites.matrix.copy(this.matrix)
  364. splitSprites.matrixWorld.copy(this.matrixWorld)
  365. this.splitSprites = splitSprites
  366. viewer.scene.scene.add(splitSprites)
  367. this.areaPlanes = []
  368. }
  369. if(this.texMeshUseLevel == void 0 || geometryNode.level == this.texMeshUseLevel){//只需要某一层level的点
  370. let showPointLabel = true, showCenterLabel = false
  371. //let spritesGeo = new THREE.BufferGeometry();
  372. let scaleRatio = 1.4 //稍微放大些,填满缝隙
  373. let spriteWidth1 = this.material.spacing / Math.pow(2, geometryNode.level)
  374. if(spriteWidth1 > 3)return
  375. let spriteWidth = spriteWidth1 * scaleRatio
  376. if(this.texMeshUseLevel == void 0 ){
  377. this.texMeshUseLevel = geometryNode.level
  378. console.log('texMeshUseLevel ',geometryNode.level)
  379. }
  380. let geometry = geometryNode.geometry
  381. let count = geometry.attributes.position.count
  382. let end = Math.min(count, 6000)
  383. let start = Math.min(5000, end)
  384. console.warn('check points count:', end-start)
  385. let position = geometry.attributes.position.array
  386. let normal = geometry.attributes.normal.array
  387. let i
  388. let up = new THREE.Vector3(0,1,0) , zeroVec = new THREE.Vector3 //up写成z向上居然结果一样
  389. let positions = [];
  390. let normals = [];
  391. let newPositions = [];
  392. let newIndices = []
  393. let groupMaxPointCount = 1000 ;//太多找环会崩
  394. let minDisSquare = Math.pow(spriteWidth1 * 1.8 , 2 ) //这个数太小就连不上啦 1.65太小
  395. let minDot = Math.cos(THREE.Math.degToRad(5))//括号内是最小偏差角度, 20太大。太大的话会将立方体的相邻两面视为一个面。
  396. //根据相邻点位置和角度是否相近来分组。有风险:两大区域可能因为一个模棱两可中间点连接在一起。
  397. let closeGroups = []
  398. let groupTolerateMaxPoint = 6//组内点<=这个数的最后会被删除
  399. let removedCount = 0
  400. let useGroupCount = 0
  401. let splitSprites = new THREE.Object3D
  402. splitSprites.name = 'sub_splitSprites_'+geometryNode.name
  403. splitSprites.position.copy(sceneNode.position)
  404. splitSprites.rotation.copy(sceneNode.rotation)
  405. this.splitSprites.add(splitSprites)
  406. for(i=start;i<end;i++){
  407. let pos = new THREE.Vector3(position[3*i], position[3*i+1], position[3*i+2] );
  408. let nor = new THREE.Vector3(normal[3*i],normal[3*i+1],normal[3*i+2]);
  409. pos.nor = nor
  410. pos.index = i
  411. positions.push(pos)
  412. normals.push(nor)
  413. let groups = closeGroups.filter(group=>{
  414. if(group.length>groupMaxPointCount)return //满员了
  415. var hasClosed = group.some(p=>{
  416. var dis = p.distanceToSquared(pos)
  417. var dot = p.nor.dot(nor)
  418. if(dis<minDisSquare && dot>minDot){
  419. //return dis / minDisSquare + (Math.abs(p.nor.x - nor.x) + Math.abs(p.nor.y - nor.y) + Math.abs(p.nor.z - nor.z)) < 1.7
  420. return dis / minDisSquare - p.nor.dot(nor) < 0
  421. }
  422. })
  423. return hasClosed
  424. })
  425. if(groups.length == 0){//创建一个新的
  426. var newGroup = []
  427. closeGroups.push(newGroup)
  428. groups = [newGroup]
  429. }
  430. if(groups.length == 1){//直接加入原有的
  431. pos.belongTo = groups[0];
  432. }else if(groups.length>1){ // comebine多个组成一个
  433. let newBigGroup = [];
  434. groups.forEach(e=>{
  435. newBigGroup.push(...e)
  436. let index = closeGroups.indexOf(e);
  437. closeGroups.splice(index, 1)
  438. })
  439. closeGroups.push(newBigGroup)
  440. pos.belongTo = newBigGroup
  441. newBigGroup.forEach(e=>{e.belongTo = newBigGroup})
  442. }
  443. pos.belongTo.push(pos)
  444. }
  445. closeGroups.forEach((points,index)=>{//建造面
  446. if(points.length <= groupTolerateMaxPoint ){
  447. /* let sprite = new THREE.Mesh(planeGeo, getPlaneMat(pos.belongTo, true))
  448. sprite.lookAt(nor);
  449. sprite.position.copy(pos)
  450. sprite.scale.set(spriteWidth,spriteWidth,spriteWidth)
  451. sprite.name = geometryNode.name+'_index'+i
  452. splitSprites.add(sprite)
  453. removedCount ++; */
  454. removedCount += points.length;
  455. return
  456. }
  457. useGroupCount ++
  458. points.sort(function(a,b){
  459. return a.index - b.index
  460. })
  461. console.log(`开始解析 ${geometryNode.name} - 第${index}组,总第${points[0].index}个点,组内有${points.length}个点`)
  462. let planeMat = getPlaneMat(points, true)
  463. if(showPointLabel){
  464. points.forEach((p,i)=>{
  465. var label = new TextSprite({
  466. text : index+"-"+i+" ("+p.index+")"+geometryNode.name, dontFixOrient:true,
  467. backgroundColor: {r: planeMat.color.r*255, g: planeMat.color.g*255, b: planeMat.color.b*255, a:0.6},
  468. });
  469. label.lookAt(p.nor);
  470. label.position.copy(p)
  471. label.scale.set(spriteWidth/3, spriteWidth/3, spriteWidth/3)
  472. splitSprites.add(label)
  473. /* let sprite = new THREE.Mesh(planeGeo,planeMat)
  474. sprite.lookAt(p.nor);
  475. sprite.position.copy(p)
  476. sprite.scale.set(spriteWidth/3,spriteWidth/3,spriteWidth/3)
  477. sprite.name = geometryNode.name+'_group'+index+"_"+ i
  478. splitSprites.add(sprite) */
  479. })
  480. }
  481. var avePos = points.reduce(function(total, currentValue){
  482. return total.add(currentValue)
  483. }, new THREE.Vector3).multiplyScalar(1/points.length)
  484. let planeNormals = []
  485. {//获得planeNormals
  486. //随机找两个距离远的点算normal。 按距离排序后, //抽取若干个点,然后算两两之间的法线,其中距离远的多抽取几个。
  487. var sortPoints = points.slice(0).sort(function(a,b){
  488. return a.distanceToSquared(avePos) - b.distanceToSquared(avePos)
  489. })//从小到大
  490. var pickPoints
  491. var length = sortPoints.length
  492. if(length>=7){
  493. var ratio = [0.02,0.15,0.4,0.55,0.7,0.86,0.99];
  494. var index = ratio.map(e=>Math.round(e * (length-1)))
  495. //console.log('index ',index)
  496. pickPoints = index.map(e=>sortPoints[e])
  497. }else{
  498. pickPoints = sortPoints
  499. }
  500. //console.log('pickPoints', pickPoints)
  501. let num = pickPoints.length
  502. for(let i=0;i<num;i++){//任意一个三角形能算出一个normal
  503. for(let j=i+1;j<num;j++){
  504. for(let u=j+1;u<num;u++){
  505. var p1 = pickPoints[i]
  506. var p2 = pickPoints[j]
  507. var p3 = pickPoints[u]
  508. let vec1 = new THREE.Vector3().subVectors(p1,p3)
  509. let vec2 = new THREE.Vector3().subVectors(p2,p3)
  510. let nor = vec1.cross(vec2).normalize()
  511. if(planeNormals[0]){
  512. if(nor.dot(planeNormals[0])<0)nor.negate() //反向下
  513. }
  514. console.log('nor',nor)
  515. planeNormals.push(nor)
  516. }
  517. }
  518. }
  519. }
  520. var aveNor = planeNormals.reduce(function(total, currentValue){
  521. return total.add(currentValue)
  522. }, new THREE.Vector3).normalize()
  523. console.log('aveNor',aveNor, 'avePos' ,avePos, index)
  524. if(showCenterLabel){
  525. var label = new TextSprite({
  526. //index+"-"+i+" ("+p.index+")"+geometryNode.name
  527. text : `我是${index}组 ${geometryNode.name} 中心点`, dontFixOrient:true,
  528. backgroundColor: {r: planeMat.color.r*255, g: planeMat.color.g*255, b: planeMat.color.b*255, a:0.6},
  529. });
  530. label.lookAt(aveNor);
  531. label.position.copy(avePos)
  532. label.scale.set(spriteWidth, spriteWidth, spriteWidth)
  533. splitSprites.add(label)
  534. }
  535. var facePlane = new THREE.Plane().setFromNormalAndCoplanarPoint(aveNor, avePos )
  536. var coplanarPoints = points.map(p=> facePlane.projectPoint(p, new THREE.Vector3() ))
  537. var originPoint0 = coplanarPoints[0].clone()
  538. var qua = math.getQuaBetween2Vector(facePlane.normal, new THREE.Vector3(0,0,1), new THREE.Vector3(0,0,1));
  539. let points2d = coplanarPoints.map(e=>e.clone().applyQuaternion(qua))
  540. let quaInverse = qua.clone().invert()
  541. //--------------------
  542. let lines = []
  543. points2d.forEach((p,j)=>{
  544. p.id = j
  545. for(let i=0;i<j;i++){
  546. if(p.distanceToSquared(points2d[i])<minDisSquare*1.5){
  547. lines.push({p1:i,p2:j})
  548. }
  549. }
  550. })
  551. console.log('points count:',points2d.length, 'lines:',lines)
  552. var rings = searchRings({
  553. points:points2d,
  554. lines,
  555. onlyGetOutRing:true,
  556. precision: Math.max(spriteWidth1/10, 0.01)
  557. })
  558. console.log( 'rings:', rings )//mesh间可能重叠 但换上贴图材质应该看不出(但只要searchRings时getSliceLines就不会重叠)
  559. if(!rings)return
  560. let planeMat2 = planeMat.clone(); planeMat2.opacity = 0.5;
  561. var firstPos = points2d[0].clone()
  562. firstPos.z = 0 //因为shape只读取了xy,所以位移下, 再算出最终位置,得到差距
  563. firstPos.applyQuaternion(quaInverse)
  564. var vec = originPoint0.clone().sub(firstPos)
  565. rings.forEach(ring=>{
  566. var shapeGeo = MeshDraw.getShapeGeo(ring.points)
  567. var areaPlane = new THREE.Mesh(shapeGeo, planeMat2)
  568. areaPlane.quaternion.copy(quaInverse)
  569. areaPlane.position.copy(vec)
  570. areaPlane.name = 'areaPlane_'+index
  571. splitSprites.add(areaPlane)
  572. this.areaPlanes.push(areaPlane)
  573. })
  574. })
  575. console.log(geometryNode.name, '中:')
  576. console.log('removed point count: ', removedCount/* splitSprites.children.length */)
  577. console.log(closeGroups)
  578. console.log('comebine mesh Len:', useGroupCount)
  579. /*
  580. spritesGeo.setAttribute('position', new THREE.Float32BufferAttribute(new Float32Array(newPositions), 3));
  581. spritesGeo.setIndex( newIndices );
  582. let sprites = new THREE.Mesh(spritesGeo, getPlaneMat('use'))
  583. sprites.name = geometryNode.name
  584. sprites.position.copy(sceneNode.position)
  585. sprites.rotation.copy(sceneNode.rotation)
  586. sceneNode.sprites = sprites
  587. sprites.pointsNode = sceneNode
  588. if(geometryNode.level == 0){
  589. let root = new THREE.Object3D;
  590. root.name = 'spriteNodeRoot'
  591. root.matrixAutoUpdate = false //同pointcloud一样不自动更新,直接使用
  592. root.matrix.copy(this.matrix)
  593. root.matrixWorld.copy(this.matrixWorld)
  594. viewer.scene.scene.add(root)
  595. this.spriteNodeRoot = root
  596. }
  597. this.spriteNodeRoot.add(sprites) */
  598. console.log('computeTime: ' + (Date.now() - startTime))
  599. }
  600. //------------------
  601. /*
  602. viewer.scene.pointclouds[0].spriteNodeRoot.traverse(e=>e.material && (e.material = viewer.images360.cube.material))
  603. viewer.scene.scene.children[12].visible = false
  604. */
  605. }
  606. buildTexMesh(geometryNode,sceneNode){
  607. if(geometryNode.level <= 0){
  608. let startTime = Date.now()
  609. let splitSprites = new THREE.Object3D
  610. splitSprites.name = 'splitSprites_'+geometryNode.name
  611. splitSprites.matrixAutoUpdate = false //同pointcloud一样不自动更新,直接使用
  612. splitSprites.matrix.copy(this.matrix)
  613. splitSprites.matrixWorld.copy(this.matrixWorld)
  614. viewer.scene.scene.add(splitSprites)
  615. let spritesGeo = new THREE.BufferGeometry();
  616. let scaleRatio = 1.4 //稍微放大些,填满缝隙
  617. let spriteWidth1 = this.material.spacing / Math.pow(2, geometryNode.level)
  618. let spriteWidth = spriteWidth1 * scaleRatio
  619. console.log('spriteWidth:',spriteWidth)
  620. const removeChip = false
  621. let geometry = geometryNode.geometry
  622. let count = geometry.attributes.position.count
  623. //count = 4000
  624. let position = geometry.attributes.position.array
  625. let normal = geometry.attributes.normal.array
  626. let i
  627. let up = new THREE.Vector3(0,1,0) , zeroVec = new THREE.Vector3 //up写成z向上居然结果一样
  628. let positions = [];
  629. let normals = [];
  630. let newPositions = [];
  631. //let newNormals = [];
  632. let newIndices = []
  633. let cornerPoints = [new THREE.Vector3(-1,1,0),new THREE.Vector3(1,1,0),new THREE.Vector3(-1,-1,0),new THREE.Vector3(1,-1,0) ]
  634. let indices = [0, 2, 1, 2, 3, 1]
  635. cornerPoints.forEach(e=>e.multiplyScalar(spriteWidth/2))
  636. let minDisSquare = spriteWidth1 * spriteWidth1 * 1.5
  637. let closeGroups = []
  638. let groupTolerateMaxPoint = 4//组内点<=这个数的最后会被删除
  639. let removedCount = 0
  640. for(i=0;i<count;i++){
  641. let pos = new THREE.Vector3(position[3*i], position[3*i+1], position[3*i+2] );
  642. let nor = new THREE.Vector3(normal[3*i],normal[3*i+1],normal[3*i+2]);
  643. pos.nor = nor
  644. positions.push(pos)
  645. normals.push(nor)
  646. if(removeChip){
  647. let groups = closeGroups.filter(group=>{
  648. var hasClosed = group.some(p=>{
  649. var dis = p.distanceToSquared(pos)
  650. if(dis<minDisSquare){
  651. //return dis / minDisSquare + (Math.abs(p.nor.x - nor.x) + Math.abs(p.nor.y - nor.y) + Math.abs(p.nor.z - nor.z)) < 1.7
  652. return dis / minDisSquare - p.nor.dot(nor) < 0
  653. }
  654. })
  655. return hasClosed
  656. })
  657. if(groups.length == 0){//创建一个新的
  658. var newGroup = []
  659. closeGroups.push(newGroup)
  660. groups = [newGroup]
  661. }
  662. if(groups.length == 1){//直接加入原有的
  663. pos.belongTo = groups[0];
  664. }else if(groups.length>1){ // comebine多个组成一个
  665. let newBigGroup = [];
  666. groups.forEach(e=>{
  667. newBigGroup.push(...e)
  668. let index = closeGroups.indexOf(e);
  669. closeGroups.splice(index, 1)
  670. })
  671. closeGroups.push(newBigGroup)
  672. pos.belongTo = newBigGroup
  673. newBigGroup.forEach(e=>{e.belongTo = newBigGroup})
  674. }
  675. pos.belongTo.push(pos)
  676. }
  677. }
  678. for(i=0;i<count;i++){
  679. let pos = positions[i]
  680. let nor = normals[i]
  681. if(Math.abs(nor.z)>0.2)continue
  682. if(removeChip){
  683. if(pos.belongTo.length <= groupTolerateMaxPoint){
  684. let sprite = new THREE.Mesh(planeGeo, getPlaneMat(pos.belongTo, true))
  685. sprite.lookAt(nor);
  686. sprite.position.copy(pos)
  687. sprite.scale.set(spriteWidth,spriteWidth,spriteWidth)
  688. sprite.name = geometryNode.name+'_index'+i
  689. splitSprites.add(sprite)
  690. removedCount ++;
  691. continue
  692. }else{
  693. /*
  694. let sprite = new THREE.Mesh(planeGeo, getPlaneMat(pos.belongTo))
  695. sprite.lookAt(nor);
  696. sprite.position.copy(pos)
  697. sprite.scale.set(spriteWidth/3,spriteWidth/3,spriteWidth/3)
  698. sprite.name = geometryNode.name+'_index'+i
  699. splitSprites.add(sprite)
  700. */
  701. }
  702. }
  703. let matrix = (new THREE.Matrix4).lookAt( nor, zeroVec, up);
  704. matrix.elements[12] = pos.x
  705. matrix.elements[13] = pos.y
  706. matrix.elements[14] = pos.z
  707. cornerPoints.forEach(p=>{
  708. let point = p.clone();
  709. point.applyMatrix4(matrix)
  710. newPositions.push(...point.toArray())
  711. //newNormals
  712. })
  713. indices.forEach(index=>{
  714. newIndices.push(index + i*4)
  715. })
  716. }
  717. /* closeGroups.forEach(e=>{
  718. if(e.length <= groupTolerateMaxPoint )return
  719. }) */
  720. console.log('removed count: ', removedCount/* splitSprites.children.length */)
  721. console.log(closeGroups)
  722. console.log('computeTime: ' + (Date.now() - startTime))
  723. spritesGeo.setAttribute('position', new THREE.Float32BufferAttribute(new Float32Array(newPositions), 3));
  724. spritesGeo.setIndex( newIndices );
  725. let sprites = new THREE.Mesh(spritesGeo, getPlaneMat('use'))
  726. sprites.name = geometryNode.name
  727. sprites.position.copy(sceneNode.position)
  728. sprites.rotation.copy(sceneNode.rotation)
  729. sceneNode.sprites = sprites
  730. sprites.pointsNode = sceneNode
  731. if(geometryNode.level == 0){
  732. let root = new THREE.Object3D;
  733. root.name = 'spriteNodeRoot'
  734. root.matrixAutoUpdate = false //同pointcloud一样不自动更新,直接使用
  735. root.matrix.copy(this.matrix)
  736. root.matrixWorld.copy(this.matrixWorld)
  737. viewer.scene.scene.add(root)
  738. this.spriteNodeRoot = root
  739. }
  740. this.spriteNodeRoot.add(sprites)
  741. viewer.setObjectLayers(sprites,'sceneObjects')
  742. }
  743. }
  744. updateVisibleBounds () {
  745. let leafNodes = [];
  746. for (let i = 0; i < this.visibleNodes.length; i++) {
  747. let node = this.visibleNodes[i];
  748. let isLeaf = true;
  749. for (let j = 0; j < node.children.length; j++) {
  750. let child = node.children[j];
  751. if (child instanceof PointCloudOctreeNode) {
  752. isLeaf = isLeaf && !child.sceneNode.visible;
  753. } else if (child instanceof PointCloudOctreeGeometryNode) {
  754. isLeaf = true;
  755. }
  756. }
  757. if (isLeaf) {
  758. leafNodes.push(node);
  759. }
  760. }
  761. this.visibleBounds.min = new THREE.Vector3(Infinity, Infinity, Infinity);
  762. this.visibleBounds.max = new THREE.Vector3(-Infinity, -Infinity, -Infinity);
  763. for (let i = 0; i < leafNodes.length; i++) {
  764. let node = leafNodes[i];
  765. this.visibleBounds.expandByPoint(node.getBoundingBox().min);
  766. this.visibleBounds.expandByPoint(node.getBoundingBox().max);
  767. }
  768. }
  769. updateMaterial (material, visibleNodes, camera, renderer, resolution) {
  770. material.fov = camera.fov * (Math.PI / 180);
  771. /* material.screenWidth = renderer.domElement.clientWidth;
  772. material.screenHeight = renderer.domElement.clientHeight; */
  773. material.resolution = resolution
  774. //material.spacing = this.pcoGeometry.spacing; // * Math.max(this.scale.x, this.scale.y, this.scale.z); //应该不需要
  775. material.near = camera.near;
  776. material.far = camera.far;
  777. material.uniforms.octreeSize.value = this.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
  778. }
  779. computeVisibilityTextureData(nodes, camera){
  780. if(Potree.measureTimings) performance.mark("computeVisibilityTextureData-start");
  781. let data = new Uint8Array(nodes.length * 4);
  782. let visibleNodeTextureOffsets = new Map();
  783. // copy array
  784. nodes = nodes.slice();
  785. // sort by level and index, e.g. r, r0, r3, r4, r01, r07, r30, ...
  786. let sort = function (a, b) {
  787. let na = a.geometryNode.name;
  788. let nb = b.geometryNode.name;
  789. if (na.length !== nb.length) return na.length - nb.length;
  790. if (na < nb) return -1;
  791. if (na > nb) return 1;
  792. return 0;
  793. };
  794. nodes.sort(sort);
  795. let worldDir = new THREE.Vector3();
  796. let nodeMap = new Map();
  797. let offsetsToChild = new Array(nodes.length).fill(Infinity);
  798. for(let i = 0; i < nodes.length; i++){
  799. let node = nodes[i];
  800. nodeMap.set(node.name, node);
  801. visibleNodeTextureOffsets.set(node, i);
  802. if(i > 0){
  803. let index = parseInt(node.name.slice(-1));
  804. let parentName = node.name.slice(0, -1);
  805. let parent = nodeMap.get(parentName);
  806. let parentOffset = visibleNodeTextureOffsets.get(parent);
  807. let parentOffsetToChild = (i - parentOffset);
  808. offsetsToChild[parentOffset] = Math.min(offsetsToChild[parentOffset], parentOffsetToChild);
  809. data[parentOffset * 4 + 0] = data[parentOffset * 4 + 0] | (1 << index);
  810. data[parentOffset * 4 + 1] = (offsetsToChild[parentOffset] >> 8);
  811. data[parentOffset * 4 + 2] = (offsetsToChild[parentOffset] % 256);
  812. }
  813. let density = node.geometryNode.density;
  814. if(typeof density === "number"){
  815. let lodOffset = Math.log2(density) / 2 - 1.5;
  816. let offsetUint8 = (lodOffset + 10) * 10;
  817. data[i * 4 + 3] = offsetUint8;
  818. }else{
  819. data[i * 4 + 3] = 100;
  820. }
  821. }
  822. if(Potree.measureTimings){
  823. performance.mark("computeVisibilityTextureData-end");
  824. performance.measure("render.computeVisibilityTextureData", "computeVisibilityTextureData-start", "computeVisibilityTextureData-end");
  825. }
  826. return {
  827. data: data,
  828. offsets: visibleNodeTextureOffsets
  829. };
  830. }
  831. nodeIntersectsProfile (node, profile) {
  832. let bbWorld = node.boundingBox.clone().applyMatrix4(this.matrixWorld);
  833. let bsWorld = bbWorld.getBoundingSphere(new THREE.Sphere());
  834. let intersects = false;
  835. for (let i = 0; i < profile.points.length - 1; i++) {
  836. let start = new THREE.Vector3(profile.points[i + 0].x, profile.points[i + 0].y, bsWorld.center.z);
  837. let end = new THREE.Vector3(profile.points[i + 1].x, profile.points[i + 1].y, bsWorld.center.z);
  838. let closest = new THREE.Line3(start, end).closestPointToPoint(bsWorld.center, true, new THREE.Vector3());
  839. let distance = closest.distanceTo(bsWorld.center);
  840. intersects = intersects || (distance < (bsWorld.radius + profile.width));
  841. }
  842. //console.log(`${node.name}: ${intersects}`);
  843. return intersects;
  844. }
  845. deepestNodeAt(position){
  846. const toObjectSpace = this.matrixWorld.clone().invert();
  847. const objPos = position.clone().applyMatrix4(toObjectSpace);
  848. let current = this.root;
  849. while(true){
  850. let containingChild = null;
  851. for(const child of current.children){
  852. if(child !== undefined){
  853. if(child.getBoundingBox().containsPoint(objPos)){
  854. containingChild = child;
  855. }
  856. }
  857. }
  858. if(containingChild !== null && containingChild instanceof PointCloudOctreeNode){
  859. current = containingChild;
  860. }else{
  861. break;
  862. }
  863. }
  864. const deepest = current;
  865. return deepest;
  866. }
  867. nodesOnRay (nodes, ray) {
  868. let nodesOnRay = [];
  869. let _ray = ray.clone();
  870. for (let i = 0; i < nodes.length; i++) {
  871. let node = nodes[i];
  872. let sphere = node.getBoundingSphere().clone().applyMatrix4(this.matrixWorld);
  873. if (_ray.intersectsSphere(sphere)) {
  874. nodesOnRay.push(node);
  875. }
  876. }
  877. return nodesOnRay;
  878. }
  879. updateMatrixWorld (force) {
  880. if (this.matrixAutoUpdate === true) this.updateMatrix();
  881. if (this.matrixWorldNeedsUpdate === true || force === true) {
  882. if (!this.parent) {
  883. this.matrixWorld.copy(this.matrix);
  884. } else {
  885. this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix);
  886. }
  887. this.matrixWorldNeedsUpdate = false;
  888. force = true;
  889. }
  890. }
  891. hideDescendants (object) {
  892. let stack = [];
  893. for (let i = 0; i < object.children.length; i++) {
  894. let child = object.children[i];
  895. if (child.visible) {
  896. stack.push(child);
  897. }
  898. }
  899. while (stack.length > 0) {
  900. let object = stack.shift();
  901. object.visible = false;
  902. for (let i = 0; i < object.children.length; i++) {
  903. let child = object.children[i];
  904. if (child.visible) {
  905. stack.push(child);
  906. }
  907. }
  908. }
  909. }
  910. moveToOrigin () {
  911. this.position.set(0, 0, 0);
  912. this.updateMatrixWorld(true);
  913. let box = this.boundingBox;
  914. let transform = this.matrixWorld;
  915. let tBox = Utils.computeTransformedBoundingBox(box, transform);
  916. this.position.set(0, 0, 0).sub(tBox.getCenter(new THREE.Vector3()));
  917. };
  918. moveToGroundPlane () {
  919. this.updateMatrixWorld(true);
  920. let box = this.boundingBox;
  921. let transform = this.matrixWorld;
  922. let tBox = Utils.computeTransformedBoundingBox(box, transform);
  923. this.position.y += -tBox.min.y;
  924. };
  925. getBoundingBoxWorld () {
  926. this.updateMatrixWorld(true);
  927. let box = this.boundingBox;
  928. let transform = this.matrixWorld;
  929. let tBox = Utils.computeTransformedBoundingBox(box, transform);
  930. return tBox;
  931. };
  932. /**
  933. * returns points inside the profile points
  934. *
  935. * maxDepth: search points up to the given octree depth
  936. *
  937. *
  938. * The return value is an array with all segments of the profile path
  939. * let segment = {
  940. * start: THREE.Vector3,
  941. * end: THREE.Vector3,
  942. * points: {}
  943. * project: function()
  944. * };
  945. *
  946. * The project() function inside each segment can be used to transform
  947. * that segments point coordinates to line up along the x-axis.
  948. *
  949. *
  950. */
  951. getPointsInProfile (profile, maxDepth, callback) {
  952. if (callback) {
  953. let request = new Potree.ProfileRequest(this, profile, maxDepth, callback);
  954. this.profileRequests.push(request);
  955. return request;
  956. }
  957. let points = {
  958. segments: [],
  959. boundingBox: new THREE.Box3(),
  960. projectedBoundingBox: new THREE.Box2()
  961. };
  962. // evaluate segments
  963. for (let i = 0; i < profile.points.length - 1; i++) {
  964. let start = profile.points[i];
  965. let end = profile.points[i + 1];
  966. let ps = this.getProfile(start, end, profile.width, maxDepth);
  967. let segment = {
  968. start: start,
  969. end: end,
  970. points: ps,
  971. project: null
  972. };
  973. points.segments.push(segment);
  974. points.boundingBox.expandByPoint(ps.boundingBox.min);
  975. points.boundingBox.expandByPoint(ps.boundingBox.max);
  976. }
  977. // add projection functions to the segments
  978. let mileage = new THREE.Vector3();
  979. for (let i = 0; i < points.segments.length; i++) {
  980. let segment = points.segments[i];
  981. let start = segment.start;
  982. let end = segment.end;
  983. let project = (function (_start, _end, _mileage, _boundingBox) {
  984. let start = _start;
  985. let end = _end;
  986. let mileage = _mileage;
  987. let boundingBox = _boundingBox;
  988. let xAxis = new THREE.Vector3(1, 0, 0);
  989. let dir = new THREE.Vector3().subVectors(end, start);
  990. dir.y = 0;
  991. dir.normalize();
  992. let alpha = Math.acos(xAxis.dot(dir));
  993. if (dir.z > 0) {
  994. alpha = -alpha;
  995. }
  996. return function (position) {
  997. let toOrigin = new THREE.Matrix4().makeTranslation(-start.x, -boundingBox.min.y, -start.z);
  998. let alignWithX = new THREE.Matrix4().makeRotationY(-alpha);
  999. let applyMileage = new THREE.Matrix4().makeTranslation(mileage.x, 0, 0);
  1000. let pos = position.clone();
  1001. pos.applyMatrix4(toOrigin);
  1002. pos.applyMatrix4(alignWithX);
  1003. pos.applyMatrix4(applyMileage);
  1004. return pos;
  1005. };
  1006. }(start, end, mileage.clone(), points.boundingBox.clone()));
  1007. segment.project = project;
  1008. mileage.x += new THREE.Vector3(start.x, 0, start.z).distanceTo(new THREE.Vector3(end.x, 0, end.z));
  1009. mileage.y += end.y - start.y;
  1010. }
  1011. points.projectedBoundingBox.min.x = 0;
  1012. points.projectedBoundingBox.min.y = points.boundingBox.min.y;
  1013. points.projectedBoundingBox.max.x = mileage.x;
  1014. points.projectedBoundingBox.max.y = points.boundingBox.max.y;
  1015. return points;
  1016. }
  1017. /**
  1018. * returns points inside the given profile bounds.
  1019. *
  1020. * start:
  1021. * end:
  1022. * width:
  1023. * depth: search points up to the given octree depth
  1024. * callback: if specified, points are loaded before searching
  1025. *
  1026. *
  1027. */
  1028. getProfile (start, end, width, depth, callback) {
  1029. let request = new Potree.ProfileRequest(start, end, width, depth, callback);
  1030. this.profileRequests.push(request);
  1031. };
  1032. getVisibleExtent () {
  1033. return this.visibleBounds.applyMatrix4(this.matrixWorld);
  1034. };
  1035. intersectsPoint(position){
  1036. let rootAvailable = this.pcoGeometry.root && this.pcoGeometry.root.geometry;
  1037. if(!rootAvailable){
  1038. return false;
  1039. }
  1040. if(typeof this.signedDistanceField === "undefined"){
  1041. const resolution = 32;
  1042. const field = new Float32Array(resolution ** 3).fill(Infinity);
  1043. const positions = this.pcoGeometry.root.geometry.attributes.position;
  1044. const boundingBox = this.boundingBox;
  1045. const n = positions.count;
  1046. for(let i = 0; i < n; i = i + 3){
  1047. const x = positions.array[3 * i + 0];
  1048. const y = positions.array[3 * i + 1];
  1049. const z = positions.array[3 * i + 2];
  1050. const ix = parseInt(Math.min(resolution * (x / boundingBox.max.x), resolution - 1));
  1051. const iy = parseInt(Math.min(resolution * (y / boundingBox.max.y), resolution - 1));
  1052. const iz = parseInt(Math.min(resolution * (z / boundingBox.max.z), resolution - 1));
  1053. const index = ix + iy * resolution + iz * resolution * resolution;
  1054. field[index] = 0;
  1055. }
  1056. const sdf = {
  1057. resolution: resolution,
  1058. field: field,
  1059. };
  1060. this.signedDistanceField = sdf;
  1061. }
  1062. {
  1063. const sdf = this.signedDistanceField;
  1064. const boundingBox = this.boundingBox;
  1065. const toObjectSpace = this.matrixWorld.clone().invert();
  1066. const objPos = position.clone().applyMatrix4(toObjectSpace);
  1067. const resolution = sdf.resolution;
  1068. const ix = parseInt(resolution * (objPos.x / boundingBox.max.x));
  1069. const iy = parseInt(resolution * (objPos.y / boundingBox.max.y));
  1070. const iz = parseInt(resolution * (objPos.z / boundingBox.max.z));
  1071. if(ix < 0 || iy < 0 || iz < 0){
  1072. return false;
  1073. }
  1074. if(ix >= resolution || iy >= resolution || iz >= resolution){
  1075. return false;
  1076. }
  1077. const index = ix + iy * resolution + iz * resolution * resolution;
  1078. const value = sdf.field[index];
  1079. if(value === 0){
  1080. return true;
  1081. }
  1082. }
  1083. return false;
  1084. }
  1085. /**
  1086. *
  1087. *
  1088. *
  1089. * params.pickWindowSize: Look for points inside a pixel window of this size.
  1090. * Use odd values: 1, 3, 5, ...
  1091. *
  1092. *
  1093. * TODO: only draw pixels that are actually read with readPixels().
  1094. *
  1095. */
  1096. pick(viewer, viewport, camera, ray, params = {}){
  1097. let renderer = viewer.renderer;
  1098. let pRenderer = viewer.pRenderer;
  1099. performance.mark("pick-start");
  1100. let getVal = (a, b) => a != void 0 ? a : b;
  1101. let pickWindowSize_ = THREE.Math.clamp( Math.round((1.1-this.maxLevel/this.nodeMaxLevel)*80), 5, 100)
  1102. let pickWindowSize = getVal(params.pickWindowSize, pickWindowSize_ ); /* 65 */ //拾取像素边长,越小越精准,但点云稀疏的话可能容易出现识别不到的情况。 另外左下侧会有缝隙无法识别到,缝隙大小和这个值有关
  1103. let pickOutsideClipRegion = getVal(params.pickOutsideClipRegion, false);
  1104. let size = viewport ? viewport.resolution : renderer.getSize(new THREE.Vector2());
  1105. let width = Math.ceil(getVal(params.width, size.width)); //renderTarget大小。影响识别精度
  1106. let height = Math.ceil(getVal(params.height, size.height));
  1107. let screenshot = ()=>{
  1108. if(window.testScreen){
  1109. let dataUrl = Potree.Utils.renderTargetToDataUrl(pickState.renderTarget, width, height, renderer)
  1110. Common.downloadFile(dataUrl, 'screenshot.jpg') //为什么图片上不是只有pickWindowSize区域有颜色??
  1111. window.testScreen = 0
  1112. }
  1113. }
  1114. let pointSizeType = getVal(params.pointSizeType, this.material.pointSizeType);
  1115. let pointSize = getVal(params.pointSize, this.material.size);
  1116. let nodes = this.nodesOnRay(this.visibleNodes, ray);
  1117. if (nodes.length === 0) {
  1118. return null;
  1119. }
  1120. //console.log('nodes.length != 0', this.name)
  1121. if (!this.pickState) {
  1122. let scene = new THREE.Scene();
  1123. let material = new Potree.PointCloudMaterial();
  1124. material.activeAttributeName = "indices";
  1125. let renderTarget = new THREE.WebGLRenderTarget(
  1126. 1, 1,
  1127. { minFilter: THREE.LinearFilter,
  1128. magFilter: THREE.NearestFilter,
  1129. format: THREE.RGBAFormat }
  1130. );
  1131. this.pickState = {
  1132. renderTarget: renderTarget,
  1133. material: material,
  1134. scene: scene
  1135. };
  1136. };
  1137. let pickState = this.pickState;
  1138. let pickMaterial = pickState.material;
  1139. { // update pick material
  1140. pickMaterial.pointSizeType = pointSizeType;
  1141. //pickMaterial.shape = this.material.shape;
  1142. pickMaterial.shape = Potree.PointShape.PARABOLOID;
  1143. pickMaterial.uniforms.uFilterReturnNumberRange.value = this.material.uniforms.uFilterReturnNumberRange.value;
  1144. pickMaterial.uniforms.uFilterNumberOfReturnsRange.value = this.material.uniforms.uFilterNumberOfReturnsRange.value;
  1145. pickMaterial.uniforms.uFilterGPSTimeClipRange.value = this.material.uniforms.uFilterGPSTimeClipRange.value;
  1146. pickMaterial.uniforms.uFilterPointSourceIDClipRange.value = this.material.uniforms.uFilterPointSourceIDClipRange.value;
  1147. pickMaterial.activeAttributeName = "indices";
  1148. pickMaterial.size = pointSize;
  1149. pickMaterial.uniforms.minSize.value = this.material.uniforms.minSize.value;
  1150. pickMaterial.uniforms.maxSize.value = this.material.uniforms.maxSize.value;
  1151. pickMaterial.classification = this.material.classification;
  1152. pickMaterial.recomputeClassification();
  1153. if(params.pickClipped){
  1154. pickMaterial.clipBoxes = this.material.clipBoxes;
  1155. pickMaterial.uniforms.clipBoxes = this.material.uniforms.clipBoxes;
  1156. if(this.material.clipTask === Potree.ClipTask.HIGHLIGHT){
  1157. pickMaterial.clipTask = Potree.ClipTask.NONE;
  1158. }else{
  1159. pickMaterial.clipTask = this.material.clipTask;
  1160. }
  1161. pickMaterial.clipMethod = this.material.clipMethod;
  1162. }else{
  1163. pickMaterial.clipBoxes = [];
  1164. }
  1165. this.updateMaterial(pickMaterial, nodes, camera, renderer, new THREE.Vector2(width, height));
  1166. }
  1167. pickState.renderTarget.setSize(width, height); //仅绘制屏幕大小的,而不乘以devicePixelRatio
  1168. let pixelPos = new THREE.Vector2(params.x, params.y);
  1169. let gl = renderer.getContext();
  1170. gl.enable(gl.SCISSOR_TEST);
  1171. gl.scissor( //规定渲染范围,只渲染一小块
  1172. parseInt(pixelPos.x - (pickWindowSize - 1) / 2),
  1173. parseInt(pixelPos.y - (pickWindowSize - 1) / 2),
  1174. parseInt(pickWindowSize), parseInt(pickWindowSize));
  1175. renderer.state.buffers.depth.setTest(pickMaterial.depthTest);
  1176. renderer.state.buffers.depth.setMask(pickMaterial.depthWrite);
  1177. renderer.state.setBlending(THREE.NoBlending);
  1178. { // RENDER
  1179. renderer.setRenderTarget(pickState.renderTarget);
  1180. gl.clearColor(0, 0, 0, 0);
  1181. renderer.clear(true, true, true);
  1182. let tmp = this.material;
  1183. this.material = pickMaterial;
  1184. pRenderer.renderOctree(this, nodes, camera, pickState.renderTarget);
  1185. screenshot();
  1186. this.material = tmp;
  1187. }
  1188. let clamp = (number, min, max) => Math.min(Math.max(min, number), max);
  1189. let x = parseInt(clamp(pixelPos.x - (pickWindowSize - 1) / 2, 0, width));
  1190. let y = parseInt(clamp(pixelPos.y - (pickWindowSize - 1) / 2, 0, height));
  1191. /* let w = parseInt(Math.min(x + pickWindowSize, width) - x);
  1192. let h = parseInt(Math.min(y + pickWindowSize, height) - y); */
  1193. let pixelCount = pickWindowSize * pickWindowSize//w * h;
  1194. let buffer = new Uint8Array(4 * pixelCount);
  1195. //w<pickWindowSize会报错
  1196. gl.readPixels(x, y, pickWindowSize, pickWindowSize, gl.RGBA, gl.UNSIGNED_BYTE, buffer);
  1197. renderer.setRenderTarget(null);
  1198. renderer.state.reset();
  1199. renderer.setScissorTest(false);
  1200. gl.disable(gl.SCISSOR_TEST);
  1201. let pixels = buffer;
  1202. let ibuffer = new Uint32Array(buffer.buffer); //四个数整合成一个
  1203. // find closest hit inside pixelWindow boundaries
  1204. let min = Number.MAX_VALUE;
  1205. let hits = [];
  1206. for (let u = 0; u < pickWindowSize; u++) {
  1207. for (let v = 0; v < pickWindowSize; v++) {
  1208. let offset = (u + v * pickWindowSize);
  1209. let distance = Math.pow(u - (pickWindowSize - 1) / 2, 2) + Math.pow(v - (pickWindowSize - 1) / 2, 2);
  1210. let pcIndex = pixels[4 * offset + 3];//nodes index(第四位)
  1211. pixels[4 * offset + 3] = 0; //去除nodes index后剩下的是index(前三位)
  1212. let pIndex = ibuffer[offset]; //index
  1213. if(!(pcIndex === 0 && pIndex === 0) && (pcIndex !== undefined) && (pIndex !== undefined)){
  1214. let hit = {
  1215. pIndex: pIndex,
  1216. pcIndex: pcIndex,
  1217. distanceToCenter: distance
  1218. };
  1219. if(params.all){
  1220. hits.push(hit);
  1221. }else{
  1222. if(hits.length > 0){
  1223. if(distance < hits[0].distanceToCenter){
  1224. hits[0] = hit;
  1225. }
  1226. }else{
  1227. hits.push(hit);
  1228. }
  1229. }
  1230. }
  1231. }
  1232. }
  1233. // { // DEBUG: show panel with pick image
  1234. // let img = Utils.pixelsArrayToImage(buffer, w, h);
  1235. // let screenshot = img.src;
  1236. // if(!this.debugDIV){
  1237. // this.debugDIV = $(`
  1238. // <div id="pickDebug"
  1239. // style="position: absolute;
  1240. // right: 400px; width: 300px;
  1241. // bottom: 44px; width: 300px;
  1242. // z-index: 1000;
  1243. // "></div>`);
  1244. // $(document.body).append(this.debugDIV);
  1245. // }
  1246. // this.debugDIV.empty();
  1247. // this.debugDIV.append($(`<img src="${screenshot}"
  1248. // style="transform: scaleY(-1); width: 300px"/>`));
  1249. // //$(this.debugWindow.document).append($(`<img src="${screenshot}"/>`));
  1250. // //this.debugWindow.document.write('<img src="'+screenshot+'"/>');
  1251. // }
  1252. for(let hit of hits){
  1253. let point = {};
  1254. if (!nodes[hit.pcIndex]) {
  1255. return null;
  1256. }
  1257. let node = nodes[hit.pcIndex];
  1258. let pc = node.sceneNode;
  1259. let geometry = node.geometryNode.geometry;
  1260. for(let attributeName in geometry.attributes){
  1261. let attribute = geometry.attributes[attributeName];
  1262. if (attributeName === 'position') {
  1263. let x = attribute.array[3 * hit.pIndex + 0];
  1264. let y = attribute.array[3 * hit.pIndex + 1];
  1265. let z = attribute.array[3 * hit.pIndex + 2];
  1266. let position = new THREE.Vector3(x, y, z);
  1267. position.applyMatrix4( pc.matrixWorld );
  1268. point[attributeName] = position;
  1269. } else if (attributeName === 'indices') {
  1270. } else {
  1271. let values = attribute.array.slice(attribute.itemSize * hit.pIndex, attribute.itemSize * (hit.pIndex + 1)) ;
  1272. if(attribute.potree){
  1273. const {scale, offset} = attribute.potree;
  1274. values = values.map(v => v / scale + offset);
  1275. }
  1276. point[attributeName] = values;
  1277. //debugger;
  1278. //if (values.itemSize === 1) {
  1279. // point[attribute.name] = values.array[hit.pIndex];
  1280. //} else {
  1281. // let value = [];
  1282. // for (let j = 0; j < values.itemSize; j++) {
  1283. // value.push(values.array[values.itemSize * hit.pIndex + j]);
  1284. // }
  1285. // point[attribute.name] = value;
  1286. //}
  1287. }
  1288. }
  1289. hit.point = point;
  1290. }
  1291. performance.mark("pick-end");
  1292. performance.measure("pick", "pick-start", "pick-end");
  1293. if(params.all){
  1294. return hits.map(hit => hit.point);
  1295. }else{
  1296. if(hits.length === 0){
  1297. return null;
  1298. }else{
  1299. return hits[0].point;
  1300. //let sorted = hits.sort( (a, b) => a.distanceToCenter - b.distanceToCenter);
  1301. //return sorted[0].point;
  1302. }
  1303. }
  1304. };
  1305. * getFittedBoxGen(boxNode){//???
  1306. let start = performance.now();
  1307. let shrinkedLocalBounds = new THREE.Box3();
  1308. let worldToBox = boxNode.matrixWorld.clone().invert();
  1309. for(let node of this.visibleNodes){
  1310. if(!node.sceneNode){
  1311. continue;
  1312. }
  1313. let buffer = node.geometryNode.buffer;
  1314. let posOffset = buffer.offset("position");
  1315. let stride = buffer.stride;
  1316. let view = new DataView(buffer.data);
  1317. let objectToBox = new THREE.Matrix4().multiplyMatrices(worldToBox, node.sceneNode.matrixWorld);
  1318. let pos = new THREE.Vector4();
  1319. for(let i = 0; i < buffer.numElements; i++){
  1320. let x = view.getFloat32(i * stride + posOffset + 0, true);
  1321. let y = view.getFloat32(i * stride + posOffset + 4, true);
  1322. let z = view.getFloat32(i * stride + posOffset + 8, true);
  1323. pos.set(x, y, z, 1);
  1324. pos.applyMatrix4(objectToBox);
  1325. if(-0.5 < pos.x && pos.x < 0.5){
  1326. if(-0.5 < pos.y && pos.y < 0.5){
  1327. if(-0.5 < pos.z && pos.z < 0.5){
  1328. shrinkedLocalBounds.expandByPoint(pos);
  1329. }
  1330. }
  1331. }
  1332. }
  1333. yield;
  1334. }
  1335. let fittedPosition = shrinkedLocalBounds.getCenter(new THREE.Vector3()).applyMatrix4(boxNode.matrixWorld);
  1336. let fitted = new THREE.Object3D();
  1337. fitted.position.copy(fittedPosition);
  1338. fitted.scale.copy(boxNode.scale);
  1339. fitted.rotation.copy(boxNode.rotation);
  1340. let ds = new THREE.Vector3().subVectors(shrinkedLocalBounds.max, shrinkedLocalBounds.min);
  1341. fitted.scale.multiply(ds);
  1342. let duration = performance.now() - start;
  1343. console.log("duration: ", duration);
  1344. yield fitted;
  1345. }
  1346. getFittedBox(boxNode, maxLevel = Infinity){
  1347. maxLevel = Infinity;
  1348. let start = performance.now();
  1349. let shrinkedLocalBounds = new THREE.Box3();
  1350. let worldToBox = boxNode.matrixWorld.clone().invert();
  1351. for(let node of this.visibleNodes){
  1352. if(!node.sceneNode || node.getLevel() > maxLevel){
  1353. continue;
  1354. }
  1355. let buffer = node.geometryNode.buffer;
  1356. let posOffset = buffer.offset("position");
  1357. let stride = buffer.stride;
  1358. let view = new DataView(buffer.data);
  1359. let objectToBox = new THREE.Matrix4().multiplyMatrices(worldToBox, node.sceneNode.matrixWorld);
  1360. let pos = new THREE.Vector4();
  1361. for(let i = 0; i < buffer.numElements; i++){
  1362. let x = view.getFloat32(i * stride + posOffset + 0, true);
  1363. let y = view.getFloat32(i * stride + posOffset + 4, true);
  1364. let z = view.getFloat32(i * stride + posOffset + 8, true);
  1365. pos.set(x, y, z, 1);
  1366. pos.applyMatrix4(objectToBox);
  1367. if(-0.5 < pos.x && pos.x < 0.5){
  1368. if(-0.5 < pos.y && pos.y < 0.5){
  1369. if(-0.5 < pos.z && pos.z < 0.5){
  1370. shrinkedLocalBounds.expandByPoint(pos);
  1371. }
  1372. }
  1373. }
  1374. }
  1375. }
  1376. let fittedPosition = shrinkedLocalBounds.getCenter(new THREE.Vector3()).applyMatrix4(boxNode.matrixWorld);
  1377. let fitted = new THREE.Object3D();
  1378. fitted.position.copy(fittedPosition);
  1379. fitted.scale.copy(boxNode.scale);
  1380. fitted.rotation.copy(boxNode.rotation);
  1381. let ds = new THREE.Vector3().subVectors(shrinkedLocalBounds.max, shrinkedLocalBounds.min);
  1382. fitted.scale.multiply(ds);
  1383. let duration = performance.now() - start;
  1384. console.log("duration: ", duration);
  1385. return fitted;
  1386. }
  1387. get progress () {
  1388. return this.visibleNodes.length / this.visibleGeometry.length;
  1389. }
  1390. find(name){
  1391. let node = null;
  1392. for(let char of name){
  1393. if(char === "r"){
  1394. node = this.root;
  1395. }else{
  1396. node = node.children[char];
  1397. }
  1398. }
  1399. return node;
  1400. }
  1401. get visible(){
  1402. return this._visible;
  1403. }
  1404. set visible(value){
  1405. if(value !== this._visible){
  1406. this._visible = value;
  1407. this.dispatchEvent({type: 'visibility_changed', pointcloud: this});
  1408. }
  1409. }
  1410. // 设置点大小
  1411. changePointSize(num, sizeFitToLevel) {
  1412. if(this.material.pointSizeType != PointSizeType.ATTENUATED){
  1413. return num && (this.material.size = num)
  1414. }
  1415. if (num == void 0) {
  1416. num = this.temp.pointSize
  1417. } else {
  1418. this.temp.pointSize = num
  1419. }
  1420. num /= (Potree.config.material.realPointSize / Potree.config.material.pointSize) //兼容
  1421. num = Math.pow(num, 1.05) * 6
  1422. if(sizeFitToLevel || Potree.settings.sizeFitToLevel){//按照点云质量来调整的版本: 近似将pointSizeType换成ADAPTIVE
  1423. let str = this.temp.pointSize+':'+this.maxLevel+':'+this.nodeMaxLevel
  1424. let value = this.temp.sizeFitToLevel[str] //储存。防止每次渲染(反复切换density)都要算。
  1425. if(value){
  1426. this.material.size = value
  1427. }else{
  1428. let base = this.material.spacing / Math.pow(2, this.maxLevel) //点云大小在level为0时设置为spacing,每长一级,大小就除以2
  1429. base *= this.nodeMaxLevel > 0 ? Math.max(0.1, Math.pow(this.maxLevel / this.nodeMaxLevel, 1.3)) : 0.1 //低质量的缩小点,因为视觉上看太大了。navvis是不铺满的,我们也留一点缝隙
  1430. this.material.size = base * 3 * num/* * window.devicePixelRatio */
  1431. //在t-8BCqxQAr93 会议室 和 t-e2Kb2iU 隧道 两个场景里调节,因为它们的spacing相差较大,观察会议室墙壁的龟裂程度
  1432. this.temp.sizeFitToLevel[str] = this.material.size
  1433. }
  1434. }else{
  1435. let base = 0.007; //let base = this.material.spacing / Math.pow(2, this.nodeMaxLevel) //点云大小在level为0时设置为spacing,每长一级,大小就除以2
  1436. //base的数值理论上应该是右侧算出来的,但发现有的场景nodeMaxLevel和nodeMaxLevelPredict差别较大的点云显示也过大,而直接换成固定值反而可以适应所有场景。该固定值来源于 getHighestNodeSpacing 最小值,修改了下。(会不会是我们的相机其实该值是固定的,根据该值算出的spacing才是有误差的? 如果换了相机是否要改值?)
  1437. this.material.size = base * 5 * num /* * window.devicePixelRatio */
  1438. }
  1439. //console.log('changePointSize ' + this.dataset_id + ' , num : ' + num + ' , size : ' + this.material.size, this.material.spacing)
  1440. }
  1441. // 设置点透明度
  1442. changePointOpacity(num, canMoreThanOne) {
  1443. //num:0-1 navvis用的是亮度
  1444. if (num == void 0) {
  1445. num = this.temp.pointOpacity
  1446. } else {
  1447. this.temp.pointOpacity = num
  1448. }
  1449. if(Potree.settings.editType == 'merge'){ //not AdditiveBlending
  1450. return this.material.opacity = num
  1451. }
  1452. if (num == 1) {
  1453. this.material.opacity = 1
  1454. } else {
  1455. let str = (Potree.settings.sizeFitToLevel?'sizeFit:':'')+ (canMoreThanOne ? 'canMoreThanOne:':'') +this.temp.pointOpacity+':'+this.maxLevel+':'+this.nodeMaxLevel
  1456. let value = this.temp.opacity[str] //储存。防止每次渲染(反复切换density)都要算。
  1457. if(value){
  1458. this.material.opacity = value
  1459. }else{
  1460. if(Potree.settings.sizeFitToLevel){//按照点云质量来调整的版本:
  1461. let base = this.material.spacing / Math.pow(1.4, this.maxLevel) //随着level提高,点云重叠几率增多
  1462. let minBase = this.material.spacing / Math.pow(1.4, this.nodeMaxLevel)
  1463. let ratio = Math.min(1 / base, 1 / minBase / 3) //ratio为一个能使opacity不大于1 的 乘量,minBase要除以一个数,该数调越大减弱效果越强。level越低opacity和面板越接,level越高效果越弱,以减免过度重叠后的亮度。
  1464. this.material.opacity = base * ratio * num
  1465. if(!canMoreThanOne){
  1466. this.material.opacity = THREE.Math.clamp(this.material.opacity, 0, 0.999) //到1就不透明了(可能出现一段一样)
  1467. }
  1468. }else{
  1469. let base = this.material.spacing / Math.pow(1.8, this.maxLevel)
  1470. let minBase = this.material.spacing / Math.pow(1.8, this.nodeMaxLevel)
  1471. //console.log(1 / base, 1 / minBase / 6)
  1472. let ratio = Math.min(1 / base, 1 / minBase / 6) //ratio为一个能使opacity不大于1 的 乘量,minBase要除以一个数,该数调越大减弱效果越强。level越低opacity和面板越接,level越高效果越弱,以减免过度重叠后的亮度。
  1473. this.material.opacity = base * ratio * num
  1474. if(!canMoreThanOne){
  1475. this.material.opacity = THREE.Math.clamp(this.material.opacity, 0, 0.999) //到1就不透明了(可能出现一段一样)
  1476. }
  1477. }
  1478. this.temp.opacity[str] = this.material.opacity
  1479. }
  1480. //缺点:防止颜色过亮主要是相机离远时,当在漫游点处由于离点云太近,可能会导致高质量点云看起来很暗。
  1481. }
  1482. //console.log('changePointOpacity ' + this.dataset_id + ', num : ' + num + ' , opacity : ' + this.material.opacity) //检查是否做到了低质量时num==opacity,中质量opacity稍小于num,高质量更小
  1483. }
  1484. updateBound(){
  1485. var boundingBox_ = this.pcoGeometry.tightBoundingBox.clone().applyMatrix4(this.matrixWorld)
  1486. this.bound = boundingBox_
  1487. }
  1488. getPanosBound(){
  1489. if(this.panos.length > 0){
  1490. let minSize = new THREE.Vector3(1,1,1)
  1491. this.panosBound = math.getBoundByPoints(this.panos.map(e=>e.position), minSize)
  1492. }else{
  1493. this.panosBound = null
  1494. }
  1495. }
  1496. getUnrotBoundPoint(type){//获取没有旋转的tightBounding的水平四个点
  1497. //如果alighment支持任意轴旋转,水平面上看到的可能就是六边形了,失去意义,到时候不能用这个。也可以若只绕z旋转, 使用tightBoundingBox,否则bound
  1498. let bound = this.pcoGeometry.tightBoundingBox
  1499. if(type == 'all'){
  1500. return [new THREE.Vector3(bound.min.x, bound.min.y, bound.min.z),
  1501. new THREE.Vector3(bound.max.x, bound.min.y, bound.min.z),
  1502. new THREE.Vector3(bound.max.x, bound.max.y,bound.min.z),
  1503. new THREE.Vector3(bound.min.x, bound.max.y,bound.min.z),
  1504. new THREE.Vector3(bound.min.x, bound.min.y, bound.max.z),
  1505. new THREE.Vector3(bound.max.x, bound.min.y, bound.max.z),
  1506. new THREE.Vector3(bound.max.x, bound.max.y,bound.max.z),
  1507. new THREE.Vector3(bound.min.x, bound.max.y,bound.max.z),
  1508. ].map(e=>e.applyMatrix4(this.matrixWorld))
  1509. }else
  1510. return [new THREE.Vector3(bound.min.x, bound.min.y,0),
  1511. new THREE.Vector3(bound.max.x, bound.min.y,0),
  1512. new THREE.Vector3(bound.max.x, bound.max.y,0),
  1513. new THREE.Vector3(bound.min.x, bound.max.y,0),
  1514. ].map(e=>e.applyMatrix4(this.matrixWorld))
  1515. }
  1516. ifContainsPoint(pos){
  1517. if(!this.bound || !this.bound.containsPoint(pos))return
  1518. var points = this.getUnrotBoundPoint()
  1519. return math.isPointInArea(points, null, pos)
  1520. }
  1521. getVolume(){
  1522. var points = this.getUnrotBoundPoint()
  1523. var area = Math.abs(math.getArea(points))
  1524. return area * (this.bound.max.z - this.bound.min.z)
  1525. }
  1526. //数据集的显示影响到其下的:点云、marker .不会影响地图上的显示
  1527. /*
  1528. updateVisible(reason, ifShow){//当所有加入的条件都不为false时才显示
  1529. if(ifShow){
  1530. var index = this.unvisibleReasons.indexOf(reason);
  1531. index > -1 && this.unvisibleReasons.splice(index, 1);
  1532. if(this.unvisibleReasons.length == 0){
  1533. this.visible = true;
  1534. this.dispatchEvent({
  1535. type: 'isVisible'
  1536. visible:true
  1537. })
  1538. }
  1539. }else {
  1540. if(!this.unvisibleReasons.includes(reason)) this.unvisibleReasons.push(reason);
  1541. this.visible = false;
  1542. this.dispatchEvent({
  1543. type: 'isVisible'
  1544. visible:false
  1545. })
  1546. }
  1547. }
  1548. getVisible(reason){//获取在某条件下是否可见. 注: 用户在数据集选择可不可见为"datasetSelection"
  1549. if(this.visible)return true
  1550. else{
  1551. return !this.unvisibleReasons.includes(reason)
  1552. }
  1553. } */
  1554. /* get isVisible(){//add 手动在数据集选择是否显示(和是否全景图、隐藏点云无关)
  1555. return this._isVisible
  1556. }
  1557. set isVisible(visi){
  1558. if(!visi)this.visible = false
  1559. this._isVisible = visi
  1560. } */
  1561. }
  1562. /*
  1563. window.searchOutRing = function(points){
  1564. var points = [{x:0,y:0},{x:1,y:1},{x:0,y:1},{x:1,y:0},{x:2,y:1},{x:1,y:2},{x:1,y:3},{x:2,y:3},
  1565. {x:3,y:1},{x:3,y:2},{x:0,y:2},{x:0,y:3},{x:2,y:0},{x:-1,y:0},{x:-1,y:1},{x:-2,y:1},{x:3,y:3},
  1566. {x:3,y:0},{x:2,y:-1},{x:0,y:-1},{x:1,y:0.5},{x:2,y:0.5}, ].map((e,index)=>{
  1567. var a = new THREE.Vector2().copy(e)
  1568. a.id = index;
  1569. return a
  1570. })
  1571. var lines = []
  1572. var minDis = 2*2
  1573. points.forEach((p,j)=>{
  1574. for(let i=0;i<j;i++){
  1575. if(p.distanceToSquared(points[i])<minDis){
  1576. lines.push({p1:i,p2:j})
  1577. }
  1578. }
  1579. })
  1580. searchRings({
  1581. points,
  1582. lines,
  1583. onlyGetOutRing:true
  1584. })
  1585. }
  1586. */