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

excessive / cpml / 13079282556

07 May 2022 10:53PM UTC coverage: 57.717% (+43.7%) from 14.013%
13079282556

push

github

shakesoda
fix typo in mat4.mul

0 of 1 new or added line in 1 file covered. (0.0%)

527 existing lines in 19 files now uncovered.

4581 of 7937 relevant lines covered (57.72%)

52.86 hits per line

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

90.06
/modules/vec3.lua
1
--- A 3 component vector.
2
-- @module vec3
3

4
local modules = (...):gsub('%.[^%.]+$', '') .. "."
11✔
5
local precond = require(modules .. "_private_precond")
11✔
6
local private = require(modules .. "_private_utils")
11✔
7
local sqrt    = math.sqrt
11✔
8
local cos     = math.cos
11✔
9
local sin     = math.sin
11✔
10
local vec3    = {}
11✔
11
local vec3_mt = {}
11✔
12

13
-- Private constructor.
14
local function new(x, y, z)
15
        return setmetatable({
1,224✔
16
                x = x or 0,
612✔
17
                y = y or 0,
612✔
18
                z = z or 0
612✔
19
        }, vec3_mt)
1,224✔
20
end
21

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

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

43
--- The public constructor.
44
-- @param x Can be of three types: </br>
45
-- number X component
46
-- table {x, y, z} or {x=x, y=y, z=z}
47
-- scalar To fill the vector eg. {x, x, x}
48
-- @tparam number y Y component
49
-- @tparam number z Z component
50
-- @treturn vec3 out
51
function vec3.new(x, y, z)
11✔
52
        -- number, number, number
53
        if x and y and z then
264✔
54
                precond.typeof(x, "number", "new: Wrong argument type for x")
205✔
55
                precond.typeof(y, "number", "new: Wrong argument type for y")
205✔
56
                precond.typeof(z, "number", "new: Wrong argument type for z")
205✔
57

58
                return new(x, y, z)
205✔
59

60
        -- {x, y, z} or {x=x, y=y, z=z}
61
        elseif type(x) == "table" or type(x) == "cdata" then -- table in vanilla lua, cdata in luajit
59✔
62
                local xx, yy, zz = x.x or x[1], x.y or x[2], x.z or x[3]
4✔
63
                precond.typeof(xx, "number", "new: Wrong argument type for x")
4✔
64
                precond.typeof(yy, "number", "new: Wrong argument type for y")
4✔
65
                precond.typeof(zz, "number", "new: Wrong argument type for z")
4✔
66

67
                return new(xx, yy, zz)
4✔
68

69
        -- number
70
        elseif type(x) == "number" then
55✔
71
                return new(x, x, x)
26✔
72
        else
73
                return new()
29✔
74
        end
75
end
76

77
--- Clone a vector.
78
-- @tparam vec3 a Vector to be cloned
79
-- @treturn vec3 out
80
function vec3.clone(a)
11✔
81
        return new(a.x, a.y, a.z)
72✔
82
end
83

84
--- Add two vectors.
85
-- @tparam vec3 a Left hand operand
86
-- @tparam vec3 b Right hand operand
87
-- @treturn vec3 out
88
function vec3.add(a, b)
11✔
89
        return new(
88✔
90
                a.x + b.x,
44✔
91
                a.y + b.y,
44✔
92
                a.z + b.z
44✔
93
        )
94
end
95

96
--- Subtract one vector from another.
97
-- Order: If a and b are positions, computes the direction and distance from b
98
-- to a.
99
-- @tparam vec3 a Left hand operand
100
-- @tparam vec3 b Right hand operand
101
-- @treturn vec3 out
102
function vec3.sub(a, b)
11✔
103
        return new(
94✔
104
                a.x - b.x,
47✔
105
                a.y - b.y,
47✔
106
                a.z - b.z
47✔
107
        )
108
end
109

110
--- Multiply a vector by another vector.
111
-- Component-wise multiplication not matrix multiplication.
112
-- @tparam vec3 a Left hand operand
113
-- @tparam vec3 b Right hand operand
114
-- @treturn vec3 out
115
function vec3.mul(a, b)
11✔
116
        return new(
×
117
                a.x * b.x,
×
118
                a.y * b.y,
×
UNCOV
119
                a.z * b.z
×
120
        )
121
end
122

