• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

excessive / cpml / 1

23 Jun 2021 11:35PM UTC coverage: 53.574% (+9.4%) from 44.185%
1

push

github

web-flow
Merge pull request #62 from idbrii/actions-busted

Run tests on gh actions

4452 of 8310 relevant lines covered (53.57%)

91.18 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

89.47
/modules/vec2.lua
1
--- A 2 component vector.
2
-- @module vec2
3

4
local modules = (...):gsub('%.[^%.]+$', '') .. "."
16✔
5
local vec3    = require(modules .. "vec3")
16✔
6
local private = require(modules .. "_private_utils")
16✔
7
local acos    = math.acos
16✔
8
local atan2   = math.atan2
16✔
9
local sqrt    = math.sqrt
16✔
10
local cos     = math.cos
16✔
11
local sin     = math.sin
16✔
12
local vec2    = {}
16✔
13
local vec2_mt = {}
16✔
14

15
-- Private constructor.
16
local function new(x, y)
17
        return setmetatable({
1,092✔
18
                x = x or 0,
546✔
19
                y = y or 0
546✔
20
        }, vec2_mt)
1,092✔
21
end
22

23
-- Do the check to see if JIT is enabled. If so use the optimized FFI structs.
24
local status, ffi
25
if type(jit) == "table" and jit.status() then
16✔
26
        status, ffi = pcall(require, "ffi")
×
27
        if status then
×
28
                ffi.cdef "typedef struct { double x, y;} cpml_vec2;"
×
29
                new = ffi.typeof("cpml_vec2")
×
30
        end
31
end
32

33
--- Constants
34
-- @table vec2
35
-- @field unit_x X axis of rotation
36
-- @field unit_y Y axis of rotation
37
-- @field zero Empty vector
38
vec2.unit_x = new(1, 0)
16✔
39
vec2.unit_y = new(0, 1)
16✔
40
vec2.zero   = new(0, 0)
16✔
41

42
--- The public constructor.
43
-- @param x Can be of three types: </br>
44
-- number X component
45
-- table {x, y} or {x = x, y = y}
46
-- scalar to fill the vector eg. {x, x}
47
-- @tparam number y Y component
48
-- @treturn vec2 out
49
function vec2.new(x, y)
16✔
50
        -- number, number
51
        if x and y then
238✔
52
                assert(type(x) == "number", "new: Wrong argument type for x (<number> expected)")
224✔
53
                assert(type(y) == "number", "new: Wrong argument type for y (<number> expected)")
224✔
54

55
                return new(x, y)
224✔
56

57
        -- {x, y} or {x=x, y=y}
58
        elseif type(x) == "table" or type(x) == "cdata" then -- table in vanilla lua, cdata in luajit
14✔
59
                local xx, yy = x.x or x[1], x.y or x[2]
8✔
60
                assert(type(xx) == "number", "new: Wrong argument type for x (<number> expected)")
8✔
61
                assert(type(yy) == "number", "new: Wrong argument type for y (<number> expected)")
8✔
62

63
                return new(xx, yy)
8✔
64

65
        -- number
66
        elseif type(x) == "number" then
6✔
67
                return new(x, x)
2✔
68
        else
69
                return new()
4✔
70
        end
71
end
72

73
--- Convert point from polar to cartesian.
74
-- @tparam number radius Radius of the point
75
-- @tparam number theta Angle of the point (in radians)
76
-- @treturn vec2 out
77
function vec2.from_cartesian(radius, theta)
16✔
78
        return new(radius * cos(theta), radius * sin(theta))
2✔
79
end
80

81
--- Clone a vector.
82
-- @tparam vec2 a Vector to be cloned
83
-- @treturn vec2 out
84
function vec2.clone(a)
16✔
85
        return new(a.x, a.y)
142✔
86
end
87

88
--- Add two vectors.
89
-- @tparam vec2 a Left hand operand
90
-- @tparam vec2 b Right hand operand
91
-- @treturn vec2 out
92
function vec2.add(a, b)
16✔
93
        return new(
56✔
94
                a.x + b.x,
28✔
95
                a.y + b.y
28✔
96
        )
97
end
98

