UNPKG

5.22 kBJavaScriptView Raw
1var Point3d = require('./Point3d');
2
3/**
4 * The camera is mounted on a (virtual) camera arm. The camera arm can rotate
5 * The camera is always looking in the direction of the origin of the arm.
6 * This way, the camera always rotates around one fixed point, the location
7 * of the camera arm.
8 *
9 * Documentation:
10 * http://en.wikipedia.org/wiki/3D_projection
11 * @class Camera
12 */
13function Camera() {
14 this.armLocation = new Point3d();
15 this.armRotation = {};
16 this.armRotation.horizontal = 0;
17 this.armRotation.vertical = 0;
18 this.armLength = 1.7;
19 this.cameraOffset = new Point3d();
20 this.offsetMultiplier = 0.6;
21
22 this.cameraLocation = new Point3d();
23 this.cameraRotation = new Point3d(0.5*Math.PI, 0, 0);
24
25 this.calculateCameraOrientation();
26}
27
28/**
29 * Set offset camera in camera coordinates
30 * @param {number} x offset by camera horisontal
31 * @param {number} y offset by camera vertical
32 */
33Camera.prototype.setOffset = function(x, y) {
34 var abs = Math.abs,
35 sign = Math.sign,
36 mul = this.offsetMultiplier,
37 border = this.armLength * mul;
38
39 if (abs(x) > border) {
40 x = sign(x) * border;
41 }
42 if (abs(y) > border) {
43 y = sign(y) * border;
44 }
45 this.cameraOffset.x = x;
46 this.cameraOffset.y = y;
47 this.calculateCameraOrientation();
48};
49
50
51/**
52 * Get camera offset by horizontal and vertical
53 * @returns {number}
54 */
55Camera.prototype.getOffset = function() {
56 return this.cameraOffset;
57};
58
59/**
60 * Set the location (origin) of the arm
61 * @param {number} x Normalized value of x
62 * @param {number} y Normalized value of y
63 * @param {number} z Normalized value of z
64 */
65Camera.prototype.setArmLocation = function(x, y, z) {
66 this.armLocation.x = x;
67 this.armLocation.y = y;
68 this.armLocation.z = z;
69
70 this.calculateCameraOrientation();
71};
72
73/**
74 * Set the rotation of the camera arm
75 * @param {number} horizontal The horizontal rotation, between 0 and 2*PI.
76 * Optional, can be left undefined.
77 * @param {number} vertical The vertical rotation, between 0 and 0.5*PI
78 * if vertical=0.5*PI, the graph is shown from the
79 * top. Optional, can be left undefined.
80 */
81Camera.prototype.setArmRotation = function(horizontal, vertical) {
82 if (horizontal !== undefined) {
83 this.armRotation.horizontal = horizontal;
84 }
85
86 if (vertical !== undefined) {
87 this.armRotation.vertical = vertical;
88 if (this.armRotation.vertical < 0) this.armRotation.vertical = 0;
89 if (this.armRotation.vertical > 0.5*Math.PI) this.armRotation.vertical = 0.5*Math.PI;
90 }
91
92 if (horizontal !== undefined || vertical !== undefined) {
93 this.calculateCameraOrientation();
94 }
95};
96
97/**
98 * Retrieve the current arm rotation
99 * @return {object} An object with parameters horizontal and vertical
100 */
101Camera.prototype.getArmRotation = function() {
102 var rot = {};
103 rot.horizontal = this.armRotation.horizontal;
104 rot.vertical = this.armRotation.vertical;
105
106 return rot;
107};
108
109/**
110 * Set the (normalized) length of the camera arm.
111 * @param {number} length A length between 0.71 and 5.0
112 */
113Camera.prototype.setArmLength = function(length) {
114 if (length === undefined)
115 return;
116
117 this.armLength = length;
118
119 // Radius must be larger than the corner of the graph,
120 // which has a distance of sqrt(0.5^2+0.5^2) = 0.71 from the center of the
121 // graph
122 if (this.armLength < 0.71) this.armLength = 0.71;
123 if (this.armLength > 5.0) this.armLength = 5.0;
124
125 this.setOffset(this.cameraOffset.x, this.cameraOffset.y);
126 this.calculateCameraOrientation();
127};
128
129/**
130 * Retrieve the arm length
131 * @return {number} length
132 */
133Camera.prototype.getArmLength = function() {
134 return this.armLength;
135};
136
137/**
138 * Retrieve the camera location
139 * @return {Point3d} cameraLocation
140 */
141Camera.prototype.getCameraLocation = function() {
142 return this.cameraLocation;
143};
144
145/**
146 * Retrieve the camera rotation
147 * @return {Point3d} cameraRotation
148 */
149Camera.prototype.getCameraRotation = function() {
150 return this.cameraRotation;
151};
152
153/**
154 * Calculate the location and rotation of the camera based on the
155 * position and orientation of the camera arm
156 */
157Camera.prototype.calculateCameraOrientation = function() {
158 // calculate location of the camera
159 this.cameraLocation.x = this.armLocation.x - this.armLength * Math.sin(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical);
160 this.cameraLocation.y = this.armLocation.y - this.armLength * Math.cos(this.armRotation.horizontal) * Math.cos(this.armRotation.vertical);
161 this.cameraLocation.z = this.armLocation.z + this.armLength * Math.sin(this.armRotation.vertical);
162
163 // calculate rotation of the camera
164 this.cameraRotation.x = Math.PI/2 - this.armRotation.vertical;
165 this.cameraRotation.y = 0;
166 this.cameraRotation.z = -this.armRotation.horizontal;
167
168 var xa = this.cameraRotation.x;
169 var za = this.cameraRotation.z;
170 var dx = this.cameraOffset.x;
171 var dy = this.cameraOffset.y;
172 var sin = Math.sin, cos = Math.cos;
173
174 this.cameraLocation.x = this.cameraLocation.x + dx * cos(za) + dy * - sin(za) * cos(xa);
175 this.cameraLocation.y = this.cameraLocation.y + dx * sin(za) + dy * cos(za) * cos(xa);
176 this.cameraLocation.z = this.cameraLocation.z + dy * sin(xa);
177};
178
179module.exports = Camera;