254 lines
4.0 KiB
Lua
254 lines
4.0 KiB
Lua
|
-- The base Vector class.
|
||
|
local EPSILON = 0.0001
|
||
|
local EPSILON_SQUARED = EPSILON*EPSILON
|
||
|
Vector = Object:extend()
|
||
|
function Vector:init(x, y)
|
||
|
self.x = x or 0
|
||
|
self.y = y or x or 0
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:clone()
|
||
|
return Vector(self.x, self.y)
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:unpack()
|
||
|
return self.x, self.y
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector.__tostring(self)
|
||
|
return "(" .. tonumber(self.x) .. ", " .. tonumber(self.y) .. ")"
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:set(x, y)
|
||
|
if not y then
|
||
|
self.x = x.x
|
||
|
self.y = x.y
|
||
|
else
|
||
|
self.x = x
|
||
|
self.y = y
|
||
|
end
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:add(x, y)
|
||
|
if not y then
|
||
|
self.x = self.x + x.x
|
||
|
self.y = self.y + x.y
|
||
|
else
|
||
|
self.x = self.x + x
|
||
|
self.y = self.y + y
|
||
|
end
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:sub(x, y)
|
||
|
if not y then
|
||
|
self.x = self.x - x.x
|
||
|
self.y = self.y - x.y
|
||
|
else
|
||
|
self.x = self.x - x
|
||
|
self.y = self.y - y
|
||
|
end
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:mul(s)
|
||
|
if type(s) == "table" then
|
||
|
self.x = self.x*s.x
|
||
|
self.y = self.y*s.y
|
||
|
else
|
||
|
self.x = self.x*s
|
||
|
self.y = self.y*s
|
||
|
end
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:div(s)
|
||
|
if type(s) == "table" then
|
||
|
self.x = self.x*s.x
|
||
|
self.y = self.y*s.y
|
||
|
else
|
||
|
self.x = self.x/s
|
||
|
self.y = self.y/s
|
||
|
end
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:scale(k)
|
||
|
self.x = self.x*k
|
||
|
self.y = self.y*k
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:rotate(p, r)
|
||
|
local cos = math.cos(r)
|
||
|
local sin = math.sin(r)
|
||
|
local dx = self.x - p.x
|
||
|
local dy = self.y - p.y
|
||
|
self.x = dx*cos - sin*dy + p.x
|
||
|
self.y = sin*dx + cos*dy + p.y
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:floor()
|
||
|
self.x = math.floor(self.x)
|
||
|
self.y = math.floor(self.y)
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:ceil()
|
||
|
self.x = math.ceil(self.x)
|
||
|
self.y = math.ceil(self.y)
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:round(p)
|
||
|
self.x = math.round(self.x, p)
|
||
|
self.y = math.round(self.y, p)
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:dot(v)
|
||
|
return self.x*v.x + self.y*v.y
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:is_perpendicular(v)
|
||
|
return math.abs(self:dot(v)) < EPSILON_SQUARED
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:cross(v)
|
||
|
return self.x*v.y - self.y*v.x
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:is_parallel(v)
|
||
|
return math.abs(self:cross(v)) < EPSILON_SQUARED
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:is_set()
|
||
|
return self.x or self.y
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:is_zero()
|
||
|
return math.abs(self.x) < EPSILON and math.abs(self.y) < EPSILON
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:zero()
|
||
|
self.x = 0
|
||
|
self.y = 0
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:length()
|
||
|
return math.sqrt(self.x*self.x + self.y*self.y)
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:length_squared()
|
||
|
return self.x*self.x + self.y*self.y
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:normalize()
|
||
|
if self:is_zero() then return self end
|
||
|
return self:scale(1/self:length())
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:perpendicular()
|
||
|
return Vector(-self.y, self.x)
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:left_normal()
|
||
|
return Vector(self.y, -self.x)
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:invert()
|
||
|
self.x = self.x*-1
|
||
|
self.y = self.y*-1
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:project_to(v)
|
||
|
local lsq = v:length_squared()
|
||
|
local dp = self:dot(v)
|
||
|
return Vector(dp*v.x/lsq, dp*v.y/lsq)
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:truncate(max)
|
||
|
local s = max*max/self:length_squared()
|
||
|
s = (s > 1 and 1) or math.sqrt(s)
|
||
|
self.x = self.x*s
|
||
|
self.y = self.y*s
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:angle_to(v)
|
||
|
return math.atan2(v.y - self.y, v.x - self.x)
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:angle()
|
||
|
return math.atan2(self.y, self.x)
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:distance_squared(v)
|
||
|
local dx = v.x - self.x
|
||
|
local dy = v.y - self.y
|
||
|
return dx*dx + dy*dy
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:distance(v)
|
||
|
return math.sqrt(self:distance_squared(v))
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:bounce(normal, bounce_coefficient)
|
||
|
local d = (1 + (bounce_coefficient or 1))*self:dot(normal)
|
||
|
self.x = self.x - d*normal.x
|
||
|
self.y = self.y - d*normal.y
|
||
|
return self
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:overlaps_with_circle(cx, cy, r)
|
||
|
return mlib.circle.checkPoint(self.x, self.y, cx, cy, r)
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:overlaps_with_polygon(vs)
|
||
|
return mlib.polygon.checkPoint(self.x, self.y, vs)
|
||
|
end
|
||
|
|
||
|
|
||
|
function Vector:overlaps_with_rectangle(x, y, w, h)
|
||
|
return mlib.polygon.checkPoint(self.x, self.y, x - w/2, y - h/2, x + w/2, y - h/2, x + w/2, y + h/2, x - w/2, y + h/2)
|
||
|
end
|