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

excessive / cpml / 1

20 Apr 2022 10:56PM UTC coverage: 45.192% (+1.0%) from 44.185%
1

push

github

web-flow
Merge pull request #66 from aki-cat/master

Implement scale to mat4.from_transform method

33 of 33 new or added lines in 2 files covered. (100.0%)

38 existing lines in 2 files now uncovered.

44574 of 98633 relevant lines covered (45.19%)

1232.55 hits per line

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

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

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

814✔
13
-- Private constructor.
22✔
14
local function new(x, y, z)
11✔
15
        return setmetatable({
285,763✔
16
                x = x or 0,
228,928✔
17
                y = y or 0,
187,114✔
18
                z = z or 0
186,508✔
19
        }, vec3_mt)
330,596✔
20
end
87,264✔
21

1,829✔
22
-- Do the check to see if JIT is enabled. If so use the optimized FFI structs.
606✔
23
local status, ffi
1,212✔
24
if type(jit) == "table" and jit.status() then
2,574✔
25
        status, ffi = pcall(require, "ffi")
803✔
26
        if status then
11✔
27
                ffi.cdef "typedef struct { double x, y, z;} cpml_vec3;"
28
                new = ffi.typeof("cpml_vec3")
11✔
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)
2,530✔
39
vec3.unit_y = new(0, 1, 0)
3,366✔
40
vec3.unit_z = new(0, 0, 1)
3,377✔
41
vec3.zero   = new(0, 0, 0)
3,388✔
42

891✔
43
--- The public constructor.
22✔
44
-- @param x Can be of three types: </br>
11✔
45
-- number X component
11✔
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)
2,508✔
52
        -- number, number, number
858✔
53
        if x and y and z then
59,302✔
54
                precond.typeof(x, "number", "new: Wrong argument type for x")
67,020✔
55
                precond.typeof(y, "number", "new: Wrong argument type for y")
63,261✔
56
                precond.typeof(z, "number", "new: Wrong argument type for z")
63,140✔
57

16,865✔
58
                return new(x, y, z)
47,150✔
59

16,250✔
60
        -- {x, y, z} or {x=x, y=y, z=z}
621✔
61
        elseif type(x) == "table" or type(x) == "cdata" then -- table in vanilla lua, cdata in luajit
12,491✔
62
                local xx, yy, zz = x.x or x[1], x.y or x[2], x.z or x[3]
5,863✔
63
                precond.typeof(xx, "number", "new: Wrong argument type for x")
1,946✔
64
                precond.typeof(yy, "number", "new: Wrong argument type for y")
1,848✔
65
                precond.typeof(zz, "number", "new: Wrong argument type for z")
1,897✔
66

535✔
67
                return new(xx, yy, zz)
1,406✔
68

474✔
69
        -- number
41✔
70
        elseif type(x) == "number" then
11,123✔
71
                return new(x, x, x)
9,730✔
72
        else
2,126✔
73
                return new()
5,273✔
74
        end
1,843✔
75
end
72✔
76

77
--- Clone a vector.
34✔
78
-- @tparam vec3 a Vector to be cloned
71✔
79
-- @treturn vec3 out
80
function vec3.clone(a)
2,497✔
81
        return new(a.x, a.y, a.z)
16,975✔
82
end
5,560✔
83

142✔
84
--- Add two vectors.
11✔
85
-- @tparam vec3 a Left hand operand
82✔
86
-- @tparam vec3 b Right hand operand
25✔
87
-- @treturn vec3 out
102✔
88
function vec3.add(a, b)
2,544✔
89
        return new(
20,730✔
90
                a.x + b.x,
16,844✔
91
                a.y + b.y,
13,522✔
92
                a.z + b.z
13,431✔
93
        )
3,608✔
94
end
132✔
95

44✔
96
--- Subtract one vector from another.
55✔
97
-- Order: If a and b are positions, computes the direction and distance from b
88✔
98
-- to a.
55✔
99
-- @tparam vec3 a Left hand operand
132✔
100
-- @tparam vec3 b Right hand operand
99✔
101
-- @treturn vec3 out
66✔
102
function vec3.sub(a, b)
2,619✔
103
        return new(
21,895✔
104
                a.x - b.x,
17,896✔
105
                a.y - b.y,
14,382✔
106
                a.z - b.z
14,266✔
107
        )
3,854✔
108
end
141✔
109

