potree
Version:
WebGL point cloud viewer - WORK IN PROGRESS
319 lines (255 loc) • 7.85 kB
JavaScript
Potree.Profile = class extends THREE.Object3D {
constructor () {
super();
this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
this.name = 'Profile_' + this.constructor.counter;
this.points = [];
this.spheres = [];
this.edges = [];
this.boxes = [];
this.width = 1;
this.height = 20;
this._modifiable = true;
this.sphereGeometry = new THREE.SphereGeometry(0.4, 10, 10);
this.color = new THREE.Color(0xff0000);
this.lineColor = new THREE.Color(0xff0000);
}
createSphereMaterial () {
let sphereMaterial = new THREE.MeshLambertMaterial({
shading: THREE.SmoothShading,
color: 0xff0000,
depthTest: false,
depthWrite: false}
);
return sphereMaterial;
};
getSegments () {
let segments = [];
for (let i = 0; i < this.points.length - 1; i++) {
let start = this.points[i].clone();
let end = this.points[i + 1].clone();
segments.push({start: start, end: end});
}
return segments;
}
getSegmentMatrices () {
let segments = this.getSegments();
let matrices = [];
for (let segment of segments) {
let {start, end} = segment;
let box = new THREE.Object3D();
let length = start.clone().setZ(0).distanceTo(end.clone().setZ(0));
box.scale.set(length, 10000, this.width);
box.up.set(0, 0, 1);
let center = new THREE.Vector3().addVectors(start, end).multiplyScalar(0.5);
let diff = new THREE.Vector3().subVectors(end, start);
let target = new THREE.Vector3(diff.y, -diff.x, 0);
box.position.set(0, 0, 0);
box.lookAt(target);
box.position.copy(center);
box.updateMatrixWorld();
matrices.push(box.matrixWorld);
}
return matrices;
}
addMarker (point) {
this.points.push(point);
let sphere = new THREE.Mesh(this.sphereGeometry, this.createSphereMaterial());
this.add(sphere);
this.spheres.push(sphere);
// edges & boxes
if (this.points.length > 1) {
var lineGeometry = new THREE.Geometry();
lineGeometry.vertices.push(new THREE.Vector3(), new THREE.Vector3());
lineGeometry.colors.push(this.lineColor, this.lineColor, this.lineColor);
var lineMaterial = new THREE.LineBasicMaterial({
vertexColors: THREE.VertexColors,
linewidth: 2,
transparent: true,
opacity: 0.4
});
lineMaterial.depthTest = false;
var edge = new THREE.Line(lineGeometry, lineMaterial);
edge.visible = false;
this.add(edge);
this.edges.push(edge);
var boxGeometry = new THREE.BoxGeometry(1, 1, 1);
var boxMaterial = new THREE.MeshBasicMaterial({color: 0xff0000, transparent: true, opacity: 0.2});
var box = new THREE.Mesh(boxGeometry, boxMaterial);
box.visible = false;
this.add(box);
this.boxes.push(box);
}
{ // event listeners
let drag = (e) => {
let I = Potree.utils.getMousePointCloudIntersection(
e.drag.end,
e.viewer.scene.camera,
e.viewer.renderer,
e.viewer.scene.pointclouds);
if (I) {
let i = this.spheres.indexOf(e.drag.object);
if (i !== -1) {
this.setPosition(i, I.location);
this.dispatchEvent({
'type': 'marker_moved',
'profile': this,
'index': i
});
}
}
};
let drop = e => {
let i = this.spheres.indexOf(e.drag.object);
if (i !== -1) {
this.dispatchEvent({
'type': 'marker_dropped',
'profile': this,
'index': i
});
}
};
let mouseover = (e) => e.object.material.emissive.setHex(0x888888);
let mouseleave = (e) => e.object.material.emissive.setHex(0x000000);
sphere.addEventListener('drag', drag);
sphere.addEventListener('drop', drop);
sphere.addEventListener('mouseover', mouseover);
sphere.addEventListener('mouseleave', mouseleave);
}
let event = {
type: 'marker_added',
profile: this,
sphere: sphere
};
this.dispatchEvent(event);
this.setPosition(this.points.length - 1, point);
}
removeMarker (index) {
this.points.splice(index, 1);
this.remove(this.spheres[index]);
var edgeIndex = (index === 0) ? 0 : (index - 1);
this.remove(this.edges[edgeIndex]);
this.edges.splice(edgeIndex, 1);
this.remove(this.boxes[edgeIndex]);
this.boxes.splice(edgeIndex, 1);
this.spheres.splice(index, 1);
this.update();
this.dispatchEvent({
'type': 'marker_removed',
'profile': this
});
}
setPosition (index, position) {
let point = this.points[index];
point.copy(position);
let event = {
type: 'marker_moved',
profile: this,
index: index,
position: point.clone()
};
this.dispatchEvent(event);
this.update();
}
setWidth (width) {
this.width = width;
let event = {
type: 'width_changed',
profile: this,
width: width
};
this.dispatchEvent(event);
this.update();
}
getWidth () {
return this.width;
}
update () {
if (this.points.length === 0) {
return;
} else if (this.points.length === 1) {
let point = this.points[0];
this.spheres[0].position.copy(point);
return;
}
let min = this.points[0].clone();
let max = this.points[0].clone();
let centroid = new THREE.Vector3();
let lastIndex = this.points.length - 1;
for (let i = 0; i <= lastIndex; i++) {
let point = this.points[i];
let sphere = this.spheres[i];
let leftIndex = (i === 0) ? lastIndex : i - 1;
// let rightIndex = (i === lastIndex) ? 0 : i + 1;
let leftVertex = this.points[leftIndex];
// let rightVertex = this.points[rightIndex];
let leftEdge = this.edges[leftIndex];
let rightEdge = this.edges[i];
let leftBox = this.boxes[leftIndex];
// rightBox = this.boxes[i];
// let leftEdgeLength = point.distanceTo(leftVertex);
// let rightEdgeLength = point.distanceTo(rightVertex);
// let leftEdgeCenter = new THREE.Vector3().addVectors(leftVertex, point).multiplyScalar(0.5);
// let rightEdgeCenter = new THREE.Vector3().addVectors(point, rightVertex).multiplyScalar(0.5);
sphere.position.copy(point);
if (this._modifiable) {
sphere.visible = true;
} else {
sphere.visible = false;
}
if (leftEdge) {
leftEdge.geometry.vertices[1].copy(point);
leftEdge.geometry.verticesNeedUpdate = true;
leftEdge.geometry.computeBoundingSphere();
}
if (rightEdge) {
rightEdge.geometry.vertices[0].copy(point);
rightEdge.geometry.verticesNeedUpdate = true;
rightEdge.geometry.computeBoundingSphere();
}
if (leftBox) {
var start = leftVertex;
var end = point;
var length = start.clone().setZ(0).distanceTo(end.clone().setZ(0));
leftBox.scale.set(length, 1000000, this.width);
leftBox.up.set(0, 0, 1);
var center = new THREE.Vector3().addVectors(start, end).multiplyScalar(0.5);
var diff = new THREE.Vector3().subVectors(end, start);
var target = new THREE.Vector3(diff.y, -diff.x, 0);
leftBox.position.set(0, 0, 0);
leftBox.lookAt(target);
leftBox.position.copy(center);
}
centroid.add(point);
min.min(point);
max.max(point);
}
centroid.multiplyScalar(1 / this.points.length);
for (let i = 0; i < this.boxes.length; i++) {
var box = this.boxes[i];
box.position.z = min.z + (max.z - min.z) / 2;
}
}
raycast (raycaster, intersects) {
for (let i = 0; i < this.points.length; i++) {
let sphere = this.spheres[i];
sphere.raycast(raycaster, intersects);
}
// recalculate distances because they are not necessarely correct
// for scaled objects.
// see https://github.com/mrdoob/three.js/issues/5827
// TODO: remove this once the bug has been fixed
for (let i = 0; i < intersects.length; i++) {
let I = intersects[i];
I.distance = raycaster.ray.origin.distanceTo(I.point);
}
intersects.sort(function (a, b) { return a.distance - b.distance; });
};
get modifiable () {
return this._modifiable;
}
set modifiable (value) {
this._modifiable = value;
this.update();
}
};