• 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

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

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

13
-- Private constructor.
14
local function new(x, y, z)
15
        return setmetatable({
639,580✔
16
                x = x or 0,
319,790✔
17
                y = y or 0,
319,790✔
18
                z = z or 0
319,790✔
19
        }, vec3_mt)
639,580✔
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
6,248✔
UNCOV
25
        status, ffi = pcall(require, "ffi")
×
26
        if status then
×
27
                ffi.cdef "typedef struct { double x, y, z;} cpml_vec3;"
×
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)
6,248✔
39
vec3.unit_y = new(0, 1, 0)
6,248✔
40
vec3.unit_z = new(0, 0, 1)
6,248✔
41
vec3.zero   = new(0, 0, 0)
6,248✔
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)
6,237✔
52
        -- number, number, number
11✔
53
        if x and y and z then
138,921✔
54
                precond.typeof(x, "number", "new: Wrong argument type for x")
107,981✔
55
                precond.typeof(y, "number", "new: Wrong argument type for y")
107,926✔
56
                precond.typeof(z, "number", "new: Wrong argument type for z")
107,926✔
57

190✔
58
                return new(x, y, z)
107,736✔
59

190✔
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
31,185✔
62
                local xx, yy, zz = x.x or x[1], x.y or x[2], x.z or x[3]
3,457✔
63
                precond.typeof(xx, "number", "new: Wrong argument type for x")
3,408✔
64
                precond.typeof(yy, "number", "new: Wrong argument type for y")
3,408✔
65
                precond.typeof(zz, "number", "new: Wrong argument type for z")
3,408✔
66

6✔
67
                return new(xx, yy, zz)
3,402✔
68

6✔
69
        -- number
70
        elseif type(x) == "number" then
27,783✔
71
                return new(x, x, x)
14,791✔
72
        else
26✔
73
                return new()
13,041✔
74
        end
23✔
75
end
76

77
--- Clone a vector.
78
-- @tparam vec3 a Vector to be cloned
79
-- @treturn vec3 out
80
function vec3.clone(a)
6,237✔
81
        return new(a.x, a.y, a.z)
40,268✔
82
end
71✔
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)
6,237✔
89
        return new(
49,907✔
90
                a.x + b.x,
25,036✔
91
                a.y + b.y,
24,992✔
92
                a.z + b.z
24,992✔
93
        )
44✔
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)
6,237✔
103
        return new(
53,309✔
104
                a.x - b.x,
26,743✔
105
                a.y - b.y,
26,696✔
106
                a.z - b.z
26,696✔
107
        )
47✔
108
end
109

110
--- Multiply a vector by another vectorr.
111
-- Component-size 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)
6,237✔
UNCOV
116
        return new(
11✔
117
                a.x * b.x,
×
118
                a.y * b.y,
×
119
                a.z * b.z
×
120
        )
121
end
122

123
--- Divide a vector by a scalar.
124
-- Component-size 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)
6,226✔
129
        return new(
2,286✔
130
                a.x / b.x,
1,140✔
131
                a.y / b.y,
1,136✔
132
                a.z / b.z
1,136✔
133
        )
4✔
134
end
135

136
--- Get the normal of a vector.
137
-- @tparam vec3 a Vector to normalize
138
-- @treturn vec3 out
139
function vec3.normalize(a)
6,226✔
140
        if a:is_zero() then
6,248✔
UNCOV
141
                return new()
22✔
142
        end
143
        return a:scale(1 / a:len())
6,226✔
144
end
22✔
145

146
--- Trim a vector to a given length
147
-- @tparam vec3 a Vector to be trimmed
148
-- @tparam number len Length to trim the vector to
149
-- @treturn vec3 out
150
function vec3.trim(a, len)
6,226✔
151
        return a:normalize():scale(math.min(a:len(), len))
588✔
152
end
2✔
153

154
--- Get the cross product of two vectors.
155
-- Resulting direction is right-hand rule normal of plane defined by a and b.
156
-- Magnitude is the area spanned by the parallelograms that a and b span.
157
-- Order: Direction determined by right-hand rule.
158
-- @tparam vec3 a Left hand operand
159
-- @tparam vec3 b Right hand operand
160
-- @treturn vec3 out
161
function vec3.cross(a, b)
6,226✔
162
        return new(
29,454✔
163
                a.y * b.z - a.z * b.y,
14,820✔
164
                a.z * b.x - a.x * b.z,
14,768✔
165
                a.x * b.y - a.y * b.x
14,768✔
166
        )
52✔
167
end
168

