@fluixi/utils 1.0.0-alpha.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/index.cjs +1 -0
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +1 -0
  7. package/dist/index.mjs +1 -0
  8. package/dist/lib/array/advanced.cjs +1 -0
  9. package/dist/lib/array/advanced.d.ts +1116 -0
  10. package/dist/lib/array/advanced.d.ts.map +1 -0
  11. package/dist/lib/array/advanced.js +2429 -0
  12. package/dist/lib/array/advanced.mjs +1 -0
  13. package/dist/lib/array/array.cjs +1 -0
  14. package/dist/lib/array/array.d.ts +6 -0
  15. package/dist/lib/array/array.d.ts.map +1 -0
  16. package/dist/lib/array/array.js +31 -0
  17. package/dist/lib/array/array.mjs +1 -0
  18. package/dist/lib/array/index.cjs +1 -0
  19. package/dist/lib/array/index.d.ts +4 -0
  20. package/dist/lib/array/index.d.ts.map +1 -0
  21. package/dist/lib/array/index.js +3 -0
  22. package/dist/lib/array/index.mjs +1 -0
  23. package/dist/lib/array/utils.cjs +1 -0
  24. package/dist/lib/array/utils.d.ts +100 -0
  25. package/dist/lib/array/utils.d.ts.map +1 -0
  26. package/dist/lib/array/utils.js +165 -0
  27. package/dist/lib/array/utils.mjs +1 -0
  28. package/dist/lib/color/color.cjs +1 -0
  29. package/dist/lib/color/color.d.ts +366 -0
  30. package/dist/lib/color/color.d.ts.map +1 -0
  31. package/dist/lib/color/color.js +722 -0
  32. package/dist/lib/color/color.mjs +1 -0
  33. package/dist/lib/color/constants.cjs +1 -0
  34. package/dist/lib/color/constants.d.ts +361 -0
  35. package/dist/lib/color/constants.d.ts.map +1 -0
  36. package/dist/lib/color/constants.js +358 -0
  37. package/dist/lib/color/constants.mjs +1 -0
  38. package/dist/lib/color/conversions.cjs +1 -0
  39. package/dist/lib/color/conversions.d.ts +166 -0
  40. package/dist/lib/color/conversions.d.ts.map +1 -0
  41. package/dist/lib/color/conversions.js +766 -0
  42. package/dist/lib/color/conversions.mjs +1 -0
  43. package/dist/lib/color/helpers.cjs +1 -0
  44. package/dist/lib/color/helpers.d.ts +75 -0
  45. package/dist/lib/color/helpers.d.ts.map +1 -0
  46. package/dist/lib/color/helpers.js +419 -0
  47. package/dist/lib/color/helpers.mjs +1 -0
  48. package/dist/lib/color/index.cjs +1 -0
  49. package/dist/lib/color/index.d.ts +12 -0
  50. package/dist/lib/color/index.d.ts.map +1 -0
  51. package/dist/lib/color/index.js +15 -0
  52. package/dist/lib/color/index.mjs +1 -0
  53. package/dist/lib/color/types.cjs +1 -0
  54. package/dist/lib/color/types.d.ts +179 -0
  55. package/dist/lib/color/types.d.ts.map +1 -0
  56. package/dist/lib/color/types.js +1 -0
  57. package/dist/lib/color/types.mjs +0 -0
  58. package/dist/lib/color/utils.cjs +1 -0
  59. package/dist/lib/color/utils.d.ts +199 -0
  60. package/dist/lib/color/utils.d.ts.map +1 -0
  61. package/dist/lib/color/utils.js +858 -0
  62. package/dist/lib/color/utils.mjs +1 -0
  63. package/dist/lib/compare/comparators.cjs +1 -0
  64. package/dist/lib/compare/comparators.d.ts +65 -0
  65. package/dist/lib/compare/comparators.d.ts.map +1 -0
  66. package/dist/lib/compare/comparators.js +210 -0
  67. package/dist/lib/compare/comparators.mjs +1 -0
  68. package/dist/lib/compare/index.cjs +1 -0
  69. package/dist/lib/compare/index.d.ts +2 -0
  70. package/dist/lib/compare/index.d.ts.map +1 -0
  71. package/dist/lib/compare/index.js +1 -0
  72. package/dist/lib/compare/index.mjs +1 -0
  73. package/dist/lib/crypto/hash.cjs +1 -0
  74. package/dist/lib/crypto/hash.d.ts +6 -0
  75. package/dist/lib/crypto/hash.d.ts.map +1 -0
  76. package/dist/lib/crypto/hash.js +53 -0
  77. package/dist/lib/crypto/hash.mjs +1 -0
  78. package/dist/lib/crypto/index.cjs +1 -0
  79. package/dist/lib/crypto/index.d.ts +2 -0
  80. package/dist/lib/crypto/index.d.ts.map +1 -0
  81. package/dist/lib/crypto/index.js +1 -0
  82. package/dist/lib/crypto/index.mjs +1 -0
  83. package/dist/lib/dom/events.cjs +1 -0
  84. package/dist/lib/dom/events.d.ts +159 -0
  85. package/dist/lib/dom/events.d.ts.map +1 -0
  86. package/dist/lib/dom/events.js +50 -0
  87. package/dist/lib/dom/events.mjs +1 -0
  88. package/dist/lib/dom/index.cjs +1 -0
  89. package/dist/lib/dom/index.d.ts +3 -0
  90. package/dist/lib/dom/index.d.ts.map +1 -0
  91. package/dist/lib/dom/index.js +2 -0
  92. package/dist/lib/dom/index.mjs +1 -0
  93. package/dist/lib/dom/utils.cjs +1 -0
  94. package/dist/lib/dom/utils.d.ts +6 -0
  95. package/dist/lib/dom/utils.d.ts.map +1 -0
  96. package/dist/lib/dom/utils.js +37 -0
  97. package/dist/lib/dom/utils.mjs +1 -0
  98. package/dist/lib/functions/functions.cjs +1 -0
  99. package/dist/lib/functions/functions.d.ts +329 -0
  100. package/dist/lib/functions/functions.d.ts.map +1 -0
  101. package/dist/lib/functions/functions.js +585 -0
  102. package/dist/lib/functions/functions.mjs +1 -0
  103. package/dist/lib/functions/index.cjs +1 -0
  104. package/dist/lib/functions/index.d.ts +3 -0
  105. package/dist/lib/functions/index.d.ts.map +1 -0
  106. package/dist/lib/functions/index.js +1 -0
  107. package/dist/lib/functions/index.mjs +1 -0
  108. package/dist/lib/functions/types.cjs +1 -0
  109. package/dist/lib/functions/types.d.ts +2 -0
  110. package/dist/lib/functions/types.d.ts.map +1 -0
  111. package/dist/lib/functions/types.js +1 -0
  112. package/dist/lib/functions/types.mjs +0 -0
  113. package/dist/lib/helpers.cjs +1 -0
  114. package/dist/lib/helpers.d.ts +13 -0
  115. package/dist/lib/helpers.d.ts.map +1 -0
  116. package/dist/lib/helpers.js +66 -0
  117. package/dist/lib/helpers.mjs +1 -0
  118. package/dist/lib/index.cjs +1 -0
  119. package/dist/lib/index.d.ts +6 -0
  120. package/dist/lib/index.d.ts.map +1 -0
  121. package/dist/lib/index.js +8 -0
  122. package/dist/lib/index.mjs +1 -0
  123. package/dist/lib/maths/constants.cjs +1 -0
  124. package/dist/lib/maths/constants.d.ts +84 -0
  125. package/dist/lib/maths/constants.d.ts.map +1 -0
  126. package/dist/lib/maths/constants.js +79 -0
  127. package/dist/lib/maths/constants.mjs +1 -0
  128. package/dist/lib/maths/fn/advanced.cjs +1 -0
  129. package/dist/lib/maths/fn/advanced.d.ts +149 -0
  130. package/dist/lib/maths/fn/advanced.d.ts.map +1 -0
  131. package/dist/lib/maths/fn/advanced.js +264 -0
  132. package/dist/lib/maths/fn/advanced.mjs +1 -0
  133. package/dist/lib/maths/fn/basic.cjs +1 -0
  134. package/dist/lib/maths/fn/basic.d.ts +182 -0
  135. package/dist/lib/maths/fn/basic.d.ts.map +1 -0
  136. package/dist/lib/maths/fn/basic.js +343 -0
  137. package/dist/lib/maths/fn/basic.mjs +1 -0
  138. package/dist/lib/maths/fn/complex.cjs +1 -0
  139. package/dist/lib/maths/fn/complex.d.ts +153 -0
  140. package/dist/lib/maths/fn/complex.d.ts.map +1 -0
  141. package/dist/lib/maths/fn/complex.js +383 -0
  142. package/dist/lib/maths/fn/complex.mjs +1 -0
  143. package/dist/lib/maths/fn/index.cjs +1 -0
  144. package/dist/lib/maths/fn/index.d.ts +10 -0
  145. package/dist/lib/maths/fn/index.d.ts.map +1 -0
  146. package/dist/lib/maths/fn/index.js +9 -0
  147. package/dist/lib/maths/fn/index.mjs +1 -0
  148. package/dist/lib/maths/fn/trigo.cjs +1 -0
  149. package/dist/lib/maths/fn/trigo.d.ts +147 -0
  150. package/dist/lib/maths/fn/trigo.d.ts.map +1 -0
  151. package/dist/lib/maths/fn/trigo.js +227 -0
  152. package/dist/lib/maths/fn/trigo.mjs +1 -0
  153. package/dist/lib/maths/fn/vector.cjs +1 -0
  154. package/dist/lib/maths/fn/vector.d.ts +512 -0
  155. package/dist/lib/maths/fn/vector.d.ts.map +1 -0
  156. package/dist/lib/maths/fn/vector.js +1136 -0
  157. package/dist/lib/maths/fn/vector.mjs +1 -0
  158. package/dist/lib/maths/formatter.cjs +1 -0
  159. package/dist/lib/maths/formatter.d.ts +35 -0
  160. package/dist/lib/maths/formatter.d.ts.map +1 -0
  161. package/dist/lib/maths/formatter.js +56 -0
  162. package/dist/lib/maths/formatter.mjs +1 -0
  163. package/dist/lib/maths/guards.cjs +1 -0
  164. package/dist/lib/maths/guards.d.ts +166 -0
  165. package/dist/lib/maths/guards.d.ts.map +1 -0
  166. package/dist/lib/maths/guards.js +315 -0
  167. package/dist/lib/maths/guards.mjs +1 -0
  168. package/dist/lib/maths/index.cjs +1 -0
  169. package/dist/lib/maths/index.d.ts +24 -0
  170. package/dist/lib/maths/index.d.ts.map +1 -0
  171. package/dist/lib/maths/index.js +29 -0
  172. package/dist/lib/maths/index.mjs +1 -0
  173. package/dist/lib/maths/parser.cjs +1 -0
  174. package/dist/lib/maths/parser.d.ts +20 -0
  175. package/dist/lib/maths/parser.d.ts.map +1 -0
  176. package/dist/lib/maths/parser.js +78 -0
  177. package/dist/lib/maths/parser.mjs +1 -0
  178. package/dist/lib/maths/random.cjs +1 -0
  179. package/dist/lib/maths/random.d.ts +27 -0
  180. package/dist/lib/maths/random.d.ts.map +1 -0
  181. package/dist/lib/maths/random.js +49 -0
  182. package/dist/lib/maths/random.mjs +1 -0
  183. package/dist/lib/maths/types/advanced.cjs +1 -0
  184. package/dist/lib/maths/types/advanced.d.ts +357 -0
  185. package/dist/lib/maths/types/advanced.d.ts.map +1 -0
  186. package/dist/lib/maths/types/advanced.js +5 -0
  187. package/dist/lib/maths/types/advanced.mjs +0 -0
  188. package/dist/lib/maths/types/basic.cjs +1 -0
  189. package/dist/lib/maths/types/basic.d.ts +95 -0
  190. package/dist/lib/maths/types/basic.d.ts.map +1 -0
  191. package/dist/lib/maths/types/basic.js +5 -0
  192. package/dist/lib/maths/types/basic.mjs +0 -0
  193. package/dist/lib/maths/types/index.cjs +1 -0
  194. package/dist/lib/maths/types/index.d.ts +4 -0
  195. package/dist/lib/maths/types/index.d.ts.map +1 -0
  196. package/dist/lib/maths/types/index.js +3 -0
  197. package/dist/lib/maths/types/index.mjs +0 -0
  198. package/dist/lib/maths/types/negative.cjs +1 -0
  199. package/dist/lib/maths/types/negative.d.ts +51 -0
  200. package/dist/lib/maths/types/negative.d.ts.map +1 -0
  201. package/dist/lib/maths/types/negative.js +5 -0
  202. package/dist/lib/maths/types/negative.mjs +0 -0
  203. package/dist/lib/maths/types/operations.cjs +1 -0
  204. package/dist/lib/maths/types/operations.d.ts +188 -0
  205. package/dist/lib/maths/types/operations.d.ts.map +1 -0
  206. package/dist/lib/maths/types/operations.js +6 -0
  207. package/dist/lib/maths/types/operations.mjs +0 -0
  208. package/dist/lib/object/clone.cjs +1 -0
  209. package/dist/lib/object/clone.d.ts +46 -0
  210. package/dist/lib/object/clone.d.ts.map +1 -0
  211. package/dist/lib/object/clone.js +104 -0
  212. package/dist/lib/object/clone.mjs +1 -0
  213. package/dist/lib/object/diff.cjs +1 -0
  214. package/dist/lib/object/diff.d.ts +203 -0
  215. package/dist/lib/object/diff.d.ts.map +1 -0
  216. package/dist/lib/object/diff.js +805 -0
  217. package/dist/lib/object/diff.mjs +1 -0
  218. package/dist/lib/object/getter-setter.cjs +1 -0
  219. package/dist/lib/object/getter-setter.d.ts +361 -0
  220. package/dist/lib/object/getter-setter.d.ts.map +1 -0
  221. package/dist/lib/object/getter-setter.js +1771 -0
  222. package/dist/lib/object/getter-setter.mjs +1 -0
  223. package/dist/lib/object/index.cjs +6 -0
  224. package/dist/lib/object/index.d.ts +13 -0
  225. package/dist/lib/object/index.d.ts.map +1 -0
  226. package/dist/lib/object/index.js +12 -0
  227. package/dist/lib/object/index.mjs +6 -0
  228. package/dist/lib/object/merge.cjs +1 -0
  229. package/dist/lib/object/merge.d.ts +93 -0
  230. package/dist/lib/object/merge.d.ts.map +1 -0
  231. package/dist/lib/object/merge.js +474 -0
  232. package/dist/lib/object/merge.mjs +1 -0
  233. package/dist/lib/object/object.cjs +1 -0
  234. package/dist/lib/object/object.d.ts +128 -0
  235. package/dist/lib/object/object.d.ts.map +1 -0
  236. package/dist/lib/object/object.js +432 -0
  237. package/dist/lib/object/object.mjs +1 -0
  238. package/dist/lib/object/omit.cjs +1 -0
  239. package/dist/lib/object/omit.d.ts +351 -0
  240. package/dist/lib/object/omit.d.ts.map +1 -0
  241. package/dist/lib/object/omit.js +656 -0
  242. package/dist/lib/object/omit.mjs +1 -0
  243. package/dist/lib/object/reconcile.cjs +1 -0
  244. package/dist/lib/object/reconcile.d.ts +7 -0
  245. package/dist/lib/object/reconcile.d.ts.map +1 -0
  246. package/dist/lib/object/reconcile.js +122 -0
  247. package/dist/lib/object/reconcile.mjs +1 -0
  248. package/dist/lib/object/selector.cjs +1 -0
  249. package/dist/lib/object/selector.d.ts +50 -0
  250. package/dist/lib/object/selector.d.ts.map +1 -0
  251. package/dist/lib/object/selector.js +371 -0
  252. package/dist/lib/object/selector.mjs +1 -0
  253. package/dist/lib/object/sort.cjs +1 -0
  254. package/dist/lib/object/sort.d.ts +149 -0
  255. package/dist/lib/object/sort.d.ts.map +1 -0
  256. package/dist/lib/object/sort.js +298 -0
  257. package/dist/lib/object/sort.mjs +1 -0
  258. package/dist/lib/object/transform.cjs +1 -0
  259. package/dist/lib/object/transform.d.ts +620 -0
  260. package/dist/lib/object/transform.d.ts.map +1 -0
  261. package/dist/lib/object/transform.js +1058 -0
  262. package/dist/lib/object/transform.mjs +1 -0
  263. package/dist/lib/object/types.cjs +1 -0
  264. package/dist/lib/object/types.d.ts +250 -0
  265. package/dist/lib/object/types.d.ts.map +1 -0
  266. package/dist/lib/object/types.js +1 -0
  267. package/dist/lib/object/types.mjs +0 -0
  268. package/dist/lib/object/utils.cjs +6 -0
  269. package/dist/lib/object/utils.d.ts +165 -0
  270. package/dist/lib/object/utils.d.ts.map +1 -0
  271. package/dist/lib/object/utils.js +444 -0
  272. package/dist/lib/object/utils.mjs +6 -0
  273. package/dist/lib/primitive/boolean/boolean.cjs +1 -0
  274. package/dist/lib/primitive/boolean/boolean.d.ts +276 -0
  275. package/dist/lib/primitive/boolean/boolean.d.ts.map +1 -0
  276. package/dist/lib/primitive/boolean/boolean.js +615 -0
  277. package/dist/lib/primitive/boolean/boolean.mjs +1 -0
  278. package/dist/lib/primitive/boolean/index.cjs +1 -0
  279. package/dist/lib/primitive/boolean/index.d.ts +3 -0
  280. package/dist/lib/primitive/boolean/index.d.ts.map +1 -0
  281. package/dist/lib/primitive/boolean/index.js +2 -0
  282. package/dist/lib/primitive/boolean/index.mjs +1 -0
  283. package/dist/lib/primitive/boolean/types.cjs +1 -0
  284. package/dist/lib/primitive/boolean/types.d.ts +14 -0
  285. package/dist/lib/primitive/boolean/types.d.ts.map +1 -0
  286. package/dist/lib/primitive/boolean/types.js +1 -0
  287. package/dist/lib/primitive/boolean/types.mjs +0 -0
  288. package/dist/lib/primitive/date/date.cjs +1 -0
  289. package/dist/lib/primitive/date/date.d.ts +641 -0
  290. package/dist/lib/primitive/date/date.d.ts.map +1 -0
  291. package/dist/lib/primitive/date/date.js +1998 -0
  292. package/dist/lib/primitive/date/date.mjs +1 -0
  293. package/dist/lib/primitive/date/index.cjs +1 -0
  294. package/dist/lib/primitive/date/index.d.ts +3 -0
  295. package/dist/lib/primitive/date/index.d.ts.map +1 -0
  296. package/dist/lib/primitive/date/index.js +2 -0
  297. package/dist/lib/primitive/date/index.mjs +1 -0
  298. package/dist/lib/primitive/date/types.cjs +1 -0
  299. package/dist/lib/primitive/date/types.d.ts +205 -0
  300. package/dist/lib/primitive/date/types.d.ts.map +1 -0
  301. package/dist/lib/primitive/date/types.js +7 -0
  302. package/dist/lib/primitive/date/types.mjs +0 -0
  303. package/dist/lib/primitive/index.cjs +5 -0
  304. package/dist/lib/primitive/index.d.ts +5 -0
  305. package/dist/lib/primitive/index.d.ts.map +1 -0
  306. package/dist/lib/primitive/index.js +4 -0
  307. package/dist/lib/primitive/index.mjs +5 -0
  308. package/dist/lib/primitive/string/index.cjs +5 -0
  309. package/dist/lib/primitive/string/index.d.ts +3 -0
  310. package/dist/lib/primitive/string/index.d.ts.map +1 -0
  311. package/dist/lib/primitive/string/index.js +2 -0
  312. package/dist/lib/primitive/string/index.mjs +5 -0
  313. package/dist/lib/primitive/string/parser-2.cjs +8 -0
  314. package/dist/lib/primitive/string/parser-2.d.ts +17 -0
  315. package/dist/lib/primitive/string/parser-2.d.ts.map +1 -0
  316. package/dist/lib/primitive/string/parser-2.js +656 -0
  317. package/dist/lib/primitive/string/parser-2.mjs +8 -0
  318. package/dist/lib/primitive/string/parser.cjs +3 -0
  319. package/dist/lib/primitive/string/parser.d.ts +9 -0
  320. package/dist/lib/primitive/string/parser.d.ts.map +1 -0
  321. package/dist/lib/primitive/string/parser.js +775 -0
  322. package/dist/lib/primitive/string/parser.mjs +3 -0
  323. package/dist/lib/primitive/string/string.cjs +5 -0
  324. package/dist/lib/primitive/string/string.d.ts +535 -0
  325. package/dist/lib/primitive/string/string.d.ts.map +1 -0
  326. package/dist/lib/primitive/string/string.js +1301 -0
  327. package/dist/lib/primitive/string/string.mjs +5 -0
  328. package/dist/lib/primitive/string/types.cjs +1 -0
  329. package/dist/lib/primitive/string/types.d.ts +318 -0
  330. package/dist/lib/primitive/string/types.d.ts.map +1 -0
  331. package/dist/lib/primitive/string/types.js +5 -0
  332. package/dist/lib/primitive/string/types.mjs +0 -0
  333. package/dist/lib/primitive/types.cjs +1 -0
  334. package/dist/lib/primitive/types.d.ts +27 -0
  335. package/dist/lib/primitive/types.d.ts.map +1 -0
  336. package/dist/lib/primitive/types.js +1 -0
  337. package/dist/lib/primitive/types.mjs +0 -0
  338. package/dist/lib/url/index.cjs +1 -0
  339. package/dist/lib/url/index.d.ts +3 -0
  340. package/dist/lib/url/index.d.ts.map +1 -0
  341. package/dist/lib/url/index.js +2 -0
  342. package/dist/lib/url/index.mjs +1 -0
  343. package/dist/lib/url/parser.cjs +1 -0
  344. package/dist/lib/url/parser.d.ts +216 -0
  345. package/dist/lib/url/parser.d.ts.map +1 -0
  346. package/dist/lib/url/parser.js +488 -0
  347. package/dist/lib/url/parser.mjs +1 -0
  348. package/dist/lib/url/types.cjs +1 -0
  349. package/dist/lib/url/types.d.ts +18 -0
  350. package/dist/lib/url/types.d.ts.map +1 -0
  351. package/dist/lib/url/types.js +1 -0
  352. package/dist/lib/url/types.mjs +0 -0
  353. package/dist/tsconfig.lib.tsbuildinfo +1 -0
  354. package/package.json +150 -0