99
--- Subtract one vector from another.
100
-- @tparam vec2 a Left hand operand
101
-- @tparam vec2 b Right hand operand
102
-- @treturn vec2 out
103
function vec2.sub(a, b)
16✔
104
        return new(
36✔
105
                a.x - b.x,
18✔
106
                a.y - b.y
18✔
107
        )
108
end
109

110
--- Multiply a vector by another vector.
111
-- @tparam vec2 a Left hand operand
112
-- @tparam vec2 b Right hand operand
113
-- @treturn vec2 out
114
function vec2.mul(a, b)
16✔
115
        return new(
×
116
                a.x * b.x,
×
117
                a.y * b.y
×
118
        )
119
end
120

121
--- Divide a vector by another vector.
122
-- @tparam vec2 a Left hand operand
123
-- @tparam vec2 b Right hand operand
124
-- @treturn vec2 out
125
function vec2.div(a, b)
16✔
126
        return new(
8✔
127
                a.x / b.x,
4✔
128
                a.y / b.y
4✔
129
        )
130
end
131

132
--- Get the normal of a vector.
133
-- @tparam vec2 a Vector to normalize
134
-- @treturn vec2 out
135
function vec2.normalize(a)
16✔
136
        if a:is_zero() then
4✔
137
                return new()
×
138
        end
139
        return a:scale(1 / a:len())
4✔
140
end
141

142
--- Trim a vector to a given length.
143
-- @tparam vec2 a Vector to be trimmed
144
-- @tparam number len Length to trim the vector to
145
-- @treturn vec2 out
146
function vec2.trim(a, len)
16✔
147
        return a:normalize():scale(math.min(a:len(), len))
2✔
148
end
149

150
--- Get the cross product of two vectors.
151
-- @tparam vec2 a Left hand operand
152
-- @tparam vec2 b Right hand operand
153
-- @treturn number magnitude
154
function vec2.cross(a, b)
16✔
155
        return a.x * b.y - a.y * b.x
2✔
156
end
157

158
--- Get the dot product of two vectors.
159
-- @tparam vec2 a Left hand operand
160
-- @tparam vec2 b Right hand operand
161
-- @treturn number dot
162
function vec2.dot(a, b)
16✔
163
        return a.x * b.x + a.y * b.y
34✔
164
end
165

166
--- Get the length of a vector.
167
-- @tparam vec2 a Vector to get the length of
168
-- @treturn number len
169
function vec2.len(a)
16✔
170
        return sqrt(a.x * a.x + a.y * a.y)
76✔
171
end
172

173
--- Get the squared length of a vector.
174
-- @tparam vec2 a Vector to get the squared length of
175
-- @treturn number len
176
function vec2.len2(a)
16✔
177
        return a.x * a.x + a.y * a.y
2✔
178
end
179

180
--- Get the distance between two vectors.
181
-- @tparam vec2 a Left hand operand
182
-- @tparam vec2 b Right hand operand
183
-- @treturn number dist
184
function vec2.dist(a, b)
16✔
185
        local dx = a.x - b.x
2✔
186
        local dy = a.y - b.y
2✔
187
        return sqrt(dx * dx + dy * dy)
2✔
188
end
189

190
--- Get the squared distance between two vectors.
191
-- @tparam vec2 a Left hand operand
192
-- @tparam vec2 b Right hand operand
193
-- @treturn number dist
194
function vec2.dist2(a, b)
16✔
195
        local dx = a.x - b.x
2✔
196
        local dy = a.y - b.y
2✔
197
        return dx * dx + dy * dy
2✔
198
end
199

200
--- Scale a vector by a scalar.
201
-- @tparam vec2 a Left hand operand
202
-- @tparam number b Right hand operand
203
-- @treturn vec2 out
204
function vec2.scale(a, b)
16✔
205
        return new(
44✔
206
                a.x * b,
22✔
207
                a.y * b
22✔
208
        )
209
end
210

211
--- Rotate a vector.
212
-- @tparam vec2 a Vector to rotate
213
-- @tparam number phi Angle to rotate vector by (in radians)
214
-- @treturn vec2 out
215
function vec2.rotate(a, phi)
16✔
216
        local c = cos(phi)
4✔
217
        local s = sin(phi)
4✔
218
        return new(
8✔
219
                c * a.x - s * a.y,
4✔
220
                s * a.x + c * a.y
4✔
221
        )
222
end
223

