/spacey

To get this branch, use:
bzr branch /bzr/spacey
13 by Josh C
constant velocity for bullets. using hump.vector e9b86ef
1
--[[
2
Copyright (c) 2010-2013 Matthias Richter
3
4
Permission is hereby granted, free of charge, to any person obtaining a copy
5
of this software and associated documentation files (the "Software"), to deal
6
in the Software without restriction, including without limitation the rights
7
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
copies of the Software, and to permit persons to whom the Software is
9
furnished to do so, subject to the following conditions:
10
11
The above copyright notice and this permission notice shall be included in
12
all copies or substantial portions of the Software.
13
14
Except as contained in this notice, the name(s) of the above copyright holders
15
shall not be used in advertising or otherwise to promote the sale, use or
16
other dealings in this Software without prior written authorization.
17
18
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
THE SOFTWARE.
25
]]--
26
27
local assert = assert
28
local sqrt, cos, sin = math.sqrt, math.cos, math.sin
29
30
local vector = {}
31
vector.__index = vector
32
33
local function new(x,y)
34
	return setmetatable({x = x or 0, y = y or 0}, vector)
35
end
36
37
local function isvector(v)
38
	return getmetatable(v) == vector
39
end
40
41
function vector:clone()
42
	return new(self.x, self.y)
43
end
44
45
function vector:unpack()
46
	return self.x, self.y
47
end
48
49
function vector:__tostring()
50
	return "("..tonumber(self.x)..","..tonumber(self.y)..")"
51
end
52
53
function vector.__unm(a)
54
	return new(-a.x, -a.y)
55
end
56
57
function vector.__add(a,b)
58
	assert(isvector(a) and isvector(b), "Add: wrong argument types (<vector> expected)")
59
	return new(a.x+b.x, a.y+b.y)
60
end
61
62
function vector.__sub(a,b)
63
	assert(isvector(a) and isvector(b), "Sub: wrong argument types (<vector> expected)")
64
	return new(a.x-b.x, a.y-b.y)
65
end
66
67
function vector.__mul(a,b)
68
	if type(a) == "number" then
69
		return new(a*b.x, a*b.y)
70
	elseif type(b) == "number" then
71
		return new(b*a.x, b*a.y)
72
	else
73
		assert(isvector(a) and isvector(b), "Mul: wrong argument types (<vector> or <number> expected)")
74
		return a.x*b.x + a.y*b.y
75
	end
76
end
77
78
function vector.__div(a,b)
79
	assert(isvector(a) and type(b) == "number", "wrong argument types (expected <vector> / <number>)")
80
	return new(a.x / b, a.y / b)
81
end
82
83
function vector.__eq(a,b)
84
	return a.x == b.x and a.y == b.y
85
end
86
87
function vector.__lt(a,b)
88
	return a.x < b.x or (a.x == b.x and a.y < b.y)
89
end
90
91
function vector.__le(a,b)
92
	return a.x <= b.x and a.y <= b.y
93
end
94
95
function vector.permul(a,b)
96
	assert(isvector(a) and isvector(b), "permul: wrong argument types (<vector> expected)")
97
	return new(a.x*b.x, a.y*b.y)
98
end
99
100
function vector:len2()
101
	return self.x * self.x + self.y * self.y
102
end
103
104
function vector:len()
105
	return sqrt(self.x * self.x + self.y * self.y)
106
end
107
108
function vector.dist(a, b)
109
	assert(isvector(a) and isvector(b), "dist: wrong argument types (<vector> expected)")
110
	local dx = a.x - b.x
111
	local dy = a.y - b.y
112
	return sqrt(dx * dx + dy * dy)
113
end
114
115
function vector:normalize_inplace()
116
	local l = self:len()
117
	if l > 0 then
118
		self.x, self.y = self.x / l, self.y / l
119
	end
120
	return self
121
end
122
123
function vector:normalized()
124
	return self:clone():normalize_inplace()
125
end
126
127
function vector:rotate_inplace(phi)
128
	local c, s = cos(phi), sin(phi)
129
	self.x, self.y = c * self.x - s * self.y, s * self.x + c * self.y
130
	return self
131
end
132
133
function vector:rotated(phi)
134
	local c, s = cos(phi), sin(phi)
135
	return new(c * self.x - s * self.y, s * self.x + c * self.y)
136
end
137
138
function vector:perpendicular()
139
	return new(-self.y, self.x)
140
end
141
142
function vector:projectOn(v)
143
	assert(isvector(v), "invalid argument: cannot project vector on " .. type(v))
144
	-- (self * v) * v / v:len2()
145
	local s = (self.x * v.x + self.y * v.y) / (v.x * v.x + v.y * v.y)
146
	return new(s * v.x, s * v.y)
147
end
148
149
function vector:mirrorOn(v)
150
	assert(isvector(v), "invalid argument: cannot mirror vector on " .. type(v))
151
	-- 2 * self:projectOn(v) - self
152
	local s = 2 * (self.x * v.x + self.y * v.y) / (v.x * v.x + v.y * v.y)
153
	return new(s * v.x - self.x, s * v.y - self.y)
154
end
155
156
function vector:cross(v)
157
	assert(isvector(v), "cross: wrong argument types (<vector> expected)")
158
	return self.x * v.y - self.y * v.x
159
end
160
161
-- ref.: http://blog.signalsondisplay.com/?p=336
162
function vector:trim_inplace(maxLen)
163
	local s = maxLen * maxLen / self:len2()
164
	s = s < 1 and 1 or math.sqrt(s)
165
	self.x, self.y = self.x * s, self.y * s
166
	return self
167
end
168
169
function vector:trimmed(maxLen)
170
	return self:clone():trim_inplace(maxLen)
171
end
172
173
174
-- the module
175
return setmetatable({new = new, isvector = isvector},
176
{__call = function(_, ...) return new(...) end})