PointCloudOctree.js 61 KB

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