224
--- Get the perpendicular vector of a vector.
225
-- @tparam vec2 a Vector to get perpendicular axes from
226
-- @treturn vec2 out
227
function vec2.perpendicular(a)
16✔
228
        return new(-a.y, a.x)
2✔
229
end
230

231
--- Signed angle from one vector to another.
232
-- Rotations from +x to +y are positive.
233
-- @tparam vec2 a Vector
234
-- @tparam vec2 b Vector
235
-- @treturn number angle in (-pi, pi]
236
function vec2.angle_to(a, b)
16✔
237
        if b then
32✔
238
                local angle = atan2(b.y, b.x) - atan2(a.y, a.x)
32✔
239
                -- convert to (-pi, pi]
240
                if angle > math.pi       then
32✔
241
                        angle = angle - 2 * math.pi
2✔
242
                elseif angle <= -math.pi then
30✔
243
                        angle = angle + 2 * math.pi
6✔
244
                end
245
                return angle
32✔
246
        end
247

248
        return atan2(a.y, a.x)
×
249
end
250

251
--- Unsigned angle between two vectors.
252
-- Directionless and thus commutative.
253
-- @tparam vec2 a Vector
254
-- @tparam vec2 b Vector
255
-- @treturn number angle in [0, pi]
256
function vec2.angle_between(a, b)
16✔
257
        if b then
32✔
258
                if vec2.is_vec2(a) then
32✔
259
                        return acos(a:dot(b) / (a:len() * b:len()))
32✔
260
                end
261

262
                return acos(vec3.dot(a, b) / (vec3.len(a) * vec3.len(b)))
×
263
        end
264

265
        return 0
×
266
end
267

268
--- Lerp between two vectors.
269
-- @tparam vec2 a Left hand operand
270
-- @tparam vec2 b Right hand operand
271
-- @tparam number s Step value
272
-- @treturn vec2 out
273
function vec2.lerp(a, b, s)
16✔
274
        return a + (b - a) * s
2✔
275
end
276

277
--- Unpack a vector into individual components.
278
-- @tparam vec2 a Vector to unpack
279
-- @treturn number x
280
-- @treturn number y
281
function vec2.unpack(a)
16✔
282
        return a.x, a.y
2✔
283
end
284

285
--- Return the component-wise minimum of two vectors.
286
-- @tparam vec2 a Left hand operand
287
-- @tparam vec2 b Right hand operand
288
-- @treturn vec2 A vector where each component is the lesser value for that component between the two given vectors.
289
function vec2.component_min(a, b)
16✔
290
        return new(math.min(a.x, b.x), math.min(a.y, b.y))
18✔
291
end
292

293
--- Return the component-wise maximum of two vectors.
294
-- @tparam vec2 a Left hand operand
295
-- @tparam vec2 b Right hand operand
296
-- @treturn vec2 A vector where each component is the lesser value for that component between the two given vectors.
297
function vec2.component_max(a, b)
16✔
298
        return new(math.max(a.x, b.x), math.max(a.y, b.y))
18✔
299
end
300

301

302
--- Return a boolean showing if a table is or is not a vec2.
303
-- @tparam vec2 a Vector to be tested
304
-- @treturn boolean is_vec2
305
function vec2.is_vec2(a)
16✔
306
        if type(a) == "cdata" then
262✔
307
                return ffi.istype("cpml_vec2", a)
×
308
        end
309

310
        return
×
311
                type(a)   == "table"  and
262✔
312
                type(a.x) == "number" and
234✔
313
                type(a.y) == "number"
262✔
314
end
315

316
--- Return a boolean showing if a table is or is not a zero vec2.
317
-- @tparam vec2 a Vector to be tested
318
-- @treturn boolean is_zero
319
function vec2.is_zero(a)
16✔
320
        return a.x == 0 and a.y == 0
6✔
321
end
322

323
--- Convert point from cartesian to polar.
324
-- @tparam vec2 a Vector to convert
325
-- @treturn number radius
326
-- @treturn number theta
327
function vec2.to_polar(a)
16✔
328
        local radius = sqrt(a.x^2 + a.y^2)
2✔
329
        local theta  = atan2(a.y, a.x)
2✔
330
        theta = theta > 0 and theta or theta + 2 * math.pi
2✔
331
        return radius, theta
