Vec3_1-0.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. local THIS_VERSION = "1.0"
  2. --- 3D vector class/operations.
  3. --
  4. -- Note that methods can be called in either an object-oriented way:
  5. -- v1 = Vec3(1, 2, 3)
  6. -- v2 = v1:add({ x = 2, y = 2, z = 0 })
  7. -- or as simple functions:
  8. -- Vec3.add({ x = 1, y = 2, z = 3 }, { x = 2, y = 2, z = 0 })
  9. --
  10. -- All methods that can be called on a Vec3 using ":" may be called on a table
  11. -- using the second functional syntax, but the first parameter MUST have the
  12. -- expected components "x", "y", and "z". If a vector is used as the second
  13. -- paramter, it may instead be a list/array with numeric indices, like
  14. -- { 1.0, 2.0, 3.0 } in place of { x = 1.0, y = 2.0, z = 3.0 }.
  15. --
  16. -- @author prestidigitator (as registered at forum.minetest.net)
  17. -- @copyright 2013, licensed under WTFPL
  18. --
  19. local Vec3 = {}
  20. local Vec3_meta = {}
  21. local Vec3_inst_meta = {}
  22. Vec3.VERSION = THIS_VERSION
  23. setmetatable(Vec3, Vec3_meta)
  24. Vec3_inst_meta.__index = Vec3
  25. --- Constructs a Vec3 from three numbers.
  26. --
  27. -- Call with one of:
  28. -- Vec3.new(x, y, z)
  29. -- Vec3(x, y, z)
  30. --
  31. -- @return a new Vec3 object
  32. local function Vec3_new(x, y, z)
  33. local obj = { x = x or 0.0, y = y or 0.0, z = z or 0.0 }
  34. setmetatable(obj, Vec3_inst_meta)
  35. return obj
  36. end
  37. Vec3.new = Vec3_new
  38. --- Constructs a new copy of a Vec3.
  39. --
  40. -- Call with one of:
  41. -- vec:new_copy()
  42. -- Vec3.new_copy(vec)
  43. -- Vec3(vec)
  44. --
  45. -- @return a new Vec3 object that is a copy of the parameter
  46. local function Vec3_new_copy(v)
  47. local obj = { x = v.x or v[1] or 0.0,
  48. y = v.y or v[2] or 0.0,
  49. z = v.z or v[3] or 0.0 }
  50. setmetatable(obj, Vec3_inst_meta)
  51. return obj
  52. end
  53. Vec3.new_copy = Vec3_new_copy
  54. Vec3_meta.__call = function(class, a, b, c)
  55. if type(a) == "table" then
  56. return Vec3.new_copy(a)
  57. else
  58. return Vec3.new(a, b, c)
  59. end
  60. end
  61. --- Computes the square of the length of a Vec3.
  62. --
  63. -- Call with one of:
  64. -- vec:len_sq()
  65. -- Vec3.len_sq(vec)
  66. --
  67. -- @return a number
  68. local function Vec3_len_sq(v)
  69. return v.x^2 + v.y^2 + v.z^2
  70. end
  71. Vec3.len_sq = Vec3_len_sq
  72. --- Computes the length of a Vec3.
  73. --
  74. -- Call with one of:
  75. -- vec:len()
  76. -- Vec3.len(vec)
  77. --
  78. -- @return a number
  79. local function Vec3_len(v)
  80. return math.sqrt(v.x^2 + v.y^2 + v.z^2)
  81. end
  82. Vec3.len = Vec3_len
  83. --- Computes a unit vector pointing in the same direction as a Vec3.
  84. -- Undefined for a zero-vector and may throw an error.
  85. --
  86. -- Call with one of:
  87. -- vec:unit()
  88. -- Vec3.unit(vec)
  89. --
  90. -- @return a new Vec3 with length 1.0
  91. local function Vec3_unit(v)
  92. local len = math.sqrt(v.x^2 + v.y^2 + v.z^2)
  93. return Vec3.new(v.x/len, v.y/len, v.z/len)
  94. end
  95. Vec3.unit = Vec3_unit
  96. --- Multiplies a Vec3 by a number.
  97. --
  98. -- Call with one of:
  99. -- vec:mul(m)
  100. -- Vec3.mul(vec, m)
  101. -- vec*m
  102. -- m*vec
  103. --
  104. -- @return a new Vec3 object with the result of the operation
  105. local function Vec3_mul(v, m)
  106. local mn = tonumber(m)
  107. if not mn then error("Can't multiply vector by non-scalar") end
  108. return Vec3.new(v.x*mn, v.y*mn, v.z*mn)
  109. end
  110. Vec3.mul = Vec3_mul
  111. Vec3_inst_meta.__mul = function(a, b)
  112. if type(a) == "table" then
  113. return Vec3_mul(a, b)
  114. else
  115. return Vec3_mul(b, a)
  116. end
  117. end
  118. --- Divides a Vec3 by a number.
  119. --
  120. -- Call with one of:
  121. -- vec:div(m)
  122. -- Vec3.div(vec, m)
  123. -- vec/m
  124. --
  125. -- @return a new Vec3 object with the result of the operation
  126. local function Vec3_div(v, m)
  127. return Vec3.new(v.x/m, v.y/m, v.z/m)
  128. end
  129. Vec3.div = Vec3_div
  130. Vec3_inst_meta.__div = Vec3_div
  131. --- Negates a Vec3 (signs of all components are inverted).
  132. --
  133. -- Call with one of:
  134. -- vec:unm()
  135. -- Vec3.unm(vec)
  136. -- -vec
  137. --
  138. -- @return a new Vec3 object with the result of the operation
  139. local function Vec3_unm(v)
  140. return Vec3.new(-v.x, -v.y, -v.z)
  141. end
  142. Vec3.unm = Vec3_unm
  143. Vec3_inst_meta.__unm = Vec3_unm
  144. --- Adds two Vec3s or a Vec3 composed of three given components.
  145. --
  146. -- Call with one of:
  147. -- vec1:add(vec2)
  148. -- vec1:add(x, y, z)
  149. -- Vec3.add(vec1, vec2)
  150. -- Vec3.add(vec1, x, y, z)
  151. -- vec1 + vec2
  152. --
  153. -- @return a new Vec3 object with the result of the operation
  154. local function Vec3_add(v, a, b, c)
  155. if type(a) == "table" then
  156. return Vec3.new(v.x + (a.x or a[1] or 0.0),
  157. v.y + (a.y or a[2] or 0.0),
  158. v.z + (a.z or a[3] or 0.0))
  159. else
  160. return Vec3.new(v.x + a, v.y + b, v.z + c)
  161. end
  162. end
  163. Vec3.add = Vec3_add
  164. --- Subtracts two Vec3s or a Vec3 composed of three given components.
  165. --
  166. -- Call with one of:
  167. -- vec1:sub(vec2)
  168. -- vec1:sub(x, y, z)
  169. -- Vec3.sub(vec1, vec2)
  170. -- Vec3.sub(vec1, x, y, z)
  171. -- vec1 - vec2
  172. --
  173. -- @return a new Vec3 object with the result of the operation
  174. local function Vec3_sub(v, a, b, c)
  175. if type(a) == "table" then
  176. return Vec3.new(v.x - (a.x or a[1] or 0.0),
  177. v.y - (a.y or a[2] or 0.0),
  178. v.z - (a.z or a[3] or 0.0))
  179. else
  180. return Vec3.new(v.x - a, v.y - b, v.z - c)
  181. end
  182. end
  183. Vec3.sub = Vec3_sub
  184. --- Tests two Vec3s or a Vec3 composed of three given components for
  185. -- exact component-wise equality.
  186. --
  187. -- Call with one of:
  188. -- vec1:eq(vec2)
  189. -- vec1:eq(x, y, z)
  190. -- Vec3.eq(vec1, vec2)
  191. -- Vec3.eq(vec1, x, y, z)
  192. -- vec1 == vec2
  193. -- vec1 ~= vec2
  194. -- Note that because of built-in Lua logic "==" and "~=" work ONLY if
  195. -- vec1 and vec2 are actually Vec3s (not tables).
  196. --
  197. -- @return a new Vec3 object with the result of the operation
  198. local function Vec3_eq(v, a, b, c)
  199. if type(a) == "table" then
  200. return v.x == (a.x or a[1] or 0.0) and
  201. v.y == (a.y or a[2] or 0.0) and
  202. v.z == (a.z or a[3] or 0.0)
  203. else
  204. return v.x == a and v.y == b and v.z == c
  205. end
  206. end
  207. Vec3.eq = Vec3_eq
  208. --- Takes the dot product of a Vec3 and a Vec3s or a Vec3 composed of
  209. -- three given components.
  210. --
  211. -- Call with one of:
  212. -- vec1:dot(vec2)
  213. -- vec1:dot(x, y, z)
  214. -- Vec3.dot(vec1, vec2)
  215. -- Vec3.dot(vec1, x, y, z)
  216. --
  217. -- @return a number
  218. local function Vec3_dot(v, a, b, c)
  219. if type(a) == "table" then
  220. return v.x * (a.x or a[1] or 0.0) +
  221. v.y * (a.y or a[2] or 0.0) +
  222. v.z * (a.z or a[3] or 0.0)
  223. else
  224. return v.x * a + v.y * b + v.z * c
  225. end
  226. end
  227. Vec3.dot = Vec3_dot
  228. --- Takes the cross product of a Vec3 and a Vec3s or a Vec3 composed of
  229. -- three given components.
  230. --
  231. -- Call with one of:
  232. -- vec1:cross(vec2)
  233. -- vec1:cross(x, y, z)
  234. -- Vec3.cross(vec1, vec2)
  235. -- Vec3.cross(vec1, x, y, z)
  236. --
  237. -- @return a new Vec3 with the result of the operation
  238. local function Vec3_cross(v, a, b, c)
  239. local ux, uy, uz
  240. if type(a) == "table" then
  241. ux = a.x or a[1] or 0.0
  242. uy = a.y or a[2] or 0.0
  243. uz = a.z or a[3] or 0.0
  244. else
  245. ux = a or 0.0
  246. uy = b or 0.0
  247. uz = c or 0.0
  248. end
  249. return Vec3.new(v.y*uz - v.z*uy, v.z*ux - v.x*uz, v.x*uy - v.y*ux)
  250. end
  251. Vec3.cross = Vec3_cross
  252. --- Rotates this (the first) vector around the second vector by the
  253. -- given angle.
  254. --
  255. -- Call with one of:
  256. -- vec:rot_around(axis, angle)
  257. -- Vec3.rot_around(vec, axis, angle)
  258. --
  259. -- @param axis
  260. -- The axis about which to rotate.
  261. -- @param angle
  262. -- The angle by which to rotate this vector, in radians.
  263. -- @return
  264. -- a new Vec3 with the result of the operation.
  265. local function Vec3_rot_around(v, axis, angle)
  266. local uaxis = Vec3.new_copy(axis):unit()
  267. local alen = uaxis:dotvec(v)
  268. local avec = uaxis:mul(alen)
  269. local pvec = Vec3.subvec(v, avec)
  270. local rvec = uaxis:crossvec(v)
  271. local v1 = pvec:mul(math.cos(angle))
  272. local v2 = rvec:mul(math.sin(angle))
  273. return avec:addvec(v1):addvec(v2)
  274. end
  275. Vec3.rot_around = Vec3_rot_around
  276. --- Adds two Vec3s. Optimized for pure Vec3/table operations by removing
  277. -- type checking and conditionals. If called with Vec3-likes table(s),
  278. -- ensure all expected components "x", "y", and "z" exist.
  279. --
  280. -- Call with one of:
  281. -- vec1:addvec(vec2)
  282. -- Vec3.addvec(vec1, vec2)
  283. --
  284. -- @return a new Vec3 object with the result of the operation
  285. local function Vec3_addvec(v1, v2)
  286. return Vec3.new(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z)
  287. end
  288. Vec3.addvec = Vec3_addvec
  289. Vec3_inst_meta.__add = Vec3_addvec
  290. --- Subtracts two Vec3s. Optimized for pure Vec3/table operations by
  291. -- removing type checking and conditionals. If called with Vec3-likes
  292. -- table(s), ensure all expected components "x", "y", and "z" exist.
  293. --
  294. -- Call with one of:
  295. -- vec1:subvec(vec2)
  296. -- Vec3.subvec(vec1, vec2)
  297. --
  298. -- @return a new Vec3 object with the result of the operation
  299. local function Vec3_subvec(v1, v2)
  300. return Vec3.new(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z)
  301. end
  302. Vec3.subvec = Vec3_subvec
  303. Vec3_inst_meta.__sub = Vec3_subvec
  304. --- Tests two Vec3s for exact component-wise equality. Optimized for pure
  305. -- Vec3/table operations by removing type checking and conditionals.
  306. -- If called with Vec3-likes table(s), ensure all expected components
  307. -- "x", "y", and "z" exist.
  308. --
  309. -- Call with one of:
  310. -- vec1:eqvec(vec2)
  311. -- Vec3.eqvec(vec1, vec2)
  312. --
  313. -- @return a new Vec3 object with the result of the operation
  314. local function Vec3_eqvec(v1, v2)
  315. return v1.x == v2.x and v1.y == v2.y and v1.z == v2.z
  316. end
  317. Vec3.eqvec = Vec3_eqvec
  318. Vec3_inst_meta.__eq = Vec3_eqvec
  319. --- Takes the dot product of two Vec3s. Optimized for pure Vec3/table
  320. -- operations by removing type checking and conditionals. If called
  321. -- with Vec3-likes table(s), ensure all expected components "x", "y",
  322. -- and "z" exist.
  323. --
  324. -- Call with one of:
  325. -- vec1:dotvec(vec2)
  326. -- Vec3.dotvec(vec1, vec2)
  327. --
  328. -- @return a number
  329. local function Vec3_dotvec(v1, v2)
  330. return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z
  331. end
  332. Vec3.dotvec = Vec3_dotvec
  333. --- Takes the cross product of two Vec3s. Optimized for pure Vec3/table
  334. -- operations by removing type checking and conditionals. If called
  335. -- with Vec3-likes table(s), ensure all expected components "x", "y",
  336. -- and "z" exist.
  337. --
  338. -- Call with one of:
  339. -- vec1:crossvec(vec2)
  340. -- Vec3.crossvec(vec1, vec2)
  341. --
  342. -- @return a new Vec3 with the result of the operation
  343. local function Vec3_crossvec(v1, v2)
  344. return Vec3.new(v1.y*v2.z - v1.z*v2.y,
  345. v1.z*v2.x - v1.x*v2.z,
  346. v1.x*v2.y - v1.y*v2.x)
  347. end
  348. Vec3.crossvec = Vec3_crossvec
  349. --- Converts Vec3 to a string with format "(x,y,z)".
  350. --
  351. -- Call with one of:
  352. -- vec:tostring()
  353. -- Vec3.tostring(vec)
  354. -- tostring(vec)
  355. --
  356. -- @return a string
  357. local function Vec3_tostring(v)
  358. return "("..
  359. (v.x or v[1] or "0")
  360. ..","..
  361. (v.y or v[2] or "0")
  362. ..","..
  363. (v.z or v[3] or "0")
  364. ..")"
  365. end
  366. Vec3.tostring = Vec3_tostring
  367. Vec3_inst_meta.__tostring = Vec3_tostring
  368. return Vec3