169
--- Get the dot product of two vectors.
170
-- @tparam vec3 a Left hand operand
171
-- @tparam vec3 b Right hand operand
172
-- @treturn number dot
173
function vec3.dot(a, b)
6,226✔
174
        return a.x * b.x + a.y * b.y + a.z * b.z
33,416✔
175
end
118✔
176

177
--- Get the length of a vector.
178
-- @tparam vec3 a Vector to get the length of
179
-- @treturn number len
180
function vec3.len(a)
6,226✔
181
        return sqrt(a.x * a.x + a.y * a.y + a.z * a.z)
14,742✔
182
end
52✔
183

184
--- Get the squared length of a vector.
185
-- @tparam vec3 a Vector to get the squared length of
186
-- @treturn number len
187
function vec3.len2(a)
6,226✔
188
        return a.x * a.x + a.y * a.y + a.z * a.z
7,380✔
189
end
26✔
190

191
--- Get the distance between two vectors.
192
-- @tparam vec3 a Left hand operand
193
-- @tparam vec3 b Right hand operand
194
-- @treturn number dist
195
function vec3.dist(a, b)
6,226✔
196
        local dx = a.x - b.x
6,248✔
197
        local dy = a.y - b.y
6,248✔
198
        local dz = a.z - b.z
6,248✔
199
        return sqrt(dx * dx + dy * dy + dz * dz)
6,248✔
200
end
22✔
201

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

213
--- Scale a vector by a scalar.
214
-- @tparam vec3 a Left hand operand
215
-- @tparam number b Right hand operand
216
-- @treturn vec3 out
217
function vec3.scale(a, b)
6,226✔
218
        return new(
63,414✔
219
                a.x * b,
31,920✔
220
                a.y * b,
31,808✔
221
                a.z * b
31,808✔
222
        )
112✔
223
end
224

225
--- Rotate vector about an axis.
226
-- @tparam vec3 a Vector to rotate
227
-- @tparam number phi Angle to rotate vector by (in radians)
228
-- @tparam vec3 axis Axis to rotate by
229
-- @treturn vec3 out
230
function vec3.rotate(a, phi, axis)
6,226✔
231
        if not vec3.is_vec3(axis) then
1,720✔
232
                return a
572✔
233
        end
2✔
234

235
        local u = axis:normalize()
1,132✔
236
        local c = cos(phi)
1,136✔
237
        local s = sin(phi)
1,136✔
238

4✔
239
        -- Calculate generalized rotation matrix
240
        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))
1,132✔
241
        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))
1,136✔
242
        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))      )
1,136✔
243

4✔
244
        return new(
2,264✔
245
                a:dot(m1),
1,140✔
246
                a:dot(m2),
1,136✔
247
                a:dot(m3)
1,136✔
248
        )
4✔
249
end
250

251
--- Get the perpendicular vector of a vector.
252
-- @tparam vec3 a Vector to get perpendicular axes from
253
-- @treturn vec3 out
254
function vec3.perpendicular(a)
6,226✔
255
        return new(-a.y, a.x, 0)
588✔
256
end
2✔
257

258
--- Lerp between two vectors.
259
-- @tparam vec3 a Left hand operand
260
-- @tparam vec3 b Right hand operand
261
-- @tparam number s Step value
262
-- @treturn vec3 out
263
function vec3.lerp(a, b, s)
6,226✔
264
        return a + (b - a) * s
588✔
265
end
2✔
266

267
-- Round all components to nearest int (or other precision).
268
-- @tparam vec3 a Vector to round.
269
-- @tparam precision Digits after the decimal (round numebr if unspecified)
270
-- @treturn vec3 Rounded vector
271
function vec3.round(a, precision)
6,226✔
272
        return vec3.new(private.round(a.x, precision), private.round(a.y, precision), private.round(a.z, precision))
1,720✔
273
end
6✔
274

275
--- Unpack a vector into individual components.
276
-- @tparam vec3 a Vector to unpack
277
-- @treturn number x
278
-- @treturn number y
279
-- @treturn number z
280
function vec3.unpack(a)
6,226✔
281
        return a.x, a.y, a.z
1,720✔
282
end
6✔
283

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

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

300
-- Negate x axis only of vector.
301
-- @tparam vec2 a Vector to x-flip.
302
-- @treturn vec2 x-flipped vector
303
function vec3.flip_x(a)
6,226✔
304
        return vec3.new(-a.x, a.y, a.z)
588✔
305
end
2✔
306

307
-- Negate y axis only of vector.
308
-- @tparam vec2 a Vector to y-flip.
309
-- @treturn vec2 y-flipped vector
310
function vec3.flip_y(a)
6,226✔
311
        return vec3.new(a.x, -a.y, a.z)
