/traderous

To get this branch, use:
bzr branch http://9ix.org/bzr/traderous

« back to all changes in this revision

Viewing changes to vector.lua

  • Committer: Josh C
  • Date: 2013-05-29 02:51:39 UTC
  • Revision ID: josh@9ix.org-20130529025139-g8sboz3p23excyz4
F1 = screenshot

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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})