@@ -0,0 +1,1136 @@
1
+ /**
2
+ * Vector operations for 2D, 3D, and 4D vectors.
3
+ * @module VectorFunctions
4
+ */
5
+ // Constants
6
+ // const EPSILON = Math.E;
7
+ // const DEG_TO_RAD = Math.PI / 180;
8
+ // const RAD_TO_DEG = 180 / Math.PI;
9
+ /**
10
+ * Validates that a value is a finite number.
11
+ * @param value - The value to validate
12
+ * @param name - Name of the value for error messages
13
+ * @throws {Error} If value is not a finite number
14
+ */
15
+ function validateNumber(value, name) {
16
+ if (typeof value !== 'number' || !Number.isFinite(value)) {
17
+ throw new Error(`${name} must be a finite number, got ${value}`);
18
+ }
19
+ }
20
+ /**
21
+ * Checks if a value is approximately zero within epsilon.
22
+ * @param value - The value to check
23
+ * @returns True if the value is effectively zero
24
+ */
25
+ function isApproximatelyZero(value) {
26
+ return Math.abs(value) < 1e-9;
27
+ }
28
+ /**
29
+ * Checks if two numbers are approximately equal.
30
+ * @param a - First number
31
+ * @param b - Second number
32
+ * @returns True if numbers are approximately equal
33
+ */
34
+ function approximatelyEqual(a, b) {
35
+ return Math.abs(a - b) < 1e-6;
36
+ }
37
+ /**
38
+ * Validates a 2D vector.
39
+ * @param vector - The vector to validate
40
+ * @param name - Name for error messages
41
+ * @throws {Error} If vector is invalid
42
+ */
43
+ function validateVector2D(vector, name = 'Vector2D') {
44
+ if (!vector || typeof vector !== 'object') {
45
+ throw new Error(`${name} must be an object`);
46
+ }
47
+ validateNumber(vector.x, `${name}.x`);
48
+ validateNumber(vector.y, `${name}.y`);
49
+ }
50
+ /**
51
+ * Validates a 3D vector.
52
+ * @param vector - The vector to validate
53
+ * @param name - Name for error messages
54
+ * @throws {Error} If vector is invalid
55
+ */
56
+ function validateVector3D(vector, name = 'Vector3D') {
57
+ if (!vector || typeof vector !== 'object') {
58
+ throw new Error(`${name} must be an object`);
59
+ }
60
+ validateNumber(vector.x, `${name}.x`);
61
+ validateNumber(vector.y, `${name}.y`);
62
+ validateNumber(vector.z, `${name}.z`);
63
+ }
64
+ /**
65
+ * Validates a 4D vector.
66
+ * @param vector - The vector to validate
67
+ * @param name - Name for error messages
68
+ * @throws {Error} If vector is invalid
69
+ */
70
+ function validateVector4D(vector, name = 'Vector4D') {
71
+ if (!vector || typeof vector !== 'object') {
72
+ throw new Error(`${name} must be an object`);
73
+ }
74
+ validateNumber(vector.x, `${name}.x`);
75
+ validateNumber(vector.y, `${name}.y`);
76
+ validateNumber(vector.z, `${name}.z`);
77
+ validateNumber(vector.w, `${name}.w`);
78
+ }
79
+ /**
80
+ * Creates a 2D vector with validation.
81
+ * @param x - X component
82
+ * @param y - Y component
83
+ * @returns Validated 2D vector
84
+ */
85
+ export function createVector2D(x, y) {
86
+ validateNumber(x, 'x');
87
+ validateNumber(y, 'y');
88
+ return { x, y };
89
+ }
90
+ /**
91
+ * Creates a 3D vector with validation.
92
+ * @param x - X component
93
+ * @param y - Y component
94
+ * @param z - Z component
95
+ * @returns Validated 3D vector
96
+ */
97
+ export function createVector3D(x, y, z) {
98
+ validateNumber(x, 'x');
99
+ validateNumber(y, 'y');
100
+ validateNumber(z, 'z');
101
+ return { x, y, z };
102
+ }
103
+ /**
104
+ * Creates a 4D vector with validation.
105
+ * @param x - X component
106
+ * @param y - Y component
107
+ * @param z - Z component
108
+ * @param w - W component
109
+ * @returns Validated 4D vector
110
+ */
111
+ export function createVector4D(x, y, z, w) {
112
+ validateNumber(x, 'x');
113
+ validateNumber(y, 'y');
114
+ validateNumber(z, 'z');
115
+ validateNumber(w, 'w');
116
+ return { x, y, z, w };
117
+ }
118
+ /**
119
+ * Calculates the magnitude (length) of a 2D vector.
120
+ * @param vector - The 2D vector
121
+ * @returns The magnitude of the vector (non-negative)
122
+ */
123
+ export function magnitude2D(vector) {
124
+ validateVector2D(vector);
125
+ const magnitude = Math.sqrt(vector.x * vector.x + vector.y * vector.y);
126
+ return isApproximatelyZero(magnitude) ? 0 : magnitude;
127
+ }
128
+ /**
129
+ * Calculates the squared magnitude of a 2D vector (faster, no sqrt).
130
+ * @param vector - The 2D vector
131
+ * @returns The squared magnitude
132
+ */
133
+ export function magnitudeSquared2D(vector) {
134
+ validateVector2D(vector);
135
+ return vector.x * vector.x + vector.y * vector.y;
136
+ }
137
+ /**
138
+ * Calculates the magnitude (length) of a 3D vector.
139
+ * @param vector - The 3D vector
140
+ * @returns The magnitude of the vector (non-negative)
141
+ */
142
+ export function magnitude3D(vector) {
143
+ validateVector3D(vector);
144
+ const magnitude = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
145
+ return isApproximatelyZero(magnitude) ? 0 : magnitude;
146
+ }
147
+ /**
148
+ * Calculates the squared magnitude of a 3D vector (faster, no sqrt).
149
+ * @param vector - The 3D vector
150
+ * @returns The squared magnitude
151
+ */
152
+ export function magnitudeSquared3D(vector) {
153
+ validateVector3D(vector);
154
+ return vector.x * vector.x + vector.y * vector.y + vector.z * vector.z;
155
+ }
156
+ /**
157
+ * Calculates the magnitude (length) of a 4D vector.
158
+ * @param vector - The 4D vector
159
+ * @returns The magnitude of the vector (non-negative)
160
+ */
161
+ export function magnitude4D(vector) {
162
+ validateVector4D(vector);
163
+ const magnitude = Math.sqrt(vector.x * vector.x +
164
+ vector.y * vector.y +
165
+ vector.z * vector.z +
166
+ vector.w * vector.w);
167
+ return isApproximatelyZero(magnitude) ? 0 : magnitude;
168
+ }
169
+ /**
170
+ * Calculates the squared magnitude of a 4D vector (faster, no sqrt).
171
+ * @param vector - The 4D vector
172
+ * @returns The squared magnitude
173
+ */
174
+ export function magnitudeSquared4D(vector) {
175
+ validateVector4D(vector);
176
+ return (vector.x * vector.x +
177
+ vector.y * vector.y +
178
+ vector.z * vector.z +
179
+ vector.w * vector.w);
180
+ }
181
+ /**
182
+ * Normalizes a 2D vector (makes it unit length).
183
+ * @param vector - The 2D vector to normalize
184
+ * @returns The normalized vector (unit vector)
185
+ * @throws {Error} If the vector has zero or near-zero magnitude
186
+ */
187
+ export function normalize2D(vector) {
188
+ validateVector2D(vector);
189
+ const mag = magnitude2D(vector);
190
+ if (isApproximatelyZero(mag)) {
191
+ throw new Error('Cannot normalize zero or near-zero vector');
192
+ }
193
+ return {
194
+ x: vector.x / mag,
195
+ y: vector.y / mag,
196
+ };
197
+ }
198
+ /**
199
+ * Safely normalizes a 2D vector, returns zero vector if magnitude is near zero.
200
+ * @param vector - The 2D vector to normalize
201
+ * @returns The normalized vector or zero vector
202
+ */
203
+ export function safeNormalize2D(vector) {
204
+ validateVector2D(vector);
205
+ const mag = magnitude2D(vector);
206
+ if (isApproximatelyZero(mag)) {
207
+ return { x: 0, y: 0 };
208
+ }
209
+ return {
210
+ x: vector.x / mag,
211
+ y: vector.y / mag,
212
+ };
213
+ }
214
+ /**
215
+ * Normalizes a 3D vector (makes it unit length).
216
+ * @param vector - The 3D vector to normalize
217
+ * @returns The normalized vector (unit vector)
218
+ * @throws {Error} If the vector has zero or near-zero magnitude
219
+ */
220
+ export function normalize3D(vector) {
221
+ validateVector3D(vector);
222
+ const mag = magnitude3D(vector);
223
+ if (isApproximatelyZero(mag)) {
224
+ throw new Error('Cannot normalize zero or near-zero vector');
225
+ }
226
+ return {
227
+ x: vector.x / mag,
228
+ y: vector.y / mag,
229
+ z: vector.z / mag,
230
+ };
231
+ }
232
+ /**
233
+ * Safely normalizes a 3D vector, returns zero vector if magnitude is near zero.
234
+ * @param vector - The 3D vector to normalize
235
+ * @returns The normalized vector or zero vector
236
+ */
237
+ export function safeNormalize3D(vector) {
238
+ validateVector3D(vector);
239
+ const mag = magnitude3D(vector);
240
+ if (isApproximatelyZero(mag)) {
241
+ return { x: 0, y: 0, z: 0 };
242
+ }
243
+ return {
244
+ x: vector.x / mag,
245
+ y: vector.y / mag,
246
+ z: vector.z / mag,
247
+ };
248
+ }
249
+ /**
250
+ * Normalizes a 4D vector (makes it unit length).
251
+ * @param vector - The 4D vector to normalize
252
+ * @returns The normalized vector (unit vector)
253
+ * @throws {Error} If the vector has zero or near-zero magnitude
254
+ */
255
+ export function normalize4D(vector) {
256
+ validateVector4D(vector);
257
+ const mag = magnitude4D(vector);
258
+ if (isApproximatelyZero(mag)) {
259
+ throw new Error('Cannot normalize zero or near-zero vector');
260
+ }
261
+ return {
262
+ x: vector.x / mag,
263
+ y: vector.y / mag,
264
+ z: vector.z / mag,
265
+ w: vector.w / mag,
266
+ };
267
+ }
268
+ /**
269
+ * Safely normalizes a 4D vector, returns zero vector if magnitude is near zero.
270
+ * @param vector - The 4D vector to normalize
271
+ * @returns The normalized vector or zero vector
272
+ */
273
+ export function safeNormalize4D(vector) {
274
+ validateVector4D(vector);
275
+ const mag = magnitude4D(vector);
276
+ if (isApproximatelyZero(mag)) {
277
+ return { x: 0, y: 0, z: 0, w: 0 };
278
+ }
279
+ return {
280
+ x: vector.x / mag,
281
+ y: vector.y / mag,
282
+ z: vector.z / mag,
283
+ w: vector.w / mag,
284
+ };
285
+ }
286
+ /**
287
+ * Calculates the dot product of two 2D vectors.
288
+ * @param a - First vector
289
+ * @param b - Second vector
290
+ * @returns The dot product (scalar)
291
+ */
292
+ export function dotProduct2D(a, b) {
293
+ validateVector2D(a, 'First vector');
294
+ validateVector2D(b, 'Second vector');
295
+ return a.x * b.x + a.y * b.y;
296
+ }
297
+ /**
298
+ * Calculates the dot product of two 3D vectors.
299
+ * @param a - First vector
300
+ * @param b - Second vector
301
+ * @returns The dot product (scalar)
302
+ */
303
+ export function dotProduct3D(a, b) {
304
+ validateVector3D(a, 'First vector');
305
+ validateVector3D(b, 'Second vector');
306
+ return a.x * b.x + a.y * b.y + a.z * b.z;
307
+ }
308
+ /**
309
+ * Calculates the dot product of two 4D vectors.
310
+ * @param a - First vector
311
+ * @param b - Second vector
312
+ * @returns The dot product (scalar)
313
+ */
314
+ export function dotProduct4D(a, b) {
315
+ validateVector4D(a, 'First vector');
316
+ validateVector4D(b, 'Second vector');
317
+ return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
318
+ }
319
+ /**
320
+ * Calculates the cross product of two 3D vectors.
321
+ * @param a - First vector
322
+ * @param b - Second vector
323
+ * @returns The cross product vector (orthogonal to both inputs)
324
+ */
325
+ export function crossProduct3D(a, b) {
326
+ validateVector3D(a, 'First vector');
327
+ validateVector3D(b, 'Second vector');
328
+ return {
329
+ x: a.y * b.z - a.z * b.y,
330
+ y: a.z * b.x - a.x * b.z,
331
+ z: a.x * b.y - a.y * b.x,
332
+ };
333
+ }
334
+ /**
335
+ * Adds two 2D vectors.
336
+ * @param a - First vector
337
+ * @param b - Second vector
338
+ * @returns The sum vector
339
+ */
340
+ export function addVectors2D(a, b) {
341
+ validateVector2D(a, 'First vector');
342
+ validateVector2D(b, 'Second vector');
343
+ return {
344
+ x: a.x + b.x,
345
+ y: a.y + b.y,
346
+ };
347
+ }
348
+ /**
349
+ * Adds two 3D vectors.
350
+ * @param a - First vector
351
+ * @param b - Second vector
352
+ * @returns The sum vector
353
+ */
354
+ export function addVectors3D(a, b) {
355
+ validateVector3D(a, 'First vector');
356
+ validateVector3D(b, 'Second vector');
357
+ return {
358
+ x: a.x + b.x,
359
+ y: a.y + b.y,
360
+ z: a.z + b.z,
361
+ };
362
+ }
363
+ /**
364
+ * Adds two 4D vectors.
365
+ * @param a - First vector
366
+ * @param b - Second vector
367
+ * @returns The sum vector
368
+ */
369
+ export function addVectors4D(a, b) {
370
+ validateVector4D(a, 'First vector');
371
+ validateVector4D(b, 'Second vector');
372
+ return {
373
+ x: a.x + b.x,
374
+ y: a.y + b.y,
375
+ z: a.z + b.z,
376
+ w: a.w + b.w,
377
+ };
378
+ }
379
+ /**
380
+ * Subtracts two 2D vectors.
381
+ * @param a - First vector
382
+ * @param b - Second vector
383
+ * @returns The difference vector (a - b)
384
+ */
385
+ export function subtractVectors2D(a, b) {
386
+ validateVector2D(a, 'First vector');
387
+ validateVector2D(b, 'Second vector');
388
+ return {
389
+ x: a.x - b.x,
390
+ y: a.y - b.y,
391
+ };
392
+ }
393
+ /**
394
+ * Subtracts two 3D vectors.
395
+ * @param a - First vector
396
+ * @param b - Second vector
397
+ * @returns The difference vector (a - b)
398
+ */
399
+ export function subtractVectors3D(a, b) {
400
+ validateVector3D(a, 'First vector');
401
+ validateVector3D(b, 'Second vector');
402
+ return {
403
+ x: a.x - b.x,
404
+ y: a.y - b.y,
405
+ z: a.z - b.z,
406
+ };
407
+ }
408
+ /**
409
+ * Subtracts two 4D vectors.
410
+ * @param a - First vector
411
+ * @param b - Second vector
412
+ * @returns The difference vector (a - b)
413
+ */
414
+ export function subtractVectors4D(a, b) {
415
+ validateVector4D(a, 'First vector');
416
+ validateVector4D(b, 'Second vector');
417
+ return {
418
+ x: a.x - b.x,
419
+ y: a.y - b.y,
420
+ z: a.z - b.z,
421
+ w: a.w - b.w,
422
+ };
423
+ }
424
+ /**
425
+ * Multiplies a 2D vector by a scalar.
426
+ * @param vector - The vector
427
+ * @param scalar - The scalar
428
+ * @returns The scaled vector
429
+ */
430
+ export function scaleVector2D(vector, scalar) {
431
+ validateVector2D(vector);
432
+ validateNumber(scalar, 'scalar');
433
+ return {
434
+ x: vector.x * scalar,
435
+ y: vector.y * scalar,
436
+ };
437
+ }
438
+ /**
439
+ * Multiplies a 3D vector by a scalar.
440
+ * @param vector - The vector
441
+ * @param scalar - The scalar
442
+ * @returns The scaled vector
443
+ */
444
+ export function scaleVector3D(vector, scalar) {
445
+ validateVector3D(vector);
446
+ validateNumber(scalar, 'scalar');
447
+ return {
448
+ x: vector.x * scalar,
449
+ y: vector.y * scalar,
450
+ z: vector.z * scalar,
451
+ };
452
+ }
453
+ /**
454
+ * Multiplies a 4D vector by a scalar.
455
+ * @param vector - The vector
456
+ * @param scalar - The scalar
457
+ * @returns The scaled vector
458
+ */
459
+ export function scaleVector4D(vector, scalar) {
460
+ validateVector4D(vector);
461
+ validateNumber(scalar, 'scalar');
462
+ return {
463
+ x: vector.x * scalar,
464
+ y: vector.y * scalar,
465
+ z: vector.z * scalar,
466
+ w: vector.w * scalar,
467
+ };
468
+ }
469
+ /**
470
+ * Calculates the angle between two 2D vectors in radians.
471
+ * @param a - First vector
472
+ * @param b - Second vector
473
+ * @returns The angle in radians [0, π]
474
+ * @throws {Error} If either vector has zero or near-zero magnitude
475
+ */
476
+ export function angleBetween2D(a, b) {
477
+ validateVector2D(a, 'First vector');
478
+ validateVector2D(b, 'Second vector');
479
+ const dot = dotProduct2D(a, b);
480
+ const magA = magnitude2D(a);
481
+ const magB = magnitude2D(b);
482
+ if (isApproximatelyZero(magA) || isApproximatelyZero(magB)) {
483
+ throw new Error('Cannot calculate angle with zero or near-zero vector');
484
+ }
485
+ // Clamp to [-1, 1] to avoid floating-point errors
486
+ const cosTheta = Math.max(-1, Math.min(1, dot / (magA * magB)));
487
+ return Math.acos(cosTheta);
488
+ }
489
+ /**
490
+ * Calculates the angle between two 3D vectors in radians.
491
+ * @param a - First vector
492
+ * @param b - Second vector
493
+ * @returns The angle in radians [0, π]
494
+ * @throws {Error} If either vector has zero or near-zero magnitude
495
+ */
496
+ export function angleBetween3D(a, b) {
497
+ validateVector3D(a, 'First vector');
498
+ validateVector3D(b, 'Second vector');
499
+ const dot = dotProduct3D(a, b);
500
+ const magA = magnitude3D(a);
501
+ const magB = magnitude3D(b);
502
+ if (isApproximatelyZero(magA) || isApproximatelyZero(magB)) {
503
+ throw new Error('Cannot calculate angle with zero or near-zero vector');
504
+ }
505
+ // Clamp to [-1, 1] to avoid floating-point errors
506
+ const cosTheta = Math.max(-1, Math.min(1, dot / (magA * magB)));
507
+ return Math.acos(cosTheta);
508
+ }
509
+ /**
510
+ * Calculates the signed angle between two 2D vectors in radians.
511
+ * @param a - First vector
512
+ * @param b - Second vector
513
+ * @returns The signed angle in radians (-π to π)
514
+ * @throws {Error} If either vector has zero or near-zero magnitude
515
+ */
516
+ export function signedAngleBetween2D(a, b) {
517
+ validateVector2D(a, 'First vector');
518
+ validateVector2D(b, 'Second vector');
519
+ const angle = angleBetween2D(a, b);
520
+ const cross = a.x * b.y - a.y * b.x; // 2D cross product (scalar)
521
+ // Return signed angle
522
+ return cross >= 0 ? angle : -angle;
523
+ }
524
+ /**
525
+ * Calculates the distance between two 2D points.
526
+ * @param a - First point
527
+ * @param b - Second point
528
+ * @returns The Euclidean distance (non-negative)
529
+ */
530
+ export function distance2D(a, b) {
531
+ validateVector2D(a, 'First point');
532
+ validateVector2D(b, 'Second point');
533
+ const dx = b.x - a.x;
534
+ const dy = b.y - a.y;
535
+ const distance = Math.sqrt(dx * dx + dy * dy);
536
+ return isApproximatelyZero(distance) ? 0 : distance;
537
+ }
538
+ /**
539
+ * Calculates the squared distance between two 2D points (faster, no sqrt).
540
+ * @param a - First point
541
+ * @param b - Second point
542
+ * @returns The squared Euclidean distance
543
+ */
544
+ export function distanceSquared2D(a, b) {
545
+ validateVector2D(a, 'First point');
546
+ validateVector2D(b, 'Second point');
547
+ const dx = b.x - a.x;
548
+ const dy = b.y - a.y;
549
+ return dx * dx + dy * dy;
550
+ }
551
+ /**
552
+ * Calculates the distance between two 3D points.
553
+ * @param a - First point
554
+ * @param b - Second point
555
+ * @returns The Euclidean distance (non-negative)
556
+ */
557
+ export function distance3D(a, b) {
558
+ validateVector3D(a, 'First point');
559
+ validateVector3D(b, 'Second point');
560
+ const dx = b.x - a.x;
561
+ const dy = b.y - a.y;
562
+ const dz = b.z - a.z;
563
+ const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
564
+ return isApproximatelyZero(distance) ? 0 : distance;
565
+ }
566
+ /**
567
+ * Calculates the squared distance between two 3D points (faster, no sqrt).
568
+ * @param a - First point
569
+ * @param b - Second point
570
+ * @returns The squared Euclidean distance
571
+ */
572
+ export function distanceSquared3D(a, b) {
573
+ validateVector3D(a, 'First point');
574
+ validateVector3D(b, 'Second point');
575
+ const dx = b.x - a.x;
576
+ const dy = b.y - a.y;
577
+ const dz = b.z - a.z;
578
+ return dx * dx + dy * dy + dz * dz;
579
+ }
580
+ /**
581
+ * Calculates the distance between two 4D points.
582
+ * @param a - First point
583
+ * @param b - Second point
584
+ * @returns The Euclidean distance (non-negative)
585
+ */
586
+ export function distance4D(a, b) {
587
+ validateVector4D(a, 'First point');
588
+ validateVector4D(b, 'Second point');
589
+ const dx = b.x - a.x;
590
+ const dy = b.y - a.y;
591
+ const dz = b.z - a.z;
592
+ const dw = b.w - a.w;
593
+ const distance = Math.sqrt(dx * dx + dy * dy + dz * dz + dw * dw);
594
+ return isApproximatelyZero(distance) ? 0 : distance;
595
+ }
596
+ /**
597
+ * Calculates the squared distance between two 4D points (faster, no sqrt).
598
+ * @param a - First point
599
+ * @param b - Second point
600
+ * @returns The squared Euclidean distance
601
+ */
602
+ export function distanceSquared4D(a, b) {
603
+ validateVector4D(a, 'First point');
604
+ validateVector4D(b, 'Second point');
605
+ const dx = b.x - a.x;
606
+ const dy = b.y - a.y;
607
+ const dz = b.z - a.z;
608
+ const dw = b.w - a.w;
609
+ return dx * dx + dy * dy + dz * dz + dw * dw;
610
+ }
611
+ /**
612
+ * Linearly interpolates between two 2D vectors.
613
+ * @param start - Starting vector
614
+ * @param end - Ending vector
615
+ * @param t - Interpolation factor (unclamped, can extrapolate)
616
+ * @returns The interpolated vector
617
+ */
618
+ export function lerp2D(start, end, t) {
619
+ validateVector2D(start, 'Start vector');
620
+ validateVector2D(end, 'End vector');
621
+ validateNumber(t, 't');
622
+ // Linear interpolation without clamping (allows extrapolation)
623
+ return {
624
+ x: start.x + (end.x - start.x) * t,
625
+ y: start.y + (end.y - start.y) * t,
626
+ };
627
+ }
628
+ /**
629
+ * Linearly interpolates between two 2D vectors with clamping.
630
+ * @param start - Starting vector
631
+ * @param end - Ending vector
632
+ * @param t - Interpolation factor (clamped to [0, 1])
633
+ * @returns The interpolated vector within the segment
634
+ */
635
+ export function lerpClamped2D(start, end, t) {
636
+ validateVector2D(start, 'Start vector');
637
+ validateVector2D(end, 'End vector');
638
+ validateNumber(t, 't');
639
+ // Clamp t to [0, 1]
640
+ const clampedT = Math.max(0, Math.min(1, t));
641
+ return {
642
+ x: start.x + (end.x - start.x) * clampedT,
643
+ y: start.y + (end.y - start.y) * clampedT,
644
+ };
645
+ }
646
+ /**
647
+ * Linearly interpolates between two 3D vectors.
648
+ * @param start - Starting vector
649
+ * @param end - Ending vector
650
+ * @param t - Interpolation factor (unclamped, can extrapolate)
651
+ * @returns The interpolated vector
652
+ */
653
+ export function lerp3D(start, end, t) {
654
+ validateVector3D(start, 'Start vector');
655
+ validateVector3D(end, 'End vector');
656
+ validateNumber(t, 't');
657
+ return {
658
+ x: start.x + (end.x - start.x) * t,
659
+ y: start.y + (end.y - start.y) * t,
660
+ z: start.z + (end.z - start.z) * t,
661
+ };
662
+ }
663
+ /**
664
+ * Linearly interpolates between two 3D vectors with clamping.
665
+ * @param start - Starting vector
666
+ * @param end - Ending vector
667
+ * @param t - Interpolation factor (clamped to [0, 1])
668
+ * @returns The interpolated vector within the segment
669
+ */
670
+ export function lerpClamped3D(start, end, t) {
671
+ validateVector3D(start, 'Start vector');
672
+ validateVector3D(end, 'End vector');
673
+ validateNumber(t, 't');
674
+ const clampedT = Math.max(0, Math.min(1, t));
675
+ return {
676
+ x: start.x + (end.x - start.x) * clampedT,
677
+ y: start.y + (end.y - start.y) * clampedT,
678
+ z: start.z + (end.z - start.z) * clampedT,
679
+ };
680
+ }
681
+ /**
682
+ * Linearly interpolates between two 4D vectors.
683
+ * @param start - Starting vector
684
+ * @param end - Ending vector
685
+ * @param t - Interpolation factor (unclamped, can extrapolate)
686
+ * @returns The interpolated vector
687
+ */
688
+ export function lerp4D(start, end, t) {
689
+ validateVector4D(start, 'Start vector');
690
+ validateVector4D(end, 'End vector');
691
+ validateNumber(t, 't');
692
+ return {
693
+ x: start.x + (end.x - start.x) * t,
694
+ y: start.y + (end.y - start.y) * t,
695
+ z: start.z + (end.z - start.z) * t,
696
+ w: start.w + (end.w - start.w) * t,
697
+ };
698
+ }
699
+ /**
700
+ * Linearly interpolates between two 4D vectors with clamping.
701
+ * @param start - Starting vector
702
+ * @param end - Ending vector
703
+ * @param t - Interpolation factor (clamped to [0, 1])
704
+ * @returns The interpolated vector within the segment
705
+ */
706
+ export function lerpClamped4D(start, end, t) {
707
+ validateVector4D(start, 'Start vector');
708
+ validateVector4D(end, 'End vector');
709
+ validateNumber(t, 't');
710
+ const clampedT = Math.max(0, Math.min(1, t));
711
+ return {
712
+ x: start.x + (end.x - start.x) * clampedT,
713
+ y: start.y + (end.y - start.y) * clampedT,
714
+ z: start.z + (end.z - start.z) * clampedT,
715
+ w: start.w + (end.w - start.w) * clampedT,
716
+ };
717
+ }
718
+ /**
719
+ * Spherically interpolates between two 3D vectors (SLERP).
720
+ * @param start - Starting unit vector
721
+ * @param end - Ending unit vector
722
+ * @param t - Interpolation factor (clamped to [0, 1])
723
+ * @returns The interpolated unit vector
724
+ * @throws {Error} If vectors are not unit length or have near-zero magnitude
725
+ */
726
+ export function slerp3D(start, end, t) {
727
+ validateVector3D(start, 'Start vector');
728
+ validateVector3D(end, 'End vector');
729
+ validateNumber(t, 't');
730
+ // Ensure vectors are normalized
731
+ const startMag = magnitude3D(start);
732
+ const endMag = magnitude3D(end);
733
+ if (Math.abs(startMag - 1) > 1e-8 || Math.abs(endMag - 1) > 1e-8) {
734
+ throw new Error('SLERP requires unit vectors');
735
+ }
736
+ const clampedT = Math.max(0, Math.min(1, t));
737
+ const dot = dotProduct3D(start, end);
738
+ // Clamp dot product to handle floating-point errors
739
+ const clampedDot = Math.max(-1, Math.min(1, dot));
740
+ // If vectors are nearly identical, use linear interpolation
741
+ if (clampedDot > 0.9995) {
742
+ return normalize3D(lerp3D(start, end, clampedT));
743
+ }
744
+ const theta = Math.acos(clampedDot);
745
+ const sinTheta = Math.sin(theta);
746
+ const factor1 = Math.sin((1 - clampedT) * theta) / sinTheta;
747
+ const factor2 = Math.sin(clampedT * theta) / sinTheta;
748
+ return addVectors3D(scaleVector3D(start, factor1), scaleVector3D(end, factor2));
749
+ }
750
+ /**
751
+ * Smoothly interpolates between two vectors using cubic Hermite interpolation.
752
+ * @param start - Starting vector
753
+ * @param end - Ending vector
754
+ * @param t - Interpolation factor (unclamped)
755
+ * @returns The interpolated vector
756
+ */
757
+ export function smoothstep2D(start, end, t) {
758
+ validateVector2D(start, 'Start vector');
759
+ validateVector2D(end, 'End vector');
760
+ validateNumber(t, 't');
761
+ // Apply smoothstep function: 3t² - 2t³
762
+ const smoothedT = t * t * (3 - 2 * t);
763
+ return {
764
+ x: start.x + (end.x - start.x) * smoothedT,
765
+ y: start.y + (end.y - start.y) * smoothedT,
766
+ };
767
+ }
768
+ /**
769
+ * Smoothly interpolates with clamping.
770
+ * @param start - Starting vector
771
+ * @param end - Ending vector
772
+ * @param t - Interpolation factor (clamped to [0, 1])
773
+ * @returns The interpolated vector
774
+ */
775
+ export function smoothstepClamped2D(start, end, t) {
776
+ validateVector2D(start, 'Start vector');
777
+ validateVector2D(end, 'End vector');
778
+ validateNumber(t, 't');
779
+ const clampedT = Math.max(0, Math.min(1, t));
780
+ const smoothedT = clampedT * clampedT * (3 - 2 * clampedT);
781
+ return {
782
+ x: start.x + (end.x - start.x) * smoothedT,
783
+ y: start.y + (end.y - start.y) * smoothedT,
784
+ };
785
+ }
786
+ /**
787
+ * Smoother interpolation using quintic function.
788
+ * @param start - Starting vector
789
+ * @param end - Ending vector
790
+ * @param t - Interpolation factor (unclamped)
791
+ * @returns The interpolated vector
792
+ */
793
+ export function smootherstep2D(start, end, t) {
794
+ validateVector2D(start, 'Start vector');
795
+ validateVector2D(end, 'End vector');
796
+ validateNumber(t, 't');
797
+ // Apply smootherstep function: 6t⁵ - 15t⁴ + 10t³
798
+ const smootherT = t * t * t * (t * (t * 6 - 15) + 10);
799
+ return {
800
+ x: start.x + (end.x - start.x) * smootherT,
801
+ y: start.y + (end.y - start.y) * smootherT,
802
+ };
803
+ }
804
+ /**
805
+ * Interpolates between three vectors (quadratic bezier).
806
+ * @param p0 - Start point
807
+ * @param p1 - Control point
808
+ * @param p2 - End point
809
+ * @param t - Interpolation factor
810
+ * @returns The interpolated vector
811
+ */
812
+ export function quadraticBezier2D(p0, p1, p2, t) {
813
+ validateVector2D(p0, 'Start point');
814
+ validateVector2D(p1, 'Control point');
815
+ validateVector2D(p2, 'End point');
816
+ validateNumber(t, 't');
817
+ const oneMinusT = 1 - t;
818
+ // Quadratic Bezier formula: (1-t)²P₀ + 2(1-t)tP₁ + t²P₂
819
+ const x = oneMinusT * oneMinusT * p0.x + 2 * oneMinusT * t * p1.x + t * t * p2.x;
820
+ const y = oneMinusT * oneMinusT * p0.y + 2 * oneMinusT * t * p1.y + t * t * p2.y;
821
+ return { x, y };
822
+ }
823
+ /**
824
+ * Interpolates between four vectors (cubic bezier).
825
+ * @param p0 - Start point
826
+ * @param p1 - First control point
827
+ * @param p2 - Second control point
828
+ * @param p3 - End point
829
+ * @param t - Interpolation factor
830
+ * @returns The interpolated vector
831
+ */
832
+ export function cubicBezier2D(p0, p1, p2, p3, t) {
833
+ validateVector2D(p0, 'Start point');
834
+ validateVector2D(p1, 'First control point');
835
+ validateVector2D(p2, 'Second control point');
836
+ validateVector2D(p3, 'End point');
837
+ validateNumber(t, 't');
838
+ const oneMinusT = 1 - t;
839
+ const oneMinusT2 = oneMinusT * oneMinusT;
840
+ const oneMinusT3 = oneMinusT2 * oneMinusT;
841
+ const t2 = t * t;
842
+ const t3 = t2 * t;
843
+ // Cubic Bezier formula:
844
+ // (1-t)³P₀ + 3(1-t)²tP₁ + 3(1-t)t²P₂ + t³P₃
845
+ const x = oneMinusT3 * p0.x +
846
+ 3 * oneMinusT2 * t * p1.x +
847
+ 3 * oneMinusT * t2 * p2.x +
848
+ t3 * p3.x;
849
+ const y = oneMinusT3 * p0.y +
850
+ 3 * oneMinusT2 * t * p1.y +
851
+ 3 * oneMinusT * t2 * p2.y +
852
+ t3 * p3.y;
853
+ return { x, y };
854
+ }
855
+ /**
856
+ * Maps a value from one range to another range.
857
+ * @param value - The value to map
858
+ * @param inMin - Minimum of input range
859
+ * @param inMax - Maximum of input range
860
+ * @param outMin - Minimum of output range
861
+ * @param outMax - Maximum of output range
862
+ * @returns The mapped value
863
+ */
864
+ export function mapRange(value, inMin, inMax, outMin, outMax) {
865
+ validateNumber(value, 'value');
866
+ validateNumber(inMin, 'inMin');
867
+ validateNumber(inMax, 'inMax');
868
+ validateNumber(outMin, 'outMin');
869
+ validateNumber(outMax, 'outMax');
870
+ // Avoid division by zero
871
+ if (approximatelyEqual(inMin, inMax)) {
872
+ return outMin;
873
+ }
874
+ return outMin + ((outMax - outMin) * (value - inMin)) / (inMax - inMin);
875
+ }
876
+ /**
877
+ * Maps and clamps a value from one range to another.
878
+ * @param value - The value to map
879
+ * @param inMin - Minimum of input range
880
+ * @param inMax - Maximum of input range
881
+ * @param outMin - Minimum of output range
882
+ * @param outMax - Maximum of output range
883
+ * @returns The mapped value, clamped to output range
884
+ */
885
+ export function mapRangeClamped(value, inMin, inMax, outMin, outMax) {
886
+ validateNumber(value, 'value');
887
+ validateNumber(inMin, 'inMin');
888
+ validateNumber(inMax, 'inMax');
889
+ validateNumber(outMin, 'outMin');
890
+ validateNumber(outMax, 'outMax');
891
+ // Avoid division by zero
892
+ if (approximatelyEqual(inMin, inMax)) {
893
+ return outMin;
894
+ }
895
+ const t = (value - inMin) / (inMax - inMin);
896
+ const clampedT = Math.max(0, Math.min(1, t));
897
+ return outMin + (outMax - outMin) * clampedT;
898
+ }
899
+ /**
900
+ * Rotates a 2D vector by an angle (in radians).
901
+ * @param vector - The vector to rotate
902
+ * @param angle - The angle in radians
903
+ * @returns The rotated vector
904
+ */
905
+ export function rotate2D(vector, angle) {
906
+ validateVector2D(vector);
907
+ validateNumber(angle, 'angle');
908
+ const cos = Math.cos(angle);
909
+ const sin = Math.sin(angle);
910
+ return {
911
+ x: vector.x * cos - vector.y * sin,
912
+ y: vector.x * sin + vector.y * cos,
913
+ };
914
+ }
915
+ /**
916
+ * Rotates a 2D vector by an angle (in degrees).
917
+ * @param vector - The vector to rotate
918
+ * @param degrees - The angle in degrees
919
+ * @returns The rotated vector
920
+ */
921
+ export function rotate2DDegrees(vector, degrees) {
922
+ return rotate2D(vector, degrees * (Math.PI / 180));
923
+ }
924
+ /**
925
+ * Reflects a 2D vector across a normal vector.
926
+ * @param vector - The vector to reflect
927
+ * @param normal - The normal vector (must be unit length)
928
+ * @returns The reflected vector
929
+ * @throws {Error} If normal is not unit length
930
+ */
931
+ export function reflect2D(vector, normal) {
932
+ validateVector2D(vector, 'Vector');
933
+ validateVector2D(normal, 'Normal');
934
+ // Ensure normal is unit vector
935
+ const normalMag = magnitude2D(normal);
936
+ if (Math.abs(normalMag - 1) > 1e-10) {
937
+ throw new Error('Normal vector must be unit length for reflection');
938
+ }
939
+ const dot = dotProduct2D(vector, normal);
940
+ return {
941
+ x: vector.x - 2 * dot * normal.x,
942
+ y: vector.y - 2 * dot * normal.y,
943
+ };
944
+ }
945
+ /**
946
+ * Projects vector a onto vector b.
947
+ * @param a - The vector to project
948
+ * @param b - The vector to project onto
949
+ * @returns The projection of a onto b
950
+ * @throws {Error} If b has zero or near-zero magnitude
951
+ */
952
+ export function project2D(a, b) {
953
+ validateVector2D(a, 'First vector');
954
+ validateVector2D(b, 'Second vector');
955
+ const bMagSquared = magnitudeSquared2D(b);
956
+ if (isApproximatelyZero(bMagSquared)) {
957
+ throw new Error('Cannot project onto zero or near-zero vector');
958
+ }
959
+ const scale = dotProduct2D(a, b) / bMagSquared;
960
+ return {
961
+ x: b.x * scale,
962
+ y: b.y * scale,
963
+ };
964
+ }
965
+ /**
966
+ * Checks if two 2D vectors are approximately equal.
967
+ * @param a - First vector
968
+ * @param b - Second vector
969
+ * @returns True if vectors are approximately equal
970
+ */
971
+ export function vectorsEqual2D(a, b) {
972
+ validateVector2D(a, 'First vector');
973
+ validateVector2D(b, 'Second vector');
974
+ return approximatelyEqual(a.x, b.x) && approximatelyEqual(a.y, b.y);
975
+ }
976
+ /**
977
+ * Checks if two 3D vectors are approximately equal.
978
+ * @param a - First vector
979
+ * @param b - Second vector
980
+ * @returns True if vectors are approximately equal
981
+ */
982
+ export function vectorsEqual3D(a, b) {
983
+ validateVector3D(a, 'First vector');
984
+ validateVector3D(b, 'Second vector');
985
+ return (approximatelyEqual(a.x, b.x) &&
986
+ approximatelyEqual(a.y, b.y) &&
987
+ approximatelyEqual(a.z, b.z));
988
+ }
989
+ /**
990
+ * Checks if two 4D vectors are approximately equal.
991
+ * @param a - First vector
992
+ * @param b - Second vector
993
+ * @returns True if vectors are approximately equal
994
+ */
995
+ export function vectorsEqual4D(a, b) {
996
+ validateVector4D(a, 'First vector');
997
+ validateVector4D(b, 'Second vector');
998
+ return (approximatelyEqual(a.x, b.x) &&
999
+ approximatelyEqual(a.y, b.y) &&
1000
+ approximatelyEqual(a.z, b.z) &&
1001
+ approximatelyEqual(a.w, b.w));
1002
+ }
1003
+ /**
1004
+ * Calculates the midpoint between two 2D points.
1005
+ * @param a - First point
1006
+ * @param b - Second point
1007
+ * @returns The midpoint
1008
+ */
1009
+ export function midpoint2D(a, b) {
1010
+ validateVector2D(a, 'First point');
1011
+ validateVector2D(b, 'Second point');
1012
+ return {
1013
+ x: (a.x + b.x) / 2,
1014
+ y: (a.y + b.y) / 2,
1015
+ };
1016
+ }
1017
+ /**
1018
+ * Calculates the centroid of multiple 2D points.
1019
+ * @param points - Array of points
1020
+ * @returns The centroid
1021
+ * @throws {Error} If points array is empty
1022
+ */
1023
+ export function centroid2D(points) {
1024
+ if (!Array.isArray(points) || points.length === 0) {
1025
+ throw new Error('Points array must not be empty');
1026
+ }
1027
+ let sumX = 0;
1028
+ let sumY = 0;
1029
+ for (let i = 0; i < points.length; i++) {
1030
+ validateVector2D(points[i], `points[${i}]`);
1031
+ sumX += points[i].x;
1032
+ sumY += points[i].y;
1033
+ }
1034
+ return {
1035
+ x: sumX / points.length,
1036
+ y: sumY / points.length,
1037
+ };
1038
+ }
1039
+ /**
1040
+ * Negates a 2D vector (reverses its direction).
1041
+ * @param vector - The vector to negate
1042
+ * @returns The negated vector
1043
+ */
1044
+ export function negateVector2D(vector) {
1045
+ validateVector2D(vector);
1046
+ return { x: -vector.x, y: -vector.y };
1047
+ }
1048
+ /**
1049
+ * Negates a 3D vector (reverses its direction).
1050
+ * @param vector - The vector to negate
1051
+ * @returns The negated vector
1052
+ */
1053
+ export function negateVector3D(vector) {
1054
+ validateVector3D(vector);
1055
+ return { x: -vector.x, y: -vector.y, z: -vector.z };
1056
+ }
1057
+ /**
1058
+ * Negates a 4D vector (reverses its direction).
1059
+ * @param vector - The vector to negate
1060
+ * @returns The negated vector
1061
+ */
1062
+ export function negateVector4D(vector) {
1063
+ validateVector4D(vector);
1064
+ return { x: -vector.x, y: -vector.y, z: -vector.z, w: -vector.w };
1065
+ }
1066
+ /**
1067
+ * Calculates the perpendicular 2D vector (90° rotation).
1068
+ * @param vector - The vector
1069
+ * @param clockwise - True for clockwise rotation, false for counterclockwise
1070
+ * @returns The perpendicular vector
1071
+ */
1072
+ export function perpendicular2D(vector, clockwise = true) {
1073
+ validateVector2D(vector);
1074
+ if (clockwise) {
1075
+ return { x: vector.y, y: -vector.x }; // 90° clockwise
1076
+ }
1077
+ else {
1078
+ return { x: -vector.y, y: vector.x }; // 90° counterclockwise
1079
+ }
1080
+ }
1081
+ /**
1082
+ * Creates a zero 2D vector.
1083
+ * @returns Zero vector
1084
+ */
1085
+ export function zeroVector2D() {
1086
+ return { x: 0, y: 0 };
1087
+ }
1088
+ /**
1089
+ * Creates a zero 3D vector.
1090
+ * @returns Zero vector
1091
+ */
1092
+ export function zeroVector3D() {
1093
+ return { x: 0, y: 0, z: 0 };
1094
+ }
1095
+ /**
1096
+ * Creates a zero 4D vector.
1097
+ * @returns Zero vector
1098
+ */
1099
+ export function zeroVector4D() {
1100
+ return { x: 0, y: 0, z: 0, w: 0 };
1101
+ }
1102
+ /**
1103
+ * Creates a 2D unit vector along the X axis.
1104
+ * @returns Unit vector (1, 0)
1105
+ */
1106
+ export function unitX2D() {
1107
+ return { x: 1, y: 0 };
1108
+ }
1109
+ /**
1110
+ * Creates a 2D unit vector along the Y axis.
1111
+ * @returns Unit vector (0, 1)
1112
+ */
1113
+ export function unitY2D() {
1114
+ return { x: 0, y: 1 };
1115
+ }
1116
+ /**
1117
+ * Creates a 3D unit vector along the X axis.
1118
+ * @returns Unit vector (1, 0, 0)
1119
+ */
1120
+ export function unitX3D() {
1121
+ return { x: 1, y: 0, z: 0 };
1122
+ }
1123
+ /**
1124
+ * Creates a 3D unit vector along the Y axis.
1125
+ * @returns Unit vector (0, 1, 0)
1126
+ */
1127
+ export function unitY3D() {
1128
+ return { x: 0, y: 1, z: 0 };
1129
+ }
1130
+ /**
1131
+ * Creates a 3D unit vector along the Z axis.
1132
+ * @returns Unit vector (0, 0, 1)
1133
+ */
1134
+ export function unitZ3D() {
1135
+ return { x: 0, y: 0, z: 1 };
1136
+ }