588✔
312
end
2✔
313

314
-- Negate z axis only of vector.
315
-- @tparam vec2 a Vector to z-flip.
316
-- @treturn vec2 z-flipped vector
317
function vec3.flip_z(a)
6,226✔
318
        return vec3.new(a.x, a.y, -a.z)
588✔
319
end
2✔
320

321
--- Return a boolean showing if a table is or is not a vec3.
322
-- @tparam vec3 a Vector to be tested
323
-- @treturn boolean is_vec3
324
function vec3.is_vec3(a)
6,226✔
325
        if type(a) == "cdata" then
230,349✔
UNCOV
326
                return ffi.istype("cpml_vec3", a)
814✔
327
        end
328

UNCOV
329
        return
330
                type(a)   == "table"  and
230,327✔
331
                type(a.x) == "number" and
176,805✔
332
                type(a.y) == "number" and
170,422✔
333
                type(a.z) == "number"
230,927✔
334
end
814✔
335

336
--- Return a boolean showing if a table is or is not a zero vec3.
337
-- @tparam vec3 a Vector to be tested
338
-- @treturn boolean is_zero
339
function vec3.is_zero(a)
6,226✔
340
        return a.x == 0 and a.y == 0 and a.z == 0
6,814✔
341
end
24✔
342

343
--- Return whether any component is NaN
344
-- @tparam vec3 a Vector to be tested
345
-- @treturn boolean if x,y, or z are nan
346
function vec3.has_nan(a)
6,226✔
347
        return private.is_nan(a.x) or
588✔
UNCOV
348
                private.is_nan(a.y) or
2✔
349
                private.is_nan(a.z)
566✔
350
end
2✔
351

352
--- Return a formatted string.
353
-- @tparam vec3 a Vector to be turned into a string
354
-- @treturn string formatted
355
function vec3.to_string(a)
6,215✔
356
        return string.format("(%+0.3f,%+0.3f,%+0.3f)", a.x, a.y, a.z)
598✔
357
end
3✔
358

359
vec3_mt.__index    = vec3
6,215✔
360
vec3_mt.__tostring = vec3.to_string
6,248✔
361

33✔
362
function vec3_mt.__call(_, x, y, z)
6,215✔
363
        return vec3.new(x, y, z)
134,509✔
364
end
714✔
365

366
function vec3_mt.__unm(a)
6,215✔
367
        return new(-a.x, -a.y, -a.z)
598✔
368
end
3✔
369

370
function vec3_mt.__eq(a, b)
6,215✔
371
        if not vec3.is_vec3(a) or not vec3.is_vec3(b) then
17,548✔
UNCOV
372
                return false
93✔
373
        end
374
        return a.x == b.x and a.y == b.y and a.z == b.z
17,515✔
375
end
93✔
376

377
function vec3_mt.__add(a, b)
6,215✔
378
        precond.assert(vec3.is_vec3(a), "__add: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
24,328✔
379
        precond.assert(vec3.is_vec3(b), "__add: Wrong argument type '%s' for right hand operand. (<cpml.vec3> expected)", type(b))
24,424✔
380
        return a:add(b)
24,424✔
381
end
129✔
382

383
function vec3_mt.__sub(a, b)
6,215✔
384
        precond.assert(vec3.is_vec3(a), "__sub: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
26,023✔
385
        precond.assert(vec3.is_vec3(b), "__sub: Wrong argument type '%s' for right hand operand. (<cpml.vec3> expected)", type(b))
26,128✔
386
        return a:sub(b)
26,128✔
387
end
138✔
388

389
function vec3_mt.__mul(a, b)
6,215✔
390
        precond.assert(vec3.is_vec3(a), "__mul: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
21,503✔
391
        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))
21,584✔
392

114✔
393
        if vec3.is_vec3(b) then
21,470✔
UNCOV
394
                return a:mul(b)
114✔
395
        end
396

397
        return a:scale(b)
21,470✔
398
end
114✔
399

400
function vec3_mt.__div(a, b)
6,215✔
401
        precond.assert(vec3.is_vec3(a), "__div: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
3,423✔
402
        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))
3,408✔
403

18✔
404
        if vec3.is_vec3(b) then
3,390✔
405
                return a:div(b)
583✔
406
        end
3✔
407

408
        return a:scale(1 / b)
2,825✔
409
end
15✔
410

411
if status then
6,215✔
412
        xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
33✔
UNCOV
413
                ffi.metatype(new, vec3_mt)
×
UNCOV
414
        end, function() end)
×
415
end
416

417
return setmetatable({}, vec3_mt)
6,215✔
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