PointCloudOctreeGeometry.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import * as THREE from "../libs/three.js/build/three.module.js";
  2. import {PointCloudTreeNode} from "./PointCloudTree.js";
  3. import {XHRFactory} from "./XHRFactory.js";
  4. import {Utils} from "./utils.js";
  5. export class PointCloudOctreeGeometry{
  6. constructor(){
  7. this.url = null;
  8. this.octreeDir = null;
  9. this.spacing = 0;
  10. this.boundingBox = null;
  11. this.root = null;
  12. this.nodes = null;
  13. this.pointAttributes = null;
  14. this.hierarchyStepSize = -1;
  15. this.loader = null;
  16. }
  17. }
  18. export class PointCloudOctreeGeometryNode extends PointCloudTreeNode{
  19. constructor(name, pcoGeometry, boundingBox){
  20. super();
  21. this.id = PointCloudOctreeGeometryNode.IDCount++;
  22. this.name = name;
  23. this.index = parseInt(name.charAt(name.length - 1));
  24. this.pcoGeometry = pcoGeometry;
  25. this.geometry = null;
  26. this.boundingBox = boundingBox;
  27. this.boundingSphere = boundingBox.getBoundingSphere(new THREE.Sphere());
  28. this.children = {};
  29. this.numPoints = 0;
  30. this.level = null;
  31. this.loaded = false;
  32. this.oneTimeDisposeHandlers = [];
  33. }
  34. isGeometryNode(){
  35. return true;
  36. }
  37. getLevel(){
  38. return this.level;
  39. }
  40. isTreeNode(){
  41. return false;
  42. }
  43. isLoaded(){
  44. return this.loaded;
  45. }
  46. getBoundingSphere(){
  47. return this.boundingSphere;
  48. }
  49. getBoundingBox(){
  50. return this.boundingBox;
  51. }
  52. getChildren(){
  53. let children = [];
  54. for (let i = 0; i < 8; i++) {
  55. if (this.children[i]) {
  56. children.push(this.children[i]);
  57. }
  58. }
  59. return children;
  60. }
  61. getBoundingBox(){
  62. return this.boundingBox;
  63. }
  64. getURL(){
  65. let url = '';
  66. let version = this.pcoGeometry.loader.version;
  67. if (version.equalOrHigher('1.5')) {
  68. url = this.pcoGeometry.octreeDir + '/' + this.getHierarchyPath() + '/' + this.name;
  69. } else if (version.equalOrHigher('1.4')) {
  70. url = this.pcoGeometry.octreeDir + '/' + this.name;
  71. } else if (version.upTo('1.3')) {
  72. url = this.pcoGeometry.octreeDir + '/' + this.name;
  73. }
  74. return url;
  75. }
  76. getHierarchyPath(){
  77. let path = 'r/';
  78. let hierarchyStepSize = this.pcoGeometry.hierarchyStepSize;
  79. let indices = this.name.substr(1);
  80. let numParts = Math.floor(indices.length / hierarchyStepSize);
  81. for (let i = 0; i < numParts; i++) {
  82. path += indices.substr(i * hierarchyStepSize, hierarchyStepSize) + '/';
  83. }
  84. path = path.slice(0, -1);
  85. return path;
  86. }
  87. addChild(child) {
  88. this.children[child.index] = child;
  89. child.parent = this;
  90. }
  91. load(){
  92. if (this.loading === true || this.loaded === true || Potree.numNodesLoading >= Potree.maxNodesLoading) {
  93. return;
  94. }
  95. this.loading = true;
  96. Potree.numNodesLoading++;
  97. if (this.pcoGeometry.loader.version.equalOrHigher('1.5')) {
  98. if ((this.level % this.pcoGeometry.hierarchyStepSize) === 0 && this.hasChildren) {
  99. this.loadHierachyThenPoints();
  100. } else {
  101. this.loadPoints();
  102. }
  103. } else {
  104. this.loadPoints();
  105. }
  106. }
  107. loadPoints(){
  108. this.pcoGeometry.loader.load(this);
  109. }
  110. loadHierachyThenPoints(){
  111. let node = this;
  112. // load hierarchy
  113. let callback = function (node, hbuffer) {
  114. let tStart = performance.now();
  115. let view = new DataView(hbuffer);
  116. let stack = [];
  117. let children = view.getUint8(0);
  118. let numPoints = view.getUint32(1, true);
  119. node.numPoints = numPoints;
  120. stack.push({children: children, numPoints: numPoints, name: node.name});
  121. let decoded = [];
  122. let offset = 5;
  123. while (stack.length > 0) {
  124. let snode = stack.shift();
  125. let mask = 1;
  126. for (let i = 0; i < 8; i++) {
  127. if ((snode.children & mask) !== 0) {
  128. let childName = snode.name + i;
  129. let childChildren = view.getUint8(offset);
  130. let childNumPoints = view.getUint32(offset + 1, true);
  131. stack.push({children: childChildren, numPoints: childNumPoints, name: childName});
  132. decoded.push({children: childChildren, numPoints: childNumPoints, name: childName});
  133. offset += 5;
  134. }
  135. mask = mask * 2;
  136. }
  137. if (offset === hbuffer.byteLength) {
  138. break;
  139. }
  140. }
  141. // console.log(decoded);
  142. let nodes = {};
  143. nodes[node.name] = node;
  144. let pco = node.pcoGeometry;
  145. for (let i = 0; i < decoded.length; i++) {
  146. let name = decoded[i].name;
  147. let decodedNumPoints = decoded[i].numPoints;
  148. let index = parseInt(name.charAt(name.length - 1));
  149. let parentName = name.substring(0, name.length - 1);
  150. let parentNode = nodes[parentName];
  151. let level = name.length - 1;
  152. let boundingBox = Utils.createChildAABB(parentNode.boundingBox, index);
  153. let currentNode = new PointCloudOctreeGeometryNode(name, pco, boundingBox);
  154. currentNode.level = level;
  155. currentNode.numPoints = decodedNumPoints;
  156. currentNode.hasChildren = decoded[i].children > 0;
  157. currentNode.spacing = pco.spacing / Math.pow(2, level);
  158. parentNode.addChild(currentNode);
  159. nodes[name] = currentNode;
  160. }
  161. let duration = performance.now() - tStart;
  162. if(duration > 5){
  163. let msg = `duration: ${duration}ms, numNodes: ${decoded.length}`;
  164. console.log(msg);
  165. }
  166. node.loadPoints();
  167. };
  168. if ((node.level % node.pcoGeometry.hierarchyStepSize) === 0) {
  169. // let hurl = node.pcoGeometry.octreeDir + "/../hierarchy/" + node.name + ".hrc";
  170. let hurl = node.pcoGeometry.octreeDir + '/' + node.getHierarchyPath() + '/' + node.name + '.hrc';
  171. let xhr = XHRFactory.createXMLHttpRequest();
  172. xhr.open('GET', hurl, true);
  173. xhr.responseType = 'arraybuffer';
  174. xhr.overrideMimeType('text/plain; charset=x-user-defined');
  175. xhr.onreadystatechange = () => {
  176. if (xhr.readyState === 4) {
  177. if (xhr.status === 200 || xhr.status === 0) {
  178. let hbuffer = xhr.response;
  179. callback(node, hbuffer);
  180. } else {
  181. console.log('Failed to load file! HTTP status: ' + xhr.status + ', file: ' + hurl);
  182. Potree.numNodesLoading--;
  183. }
  184. }
  185. };
  186. try {
  187. xhr.send(null);
  188. } catch (e) {
  189. console.log('fehler beim laden der punktwolke: ' + e);
  190. }
  191. }
  192. }
  193. getNumPoints(){
  194. return this.numPoints;
  195. }
  196. dispose(){
  197. if (this.geometry && this.parent != null) {
  198. this.geometry.dispose();
  199. this.geometry = null;
  200. this.loaded = false;
  201. this.dispatchEvent( { type: 'dispose' } );
  202. for (let i = 0; i < this.oneTimeDisposeHandlers.length; i++) {
  203. let handler = this.oneTimeDisposeHandlers[i];
  204. handler();
  205. }
  206. this.oneTimeDisposeHandlers = [];
  207. }
  208. }
  209. }
  210. PointCloudOctreeGeometryNode.IDCount = 0;