123
--- Divide a vector by another.
124
-- Component-wise inv multiplication. Like a non-uniform scale().
125
-- @tparam vec3 a Left hand operand
126
-- @tparam vec3 b Right hand operand
127
-- @treturn vec3 out
128
function vec3.div(a, b)
11✔
129
        return new(
4✔
130
                a.x / b.x,
2✔
131
                a.y / b.y,
2✔
132
                a.z / b.z
2✔
133
        )
134
end
135

136
--- Scale a vector to unit length (1).
137
-- @tparam vec3 a vector to normalize
138
-- @treturn vec3 out
139
function vec3.normalize(a)
11✔
140
        if a:is_zero() then
39✔
UNCOV
141
                return new()
×
142
        end
143
        return a:scale(1 / a:len())
39✔
144
end
145

146
--- Scale a vector to unit length (1), and return the input length.
147
-- @tparam vec3 a vector to normalize
148
-- @treturn vec3 out
149
-- @treturn number input vector length
150
function vec3.normalize_len(a)
11✔
151
        if a:is_zero() then
1✔
UNCOV
152
                return new(), 0
×
153
        end
154
        local len = a:len()
1✔
155
        return a:scale(1 / len), len
1✔
156
end
157

158
--- Trim a vector to a given length
159
-- @tparam vec3 a vector to be trimmed
160
-- @tparam number len Length to trim the vector to
161
-- @treturn vec3 out
162
function vec3.trim(a, len)
11✔
163
        return a:normalize():scale(math.min(a:len(), len))
1✔
164
end
165

166
--- Get the cross product of two vectors.
167
-- Resulting direction is right-hand rule normal of plane defined by a and b.
168
-- Magnitude is the area spanned by the parallelograms that a and b span.
169
-- Order: Direction determined by right-hand rule.
170
-- @tparam vec3 a Left hand operand
171
-- @tparam vec3 b Right hand operand
172
-- @treturn vec3 out
173
function vec3.cross(a, b)
11✔
174
        return new(
52✔
175
                a.y * b.z - a.z * b.y,
26✔
176
                a.z * b.x - a.x * b.z,
26✔
177
                a.x * b.y - a.y * b.x
26✔
178
        )
179
end
180

181
--- Get the dot product of two vectors.
182
-- @tparam vec3 a Left hand operand
183
-- @tparam vec3 b Right hand operand
184
-- @treturn number dot
185
function vec3.dot(a, b)
11✔
186
        return a.x * b.x + a.y * b.y + a.z * b.z
73✔
187
end
188

189
--- Get the length of a vector.
190
-- @tparam vec3 a Vector to get the length of
191
-- @treturn number len
192
function vec3.len(a)
11✔
193
        return sqrt(a.x * a.x + a.y * a.y + a.z * a.z)
56✔
194
end
195

196
--- Get the squared length of a vector.
197
-- @tparam vec3 a Vector to get the squared length of
198
-- @treturn number len
199
function vec3.len2(a)
11✔
200
        return a.x * a.x + a.y * a.y + a.z * a.z
13✔
201
end
202

203
--- Get the distance between two vectors.
204
-- @tparam vec3 a Left hand operand
205
-- @tparam vec3 b Right hand operand
206
-- @treturn number dist
207
function vec3.dist(a, b)
11✔
208
        local dx = a.x - b.x
11✔
209
        local dy = a.y - b.y
11✔
210
        local dz = a.z - b.z
11✔
211
        return sqrt(dx * dx + dy * dy + dz * dz)
11✔
212
end
213

214
--- Get the squared distance between two vectors.
215
-- @tparam vec3 a Left hand operand
216
-- @tparam vec3 b Right hand operand
217
-- @treturn number dist
218
function vec3.dist2(a, b)
11✔
219
        local dx = a.x - b.x
1✔
220
        local dy = a.y - b.y
1✔
221
        local dz = a.z - b.z
1✔
222
        return dx * dx + dy * dy + dz * dz
1✔
223
end
224

225
--- Scale a vector by a scalar.
226
-- @tparam vec3 a Left hand operand
227
-- @tparam number b Right hand operand
228
-- @treturn vec3 out
229
function vec3.scale(a, b)
11✔
230
        return new(
170✔
231
                a.x * b,
85✔
232
                a.y * b,
85✔
233
                a.z * b
85✔
234
        )
235
end
236

