potree
Version:
WebGL point cloud viewer - WORK IN PROGRESS
249 lines (198 loc) • 6.9 kB
JavaScript
Potree.PointCloudOctreeGeometry = function () {
this.url = null;
this.octreeDir = null;
this.spacing = 0;
this.boundingBox = null;
this.root = null;
this.numNodesLoading = 0;
this.nodes = null;
this.pointAttributes = null;
this.hierarchyStepSize = -1;
this.loader = null;
};
Potree.PointCloudOctreeGeometryNode = function (name, pcoGeometry, boundingBox) {
this.id = Potree.PointCloudOctreeGeometryNode.IDCount++;
this.name = name;
this.index = parseInt(name.charAt(name.length - 1));
this.pcoGeometry = pcoGeometry;
this.geometry = null;
this.boundingBox = boundingBox;
this.boundingSphere = boundingBox.getBoundingSphere();
this.children = {};
this.numPoints = 0;
this.level = null;
this.loaded = false;
this.oneTimeDisposeHandlers = [];
};
Potree.PointCloudOctreeGeometryNode.IDCount = 0;
Potree.PointCloudOctreeGeometryNode.prototype = Object.create(Potree.PointCloudTreeNode.prototype);
Potree.PointCloudOctreeGeometryNode.prototype.isGeometryNode = function () {
return true;
};
Potree.PointCloudOctreeGeometryNode.prototype.getLevel = function () {
return this.level;
};
Potree.PointCloudOctreeGeometryNode.prototype.isTreeNode = function () {
return false;
};
Potree.PointCloudOctreeGeometryNode.prototype.isLoaded = function () {
return this.loaded;
};
Potree.PointCloudOctreeGeometryNode.prototype.getBoundingSphere = function () {
return this.boundingSphere;
};
Potree.PointCloudOctreeGeometryNode.prototype.getBoundingBox = function () {
return this.boundingBox;
};
Potree.PointCloudOctreeGeometryNode.prototype.getChildren = function () {
var children = [];
for (var i = 0; i < 8; i++) {
if (this.children[i]) {
children.push(this.children[i]);
}
}
return children;
};
Potree.PointCloudOctreeGeometryNode.prototype.getBoundingBox = function () {
return this.boundingBox;
};
Potree.PointCloudOctreeGeometryNode.prototype.getURL = function () {
var url = '';
var version = this.pcoGeometry.loader.version;
if (version.equalOrHigher('1.5')) {
url = this.pcoGeometry.octreeDir + '/' + this.getHierarchyPath() + '/' + this.name;
} else if (version.equalOrHigher('1.4')) {
url = this.pcoGeometry.octreeDir + '/' + this.name;
} else if (version.upTo('1.3')) {
url = this.pcoGeometry.octreeDir + '/' + this.name;
}
return url;
};
Potree.PointCloudOctreeGeometryNode.prototype.getHierarchyPath = function () {
var path = 'r/';
var hierarchyStepSize = this.pcoGeometry.hierarchyStepSize;
var indices = this.name.substr(1);
var numParts = Math.floor(indices.length / hierarchyStepSize);
for (var i = 0; i < numParts; i++) {
path += indices.substr(i * hierarchyStepSize, hierarchyStepSize) + '/';
}
path = path.slice(0, -1);
return path;
};
Potree.PointCloudOctreeGeometryNode.prototype.addChild = function (child) {
this.children[child.index] = child;
child.parent = this;
};
Potree.PointCloudOctreeGeometryNode.prototype.load = function () {
if (this.loading === true || this.loaded === true || this.pcoGeometry.numNodesLoading > 3) {
return;
}
this.loading = true;
this.pcoGeometry.numNodesLoading++;
if (this.pcoGeometry.loader.version.equalOrHigher('1.5')) {
if ((this.level % this.pcoGeometry.hierarchyStepSize) === 0 && this.hasChildren) {
this.loadHierachyThenPoints();
} else {
this.loadPoints();
}
} else {
this.loadPoints();
}
};
Potree.PointCloudOctreeGeometryNode.prototype.loadPoints = function () {
this.pcoGeometry.loader.load(this);
};
Potree.PointCloudOctreeGeometryNode.prototype.loadHierachyThenPoints = function () {
var node = this;
// load hierarchy
var callback = function (node, hbuffer) {
var view = new DataView(hbuffer);
var stack = [];
var children = view.getUint8(0);
var numPoints = view.getUint32(1, true);
node.numPoints = numPoints;
stack.push({children: children, numPoints: numPoints, name: node.name});
var decoded = [];
var offset = 5;
while (stack.length > 0) {
var snode = stack.shift();
var mask = 1;
for (let i = 0; i < 8; i++) {
if ((snode.children & mask) !== 0) {
var childName = snode.name + i;
var childChildren = view.getUint8(offset);
var childNumPoints = view.getUint32(offset + 1, true);
stack.push({children: childChildren, numPoints: childNumPoints, name: childName});
decoded.push({children: childChildren, numPoints: childNumPoints, name: childName});
offset += 5;
}
mask = mask * 2;
}
if (offset === hbuffer.byteLength) {
break;
}
}
// console.log(decoded);
var nodes = {};
nodes[node.name] = node;
var pco = node.pcoGeometry;
for (let i = 0; i < decoded.length; i++) {
var name = decoded[i].name;
var decodedNumPoints = decoded[i].numPoints;
var index = parseInt(name.charAt(name.length - 1));
var parentName = name.substring(0, name.length - 1);
var parentNode = nodes[parentName];
var level = name.length - 1;
var boundingBox = Potree.POCLoader.createChildAABB(parentNode.boundingBox, index);
var currentNode = new Potree.PointCloudOctreeGeometryNode(name, pco, boundingBox);
currentNode.level = level;
currentNode.numPoints = decodedNumPoints;
currentNode.hasChildren = decoded[i].children > 0;
currentNode.spacing = pco.spacing / Math.pow(2, level);
parentNode.addChild(currentNode);
nodes[name] = currentNode;
}
node.loadPoints();
};
if ((node.level % node.pcoGeometry.hierarchyStepSize) === 0) {
// var hurl = node.pcoGeometry.octreeDir + "/../hierarchy/" + node.name + ".hrc";
var hurl = node.pcoGeometry.octreeDir + '/' + node.getHierarchyPath() + '/' + node.name + '.hrc';
var xhr = new XMLHttpRequest();
xhr.open('GET', hurl, true);
xhr.responseType = 'arraybuffer';
xhr.overrideMimeType('text/plain; charset=x-user-defined');
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200 || xhr.status === 0) {
var hbuffer = xhr.response;
callback(node, hbuffer);
} else {
console.log('Failed to load file! HTTP status: ' + xhr.status + ', file: ' + hurl);
}
}
};
try {
xhr.send(null);
} catch (e) {
console.log('fehler beim laden der punktwolke: ' + e);
}
}
};
Potree.PointCloudOctreeGeometryNode.prototype.getNumPoints = function () {
return this.numPoints;
};
Potree.PointCloudOctreeGeometryNode.prototype.dispose = function () {
if (this.geometry && this.parent != null) {
this.geometry.dispose();
this.geometry = null;
this.loaded = false;
// this.dispatchEvent( { type: 'dispose' } );
for (var i = 0; i < this.oneTimeDisposeHandlers.length; i++) {
var handler = this.oneTimeDisposeHandlers[i];
handler();
}
this.oneTimeDisposeHandlers = [];
}
};
// THREE.EventDispatcher.prototype.apply( Potree.PointCloudOctreeGeometryNode.prototype );
Object.assign(Potree.PointCloudOctreeGeometryNode.prototype, THREE.EventDispatcher.prototype);