1 /** 2 * potree.js 3 * http://potree.org 4 * 5 * Copyright 2012, Markus Sch�tz 6 * Licensed under the GPL Version 2 or later. 7 * - http://potree.org/wp/?page_id=7 8 * - http://www.gnu.org/licenses/gpl-3.0.html 9 * 10 */ 11 12 /** 13 * 14 * @class 15 * Single Node inside the octree. May have up to 8 children named 0 to 7 16 * 17 * This is not a SceneNode 18 */ 19 function PointcloudOctreeNode(name, poc) { 20 this.name = name; 21 this.id = poc.octreeDir + "/" + name; 22 this.pointCloud = null; 23 this.level = name.length-1; 24 this.children = new Object(); 25 this.age = 0; 26 this.poc = poc; 27 this.isLoading = false; 28 this.points = 0; 29 // because rendering transparent objects requires z-ordering and points are not ordered, 30 // opacity affects point size rather than transparency. 31 this.opacity = 0; 32 // opacity raises or falls over time, depending whether fade is positive or negative. 33 this.fade = 0; 34 35 if(PointcloudOctreeNode.lruNodes == null){ 36 PointcloudOctreeNode.lruNodes = new LRU(); 37 } 38 } 39 40 PointcloudOctreeNode.useFading = true; 41 42 /** 43 * memory usage of all poc nodes combined. Has to be updated whenever point cloud data for a node is loaded or unloaded 44 */ 45 PointcloudOctreeNode.memoryThreshold = 500*1000*1000; 46 //PointcloudOctreeNode.memoryThreshold = 40*1000*1000; 47 48 PointcloudOctreeNode.nodesLoadedThisFrame = 0; 49 50 PointcloudOctreeNode.lruNodes = null; 51 52 PointcloudOctreeNode.prototype.shouldBeRendered = false; 53 54 /** 55 * returns the size of this nodes pointcloud data. The pointcloud does not have to be loaded. 56 */ 57 PointcloudOctreeNode.prototype.sizeInBytes = function(){ 58 return this.poc.pointAttributes.byteSize * this.points; 59 }; 60 61 PointcloudOctreeNode.prototype.fadeIn = function(){ 62 if(PointcloudOctreeNode.useFading){ 63 this.fade = 1; 64 }else{ 65 this.opacity = 1; 66 } 67 }; 68 69 PointcloudOctreeNode.prototype.isFadingOut = function(){ 70 return this.fade < 0; 71 }; 72 73 PointcloudOctreeNode.prototype.fadeOut = function(){ 74 if(PointcloudOctreeNode.useFading){ 75 this.fade = -1; 76 }else{ 77 this.opacity = 0; 78 } 79 }; 80 81 82 83 PointcloudOctreeNode.prototype.isVisible = function(){ 84 return this.opacity > 0; 85 }; 86 87 88 /** 89 * cancels fading 90 */ 91 PointcloudOctreeNode.prototype.setOpacity = function(opacity){ 92 this.fade = 0; 93 this.opacity = opacity; 94 }; 95 96 PointcloudOctreeNode.prototype.setPointCloud = function(pointCloud) { 97 this.pointCloud = pointCloud; 98 //this.aabb = this.pointCloud.getAABB(); 99 this.age = 0; 100 }; 101 102 PointcloudOctreeNode.prototype.addTime = function addTime(time){ 103 this.age += time; 104 this.opacity += this.fade * time; 105 if(this.opacity > 1){ 106 this.opacity = 1; 107 this.fade = 0; 108 }else if(this.opacity < 0){ 109 this.opacity = 0; 110 this.fade = 0; 111 } 112 113 if(this.isVisible()){ 114 for(var index in this.children){ 115 this.children[index].addTime(time); 116 } 117 } 118 }; 119 120 PointcloudOctreeNode.prototype.setAABB = function(aabb){ 121 this.aabb = aabb; 122 } 123 124 PointcloudOctreeNode.prototype.addChild = function(child) { 125 126 var path = child.name.replace(this.name, ""); 127 if (path.length == 1) { 128 if (this.children[path] == null) { 129 this.children[path] = child; 130 child.parent = this; 131 } else { 132 // TODO what did i intend to do? 133 /* 134 * if(this.children[path].name.length > child.name.length){ var 135 * deeperChild = this.children[path]; this.children[path] = child; 136 * child.addChild(deeperChild); }else{ logError("node 137 * '"+this.name+"' already has a child on position " + path); } 138 */ 139 } 140 } else if (path.length > 1) { 141 var childIndex = path[0]; 142 if (this.children[childIndex] != null) { 143 this.children[childIndex].addChild(child); 144 } else { 145 this.children[childIndex] = child; 146 child.parent = this; 147 } 148 } else { 149 logError("something is wrong with the path: "); 150 logError("this.name: " + this.name); 151 logError("child.name: " + child.name); 152 logError("path: " + path); 153 } 154 155 // this.setAABBRecursive(this.aabb); 156 }; 157 158 /** 159 * removes loaded point cloud data from gpu 160 */ 161 PointcloudOctreeNode.prototype.unload = function unloadPOCNode(){ 162 if(this.pointCloud != null){ 163 // Logger.info("unload node: " + this.id); 164 this.pointCloud.unload(); 165 this.pointCloud = null; 166 }else{ 167 Logger.error("tried to unload node but it is not loaded"); 168 } 169 // debugView.set("loadedNodes: ", PointcloudOctreeNode.lruNodes.size() ); 170 }; 171 172 PointcloudOctreeNode.loadCloudAjax = function loadPOCCloudAjax(node) { 173 if(node.isLoading){ 174 Logger.error("node is already loading: " + node.name); 175 return; 176 } 177 node.isLoading = true; 178 179 var url = node.poc.octreeDir + "/" + node.name; 180 181 var xhr = new XMLHttpRequest(); 182 xhr.open('GET', url, true); 183 xhr.responseType = 'arraybuffer'; 184 xhr.overrideMimeType('text/plain; charset=x-user-defined'); 185 xhr.onreadystatechange = function() { 186 if (xhr.readyState == 4) { 187 // when accessing local files, req.status will be 0 188 if (xhr.status == 200 || xhr.status == 0) { 189 var buffer = xhr.response; 190 PointcloudOctreeNode.loadCloudData(node, buffer, url); 191 } else { 192 alert('Failed to load file! HTTP status: ' + xhr.status 193 + ", file: " + url); 194 } 195 } 196 }; 197 try{ 198 xhr.send(null); 199 }catch(e){ 200 alert("fehler beim laden der punktwolke: " + e); 201 } 202 203 }; 204 205 PointcloudOctreeNode.loadCloudData = function(node, buffer, url) { 206 PointcloudOctreeNode.nodesLoadedThisFrame++; 207 208 var pointCloud = new PointCloud(url, node.poc.pointAttributes); 209 pointCloud.setVertexBufferData(buffer); 210 pointCloud.size = buffer.byteLength / node.poc.pointAttributes.byteSize; 211 212 node.setPointCloud(pointCloud); 213 PointcloudOctreeNode.lruNodes.touch(node); 214 node.isLoading = false; 215 }; 216 217