237
--- Rotate vector about an axis.
238
-- @tparam vec3 a Vector to rotate
239
-- @tparam number phi Angle to rotate vector by (in radians)
240
-- @tparam vec3 axis Axis to rotate by
241
-- @treturn vec3 out
242
function vec3.rotate(a, phi, axis)
11✔
243
        if not vec3.is_vec3(axis) then
3✔
244
                return a
1✔
245
        end
246

247
        local u = axis:normalize()
2✔
248
        local c = cos(phi)
2✔
249
        local s = sin(phi)
2✔
250

251
        -- Calculate generalized rotation matrix
252
        local m1 = new((c + u.x * u.x * (1 - c)),       (u.x * u.y * (1 - c) - u.z * s), (u.x * u.z * (1 - c) + u.y * s))
2✔
253
        local m2 = new((u.y * u.x * (1 - c) + u.z * s), (c + u.y * u.y * (1 - c)),       (u.y * u.z * (1 - c) - u.x * s))
2✔
254
        local m3 = new((u.z * u.x * (1 - c) - u.y * s), (u.z * u.y * (1 - c) + u.x * s), (c + u.z * u.z * (1 - c))      )
2✔
255

256
        return new(
4✔
257
                a:dot(m1),
2✔
258
                a:dot(m2),
2✔
259
                a:dot(m3)
2✔
260
        )
261
end
262

263
--- Get the perpendicular vector of a vector.
264
-- @tparam vec3 a Vector to get perpendicular axes from
265
-- @treturn vec3 out
266
function vec3.perpendicular(a)
11✔
267
        return new(-a.y, a.x, 0)
1✔
268
end
269

270
--- Lerp between two vectors.
271
-- @tparam vec3 a Left hand operand
272
-- @tparam vec3 b Right hand operand
273
-- @tparam number s Step value
274
-- @treturn vec3 out
275
function vec3.lerp(a, b, s)
11✔
276
        return a + (b - a) * s
1✔
277
end
278

279
-- Round all components to nearest int (or other precision).
280
-- @tparam vec3 a Vector to round.
281
-- @tparam precision Digits after the decimal (round numebr if unspecified)
282
-- @treturn vec3 Rounded vector
283
function vec3.round(a, precision)
11✔
284
        return vec3.new(private.round(a.x, precision), private.round(a.y, precision), private.round(a.z, precision))
3✔
285
end
286

287
--- Unpack a vector into individual components.
288
-- @tparam vec3 a Vector to unpack
289
-- @treturn number x
290
-- @treturn number y
291
-- @treturn number z
292
function vec3.unpack(a)
11✔
293
        return a.x, a.y, a.z
3✔
294
end
295

296
--- Return the component-wise minimum of two vectors.
297
-- @tparam vec3 a Left hand operand
298
-- @tparam vec3 b Right hand operand
299
-- @treturn vec3 A vector where each component is the lesser value for that component between the two given vectors.
300
function vec3.component_min(a, b)
11✔
301
        return new(math.min(a.x, b.x), math.min(a.y, b.y), math.min(a.z, b.z))
9✔
302
end
303

304
--- Return the component-wise maximum of two vectors.
305
-- @tparam vec3 a Left hand operand
306
-- @tparam vec3 b Right hand operand
307
-- @treturn vec3 A vector where each component is the lesser value for that component between the two given vectors.
308
function vec3.component_max(a, b)
11✔
309
        return new(math.max(a.x, b.x), math.max(a.y, b.y), math.max(a.z, b.z))
9✔
310
end
311

312
-- Negate x axis only of vector.
313
-- @tparam vec3 a Vector to x-flip.
314
-- @treturn vec3 x-flipped vector
315
function vec3.flip_x(a)
11✔
316
        return vec3.new(-a.x, a.y, a.z)
1✔
317
end
318

319
-- Negate y axis only of vector.
320
-- @tparam vec3 a Vector to y-flip.
321
-- @treturn vec3 y-flipped vector
322
function vec3.flip_y(a)
11✔
323
        return vec3.new(a.x, -a.y, a.z)
1✔
324
end
325

326
-- Negate z axis only of vector.
327
-- @tparam vec3 a Vector to z-flip.
328
-- @treturn vec3 z-flipped vector
329
function vec3.flip_z(a)
11✔
330
        return vec3.new(a.x, a.y, -a.z)
1✔
331
end
332

