Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- --Reference:
- vec = require'vec'
- a = vec(3, 4)
- b = vec(-30, -40)
- c = vec(3, -2)
- -- Call. It faster then defineing new vectors
- a(b) --> a = {-30, -40}, a get new value, is not link to b
- a(3, 4) --> a = {3, 4}, set it back
- -- Arithmetic:
- d = a + b --> d = {-27, -36}
- d = b - a --> d = {-33, -44}
- d = a * b --> d = {-90, -160}
- d = -b * 0.2 --> d = {6, 8}
- d = a / b --> d = {0.1, 0.1}
- d = a / 2 --> d = {1.5, 2}
- d = a ^ c --> d = {27, 0.0625}
- d = a ^ 3 --> d = {27, 64}
- Also here may be strong optimisation:
- d:add(vec) average addition
- d = a:nadd( (num) x, (num) y) adding vector from two numbers to d.x and d.y
- d = d:vadd(v) faster addition of two vectors
- It works for every method with varying of args:
- add, sub, mul, div, pow, eq, lt, le, dot, det, cross, angle, dist, dist2
- Every arithmetic/equality overloadings has method veriation
- If you don't need for new vectors:
- d:sadd(vec or [num, num]) does not create new vector, only modify vector d
- It works for every method, returns new vector:
- add, sub, mul, div, pow, unm, permul, trim, norm, rotate, magn (abs),
- perp, project, mirror, clamp, lerp, alerp, floor, ceil, round
- Also it can be combined to fastest variation:
- d:snadd(num, num) add to d vector as two numbers, fastest variation
- d:svadd(vec)
- -- Equality
- a == 5 --> true, because a:len() = 5
- a == d --> false
- b > a --> true
- b <= 50 --> true, because #b = 50
- -- Len
- e = #a --> e = 5
- e = a:len() --> e = 5
- e = a:len2() --> e = 25
- -- Utility methods:
- print(a:unpack()) --> 3 4
- str = tostring(a) or a:tostring() --> str = '[3, 4]'
- print('sum of vectors: '..(a+b)) --> sum of vectors: [33, 44]
- local n = vec:fromstring(str) --> creates vector {33, 44} from string
- len = n:tonumber() --> equal 'len = #n'
- t = {a:join(b, 10, 20, c, 30, 40)}
- --> join return touple of all arguments, now t is {a.x, a.y, b.x, b.y, 10, 20, c.x, c.y, 30, 40}
- vec.isVec(b) --> return true
- d = a:clone()--> d = {3, 4}, work like call
- --Methods:
- --a:area() - S of a-rectangle (a.x * a.y)
- --a:permul(b) - like a*b, but only for vectors, little bit faster
- --a:trim(len) - vector trimming
- --a:norm() - normalize vector
- --a:floor([n]) - flooring, n - digits after the decimal point, 0 as default
- --a:ceil([n]) - ceiling, n - digits after the decimal point, 0 as default
- --a:round([n]) - ceiling, n - digits after the decimal point, 0 as default
- --a:dist(b) - return distance between a and b
- --a:dist2(b) - return distance^2 between a and b
- --a:dot(b) - dot product (a.x * b.x + a.y * b.y)
- --a:det(b) - det product (a.x * b.x - a.y * b.y)
- --a:cross(b) - cross product (a.x * b.y - a.y * b.x)
- --a:angle([b|n,m]) - return vector angle (no args) or angle between two vectors (arg can be vec or two num)
- --a:setAngle(n) - set vector by angle n
- --a:rotate(n) - return rotated vector
- --a:magn() - vector magnitude (abs(a.x), abs(a.y)), also named 'abs'
- --a:abs() - same as magn
- --a:perp([b|n,m]) - set a perpendicular to b
- --a:clamp(b, c) - clamp vector between two other vectors
- --a:project([b|n,m]) - set a to projection a to b
- --a:mirror([b|n,m]) - mirror a relatively b
- --a:lerp(b, n, dt) - interpolate vector a to vector b, with n coef and dt as delta
- --a:alerp(b, n, dt) - interpolate angle of vector a to angle of vector b, with n coef and dt as delta
- ]]
- local function isVec(v) return type(v) == 'table' and v.x and v.y end
- local function isNum(v) return type(v) == 'number' end
- local oldtype = type
- local function switch(a, b)
- if isVec(a) then
- return a, b
- end
- return b, a
- end
- local lvl = 2
- local vector, mt = {}, {}
- vector.mt = mt
- local error = error
- local pi, tau, sqrt, cos, sin, acos, atan2 = math.pi, math.pi*2, math.sqrt, math.cos, math.sin, math.acos, math.atan2
- function vector:new(x, y)
- return setmetatable({x = x, y = y}, self.mt)
- end
- setmetatable(vector, {__call = vector.new})
- mt.__index = vector
- function mt.__call(self, x, y)
- if x and y then
- self.x = x
- self.y = y
- return self
- end
- return vector(self.x, self.y)
- end
- -- OVERLOADING
- do
- -- ADD
- do
- function vector:add(v)
- return vector(self.x + v.x, self.y + v.y)
- end
- mt.__add = vector.add
- function vector:nadd(a, b)
- return vector(self.x + a, self.y + (b or a))
- end
- function vector:vadd(v)
- return vector(self.x + v.x, self.y + v.y)
- end
- function vector:sadd(v)
- self.x, self.y = self.x + v.x, self.y + v.y
- return self
- end
- function vector:snadd(a, b)
- self.x = self.x + a
- self.y = self.y + (b or a)
- return self
- end
- function vector:svadd(v)
- self.x = self.x + v.x
- self.y = self.y + v.y
- return self
- end
- end
- -- SUB
- do
- function vector:sub(v)
- return vector(self.x - v.x, self.y - v.y)
- end
- mt.__sub = vector.sub
- function vector:nsub(a, b)
- return vector(self.x - a, self.y - (b or a))
- end
- function vector:vsub(v)
- return vector(self.x - v.x, self.y - v.y)
- end
- function vector:ssub(v)
- self.x, self.y = self.x - v.x, self.y - v.y
- return self
- end
- function vector:snsub(a, b)
- self.x = self.x - a
- self.y = self.y - (b or a)
- return self
- end
- function vector:svsub(v)
- self.x = self.x - v.x
- self.y = self.y - v.y
- return self
- end
- end
- -- MUL
- do
- function vector:mul(v)
- self, v = switch(self, v)
- return isVec(v) and vector(self.x * v.x, self.y * v.y)
- or isNum(v) and vector(self.x * v, self.y * v)
- or error('Vector mul: two vectors or vector and scalar expected, got vector and '..type(v), lvl)
- end
- mt.__mul = vector.mul
- function vector:nmul(a, b)
- return vector(self.x * a, self.y * (b or a))
- end
- function vector:vmul(v)
- return vector(self.x * v.x, self.y * v.y)
- end
- function vector:smul(v)
- self, v = switch(self, v)
- if isNum(v) then
- self.x = self.x * v
- self.y = self.y * v
- elseif isVec(self) then
- self.x = self.x * v.x
- self.y = self.y * v.y
- else
- error('Vector mul: two vectors or vector and scalar expected, got vector and '..type(v), lvl)
- end
- return self
- end
- function vector:snmul(a, b)
- self.x = self.x * a
- self.y = self.y * (b or a)
- return self
- end
- function vector:svmul(v)
- self.x = self.x * v.x
- self.y = self.y * v.y
- return self
- end
- end
- -- DIV
- do
- function vector:div(v)
- self, v = switch(self, v)
- return isVec(v) and vector(self.x / v.x, self.y / v.y)
- or isNum(v) and vector(self.x / v, self.y / v)
- or error('Vector div: two vectors or vector and scalar expected, got vector and '..type(v), lvl)
- end
- mt.__div = vector.div
- function vector:ndiv(a, b)
- return vector(self.x / a, self.y / (b or a))
- end
- function vector:vdiv(v)
- return vector(self.x / v.x, self.y / v.y)
- end
- function vector:sdiv(v)
- self, v = switch(self, v)
- if isNum(v) then
- self.x = self.x / v
- self.y = self.y / v
- elseif isVec(self) then
- self.x = self.x / v.x
- self.y = self.y / v.y
- else
- error('Vector sdiv: two vectors or vector and scalar expected, got vector and '..type(v), lvl)
- end
- return self
- end
- function vector:sndiv(a, b)
- self.x = self.x / a
- self.y = self.y / (b or a)
- return self
- end
- function vector:svdiv(v)
- self.x = self.x / v.x
- self.y = self.y / v.y
- return self
- end
- end
- -- POW
- do
- function vector:pow(v)
- self, v = switch(self, v)
- return isVec(self) and vector(self.x ^ v.x, self.y ^ v.y)
- or isNum(v) and vector(self.x ^ b, self.y ^ b)
- or error('Vector pow: two vectors or vector and scalar expected, got vector and '..type(v), lvl)
- end
- mt.__pow = vector.pow
- function vector:npow(a, b)
- return vector(self.x ^ a, self.y ^ (b or a))
- end
- function vector:vpow(v)
- return vector(self.x ^ v.x, self.y ^ v.y)
- end
- function vector:spow(v)
- self, v = switch(self, v)
- if isNum(v) then
- self.x = self.x ^ v
- self.y = self.y ^ v
- elseif isVec(self) then
- self.x = self.x ^ v.x
- self.y = self.y ^ v.y
- else
- error('Vector spow: two vectors or vector and scalar expected, got vector and '..type(v), lvl)
- end
- return self
- end
- function vector:snpow(a, b)
- self.x = self.x ^ a
- self.y = self.y ^ (b or a)
- return self
- end
- function vector:svpow(v)
- self.x = self.x ^ v.x
- self.y = self.y ^ v.y
- return self
- end
- end
- -- EQ
- do
- function vector:eq(v)
- self, v = switch(self, v)
- return isVec(self) and self.x == v.x and self.y == v.y
- or isNum(v) and #self == v
- or error('Vector eq: two vectors or vector and scalar expected, got vector and '..type(v), lvl)
- end
- mt.__eq = vector.eq
- function vector:neq(a, b)
- return b and (self.x == a and self.y == b) or #self == a
- end
- function vector:veq(v)
- return self.x == v.x and self.y == v.y
- end
- end
- -- LT
- do
- function vector:lt(v)
- self, v = switch(self, v)
- return isVec(self) and self.x < v.x and self.y < v.y
- or isNum(v) and #self < v
- or error('Vector lt: two vectors or vector and scalar expected, got vector and '..type(v), lvl)
- end
- mt.__lt = vector.lt
- function vector:nlt(a, b)
- return b and (self.x < a and self.y < b) or #self < a
- end
- function vector:vlt(v)
- return self.x < v.x and self.y < v.y
- end
- end
- -- LE
- do
- function vector:le(v)
- self, v = switch(self, v)
- return isVec(self) and self.x <= v.x and self.y <= v.y
- or isNum(v) and #self <= v
- or error('Vector le: two vectors or vector and scalar expected, got vector and '..type(b), lvl)
- end
- mt.__le = vector.le
- function vector:nle(a, b)
- return b and (self.x <= a and self.y <= b) or #self <= a
- end
- function vector:vle(v)
- return self.x <= v.x and self.y <= v.y
- end
- end
- -- UNM
- do
- function vector:unm()
- return vector(-self.x, -self.y)
- end
- mt.__unm = vector.unm
- function vector:sunm()
- self.x, self.y = -self.x, -self.y
- return self
- end
- end
- -- LEN
- do
- function vector:len()
- return (self.x * self.x + self.y * self.y)^.5
- end
- mt.__len = vector.len
- function vector:len2()
- return (self.x * self.x + self.y * self.y)
- end
- end
- end
- -- CONVERSIONS
- do
- function vector:tostring()
- return '['..self.x..', '..self.y..']'
- end
- mt.__tostring = vector.tostring
- function vector:fromstring(s)
- local a, b = s:match('(%-?%d%.?%d?).-(%-?%d%.?%d?)')
- if not a or not b then
- return nil, 'parse error, format \'[n1,n2]\''
- end
- return vector(tonumber(a), tonumber(b))
- end
- function vector:tonumber()
- return #self
- end
- mt.__tonumber = vector.tonumber
- function vector:concat(v)
- return tostring(self)..tostring(v)
- end
- mt.__concat = vector.concat
- function vector:unpack(v)
- if v then
- return self.x*v, self.y*v
- else
- return self.x, self.y
- end
- end
- end
- -- TOOLS
- do
- function vector:isVec(v)
- return v and isVec(v) or isVec(self)
- end
- function vector:clone()
- return vector(self.x, self.y)
- end
- function vector:set(a, b)
- if isNum(a) then
- self.x, self.y = a, (b or a)
- elseif isVec(a) then
- self.x = a.x
- self.y = a.y
- end
- return self
- end
- local insert = table.insert
- function vector:join(...)
- local res = {}
- for i, v in ipairs{self, ...} do
- if isVec(v) then
- insert(res, v.x)
- insert(res, v.y)
- else
- insert(res, v)
- end
- end
- return unpack(res)
- end
- end
- function vector:area()
- return self.x * self.y
- end
- -- VEC TRANSFORM
- do
- function vector:spermul(a, b)
- if isVec(a) then
- self.x, self.y = self.x * a.x, self.y * a.y
- return self
- elseif isNum(a) and isNum(b) then
- self.x, self.y = self.x * a, self.y * b
- return self
- else
- local str = type(a)
- if b then str = str..', '..type(b) end
- error('Vector:permul: vector or two numbers expected, got: '..str, lvl)
- end
- end
- function vector:permul(a, b)
- return self:clone():spermul(a, b)
- end
- local sqrt = math.sqrt
- function vector:strim(l)
- if not isNum(l) then error('Vector:trim: number expected, got: '..type(l), lvl) end
- local s = l * l / self:len2()
- s = (s > 1 and 1) or sqrt(s)
- self.x, self.y = self.x * s, self.y * s
- return self
- end
- function vector:trim(l)
- return self:clone():strim(l)
- end
- function vector:snorm(v)
- local d = isVec(v) and #v or isNum(v) and v or 1
- local l = self:len()
- if l > 0 then
- self.x = self.x / l * d
- self.y = self.y / l * d
- return self
- end
- self.x = 0
- self.y = 0
- return self
- end
- function vector:norm(v)
- return self:clone():snorm(v)
- end
- function vector:setAngle(phi)
- -- phi = (phi % 2*pi)-pi
- local a = #self
- self.x, self.y = cos(phi) * a, sin(phi) * a
- return self
- end
- function vector:srotate(phi)
- local c, s = cos(phi), sin(phi)
- self.x, self.y = c * self.x - s * self.y, s * self.x + c * self.y
- return self
- end
- function vector:rotate(phi)
- return self:clone():srotate(phi)
- end
- local abs = math.abs
- function vector:smagn()
- self.x = abs(self.x)
- self.y = abs(self.y)
- return self
- end
- function vector:magn()
- return self:clone():smagn()
- end
- vector.abs = vector.magn
- vector.sabs = vector.smagn
- function vector:sperp(a, b)
- if isVec(a) then
- local d = #self/#a
- self.x = a.y * d
- self.y = -a.x * d
- return self
- elseif isNum(a) and isNum(b) then
- local d = #self/((a ^ 2 + b ^ 2)^.5)
- self.x, self.y = b*d, -a*d
- return self
- elseif not a and not b then
- self.x, self.y = self.y, -self.x
- return self
- elseif type(a) == 'boolean' then
- self.x, self.y = -self.y, self.x
- return self
- else
- local str = type(a)
- if b then str = str..', '..type(b) end
- error('Vector:perpendiculared: vector or two numbers or boolean expected, got: '..str, lvl)
- end
- end
- function vector:perp(a, b)
- return self:clone():sperp(a, b)
- end
- function vector:sproject(a, b)
- if isVec(a) then
- local s = (self.x * a.x + self.y * a.y) / (a.x * a.x + a.y * a.y)
- self.x, self.y = s * a.x, s * a.y
- return self
- elseif isNum(a) and isNum(b) then
- local s = (self.x * a + self.y * b) / (a * a + b * b)
- self.x, self.y = s * a, s * b
- return self
- else
- local str = type(a)
- str = b and str..', '..type(b) or str
- error('Vector:project: vector or two numbers expected, got: '..str, lvl)
- end
- end
- function vector:project(a, b)
- return self:clone():sproject(a, b)
- end
- function vector:smirror(a, b)
- if isVec(a) then
- local s = 2 * (self.x * a.x + self.y * a.y) / (a.x * a.x + a.y * a.y)
- -- s can be nan if #vectors is 0, 0
- if s == s then
- self.x, self.y = s * a.x - self.x, s * a.y - self.y
- return self
- end
- return a:clone()
- elseif isNum(a) and isNum(b) then
- local s = 2 * (self.x * a + self.y * b) / (a * a + b * b)
- if s == s then
- self.x, self.y = s * a - self.x, s * b - self.y
- return self
- end
- return vector(a, b)
- else
- local str = type(a)
- if b then str = str..', '..type(b) end
- error('Vector:mirror: vector or two numbers expected, got: '..str, lvl)
- end
- end
- function vector:mirror(a, b)
- return self:clone():smirror()
- end
- local function vmin(a, b) return a < b and b or a end
- local function vmax(a, b) return a > b and b or a end
- function vector:sclamp(a, b)
- self.x = vmin(vmax(self.x, a.x), b.x)
- self.y = vmin(vmax(self.y, a.y), b.y)
- return self
- end
- function vector:clamp(a, b)
- return self:clone():sclamp()
- end
- -- LERPING
- do
- local pi = math.pi
- function vector:salerp(a, b, dt)
- local ca, ta = self:angle(), a:angle()
- local theta = ta - ca
- local ca = theta > pi and ca + pi*2 or theta < -pi and ca - pi*2 or ca
- self:setAngle(ca + (ta - ca) * b)
- return self
- end
- function vector:alerp(a, b, dt)
- return self:clone():salerp(a, b, dt)
- end
- local function lerp(a, b, t) return a + (b - a) * t end
- function vector:slerp(a, b, c)
- if isNum(a) and isNum(b) then
- a = vector(a, b)
- b = c
- end
- self.x = self.x + (a.x - self.x) * b
- self.y = self.y + (a.y - self.y) * b
- return self
- end
- function vector:lerp(a, b, c)
- return self:clone():slerp(a, b, c)
- end
- end
- -- ROUNDING
- do
- local floor = math.floor
- function vector:sfloor(n)
- n = n and n * 10
- if n then
- self.x = floor(self.x * n) / n
- self.y = floor(self.y * n) / n
- else
- self.x = floor(self.x)
- self.y = floor(self.y)
- end
- return self
- end
- function vector:floor(n)
- return self:clone():sfloor()
- end
- local ceil = math.ceil
- function vector:sceil(n)
- n = n and n * 10
- if n then
- self.x = ceil(self.x * n) / n
- self.y = ceil(self.y * n) / n
- else
- self.x = ceil(self.x)
- self.y = ceil(self.y)
- end
- return self
- end
- function vector:ceil(v)
- return self:clone():sceil()
- end
- local floor = math.floor
- function vector:sround(n)
- n = n and n * 10
- if n then
- local fx, fy = floor(self.x * n)
- self.x = (floor(self.x * n + 0.5) - 1) / n
- self.x = (floor(self.y * n + 0.5) - 1) / n
- else
- self.x = floor(self.x + 0.5) - 1
- self.y = floor(self.y + 0.5) - 1
- end
- return self
- end
- function vector:round(v)
- return self:clone():sround(v)
- end
- end
- end
- -- VECTOR OPERATIONS
- do
- function vector:dot(a, b)
- if isVec(a) then
- return self.x * a.x + self.y * a.y
- elseif isNum(a) and isNum(b) then
- return self.x * a + self.y * b
- else
- local str = type(a)
- if b then str = str..', '..type(b) end
- error('Vector:dot: vector or two numbers expected, got: '..str, lvl)
- end
- end
- function vector:vdot(v)
- return self.x * v.x + self.y * v.y
- end
- function vector:ndot(x, y)
- return self.x * x + self.y * y
- end
- function vector:det(a, b)
- if isVec(a) then
- return self.x * a.x - self.y * a.y
- elseif isNum(a) and isNum(b) then
- return self.x * a - self.y * b
- else
- local str = type(a)
- if b then str = str..', '..type(b) end
- error('Vector:det: vector or two numbers expected, got: '..str, lvl)
- end
- end
- function vector:vdet(v)
- return self.x * v.x - self.y * v.y
- end
- function vector:ndet(x, y)
- return self.x * x - self.y * y
- end
- function vector:cross(a, b)
- if isVec(a) then
- return self.x * a.y - self.y * a.x
- elseif isNum(a) and isNum(b) then
- return self.x * b - self.y * a
- else
- local str = type(a)
- if b then str = str..', '..type(b) end
- error('Vector:cross: vector or two numbers expected, got: '..str, lvl)
- end
- end
- function vector:vcross(v)
- return self.x * v.y - self.y * v.x
- end
- local atan2 = math.atan2
- function vector:angle(a, b)
- if isVec(a) then
- return atan2(self.y, self.x) - atan2(a.y, a.x)
- elseif isNum(a) and isNum(b) then
- return atan2(self.y, self.x) - atan2(b, a)
- elseif isNum(a) then
- return atan2(self.y, self.x) - a
- end
- return atan2(self.y, self.x)
- end
- function vector:vangle(v)
- return atan2(self.y, self.x) - atan2(v.y, v.x)
- end
- function vector:nangle()
- return atan2(self.y, self.x)
- end
- function vector:len2()
- return self.x * self.x + self.y * self.y
- end
- function vector:len()
- return self:len2()^.5
- end
- function vector:dist(a, b)
- if isVec(a) then
- local dx = self.x - a.x
- local dy = self.y - a.y
- return sqrt(dx * dx + dy * dy)
- elseif isNum(a) and isNum(b) then
- local dx = self.x - a
- local dy = self.y - b
- return sqrt(dx * dx + dy * dy)
- else
- local str = type(a)
- str = b and str..', '..type(b) or str
- error('Vector:dist: vector or two numbers expected, got: '..str, lvl)
- end
- end
- function vector:vdist(v)
- local dx = self.x - v.x
- local dy = self.y - v.y
- return sqrt(dx * dx + dy * dy)
- end
- function vector:dist2(a, b)
- if isVec(a) then
- local dx = self.x - a.x
- local dy = self.y - a.y
- return dx * dx + dy * dy
- elseif isNum(a) and isNum(b) then
- local dx = self.x - a
- local dy = self.y - b
- return dx * dx + dy * dy
- else
- local str = type(a)
- str = b and str..', '..type(b) or str
- error('Vector:dist: vector or two numbers expected, got: '..str, lvl)
- end
- end
- function vector:vdist2(v)
- local dx = self.x - v.x
- local dy = self.y - v.y
- return dx * dx + dy * dy
- end
- function vector:dir(other)
- return self:dot(other)/(#self * #other)
- end
- end
- return vector
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement