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

excessive / cpml / 1

31 Mar 2022 01:05PM UTC coverage: 44.185% (-13.5%) from 57.717%
1

push

github

web-flow
Merge pull request #75 from idbrii/precond

Include offending type in precondition failure msg

50 of 60 new or added lines in 6 files covered. (83.33%)

205 existing lines in 6 files now uncovered.

76716 of 173626 relevant lines covered (44.18%)

1272.48 hits per line

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

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

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

16
-- Private constructor.
17
local function new(x, y)
18
        return setmetatable({
311,264✔
19
                x = x or 0,
155,632✔
20
                y = y or 0
155,632✔
21
        }, vec2_mt)
311,264✔
22
end
23

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

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

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

224✔
56
                return new(x, y)
63,392✔
57

224✔
58
        -- {x, y} or {x=x, y=y}
59
        elseif type(x) == "table" or type(x) == "cdata" then -- table in vanilla lua, cdata in luajit
4,528✔
60
                local xx, yy = x.x or x[1], x.y or x[2]
2,280✔
61
                precond.typeof(xx, "number", "new: Wrong argument type for x")
2,272✔
62
                precond.typeof(yy, "number", "new: Wrong argument type for y")
2,272✔
63

8✔
64
                return new(xx, yy)
2,264✔
65

8✔
66
        -- number
67
        elseif type(x) == "number" then
2,260✔
68
                return new(x, x)
1,142✔
69
        else
6✔
70
                return new()
1,130✔
71
        end
6✔
72
end
73

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

82
--- Clone a vector.
83
-- @tparam vec2 a Vector to be cloned
84
-- @treturn vec2 out
85
function vec2.clone(a)
4,520✔
86
        return new(a.x, a.y)
40,139✔
87
end
213✔
88

89
--- Add two vectors.
90
-- @tparam vec2 a Left hand operand
91
-- @tparam vec2 b Right hand operand
92
-- @treturn vec2 out
93
function vec2.add(a, b)
4,520✔
94
        return new(
15,844✔
95
                a.x + b.x,
7,994✔
96
                a.y + b.y
7,952✔
97
        )
42✔
98
end
99

100
--- Subtract one vector from another.
101
-- Order: If a and b are positions, computes the direction and distance from b
102
-- to a.
103
-- @tparam vec2 a Left hand operand
104
-- @tparam vec2 b Right hand operand
105
-- @treturn vec2 out
106
function vec2.sub(a, b)
4,520✔
107
        return new(
10,194✔
108
                a.x - b.x,
5,139✔
109
                a.y - b.y
5,112✔
110
        )
27✔
111
end
112

113
--- Multiply a vector by another vector.
114
-- Component-size multiplication not matrix multiplication.
115
-- @tparam vec2 a Left hand operand
116
-- @tparam vec2 b Right hand operand
117
-- @treturn vec2 out
118
function vec2.mul(a, b)
4,520✔
UNCOV
119
        return new(
24✔
120
                a.x * b.x,
×
121
                a.y * b.y
×
122
        )
123
end
124

125
--- Divide a vector by another vector.
126
-- Component-size inv multiplication. Like a non-uniform scale().
127
-- @tparam vec2 a Left hand operand
128
-- @tparam vec2 b Right hand operand
129
-- @treturn vec2 out
130
function vec2.div(a, b)
4,520✔
131
        return new(
2,284✔
132
                a.x / b.x,
1,142✔
133
                a.y / b.y
1,136✔
134
        )
6✔
135
end
136

137
--- Get the normal of a vector.
138
-- @tparam vec2 a Vector to normalize
139
-- @treturn vec2 out
140
function vec2.normalize(a)
4,520✔
141
        if a:is_zero() then
1,154✔
UNCOV
142
                return new()
6✔
143
        end
144
        return a:scale(1 / a:len())
1,130✔
145
end
6✔
146

147
--- Trim a vector to a given length.
148
-- @tparam vec2 a Vector to be trimmed
149
-- @tparam number len Length to trim the vector to
150
-- @treturn vec2 out
151
function vec2.trim(a, len)
4,520✔
152
        return a:normalize():scale(math.min(a:len(), len))
589✔
153
end
3✔
154

155
--- Get the cross product of two vectors.
156
-- Order: Positive if a is clockwise from b. Magnitude is the area spanned by
157
-- the parallelograms that a and b span.
158
-- @tparam vec2 a Left hand operand
159
-- @tparam vec2 b Right hand operand
160
-- @treturn number magnitude
161
function vec2.cross(a, b)
4,520✔
162
        return a.x * b.y - a.y * b.x
589✔
163
end
3✔
164

165
--- Get the dot product of two vectors.
166
-- @tparam vec2 a Left hand operand
167
-- @tparam vec2 b Right hand operand
168
-- @treturn number dot
169
function vec2.dot(a, b)
4,512✔
170
        return a.x * b.x + a.y * b.y
9,620✔
171
end
68✔
172

173
--- Get the length of a vector.
174
-- @tparam vec2 a Vector to get the length of
175
-- @treturn number len
176
function vec2.len(a)
4,512✔
177
        return sqrt(a.x * a.x + a.y * a.y)
21,464✔
178
end
152✔
179

180
--- Get the squared length of a vector.
181
-- @tparam vec2 a Vector to get the squared length of
182
-- @treturn number len
183
function vec2.len2(a)
4,512✔
184
        return a.x * a.x + a.y * a.y
596✔
185
end
4✔
186

187
--- Get the distance between two vectors.
188
-- @tparam vec2 a Left hand operand
189
-- @tparam vec2 b Right hand operand
190
-- @treturn number dist
191
function vec2.dist(a, b)
4,512✔
192
        local dx = a.x - b.x
596✔
193
        local dy = a.y - b.y
568✔
194
        return sqrt(dx * dx + dy * dy)
568✔
195
end
4✔
196

197
--- Get the squared distance between two vectors.
198
-- @tparam vec2 a Left hand operand
199
-- @tparam vec2 b Right hand operand
200
-- @treturn number dist
201
function vec2.dist2(a, b)
4,512✔
202
        local dx = a.x - b.x
596✔
203
        local dy = a.y - b.y
568✔
204
        return dx * dx + dy * dy
568✔
205
end
4✔
206

207
--- Scale a vector by a scalar.
208
-- @tparam vec2 a Left hand operand
209
-- @tparam number b Right hand operand
210
-- @treturn vec2 out
211
function vec2.scale(a, b)
4,512✔
212
        return new(
12,440✔
213
                a.x * b,
6,292✔
214
                a.y * b
6,248✔
215
        )
44✔
216
end
217

218
--- Rotate a vector.
219
-- @tparam vec2 a Vector to rotate
220
-- @tparam number phi Angle to rotate vector by (in radians)
221
-- @treturn vec2 out
222
function vec2.rotate(a, phi)
4,512✔
223
        local c = cos(phi)
1,160✔
224
        local s = sin(phi)
1,136✔
225
        return new(
2,264✔
226
                c * a.x - s * a.y,
1,144✔
227
                s * a.x + c * a.y
1,136✔
228
        )
8✔
229
end
230

231
--- Get the perpendicular vector of a vector.
232
-- @tparam vec2 a Vector to get perpendicular axes from
233
-- @treturn vec2 out
8✔
234
function vec2.perpendicular(a)
4,505✔
235
        return new(-a.y, a.x)
595✔
236
end
4✔
237

238
--- Signed angle from one vector to another.
239
-- Rotations from +x to +y are positive.
240
-- @tparam vec2 a Vector
241
-- @tparam vec2 b Vector
242
-- @treturn number angle in (-pi, pi]
8✔
243
function vec2.angle_to(a, b)
4,520✔
244
        if b then
9,056✔
245
                local angle = atan2(b.y, b.x) - atan2(a.y, a.x)
9,072✔
246
                -- convert to (-pi, pi]
80✔
247
                if angle > math.pi       then
9,009✔
248
                        angle = angle - 2 * math.pi
642✔
249
                elseif angle <= -math.pi then
8,452✔
250
                        angle = angle + 2 * math.pi
1,749✔
251
                end
28✔
252
                return angle
9,008✔
253
        end
64✔
254

UNCOV
255
        return atan2(a.y, a.x)
256
end
257

258
--- Unsigned angle between two vectors.
259
-- Directionless and thus commutative.
260
-- @tparam vec2 a Vector
261
-- @tparam vec2 b Vector
262
-- @treturn number angle in [0, pi]
8✔
263
function vec2.angle_between(a, b)
4,520✔
264
        if b then
9,056✔
265
                if vec2.is_vec2(a) then
9,088✔
266
                        return acos(a:dot(b) / (a:len() * b:len()))
9,072✔
267
                end
64✔
268

UNCOV
269
                return acos(vec3.dot(a, b) / (vec3.len(a) * vec3.len(b)))
270
        end
271

UNCOV
272
        return 0
273
end
274

275
--- Lerp between two vectors.
276
-- @tparam vec2 a Left hand operand
277
-- @tparam vec2 b Right hand operand
278
-- @tparam number s Step value
279
-- @treturn vec2 out
8✔
280
function vec2.lerp(a, b, s)
4,505✔
281
        return a + (b - a) * s
595✔
282
end
4✔
283

284
--- Unpack a vector into individual components.
285
-- @tparam vec2 a Vector to unpack
286
-- @treturn number x
287
-- @treturn number y
8✔
288
function vec2.unpack(a)
4,505✔
289
        return a.x, a.y
595✔
290
end
4✔
291

292
--- Return the component-wise minimum of two vectors.
293
-- @tparam vec2 a Left hand operand
294
-- @tparam vec2 b Right hand operand
295
-- @treturn vec2 A vector where each component is the lesser value for that component between the two given vectors.
8✔
296
function vec2.component_min(a, b)
4,513✔
297
        return new(math.min(a.x, b.x), math.min(a.y, b.y))
5,099✔
298
end
36✔
299

300
--- Return the component-wise maximum of two vectors.
301
-- @tparam vec2 a Left hand operand
302
-- @tparam vec2 b Right hand operand
303
-- @treturn vec2 A vector where each component is the lesser value for that component between the two given vectors.
8✔
304
function vec2.component_max(a, b)
4,513✔
305
        return new(math.max(a.x, b.x), math.max(a.y, b.y))
5,099✔
306
end
36✔
307

308

309
--- Return a boolean showing if a table is or is not a vec2.
310
-- @tparam vec2 a Vector to be tested
311
-- @treturn boolean is_vec2
8✔
312
function vec2.is_vec2(a)
4,635✔
313
        if type(a) == "cdata" then
73,785✔
UNCOV
314
                return ffi.istype("cpml_vec2", a)
524✔
315
        end
316

UNCOV
317
        return
131✔
318
                type(a)   == "table"  and
73,870✔
319
                type(a.x) == "number" and
66,526✔
320
                type(a.y) == "number"
74,221✔
321
end
524✔
322

323
--- Return a boolean showing if a table is or is not a zero vec2.
324
-- @tparam vec2 a Vector to be tested
325
-- @treturn boolean is_zero
8✔
326
function vec2.is_zero(a)
4,507✔
327
        return a.x == 0 and a.y == 0
1,721✔
328
end
12✔
329

330
--- Return whether either value is NaN
331
-- @tparam vec2 a Vector to be tested
332
-- @treturn boolean if x or y is nan
8✔
333
function vec2.has_nan(a)
4,505✔
334
        return private.is_nan(a.x) or
596✔
335
                private.is_nan(a.y)
567✔
336
end
4✔
337

338
--- Convert point from cartesian to polar.
339
-- @tparam vec2 a Vector to convert
340
-- @treturn number radius
341
-- @treturn number theta
8✔
342
function vec2.to_polar(a)
4,505✔
343
        local radius = sqrt(a.x^2 + a.y^2)
596✔
344
        local theta  = atan2(a.y, a.x)
568✔
345
        theta = theta > 0 and theta or theta + 2 * math.pi
568✔
346
        return radius, theta
567✔
347
end
4✔
348

349
-- Round all components to nearest int (or other precision).
350
-- @tparam vec2 a Vector to round.
351
-- @tparam precision Digits after the decimal (integer if unspecified)
352
-- @treturn vec2 Rounded vector
8✔
353
function vec2.round(a, precision)
4,499✔
354
        return vec2.new(private.round(a.x, precision), private.round(a.y, precision))
1,723✔
355
end
18✔
356

357
-- Negate x axis only of vector.
358
-- @tparam vec2 a Vector to x-flip.
359
-- @treturn vec2 x-flipped vector
8✔
360
function vec2.flip_x(a)
4,489✔
361
        return vec2.new(-a.x, a.y)