61✔
110
--- Multiply a vector by another vectorr.
58✔
111
-- Component-size multiplication not matrix multiplication.
108✔
112
-- @tparam vec3 a Left hand operand
58✔
113
-- @tparam vec3 b Right hand operand
152✔
114
-- @treturn vec3 out
188✔
115
function vec3.mul(a, b)
2,558✔
116
        return new(
941✔
117
                a.x * b.x,
69✔
118
                a.y * b.y,
119
                a.z * b.z
22✔
120
        )
11✔
121
end
94✔
122

47✔
123
--- Divide a vector by a scalar.
58✔
124
-- Component-size inv multiplication. Like a non-uniform scale().
47✔
125
-- @tparam vec3 a Left hand operand
11✔
126
-- @tparam vec3 b Right hand operand
11✔
127
-- @treturn vec3 out
11✔
128
function vec3.div(a, b)
2,456✔
129
        return new(
1,760✔
130
                a.x / b.x,
792✔
131
                a.y / b.y,
608✔
132
                a.z / b.z
615✔
133
        )
175✔
134
end
6✔
135

13✔
136
--- Get the normal of a vector.
17✔
137
-- @tparam vec3 a Vector to normalize
6✔
138
-- @treturn vec3 out
37✔
139
function vec3.normalize(a)
2,446✔
140
        if a:is_zero() then
9,322✔
141
                return new()
3,017✔
142
        end
126✔
143
        return a:scale(1 / a:len())
8,456✔
144
end
3,003✔
145

78✔
146
--- Trim a vector to a given length
25✔
147
-- @tparam vec3 a Vector to be trimmed
65✔
148
-- @tparam number len Length to trim the vector to
102✔
149
-- @treturn vec3 out
113✔
150
function vec3.trim(a, len)
2,539✔
151
        return a:normalize():scale(math.min(a:len(), len))
1,303✔
152
end
450✔
153

411✔
154
--- Get the cross product of two vectors.
285✔
155
-- Resulting direction is right-hand rule normal of plane defined by a and b.
57✔
156
-- Magnitude is the area spanned by the parallelograms that a and b span.
67✔
157
-- Order: Direction determined by right-hand rule.
11✔
158
-- @tparam vec3 a Left hand operand
75✔
159
-- @tparam vec3 b Right hand operand
46✔
160
-- @treturn vec3 out
96✔
161
function vec3.cross(a, b)
2,526✔
162
        return new(
11,687✔
163
                a.y * b.z - a.z * b.y,
8,783✔
164
                a.z * b.x - a.x * b.z,
7,229✔
165
                a.x * b.y - a.y * b.x
7,213✔
166
        )
1,779✔
167
end
105✔
168

63✔
169
--- Get the dot product of two vectors.
49✔
170
-- @tparam vec3 a Left hand operand
126✔
171
-- @tparam vec3 b Right hand operand
222✔
172
-- @treturn number dot
559✔
173
function vec3.dot(a, b)
3,279✔
174
        return a.x * b.x + a.y * b.y + a.z * b.z
16,657✔
175
end
5,304✔
176

679✔
177
--- Get the length of a vector.
255✔
178
-- @tparam vec3 a Vector to get the length of
316✔
179
-- @treturn number len
63✔
180
function vec3.len(a)
2,403✔
181
        return sqrt(a.x * a.x + a.y * a.y + a.z * a.z)
12,042✔
182
end
3,564✔
183

357✔
184
--- Get the squared length of a vector.
665✔
185
-- @tparam vec3 a Vector to get the squared length of
1,058✔
186
-- @treturn number len
379✔
187
function vec3.len2(a)
2,493✔
188
        return a.x * a.x + a.y * a.y + a.z * a.z
3,397✔
189
end
978✔
190

323✔
191
--- Get the distance between two vectors.
630✔
192
-- @tparam vec3 a Left hand operand
846✔
193
-- @tparam vec3 b Right hand operand
274✔
194
-- @treturn number dist
186✔
195
function vec3.dist(a, b)
2,313✔
196
        local dx = a.x - b.x
3,027✔
197
        local dy = a.y - b.y
3,155✔
198
        local dz = a.z - b.z
3,216✔
199
        return sqrt(dx * dx + dy * dy + dz * dz)
3,215✔
200
end
834✔
201

86✔
202
--- Get the squared distance between two vectors.
22✔
203
-- @tparam vec3 a Left hand operand
55✔
204
-- @tparam vec3 b Right hand operand
104✔
205
-- @treturn number dist
198✔
206
function vec3.dist2(a, b)
2,587✔
207
        local dx = a.x - b.x
1,277✔
208
        local dy = a.y - b.y
717✔
209
        local dz = a.z - b.z