333
function vec3.angle_to(a, b)
11✔
334
        local v = a:normalize():dot(b:normalize())
14✔
335
        return math.acos(v)
14✔
336
end
337

338
--- Return a boolean showing if a table is or is not a vec3.
339
-- @tparam vec3 a Vector to be tested
340
-- @treturn boolean is_vec3
341
function vec3.is_vec3(a)
11✔
342
        if type(a) == "cdata" then
407✔
UNCOV
343
                return ffi.istype("cpml_vec3", a)
×
344
        end
345

346
        return
×
347
                type(a)   == "table"  and
407✔
348
                type(a.x) == "number" and
311✔
349
                type(a.y) == "number" and
300✔
350
                type(a.z) == "number"
407✔
351
end
352

353
--- Return a boolean showing if a table is or is not a zero vec3.
354
-- @tparam vec3 a Vector to be tested
355
-- @treturn boolean is_zero
356
function vec3.is_zero(a)
11✔
357
        return a.x == 0 and a.y == 0 and a.z == 0
41✔
358
end
359

360
--- Return whether any component is NaN
361
-- @tparam vec3 a Vector to be tested
362
-- @treturn boolean if x,y, or z are nan
363
function vec3.has_nan(a)
11✔
364
        return private.is_nan(a.x) or
1✔
365
                private.is_nan(a.y) or
×
366
                private.is_nan(a.z)
1✔
367
end
368

369
--- Return a formatted string.
370
-- @tparam vec3 a Vector to be turned into a string
371
-- @treturn string formatted
372
function vec3.to_string(a)
11✔
373
        return string.format("(%+0.3f,%+0.3f,%+0.3f)", a.x, a.y, a.z)
1✔
374
end
375

376
vec3_mt.__index    = vec3
11✔
377
vec3_mt.__tostring = vec3.to_string
11✔
378

379
function vec3_mt.__call(_, x, y, z)
11✔
380
        return vec3.new(x, y, z)
257✔
381
end
382

383
function vec3_mt.__unm(a)
11✔
384
        return new(-a.x, -a.y, -a.z)
1✔
385
end
386

387
function vec3_mt.__eq(a, b)
11✔
388
        if not vec3.is_vec3(a) or not vec3.is_vec3(b) then
31✔
UNCOV
389
                return false
×
390
        end
391
        return a.x == b.x and a.y == b.y and a.z == b.z
31✔
392
end
393

394
function vec3_mt.__add(a, b)
11✔
395
        precond.assert(vec3.is_vec3(a), "__add: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
43✔
396
        precond.assert(vec3.is_vec3(b), "__add: Wrong argument type '%s' for right hand operand. (<cpml.vec3> expected)", type(b))
43✔
397
        return a:add(b)
43✔
398
end
399

400
function vec3_mt.__sub(a, b)
11✔
401
        precond.assert(vec3.is_vec3(a), "__sub: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
46✔
402
        precond.assert(vec3.is_vec3(b), "__sub: Wrong argument type '%s' for right hand operand. (<cpml.vec3> expected)", type(b))
46✔
403
        return a:sub(b)
46✔
404
end
405

406
function vec3_mt.__mul(a, b)
11✔
407
        precond.assert(vec3.is_vec3(a), "__mul: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
38✔
408
        precond.assert(vec3.is_vec3(b) or type(b) == "number", "__mul: Wrong argument type '%s' for right hand operand. (<cpml.vec3> or <number> expected)", type(b))
38✔
409

410
        if vec3.is_vec3(b) then
38✔
UNCOV
411
                return a:mul(b)
×
412
        end
413

414
        return a:scale(b)
38✔
415
end
416

417
function vec3_mt.__div(a, b)
11✔
418
        precond.assert(vec3.is_vec3(a), "__div: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
6✔
419
        precond.assert(vec3.is_vec3(b) or type(b) == "number", "__div: Wrong argument type '%s' for right hand operand. (<cpml.vec3> or <number> expected)", type(b))
6✔
420

421
        if vec3.is_vec3(b) then
6✔
422
                return a:div(b)
1✔
423
        end
424

425
        return a:scale(1 / b)
5✔
426
end
427

428
if status then
11✔
429
        xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
×
430
                ffi.metatype(new, vec3_mt)
×
UNCOV
431
        end, function() end)
×
432
end
433

434
return setmetatable({}, vec3_mt)
11✔
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