var Point3d = require('./Point3d'); /** * @class Camera * The camera is mounted on a (virtual) camera arm. The camera arm can rotate * The camera is always looking in the direction of the origin of the arm. * This way, the camera always rotates around one fixed point, the location * of the camera arm. * * Documentation: * http://en.wikipedia.org/wiki/3D_projection */ Camera = function () { this.armLocation = new Point3d(); this.armRotation = {}; this.armRotation.horizontal = 0; this.armRotation.vertical = 0; this.armLength = 1.7; this.cameraLocation = new Point3d(); this.cameraRotation = new Point3d(0.5*Math.PI, 0, 0); this.calculateCameraOrientation(); }; /** * Set the location (origin) of the arm * @param {Number} x Normalized value of x * @param {Number} y Normalized value of y * @param {Number} z Normalized value of z */ Camera.prototype.setArmLocation = function(x, y, z) { this.armLocation.x = x; this.armLocation.y = y; this.armLocation.z = z; this.calculateCameraOrientation(); }; /** * Set the rotation of the camera arm * @param {Number} horizontal The horizontal rotation, between 0 and 2*PI. * Optional, can be left undefined. * @param {Number} vertical The vertical rotation, between 0 and 0.5*PI * if vertical=0.5*PI, the graph is shown from the * top. Optional, can be left undefined. */ Camera.prototype.setArmRotation = function(horizontal, vertical) { if (horizontal !== undefined) { this.armRotation.horizontal = horizontal; } if (vertical !== undefined) { this.armRotation.vertical = vertical; if (this.armRotation.vertical < 0) this.armRotation.vertical = 0; if (this.armRotation.vertical > 0.5*Math.PI) this.armRotation.vertical = 0.5*Math.PI; } if (horizontal !== undefined || vertical !== undefined) { this.calculateCameraOrientation(); } }; /** * Retrieve the current arm rotation * @return {object} An object with parameters horizontal and vertical */ Camera.prototype.getArmRotation = function() { var rot = {}; rot.horizontal = this.armRotation.horizontal; rot.vertical = this.armRotation.vertical; return rot; }; /** * Set the (normalized) length of the camera arm. * @param {Number} length A length between 0.71 and 5.0 */ Camera.prototype.setArmLength = function(length) { if (length === undefined) return; this.armLength = length; // Radius must be larger than the corner of the graph, // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the // graph if (this.armLength < 0.71) this.armLength = 0.71; if (this.armLength > 5.0) this.armLength = 5.0; this.calculateCameraOrientation(); }; /** * Retrieve the arm length * @return {Number} length */ Camera.prototype.getArmLength = function() { return this.armLength; }; /** * Retrieve the camera location * @return {Point3d} cameraLocation */ Camera.prototype.getCameraLocation = function() { return this.cameraLocation; }; /** * Retrieve the camera rotation * @return {Point3d} cameraRotation */ Camera.prototype.getCameraRotation = function() { return this.cameraRotation; }; /** * Calculate the location and rotation of the camera based on the * position and orientation of the camera arm */ Camera.prototype.calculateCameraOrientation = function() { // calculate location of the camera this.cameraLocation.x = this.armLocation.x - this.armLength * Math.sin(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); this.cameraLocation.y = this.armLocation.y - this.armLength * Math.cos(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical); this.cameraLocation.z = this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical); // calculate rotation of the camera this.cameraRotation.x = Math.PI/2 - this.armRotation.vertical; this.cameraRotation.y = 0; this.cameraRotation.z = -this.armRotation.horizontal; }; module.exports = Camera;