641✔
210
        return dx * dx + dy * dy + dz * dz
543✔
211
end
183✔
212

58✔
213
--- Scale a vector by a scalar.
34✔
214
-- @tparam vec3 a Left hand operand
78✔
215
-- @tparam number b Right hand operand
81✔
216
-- @treturn vec3 out
129✔
217
function vec3.scale(a, b)
2,383✔
218
        return new(
32,634✔
219
                a.x * b,
25,816✔
220
                a.y * b,
21,199✔
221
                a.z * b
21,032✔
222
        )
5,292✔
223
end
271✔
224

153✔
225
--- Rotate vector about an axis.
186✔
226
-- @tparam vec3 a Vector to rotate
1,337✔
227
-- @tparam number phi Angle to rotate vector by (in radians)
1,788✔
228
-- @tparam vec3 axis Axis to rotate by
3,033✔
229
-- @treturn vec3 out
4,910✔
230
function vec3.rotate(a, phi, axis)
6,026✔
231
        if not vec3.is_vec3(axis) then
4,618✔
232
                return a
3,246✔
233
        end
1,366✔
234

968✔
235
        local u = axis:normalize()
877✔
236
        local c = cos(phi)
813✔
237
        local s = sin(phi)
777✔
238

468✔
239
        -- Calculate generalized rotation matrix
295✔
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))
599✔
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))
835✔
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))      )
653✔
243

246✔
244
        return new(
803✔
245
                a:dot(m1),
828✔
246
                a:dot(m2),
661✔
247
                a:dot(m3)
650✔
248
        )
308✔
249
end
82✔
250

105✔
251
--- Get the perpendicular vector of a vector.
129✔
252
-- @tparam vec3 a Vector to get perpendicular axes from
158✔
253
-- @treturn vec3 out
175✔
254
function vec3.perpendicular(a)
1,822✔
255
        return new(-a.y, a.x, 0)
1,052✔
256
end
561✔
257

493✔
258
--- Lerp between two vectors.
399✔
259
-- @tparam vec3 a Left hand operand
314✔
260
-- @tparam vec3 b Right hand operand
153✔
261
-- @tparam number s Step value
188✔
262
-- @treturn vec3 out
427✔
263
function vec3.lerp(a, b, s)
1,834✔
264
        return a + (b - a) * s
1,067✔
265
end
681✔
266

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

647✔
275
--- Unpack a vector into individual components.
368✔
276
-- @tparam vec3 a Vector to unpack
155✔
277
-- @treturn number x
152✔
278
-- @treturn number y
156✔
279
-- @treturn number z
326✔
280
function vec3.unpack(a)
1,617✔
281
        return a.x, a.y, a.z
1,026✔
282
end
718✔
283

420✔
284
--- Return the component-wise minimum of two vectors.
161✔
285
-- @tparam vec3 a Left hand operand
126✔
286
-- @tparam vec3 b Right hand operand
112✔
287
-- @treturn vec3 A vector where each component is the lesser value for that component between the two given vectors.
225✔
288
function vec3.component_min(a, b)
1,510✔
289
        return new(math.min(a.x, b.x), math.min(a.y, b.y), math.min(a.z, b.z))
1,532✔
290
end
657✔
291

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

842✔
300
-- Negate x axis only of vector.
730✔
301
-- @tparam vec2 a Vector to x-flip.
286✔
302
-- @treturn vec2 x-flipped vector
187✔
303
function vec3.flip_x(a)
1,405✔
304
        return vec3.new(-a.x, a.y, a.z)
747✔
305
end
524✔
306

520✔
307
-- Negate y axis only of vector.
818✔
308
-- @tparam vec2 a Vector to y-flip.
723✔
309
-- @treturn vec2 y-flipped vector
300✔
310
function vec3.flip_y(a)
1,355✔
311
        return vec3.new(a.x, -a.y, a.z)
664✔
312
end
483✔
313

454✔
314
-- Negate z axis only of vector.
658✔
315
-- @tparam vec2 a Vector to z-flip.
318✔
316
-- @treturn vec2 z-flipped vector
175✔
317
function vec3.flip_z(a)
1,309✔
318
        return vec3.new(a.x, a.y, -a.z)
590✔
319
end
456✔
320

419✔
321
--- Return a boolean showing if a table is or is not a vec3.
754✔
322
-- @tparam vec3 a Vector to be tested
462✔
323
-- @treturn boolean is_vec3
321✔
324
function vec3.is_vec3(a)
1,381✔
325
        if type(a) == "cdata" then
