Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

vector3.ts 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*
  2. * encantar.js
  3. * GPU-accelerated Augmented Reality for the web
  4. * Copyright (C) 2022-2024 Alexandre Martins <alemartf(at)gmail.com>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published
  8. * by the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. *
  19. * vector3.ts
  20. * 3D vectors
  21. */
  22. import { Nullable } from '../utils/utils';
  23. import { Quaternion } from './quaternion';
  24. /** Small number */
  25. const EPSILON = 1e-6;
  26. /** Immutable zero vector */
  27. let ZERO: Nullable<Vector3> = null;
  28. // public / non-internal methods do not change the contents of the vector
  29. /**
  30. * A vector in 3D space
  31. */
  32. export class Vector3
  33. {
  34. /** x coordinate */
  35. private _x: number;
  36. /** y coordinate */
  37. private _y: number;
  38. /** z coordinate */
  39. private _z: number;
  40. /**
  41. * Constructor
  42. */
  43. constructor(x: number = 0, y: number = 0, z: number = 0)
  44. {
  45. this._x = +x;
  46. this._y = +y;
  47. this._z = +z;
  48. }
  49. /**
  50. * Instantiate a zero vector
  51. * @returns a new zero vector
  52. */
  53. static Zero(): Vector3
  54. {
  55. return new Vector3(0, 0, 0);
  56. }
  57. /**
  58. * Immutable zero vector
  59. * @returns an immutable zero vector
  60. */
  61. static get ZERO(): Vector3
  62. {
  63. return ZERO || (ZERO = Object.freeze(Vector3.Zero()) as Vector3);
  64. }
  65. /**
  66. * The x coordinate of the vector
  67. */
  68. get x(): number
  69. {
  70. return this._x;
  71. }
  72. /**
  73. * The y coordinate of the vector
  74. */
  75. get y(): number
  76. {
  77. return this._y;
  78. }
  79. /**
  80. * The z coordinate of the vector
  81. */
  82. get z(): number
  83. {
  84. return this._z;
  85. }
  86. /**
  87. * The length of this vector
  88. * @returns sqrt(x^2 + y^2 + z^2)
  89. */
  90. length(): number
  91. {
  92. const x = this._x;
  93. const y = this._y;
  94. const z = this._z;
  95. return Math.sqrt(x*x + y*y + z*z);
  96. }
  97. /**
  98. * Compute the dot product of this and v
  99. * @param v a vector
  100. * @returns the dot product of the vectors
  101. */
  102. dot(v: Vector3): number
  103. {
  104. return this._x * v._x + this._y * v._y + this._z * v._z;
  105. }
  106. /**
  107. * Compute the distance between points this and v
  108. * @param v a vector / point
  109. * @returns the distance between the points
  110. */
  111. distanceTo(v: Vector3): number
  112. {
  113. const dx = this._x - v._x;
  114. const dy = this._y - v._y;
  115. const dz = this._z - v._z;
  116. return Math.sqrt(dx*dx + dy*dy + dz*dz);
  117. }
  118. /**
  119. * Compute the direction from this to v
  120. * @param v a vector
  121. * @returns a new unit vector pointing to v from this
  122. */
  123. directionTo(v: Vector3): Vector3
  124. {
  125. return v._clone()._subtract(this)._normalize();
  126. }
  127. /**
  128. * The cross product of this and v
  129. * @param v a vector
  130. * @returns the cross product this x v
  131. */
  132. cross(v: Vector3): Vector3
  133. {
  134. const x = this._y * v._z - this._z * v._y;
  135. const y = this._z * v._x - this._x * v._z;
  136. const z = this._x * v._y - this._y * v._x;
  137. return new Vector3(x, y, z);
  138. }
  139. /**
  140. * Check if this and v have the same coordinates
  141. * @param v a vector
  142. * @returns true if this and v have the same coordinates
  143. */
  144. equals(v: Vector3): boolean
  145. {
  146. return this._x === v._x && this._y === v._y && this._z === v._z;
  147. }
  148. /**
  149. * Convert to string
  150. * @returns a string
  151. */
  152. toString(): string
  153. {
  154. const x = this._x.toFixed(5);
  155. const y = this._y.toFixed(5);
  156. const z = this._z.toFixed(5);
  157. return `Vector3(${x},${y},${z})`;
  158. }
  159. /**
  160. * Set the coordinates of this vector
  161. * @param x x-coordinate
  162. * @param y y-coordinate
  163. * @param z z-coordinate
  164. * @returns this vector
  165. * @internal
  166. */
  167. _set(x: number, y: number, z: number): Vector3
  168. {
  169. this._x = +x;
  170. this._y = +y;
  171. this._z = +z;
  172. return this;
  173. }
  174. /**
  175. * Copy v to this
  176. * @param v a vector
  177. * @returns this vector
  178. * @internal
  179. */
  180. _copyFrom(v: Vector3): Vector3
  181. {
  182. this._x = v._x;
  183. this._y = v._y;
  184. this._z = v._z;
  185. return this;
  186. }
  187. /**
  188. * Normalize this vector
  189. * @returns this vector, normalized
  190. * @internal
  191. */
  192. _normalize(): Vector3
  193. {
  194. const length = this.length();
  195. if(length < EPSILON) // zero?
  196. return this;
  197. this._x /= length;
  198. this._y /= length;
  199. this._z /= length;
  200. return this;
  201. }
  202. /**
  203. * Add v to this vector
  204. * @param v a vector
  205. * @returns this vector
  206. * @internal
  207. */
  208. _add(v: Vector3): Vector3
  209. {
  210. this._x += v._x;
  211. this._y += v._y;
  212. this._z += v._z;
  213. return this;
  214. }
  215. /**
  216. * Subtract v from this vector
  217. * @param v a vector
  218. * @returns this vector
  219. * @internal
  220. */
  221. _subtract(v: Vector3): Vector3
  222. {
  223. this._x -= v._x;
  224. this._y -= v._y;
  225. this._z -= v._z;
  226. return this;
  227. }
  228. /**
  229. * Scale this vector by a scalar
  230. * @param s scalar
  231. * @returns this vector
  232. * @internal
  233. */
  234. _scale(s: number): Vector3
  235. {
  236. this._x *= s;
  237. this._y *= s;
  238. this._z *= s;
  239. return this;
  240. }
  241. /**
  242. * Compute the rotation q p q* in place, where q is a unit quaternion,
  243. * q* is its conjugate and multiplicative inverse, and p is this vector
  244. * @param q unit quaternion
  245. * @returns this vector
  246. * @internal
  247. */
  248. _applyRotationQuaternion(q: Quaternion): Vector3
  249. {
  250. // based on Quaternion._toRotationMatrix()
  251. const x = q.x, y = q.y, z = q.z, w = q.w;
  252. const vx = this._x, vy = this._y, vz = this._z;
  253. const x2 = x*x, y2 = y*y, z2 = z*z;
  254. const xy = 2*x*y, xz = 2*x*z, yz = 2*y*z;
  255. const wx = 2*w*x, wy = 2*w*y, wz = 2*w*z;
  256. this._x = (1-2*(y2+z2)) * vx + (xy-wz) * vy + (xz+wy) * vz;
  257. this._y = (xy+wz) * vx + (1-2*(x2+z2)) * vy + (yz-wx) * vz;
  258. this._z = (xz-wy) * vx + (yz+wx) * vy + (1-2*(x2+y2)) * vz;
  259. return this;
  260. }
  261. /**
  262. * Clone this vector
  263. * @returns a clone of this vector
  264. * @internal
  265. */
  266. _clone(): Vector3
  267. {
  268. return new Vector3(this._x, this._y, this._z);
  269. }
  270. }