Commit 04ce4a31 authored by bernie wang's avatar bernie wang
Browse files

added documentation and refactored Box into box.js

parent 0340790b
function Box(anchor, cursor, angle, boundingBox, boxHelper) {
this.id = id; // id (int) of Box
this.object_id = null; // object id (string)
this.color = new THREE.Color( 1,0,0 ); // color of corner points
this.angle = angle; // orientation of bounding box
this.anchor = anchor; // point where bounding box was created
this.cursor = cursor.clone(); // cursor
this.added = false; // (boolean) whether the box has been added to boundingboxes
this.boundingBox = boundingBox; // Box3; sets the size of the box
this.boxHelper = boxHelper; // BoxHelper; helps visualize the box
this.geometry = new THREE.Geometry(); // geometry for corner/rotating points
// visualizes the corners (in the non-rotated coordinates) of the box
this.points = new THREE.Points( this.geometry, pointMaterial );
this.points.frustumCulled = false; // allows
this.colors = []; // colors of the corner points
// add colors to points geometry
for (var i = 0; i < 6; i++) {
this.colors.push( this.color.clone().multiplyScalar( 7 ) );
}
this.geometry.colors = this.colors;
// order of corners is max, min, topleft, bottomright
this.geometry.vertices.push(anchor);
this.geometry.vertices.push(cursor);
this.geometry.vertices.push(anchor.clone());
this.geometry.vertices.push(cursor.clone());
this.geometry.vertices.push(getCenter(anchor.clone(), cursor.clone()));
}
// method for resizing bounding box given cursor coordinates
//
// since BoxHelper3 draws a box in the same orientation as that of the point cloud,
// we take the anchor and cursor, rotate them by the angle of the camera, draw the box,
// then rotate the box back
function resize(box, cursor) {
// checks and executes only if anchor does not overlap with cursor to avoid 0 determinant
if (cursor.x != box.anchor.x && cursor.y != box.anchor.y && cursor.z != box.anchor.z) {
var v1 = cursor.clone();
var v2 = box.anchor.clone();
v1.y = 0;
v2.y = 0;
// rotate cursor and anchor
rotate(v1, v2, box.angle);
// calculating corner points and rotating point
var minVector = getMin(v1, v2);
var maxVector = getMax(v1, v2);
var topLeft = getTopLeft(v1, v2);
var bottomRight = getBottomRight(v1, v2);
var topCenter = getCenter(topLeft, maxVector);
var bottomCenter = getCenter(minVector, bottomRight);
// need to do this to make matrix invertible
maxVector.y = 0.00001;
// setting bounding box limits
box.boundingBox.set(minVector.clone(), maxVector.clone());
// rotate BoxHelper back
box.boxHelper.rotation.y = box.angle;
// setting y coordinate back to zero since we are done with drawing
maxVector.y = 0;
// rotate back the corner points
rotate(minVector, maxVector, -box.angle);
rotate(topLeft, bottomRight, -box.angle);
rotate(topCenter, bottomCenter, -box.angle);
// set updated corner points used to resize box
box.geometry.vertices[0] = maxVector.clone();
box.geometry.vertices[1] = minVector.clone();
box.geometry.vertices[2] = topLeft.clone();
box.geometry.vertices[3] = bottomRight.clone();
box.geometry.vertices[4] = bottomCenter.clone();
// tell scene to update corner points
box.geometry.verticesNeedUpdate = true;
}
}
// method to rotate bounding box by clicking and dragging rotate point,
// which is the top center point on the bounding box
function rotateBox(box, cursor) {
// get corner points
var maxVector = box.geometry.vertices[0].clone();
var minVector = box.geometry.vertices[1].clone();
var topLeft = box.geometry.vertices[2].clone();
var bottomRight = box.geometry.vertices[3].clone();
var topCenter = getCenter(maxVector, topLeft);
var bottomCenter = box.geometry.vertices[4].clone();
// get relative angle of cursor with respect to
var center = getCenter(maxVector, minVector);
var angle = getAngle(center, bottomCenter, cursor, topCenter);
// update angle of Box and bounding box
box.angle = box.angle + angle;
box.boxHelper.rotation.y = box.angle;
// rotate and update corner points
rotate(minVector, maxVector, -angle);
rotate(topLeft, bottomRight, -angle);
rotate(topCenter, bottomCenter, -angle);
box.geometry.vertices[0] = maxVector.clone();
box.geometry.vertices[1] = minVector.clone();
box.geometry.vertices[2] = topLeft.clone();
box.geometry.vertices[3] = bottomRight.clone();
box.geometry.vertices[4] = bottomCenter.clone();
// tell scene to update corner points
box.geometry.verticesNeedUpdate = true;
}
// gets angle between v1 and v2 with respect to origin
//
// v3 is an optional reference point that should be v1's reflection about the origin,
// but is needed to get the correct sign of the angle
function getAngle(origin, v1, v2, v3) {
v1 = v1.clone();
v2 = v2.clone();
origin = origin.clone();
v1.sub(origin);
v2.sub(origin);
v1.y = 0;
v2.y = 0;
v1.normalize();
v2.normalize();
var angle = Math.acos(Math.min(1.0, v1.dot(v2)));
if (v3) {
v3 = v3.clone();
v3.sub(origin);
// calculates distance between v1 and v2 when v1 is rotated by angle
var temp1 = v1.clone();
rotate(temp1, v3.clone(), angle);
var d1 = distance2D(temp1, v2);
// calculates distance between v1 and v2 when v1 is rotated by -angle
var temp2 = v1.clone();
rotate(temp2, v3.clone(), -angle);
var d2 = distance2D(temp2, v2);
// compares distances to determine sign of angle
if (d2 > d1) {
angle = -angle;
}
}
return angle;
}
// highlights closest corner point that intersects with cursor
function highlightCorners() {
// get closest intersection with cursor
var intersection = intersectWithCorner();
if (intersection) {
// get closest point and its respective box
var box = intersection[0];
var p = intersection[1];
// get index of closest point
var closestIdx = closestPoint(p, box.geometry.vertices);
// if there was a previously hovered box, change its color back to red
if (hoverBox) {
changePointColor(hoverBox, hoverIdx, new THREE.Color(7, 0, 0));
}
// update hover box
hoverBox = box;
hoverIdx = closestIdx;
changePointColor(hoverBox, hoverIdx, new THREE.Color(0, 0, 7));
} else {
// change color of previously hovered box back to red
if (hoverBox) {
changePointColor(hoverBox, hoverIdx, new THREE.Color(7, 0, 0));
}
// set hover box to null since there is no intersection
hoverBox = null;
}
}
// changes and updates a box's point's color given point index and color
function changePointColor(box, idx, color) {
box.colors[idx] = color;
box.geometry.colorsNeedUpdate = true;
}
// method to translate bounding box given a reference point
function moveBox(box, v) {
// get difference in x and z coordinates between cursor when
// box was selected and current cursor position
var dx = v.x - box.cursor.x;
var dz = v.z - box.cursor.z;
// update all points related to box by dx and dz
box.anchor.x += dx;
box.anchor.z += dz;
box.cursor = v.clone();
for (var i = 0; i < box.geometry.vertices.length; i++) {
var p = box.geometry.vertices[i];
p.x += dx;
p.z += dz;
}
// shift bounding box given new corner points
var maxVector = box.geometry.vertices[0].clone();
var minVector = box.geometry.vertices[1].clone();
var topLeft = box.geometry.vertices[2].clone();
var bottomRight = box.geometry.vertices[3].clone();
var topCenter = getCenter(maxVector, topLeft);
var bottomCenter = box.geometry.vertices[4].clone();
rotate(maxVector, minVector, box.angle);
rotate(topLeft, bottomRight, box.angle);
rotate(topCenter, bottomCenter, box.angle);
// need to do this to make matrix invertible
maxVector.y += 0.0000001;
box.boundingBox.set(minVector, maxVector);
// tell scene to update corner points
box.geometry.verticesNeedUpdate = true;
}
// method to change color of bounding box
function changeBoundingBoxColor(box, color) {
var boxHelperCopy = new THREE.Box3Helper( box.boundingBox, color );
scene.add(boxHelperCopy);
scene.remove(box.boxHelper);
box.boxHelper = boxHelperCopy;
boxHelperCopy.rotation.y = box.angle;
}
// method to add box to boundingBoxes and object id table
function addBox(box) {
boundingBoxes.push(box);
id++;
addRow(box);
}
// method to highlight box given cursor
function selectBox(box, cursor) {
selectedBox = box;
if (box && cursor) {
selectedBox.cursor = cursor;
}
updateHoverBoxes(cursor);
changeBoundingBoxColor(box, new THREE.Color( 0,0,7 ) );
}
\ No newline at end of file
......@@ -48,34 +48,25 @@ init();
var id = 0;
// animate();
// Should be in init?
var sphereGeometry, sphereMaterial;
function generatePointCloud( vertices, color ) {
var geometry = new THREE.Geometry();
var colors = [];
var k = 0;
var stride = 4;
function normalizeColors(vertices, color) {
var maxColor = Number.NEGATIVE_INFINITY;
var minColor = Number.POSITIVE_INFINITY;
var intensities = [];
for ( var i = 0, l = vertices.length / 4; i < l; i ++ ) {
// creates new vector from a cluster and adds to geometry
var v = new THREE.Vector3( vertices[ stride * k + 1 ],
vertices[ stride * k + 2 ], vertices[ stride * k ] );
var colors = [];
yCoords.push(vertices[ stride * k + 2 ]);
k = 0;
var stride = 4;
// finds max and min z coordinates
for ( var i = 0, l = vertices.length / 4; i < l; i ++ ) {
if (vertices[ stride * k + 2] > maxColor) {
maxColor = vertices[ stride * k + 2];
}
if (vertices[ stride * k + 2] < minColor) {
minColor = vertices[ stride * k + 2];
}
geometry.vertices.push( v );
intensities.push(vertices[ stride * k + 2]);
k++;
}
......@@ -86,6 +77,10 @@ function generatePointCloud( vertices, color ) {
var min = getMinElement(filteredIntensities);
var max = getMaxElement(filteredIntensities);
// normalize colors
// if greater than 2 sd from mean, set to max color
// if less than 2 sd from mean, set to min color
// ortherwise normalize color based on min and max z-coordinates
for ( var i = 0; i < intensities.length; i ++ ) {
var intensity = intensities[i];
if (intensities[i] - mean >= 2 * sd) {
......@@ -97,8 +92,31 @@ function generatePointCloud( vertices, color ) {
}
colors[i] = ( color.clone().multiplyScalar( intensity * 2 ) );
}
return colors;
}
function generatePointCloud( vertices, color ) {
var geometry = new THREE.Geometry();
var k = 0;
var stride = 4;
for ( var i = 0, l = vertices.length / 4; i < l; i ++ ) {
// creates new vector from a cluster and adds to geometry
var v = new THREE.Vector3( vertices[ stride * k + 1 ],
vertices[ stride * k + 2 ], vertices[ stride * k ] );
// stores y coordinates into yCoords
yCoords.push(vertices[ stride * k + 2 ]);
// add vertex to geometry
geometry.vertices.push( v );
k++;
}
geometry.colors = colors;
geometry.colors = normalizeColors(vertices, color);
geometry.computeBoundingBox();
var material = new THREE.PointsMaterial( { size: pointSize, sizeAttenuation: false, vertexColors: THREE.VertexColors } );
......@@ -109,79 +127,38 @@ function generatePointCloud( vertices, color ) {
}
function Box(anchor, cursor, angle, boundingBox, boxHelper) {
this.color = new THREE.Color( 1,0,0 );
this.angle = angle;
this.anchor = anchor;
this.geometry = new THREE.Geometry();
// visualizes the corners (in the non-rotated coordinates) of the box
this.points = new THREE.Points( this.geometry, pointMaterial );
this.boundingBox = boundingBox; // Box3; sets the size of the box
this.boxHelper = boxHelper; // BoxHelper; helps visualize the box
this.colors = []; // colors of the corner points
for (var i = 0; i < 6; i++) {
this.colors.push( this.color.clone().multiplyScalar( 7 ) );
}
this.geometry.colors = this.colors;
this.cursor = cursor.clone();
// order of corners is max, min, topleft, bottomright
this.geometry.vertices.push(anchor);
this.geometry.vertices.push(cursor);
this.geometry.vertices.push(anchor.clone());
this.geometry.vertices.push(cursor.clone());
this.geometry.vertices.push(getCenter(anchor.clone(), cursor.clone()));
this.points.frustumCulled = false;
this.added = false;
this.id = id;
this.object_id = null;
}
// called first, populates scene and initializes renderer
function init() {
var container = document.getElementById( 'container' );
scene = new THREE.Scene();
clock = new THREE.Clock();
// set up PerspectiveCamera
camera = new THREE.PerspectiveCamera( 45, window.innerWidth / window.innerHeight, 1, 10000 );
// camera.position.y = 25;
// camera.position.z = 37;
camera.position.set(0, 100, 0);
camera.lookAt(new THREE.Vector3(0,0,0));
sphereGeometry = new THREE.SphereGeometry( 0.1, 32, 32 );
sphereMaterial = new THREE.MeshBasicMaterial( { color: 0xff0000, flatShading: THREE.FlatShading } );
//
grid = new THREE.GridHelper( 200, 20, 0xffffff, 0xffffff );
scene.add( grid );
//
// set up renderer
renderer = new THREE.WebGLRenderer({preserveDrawingBuffer: true});
renderer.setPixelRatio( window.devicePixelRatio );
renderer.setSize( window.innerWidth, window.innerHeight );
container.appendChild( renderer.domElement );
//
raycaster = new THREE.Raycaster();
raycaster.params.Points.threshold = threshold;
//
stats = new Stats();
container.appendChild( stats.dom );
//
controls = new THREE.OrbitControls( camera, renderer.domElement );
window.addEventListener( 'resize', onWindowResize, false );
......@@ -190,15 +167,14 @@ function init() {
document.getElementById('container').addEventListener( 'mouseup', onDocumentMouseUp, false );
document.addEventListener( 'mousemove', updateMouse, false );
document.getElementById( 'save' ).addEventListener( 'click', save, false );
// document.getElementById( 'export' ).addEventListener( 'click', save_image, false );
document.getElementById( 'move' ).addEventListener( 'click', moveMode, false );
document.getElementById( 'move2D' ).addEventListener( 'click', move2DMode, false );
// document.getElementById( 'label' ).addEventListener( 'click', labelMode, false );
document.getElementById( 'file_input' ).addEventListener( 'change', upload_file, false );
document.addEventListener("keydown", onKeyDown); //or however you are calling your method
document.addEventListener("keyup", onKeyUp);
}
// controller for pressing hotkeys
function onKeyDown(event) {
if (event.ctrlKey) {
toggleControl(false);
......@@ -213,12 +189,12 @@ function onKeyDown(event) {
deleteSelectedBox();
break;
case 68:
// toggleControl(false);
default:
break;
}
}
// controller for releasing hotkeys
function onKeyUp(event) {
var KeyID = event.keyCode;
switch(KeyID)
......@@ -229,6 +205,7 @@ function onKeyUp(event) {
}
}
// toggles between move2D and move3D
function toggleControl(b) {
if (b) {
controls.enabled = b;
......@@ -241,17 +218,24 @@ function toggleControl(b) {
}
}
// deletes selected box when delete key pressed
function deleteSelectedBox() {
if (selectedBox) {
scene.remove(selectedBox.points);
scene.remove(selectedBox.boxHelper);
// deletes corresponding row in object id table
deleteRow(selectedBox.id);
// removes selected box from array of currently hovered boxes
for (var i = 0; i < hoverBoxes.length; i++) {
if (hoverBoxes[i] == selectedBox) {
hoverBoxes.splice(i, 1);
break;
}
}
// removes selected box from array of bounding boxes
for (var i = 0; i < boundingBoxes.length; i++) {
if (boundingBoxes[i] == selectedBox) {
boundingBoxes.splice(i, 1);
......@@ -259,17 +243,18 @@ function deleteSelectedBox() {
}
}
// removes selected box
selectedBox = null;
}
}
// removes row of object id table given corrensponding bounding box id
function deleteRow(id) {
var row = getRow(id);
row.remove();
}
// gets 2D mouse coordinates
function updateMouse( event ) {
event.preventDefault();
mouse2D.x = ( event.clientX / window.innerWidth ) * 2 - 1;
......@@ -277,201 +262,77 @@ function updateMouse( event ) {
}
function resize(box, cursor) {
if (cursor.x != box.anchor.x && cursor.y != box.anchor.y && cursor.z != box.anchor.z) {
var v1 = cursor.clone();
var v2 = box.anchor.clone();
v1.y = 0;
v2.y = 0;
// for rotation
rotate(v1, v2, box.angle);
var minVector = getMin(v1, v2);
var maxVector = getMax(v1, v2);
var topLeft = getTopLeft(v1, v2);
var bottomRight = getBottomRight(v1, v2);
var topCenter = getCenter(topLeft, maxVector);
var bottomCenter = getCenter(minVector, bottomRight);
maxVector.y = 0.00001; // need to do this to make matrix invertible
box.boundingBox.set(minVector.clone(), maxVector.clone());
// for rotation
box.boxHelper.rotation.y = box.angle;
maxVector.y = 0;
rotate(minVector, maxVector, -box.angle);
rotate(topLeft, bottomRight, -box.angle);
rotate(topCenter, bottomCenter, -box.angle);
// set corner points
box.geometry.vertices[0] = maxVector.clone();
box.geometry.vertices[1] = minVector.clone();
box.geometry.vertices[2] = topLeft.clone();
box.geometry.vertices[3] = bottomRight.clone();
box.geometry.vertices[4] = bottomCenter.clone();
box.geometry.verticesNeedUpdate = true;
}
}
function rotateBox(box, cursor) {
var maxVector = box.geometry.vertices[0].clone();
var minVector = box.geometry.vertices[1].clone();
var topLeft = box.geometry.vertices[2].clone();
var bottomRight = box.geometry.vertices[3].clone();
var topCenter = getCenter(maxVector, topLeft);
var bottomCenter = box.geometry.vertices[4].clone();
var center = getCenter(maxVector, minVector);
var angle = getAngle(center, bottomCenter, cursor, topCenter);
box.angle = box.angle + angle;
box.boxHelper.rotation.y = box.angle;
rotate(minVector, maxVector, -angle);
rotate(topLeft, bottomRight, -angle);
rotate(topCenter, bottomCenter, -angle);
box.geometry.vertices[0] = maxVector.clone();
box.geometry.vertices[1] = minVector.clone();
box.geometry.vertices[2] = topLeft.clone();
box.geometry.vertices[3] = bottomRight.clone();
box.geometry.vertices[4] = bottomCenter.clone();
box.geometry.verticesNeedUpdate = true;
}
function getAngle(origin, v1, v2, v3) {
v1 = v1.clone();
v2 = v2.clone();
origin = origin.clone();
v1.sub(origin);
v2.sub(origin);
v1.y = 0;
v2.y = 0;
v1.normalize();
v2.normalize();
var angle = Math.acos(Math.min(1.0, v1.dot(v2)));
if (v3) {
v3 = v3.clone();
v3.sub(origin);
var d1 = distance2D(v1, v2);