vis.js is a dynamic, browser-based visualization library
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

178 lines
5.1 KiB

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