]> git.lizzy.rs Git - hydra-dragonfire.git/blob - builtin/vector.lua
Fix vector equals operator
[hydra-dragonfire.git] / builtin / vector.lua
1 --[[ builtin/vector.lua ]]--
2
3 local function wrap(op, body_wrapper, ...)
4         return loadstring("return function(a, b) " .. body_wrapper(op, ...) .. "end")()
5 end
6
7 local function arith_mt(...)
8         return {
9                 __add = wrap("+", ...),
10                 __sub = wrap("-", ...),
11                 __mul = wrap("*", ...),
12                 __div = wrap("/", ...),
13                 __mod = wrap("%", ...),
14                 __index = {},
15         }
16 end
17
18 -- vec2
19
20 local mt_vec2 = arith_mt(function(op)
21         return [[
22                 if type(b) == "number" then
23                         return vec2(a.x ]] .. op.. [[ b, a.y ]] .. op .. [[ b)
24                 else
25                         return vec2(a.x ]] .. op.. [[ b.x, a.y ]] .. op.. [[ b.y)
26                 end
27         ]]
28 end)
29
30 function mt_vec2:__neg()
31         return vec2(-self.x, -self.y)
32 end
33
34 function mt_vec2:__len()
35         return math.sqrt(self:dot(self))
36 end
37
38 function mt_vec2:__eq(other)
39         return type(other) == "table" and self.x == other.x and self.y == other.y
40 end
41
42 function mt_vec2:__tostring()
43         return "(" .. self.x .. ", " .. self.y .. ")"
44 end
45
46 function mt_vec2.__index:validate()
47         assert(type(self.x) == "number")
48         assert(type(self.y) == "number")
49         return self
50 end
51
52 function mt_vec2.__index:round()
53         return vec2(math.round(self.x), math.round(self.y))
54 end
55
56 function mt_vec2.__index:manhattan()
57         return math.abs(self.x) + math.abs(self.y)
58 end
59
60 function mt_vec2.__index:volume()
61         return self.x * self.y
62 end
63
64 function mt_vec2.__index:dot(other)
65         return self.x * other.x + self.y * other.y
66 end
67
68 function mt_vec2.__index:norm()
69         return self / #self
70 end
71
72 function vec2(a, b)
73         local o = {}
74
75         if type(a) == "number" then
76                 o.x = a
77                 o.y = b or a
78         else
79                 o.x = a.x
80                 o.y = a.y
81         end
82
83         setmetatable(o, mt_vec2)
84         return o:validate()
85 end
86
87 -- vec3
88
89 local mt_vec3 = arith_mt(function(op)
90         return [[
91                 if type(b) == "number" then
92                         return vec3(a.x ]] .. op.. [[ b, a.y ]] .. op .. [[ b, a.z ]] .. op .. [[ b)
93                 else
94                         return vec3(a.x ]] .. op.. [[ b.x, a.y ]] .. op.. [[ b.y, a.z ]] .. op.. [[ b.z)
95                 end
96         ]]
97 end)
98
99 function mt_vec3:__neg()
100         return vec3(-self.x, -self.y, -self.z)
101 end
102
103 function mt_vec3:__len()
104         return math.sqrt(self:dot(self))
105 end
106
107 function mt_vec3:__eq(other)
108         return type(other) == "table" and self.x == other.x and self.y == other.y and self.z == other.z
109 end
110
111 function mt_vec3:__tostring()
112         return "(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ")"
113 end
114
115 function mt_vec3.__index:validate()
116         assert(type(self.x) == "number")
117         assert(type(self.y) == "number")
118         assert(type(self.z) == "number")
119         return self
120 end
121
122 function mt_vec3.__index:round()
123         return vec3(math.floor(self.x), math.floor(self.y), math.floor(self.z))
124 end
125
126 function mt_vec3.__index:manhattan()
127         return math.abs(self.x) + math.abs(self.y) + math.abs(self.z)
128 end
129
130 function mt_vec3.__index:volume()
131         return self.x * self.y * self.z
132 end
133
134 function mt_vec3.__index:dot(other)
135         return self.x * other.x + self.y * other.y + self.z * other.z
136 end
137
138 function mt_vec3.__index:cross(other)
139         return vec3(
140                 self.y * other.z - self.z * other.y,
141                 self.z * other.x - self.x * other.z,
142                 self.x * other.y - self.y * other.x
143         )
144 end
145
146 function mt_vec3.__index:norm()
147         return self / #self
148 end
149
150 function vec3(a, b, c)
151         local o = {}
152
153         if type(a) == "number" then
154                 o.x = a
155                 o.y = b or a
156                 o.z = c or a
157         else
158                 o.x = a.x
159                 o.y = a.y
160                 o.z = a.z
161         end
162
163         setmetatable(o, mt_vec3)
164         return o:validate()
165 end
166
167 -- box
168
169 local mt_box = arith_mt(function(op)
170         return "return box(a.min " .. op .. " b, a.max " .. op .. " b)"
171 end)
172
173 function mt_box:__neg()
174         return box(-self.min, -self.max)
175 end
176
177 function mt_box:__eq(other)
178         return self.min == other.min and self.max == other.max
179 end
180
181 function mt_box:__tostring()
182         return "[" .. self.min .. "; " .. self.max .. "]"
183 end
184
185 function mt_box.__index:validate()
186         if type(self.min) == "number" then
187                 assert(type(self.max) == "number")
188         else
189                 assert(not self.min.z == not self.max.z)
190                 self.min:validate()
191                 self.max:validate()
192         end
193 end
194
195 function mt_box.__index:volume()
196         local diff = self.max - self.min
197         if type(diff) == "number" then
198                 return diff
199         else
200                 return diff:volume()
201         end
202 end
203
204 function mt_box.__index:contains(other)
205         if type(other) == "number" or other.x then
206                 return self.min <= other and self.max >= other
207         else
208                 return self.min <= other.min and self.max >= other.max
209         end
210 end
211
212 function box(a, b)
213         local o = {}
214
215         if type(a) == "number" or a.x then
216                 o.min = a
217                 o.max = b
218         else
219                 o.min = a.min
220                 o.max = a.max
221         end
222
223         setmetatable(o, mt_box)
224         return o:validate()
225 end