609✔
362
end
6✔
363

364
-- Negate y axis only of vector.
365
-- @tparam vec2 a Vector to y-flip.
366
-- @treturn vec2 y-flipped vector
8✔
367
function vec2.flip_y(a)
4,489✔
368
        return vec2.new(a.x, -a.y)
609✔
369
end
6✔
370

371
-- Convert vec2 to vec3.
372
-- @tparam vec2 a Vector to convert.
373
-- @tparam number the new z component, or nil for 0
374
-- @treturn vec3 Converted vector
8✔
375
function vec2.to_vec3(a, z)
4,490✔
376
        return vec3(a.x, a.y, z or 0)
1,170✔
377
end
12✔
378

379
--- Return a formatted string.
380
-- @tparam vec2 a Vector to be turned into a string
381
-- @treturn string formatted
8✔
382
function vec2.to_string(a)
4,481✔
383
        return string.format("(%+0.3f,%+0.3f)", a.x, a.y)
616✔
384
end
7✔
385

8✔
386
vec2_mt.__index    = vec2
4,488✔
387
vec2_mt.__tostring = vec2.to_string
4,536✔
388

64✔
389
function vec2_mt.__call(_, x, y)
4,594✔
390
        return vec2.new(x, y)
63,896✔
391
end
798✔
392

8✔
393
function vec2_mt.__unm(a)
4,481✔
394
        return new(-a.x, -a.y)
616✔
395
end
7✔
396

8✔
397
function vec2_mt.__eq(a, b)
4,504✔
398
        if not vec2.is_vec2(a) or not vec2.is_vec2(b) then
13,496✔
UNCOV
399
                return false
168✔
400
        end
24✔
401
        return a.x == b.x and a.y == b.y
13,440✔
402
end
168✔
403

8✔
404
function vec2_mt.__add(a, b)
4,493✔
405
        precond.assert(vec2.is_vec2(a), "__add: Wrong argument type '%s' for left hand operand. (<cpml.vec2> expected)", type(a))
7,349✔
406
        precond.assert(vec2.is_vec2(b), "__add: Wrong argument type '%s' for right hand operand. (<cpml.vec2> expected)", type(b))
7,384✔
407
        return a:add(b)
7,371✔
408
end
91✔
409

8✔
410
function vec2_mt.__sub(a, b)
4,488✔
411
        precond.assert(vec2.is_vec2(a), "__add: Wrong argument type '%s' for left hand operand. (<cpml.vec2> expected)", type(a))
4,544✔
412
        precond.assert(vec2.is_vec2(b), "__add: Wrong argument type '%s' for right hand operand. (<cpml.vec2> expected)", type(b))
4,544✔
413
        return a:sub(b)
4,536✔
414
end
56✔
415

8✔
416
function vec2_mt.__mul(a, b)
4,482✔
417
        precond.assert(vec2.is_vec2(a), "__mul: Wrong argument type '%s' for left hand operand. (<cpml.vec2> expected)", type(a))
1,178✔
418
        assert(vec2.is_vec2(b) or type(b) == "number", "__mul: Wrong argument type for right hand operand. (<cpml.vec2> or <number> expected)")
1,134✔
419

16✔
420
        if vec2.is_vec2(b) then
1,120✔
UNCOV
421
                return a:mul(b)
14✔
422
        end
423

2✔
424
        return a:scale(b)
1,120✔
425
end
14✔
426

8✔
427
function vec2_mt.__div(a, b)
4,486✔
428
        precond.assert(vec2.is_vec2(a), "__div: Wrong argument type '%s' for left hand operand. (<cpml.vec2> expected)", type(a))
3,422✔
429
        assert(vec2.is_vec2(b) or type(b) == "number", "__div: Wrong argument type for right hand operand. (<cpml.vec2> or <number> expected)")
3,402✔
430

48✔
431
        if vec2.is_vec2(b) then
3,361✔
432
                return a:div(b)
602✔
433
        end
7✔
434

5✔
435
        return a:scale(1 / b)
2,800✔
436
end
35✔
437

8✔
438
if status then
4,480✔
UNCOV
439
        xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
56✔
440
                ffi.metatype(new, vec2_mt)
×
441
        end, function() end)
442
end
443

8✔
444
return setmetatable({}, vec2_mt)
4,480✔
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