-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvector.typ
116 lines (100 loc) · 2.75 KB
/
vector.typ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/// Return a new vector of dimension `dim` with all fields
/// set to `init` (defaults to 0).
#let new(dim, init: 0) = {
return range(0, dim).map(x => init)
}
/// Return dimension of vector v
#let dim(v) = { assert(type(v) == "array", message: "Expected vector to be of array type, got: " + repr(v)); return v.len() }
/// Convert vector `v` to row or column matrix
#let as-mat(v, mode: "row") = {
if mode == "column" {
return (v,)
} else if mode == "row" {
return (for c in v { (c,) }, )
} else {
panic("Invalid mode " + mode)
}
}
/// Convert vector to vector of different dimension
/// with missing fields of `v` set to fields of vector `init`
#let as-vec(v, init: (0, 0, 0)) = {
for i in range(0, calc.min(dim(v), dim(init))) {
init.at(i) = v.at(i)
}
return init
}
/// Return length of vector v
#let len(v) = {
return calc.sqrt(v.fold(0, (s, c) => s + c * c))
}
/// Add two vectors of the same dimension
#let add(v1, v2) = {
if dim(v1) != dim(v2) {
v1 = as-vec(v1)
v2 = as-vec(v2)
}
assert(dim(v1) == dim(v2), message: "Cannot add vectors, " + repr(v1) + " and " + repr(v2) + " are not of the same dimensions.")
return v1.enumerate().map(t => t.at(1) + v2.at(t.at(0)))
}
/// Substract two vectors of the same dimension
#let sub(v1, v2) = {
if dim(v1) != dim(v2) {
v1 = as-vec(v1)
v2 = as-vec(v2)
}
assert(dim(v1) == dim(v2), message: "Cannot subtract vectors, " + repr(v1) + " and " + repr(v2) + " are not of the same dimensions.")
return v1.enumerate().map(t => t.at(1) - v2.at(t.at(0)))
}
/// Multiply each vector field with number `x`
#let scale(v, x) = {
return v.map(c => c * x)
}
/// Divide each vector field by number `x`
#let div(v, x) = {
return v.map(c => c / x)
}
/// Negate each vector field
#let neg(v) = {
return scale(v, -1)
}
/// Normalize vector (divide by its length)
#let norm(v) = {
return div(v, len(v))
}
/// Calculate dot product between two vectors `v1` and `v2`
#let dot(v1, v2) = {
assert(dim(v1) == dim(v2))
return v1.enumerate().fold(0, (s, t) => s + t.at(1) * v2.at(t.at(0)))
}
/// Calculate cross product of two vectors of dim 3
#let cross(v1, v2) = {
assert(dim(v1) == 3 and dim(v2) == 3)
let x = v1.at(1) * v2.at(2) - v1.at(2) * v1.at(1)
let y = v1.at(2) * v2.at(0) - v1.at(0) * v1.at(2)
let z = v1.at(0) * v2.at(1) - v1.at(1) * v1.at(0)
return (x, y, z)
}
/// Calculate angle between three points
#let angle(v1, c, v2) = {
assert(dim(v1) == dim(v2))
if dim(v1) == 2 or dim(v1) == 3 {
v1 = sub(v1, c)
v2 = sub(v2, c)
return calc.acos(dot(norm(v1), norm(v2)))
} else {
panic("Invalid vector dimension")
}
}
/// Linear interpolation
#let lerp(v1, v2, t) = {
return add(
v1,
scale(
sub(
v2,
v1
),
t,
)
)
}