2✔
332
end
333

334
-- Round all components to nearest int (or other precision).
335
-- @tparam vec2 a Vector to round.
336
-- @tparam precision Digits after the decimal (round numebr if unspecified)
337
-- @treturn vec2 Rounded vector
338
function vec2.round(a, precision)
16✔
339
        return vec2.new(private.round(a.x, precision), private.round(a.y, precision))
6✔
340
end
341

342
-- Negate x axis only of vector.
343
-- @tparam vec2 a Vector to x-flip.
344
-- @treturn vec2 x-flipped vector
345
function vec2.flip_x(a)
16✔
346
        return vec2.new(-a.x, a.y)
2✔
347
end
348

349
-- Negate y axis only of vector.
350
-- @tparam vec2 a Vector to y-flip.
351
-- @treturn vec2 y-flipped vector
352
function vec2.flip_y(a)
16✔
353
        return vec2.new(a.x, -a.y)
2✔
354
end
355

356
-- Convert vec2 to vec3.
357
-- @tparam vec2 a Vector to convert.
358
-- @tparam number the new z component, or nil for 0
359
-- @treturn vec3 Converted vector
360
function vec2.to_vec3(a, z)
16✔
361
        return vec3(a.x, a.y, z or 0)
4✔
362
end
363

364
--- Return a formatted string.
365
-- @tparam vec2 a Vector to be turned into a string
366
-- @treturn string formatted
367
function vec2.to_string(a)
16✔
368
        return string.format("(%+0.3f,%+0.3f)", a.x, a.y)
2✔
369
end
370

371
vec2_mt.__index    = vec2
16✔
372
vec2_mt.__tostring = vec2.to_string
16✔
373

374
function vec2_mt.__call(_, x, y)
16✔
375
        return vec2.new(x, y)
226✔
376
end
377

378
function vec2_mt.__unm(a)
16✔
379
        return new(-a.x, -a.y)
2✔
380
end
381

382
function vec2_mt.__eq(a, b)
16✔
383
        if not vec2.is_vec2(a) or not vec2.is_vec2(b) then
48✔
384
                return false
×
385
        end
386
        return a.x == b.x and a.y == b.y
48✔
387
end
388

389
function vec2_mt.__add(a, b)
16✔
390
        assert(vec2.is_vec2(a), "__add: Wrong argument type for left hand operand. (<cpml.vec2> expected)")
26✔
391
        assert(vec2.is_vec2(b), "__add: Wrong argument type for right hand operand. (<cpml.vec2> expected)")
26✔
392
        return a:add(b)
26✔
393
end
394

395
function vec2_mt.__sub(a, b)
16✔
396
        assert(vec2.is_vec2(a), "__add: Wrong argument type for left hand operand. (<cpml.vec2> expected)")
16✔
397
        assert(vec2.is_vec2(b), "__add: Wrong argument type for right hand operand. (<cpml.vec2> expected)")
16✔
398
        return a:sub(b)
16✔
399
end
400

401
function vec2_mt.__mul(a, b)
16✔
402
        assert(vec2.is_vec2(a), "__mul: Wrong argument type for left hand operand. (<cpml.vec2> expected)")
4✔
403
        assert(vec2.is_vec2(b) or type(b) == "number", "__mul: Wrong argument type for right hand operand. (<cpml.vec2> or <number> expected)")
4✔
404

405
        if vec2.is_vec2(b) then
4✔
406
                return a:mul(b)
×
407
        end
408

409
        return a:scale(b)
4✔
410
end
411

412
function vec2_mt.__div(a, b)
16✔
413
        assert(vec2.is_vec2(a), "__div: Wrong argument type for left hand operand. (<cpml.vec2> expected)")
12✔
414
        assert(vec2.is_vec2(b) or type(b) == "number", "__div: Wrong argument type for right hand operand. (<cpml.vec2> or <number> expected)")
12✔
415

416
        if vec2.is_vec2(b) then
12✔
417
                return a:div(b)
2✔
418
        end
419

420
        return a:scale(1 / b)
10✔
421
end
422

423
if status then
16✔
424
        xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
×
425
                ffi.metatype(new, vec2_mt)
×
426
        end, function() end)
×
427
end
428

429
return setmetatable({}, vec2_mt)
16✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc