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