26,354✔
326
                return ffi.istype("cpml_vec3", a)
6,393✔
327
        end
720✔
328

918✔
329
        return
1,012✔
330
                type(a)   == "table"  and
30,270✔
UNCOV
331
                type(a.x) == "number" and
26,650✔
332
                type(a.y) == "number" and
27,655✔
333
                type(a.z) == "number"
37,994✔
UNCOV
334
end
15,862✔
335

18,185✔
336
--- Return a boolean showing if a table is or is not a zero vec3.
29,115✔
337
-- @tparam vec3 a Vector to be tested
16,791✔
338
-- @treturn boolean is_zero
19,813✔
339
function vec3.is_zero(a)
24,028✔
340
        return a.x == 0 and a.y == 0 and a.z == 0
36,077✔
341
end
54,401✔
342

48,954✔
343
--- Return whether any component is NaN
43,922✔
344
-- @tparam vec3 a Vector to be tested
39,954✔
345
-- @treturn boolean if x,y, or z are nan
20,747✔
346
function vec3.has_nan(a)
14,439✔
347
        return private.is_nan(a.x) or
10,886✔
348
                private.is_nan(a.y) or
8,834✔
349
                private.is_nan(a.z)
6,412✔
350
end
4,722✔
351

4,624✔
352
--- Return a formatted string.
2,539✔
UNCOV
353
-- @tparam vec3 a Vector to be turned into a string
2,711✔
354
-- @treturn string formatted
1,417✔
355
function vec3.to_string(a)
1,822✔
356
        return string.format("(%+0.3f,%+0.3f,%+0.3f)", a.x, a.y, a.z)
1,891✔
357
end
1,012✔
358

588✔
359
vec3_mt.__index    = vec3
766✔
360
vec3_mt.__tostring = vec3.to_string
1,337✔
361

290✔
362
function vec3_mt.__call(_, x, y, z)
905✔
363
        return vec3.new(x, y, z)
8,616✔
364
end
1,849✔
365

1,193✔
366
function vec3_mt.__unm(a)
1,793✔
367
        return new(-a.x, -a.y, -a.z)
1,295✔
368
end
3,713✔
369

1,837✔
370
function vec3_mt.__eq(a, b)
4,233✔
371
        if not vec3.is_vec3(a) or not vec3.is_vec3(b) then
7,716✔
372
                return false
7,198✔
373
        end
11,124✔
374
        return a.x == b.x and a.y == b.y and a.z == b.z
20,059✔
375
end
7,836✔
376

3,936✔
UNCOV
377
function vec3_mt.__add(a, b)
5,931✔
378
        precond.assert(vec3.is_vec3(a), "__add: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
5,095✔
379
        precond.assert(vec3.is_vec3(b), "__add: Wrong argument type '%s' for right hand operand. (<cpml.vec3> expected)", type(b))
5,995✔
380
        return a:add(b)
3,479✔
381
end
2,915✔
382

4,947✔
383
function vec3_mt.__sub(a, b)
4,120✔
384
        precond.assert(vec3.is_vec3(a), "__sub: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
4,174✔
385
        precond.assert(vec3.is_vec3(b), "__sub: Wrong argument type '%s' for right hand operand. (<cpml.vec3> expected)", type(b))
5,667✔
386
        return a:sub(b)
4,855✔
387
end
3,587✔
388

5,406✔
389
function vec3_mt.__mul(a, b)
7,404✔
390
        precond.assert(vec3.is_vec3(a), "__mul: Wrong argument type '%s' for left hand operand. (<cpml.vec3> expected)", type(a))
8,304✔
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))
7,412✔
392

4,558✔
393
        if vec3.is_vec3(b) then
5,820✔
394
                return a:mul(b)
6,981✔
395
        end
8,332✔
396

8,243✔
397
        return a:scale(b)
7,385✔
398
end
5,266✔
UNCOV
399

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

3,779✔
404
        if vec3.is_vec3(b) then
4,731✔
405
                return a:div(b)
3,889✔
406
        end
2,858✔
407

3,223✔
408
        return a:scale(1 / b)
3,966✔
409
end
2,501✔
410

1,563✔
411
if status then
2,239✔
412
        xpcall(function() -- Allow this to silently fail; assume failure means someone messed with package.loaded
2,103✔
413
                ffi.metatype(new, vec3_mt)
1,850✔
414
        end, function() end)
1,147✔
415
end
1,191✔
416

1,243✔
UNCOV
417
return setmetatable({}, vec3_mt)
825✔
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