@altpsyche/maths 0.9.5 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -1
- package/dist/figure/axis3.d.ts +45 -0
- package/dist/figure/axis3.js +75 -0
- package/dist/figure/camera.d.ts +100 -0
- package/dist/figure/camera.js +74 -0
- package/dist/figure/extent.d.ts +7 -3
- package/dist/figure/extent.js +8 -5
- package/dist/figure/figure.d.ts +11 -1
- package/dist/figure/figure.js +13 -0
- package/dist/figure/section.d.ts +37 -0
- package/dist/figure/section.js +184 -0
- package/dist/figure/space.d.ts +103 -0
- package/dist/figure/space.js +162 -0
- package/dist/index.d.ts +11 -1
- package/dist/index.js +6 -1
- package/dist/values/mat4.d.ts +118 -0
- package/dist/values/mat4.js +193 -0
- package/package.json +1 -1
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The transform a point in space carries: how a figure's camera turns a place in
|
|
3
|
+
* the world into a place on the page.
|
|
4
|
+
*
|
|
5
|
+
* Sixteen numbers, column-major, matching the engine's layout the way `Mat3`
|
|
6
|
+
* does: the first four are the first column rather than the first row, and the
|
|
7
|
+
* entry at flat index `col * 4 + row` is the one in that column and row. The
|
|
8
|
+
* fourth row exists so that a translation is a multiplication like every other
|
|
9
|
+
* move, and the fourth coordinate a point picks up is what a perspective divide
|
|
10
|
+
* reads.
|
|
11
|
+
*
|
|
12
|
+
* There is no inverse here because nothing needs one: a camera builds its view
|
|
13
|
+
* and its projection forwards and never undoes either. The day something has to
|
|
14
|
+
* go from the page back into the world, that is when an inverse is written.
|
|
15
|
+
*/
|
|
16
|
+
import { vec3 } from './vec3.js';
|
|
17
|
+
const IDENTITY = [
|
|
18
|
+
1, 0, 0, 0,
|
|
19
|
+
0, 1, 0, 0,
|
|
20
|
+
0, 0, 1, 0,
|
|
21
|
+
0, 0, 0, 1,
|
|
22
|
+
];
|
|
23
|
+
/** Column-major product, so `multiply(a, b)` applies `b` to a point first and
|
|
24
|
+
* then `a`, which is the order a projection sits outside a view. */
|
|
25
|
+
function multiply(a, b) {
|
|
26
|
+
const [a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15] = a;
|
|
27
|
+
const [b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15] = b;
|
|
28
|
+
return [
|
|
29
|
+
a0 * b0 + a4 * b1 + a8 * b2 + a12 * b3,
|
|
30
|
+
a1 * b0 + a5 * b1 + a9 * b2 + a13 * b3,
|
|
31
|
+
a2 * b0 + a6 * b1 + a10 * b2 + a14 * b3,
|
|
32
|
+
a3 * b0 + a7 * b1 + a11 * b2 + a15 * b3,
|
|
33
|
+
a0 * b4 + a4 * b5 + a8 * b6 + a12 * b7,
|
|
34
|
+
a1 * b4 + a5 * b5 + a9 * b6 + a13 * b7,
|
|
35
|
+
a2 * b4 + a6 * b5 + a10 * b6 + a14 * b7,
|
|
36
|
+
a3 * b4 + a7 * b5 + a11 * b6 + a15 * b7,
|
|
37
|
+
a0 * b8 + a4 * b9 + a8 * b10 + a12 * b11,
|
|
38
|
+
a1 * b8 + a5 * b9 + a9 * b10 + a13 * b11,
|
|
39
|
+
a2 * b8 + a6 * b9 + a10 * b10 + a14 * b11,
|
|
40
|
+
a3 * b8 + a7 * b9 + a11 * b10 + a15 * b11,
|
|
41
|
+
a0 * b12 + a4 * b13 + a8 * b14 + a12 * b15,
|
|
42
|
+
a1 * b12 + a5 * b13 + a9 * b14 + a13 * b15,
|
|
43
|
+
a2 * b12 + a6 * b13 + a10 * b14 + a14 * b15,
|
|
44
|
+
a3 * b12 + a7 * b13 + a11 * b14 + a15 * b15,
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
/** The last column carries the offset, so this moves a point and leaves a
|
|
48
|
+
* direction where it was. */
|
|
49
|
+
function translation(v) {
|
|
50
|
+
return [
|
|
51
|
+
1, 0, 0, 0,
|
|
52
|
+
0, 1, 0, 0,
|
|
53
|
+
0, 0, 1, 0,
|
|
54
|
+
v.x, v.y, v.z, 1,
|
|
55
|
+
];
|
|
56
|
+
}
|
|
57
|
+
function scaling(v) {
|
|
58
|
+
return [
|
|
59
|
+
v.x, 0, 0, 0,
|
|
60
|
+
0, v.y, 0, 0,
|
|
61
|
+
0, 0, v.z, 0,
|
|
62
|
+
0, 0, 0, 1,
|
|
63
|
+
];
|
|
64
|
+
}
|
|
65
|
+
/** Turns y towards z, so a positive angle is anticlockwise seen from the far
|
|
66
|
+
* end of the x axis looking back at the origin. */
|
|
67
|
+
function rotationX(radians) {
|
|
68
|
+
const c = Math.cos(radians);
|
|
69
|
+
const s = Math.sin(radians);
|
|
70
|
+
return [
|
|
71
|
+
1, 0, 0, 0,
|
|
72
|
+
0, c, s, 0,
|
|
73
|
+
0, -s, c, 0,
|
|
74
|
+
0, 0, 0, 1,
|
|
75
|
+
];
|
|
76
|
+
}
|
|
77
|
+
/** Turns z towards x, which is the odd one out: the pair of axes runs z then x
|
|
78
|
+
* rather than x then z, and writing it the other way flips every y rotation. */
|
|
79
|
+
function rotationY(radians) {
|
|
80
|
+
const c = Math.cos(radians);
|
|
81
|
+
const s = Math.sin(radians);
|
|
82
|
+
return [
|
|
83
|
+
c, 0, -s, 0,
|
|
84
|
+
0, 1, 0, 0,
|
|
85
|
+
s, 0, c, 0,
|
|
86
|
+
0, 0, 0, 1,
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
/** Turns x towards y, which is the flat rotation `Mat3` gives with a z left
|
|
90
|
+
* alone. */
|
|
91
|
+
function rotationZ(radians) {
|
|
92
|
+
const c = Math.cos(radians);
|
|
93
|
+
const s = Math.sin(radians);
|
|
94
|
+
return [
|
|
95
|
+
c, s, 0, 0,
|
|
96
|
+
-s, c, 0, 0,
|
|
97
|
+
0, 0, 1, 0,
|
|
98
|
+
0, 0, 0, 1,
|
|
99
|
+
];
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The view matrix of an eye at `eye` looking at `target`, with `up` saying which
|
|
103
|
+
* way is up.
|
|
104
|
+
*
|
|
105
|
+
* View space looks down its own negative z, so the target comes out on the
|
|
106
|
+
* negative z axis at the distance between the eye and the target. An `up` lying
|
|
107
|
+
* along the line of sight has no sideways direction in it and gives a matrix of
|
|
108
|
+
* zeroes, which is the pose a caller has to avoid rather than one this can fix.
|
|
109
|
+
*/
|
|
110
|
+
function lookAt(eye, target, up) {
|
|
111
|
+
const forward = vec3.normalize(vec3.sub(target, eye));
|
|
112
|
+
const right = vec3.normalize(vec3.cross(forward, up));
|
|
113
|
+
const above = vec3.cross(right, forward);
|
|
114
|
+
return [
|
|
115
|
+
right.x, above.x, -forward.x, 0,
|
|
116
|
+
right.y, above.y, -forward.y, 0,
|
|
117
|
+
right.z, above.z, -forward.z, 0,
|
|
118
|
+
-vec3.dot(right, eye), -vec3.dot(above, eye), vec3.dot(forward, eye), 1,
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* The projection of an eye that sees things smaller the further off they are.
|
|
123
|
+
*
|
|
124
|
+
* The third column puts the negated view-space z into the fourth coordinate, so
|
|
125
|
+
* a point twice as far away comes back with twice the divisor and lands half as
|
|
126
|
+
* far from the middle of the frame.
|
|
127
|
+
*/
|
|
128
|
+
function perspective({ fov, aspect, near, far }) {
|
|
129
|
+
const focal = 1 / Math.tan(fov / 2);
|
|
130
|
+
return [
|
|
131
|
+
focal / aspect, 0, 0, 0,
|
|
132
|
+
0, focal, 0, 0,
|
|
133
|
+
0, 0, (far + near) / (near - far), -1,
|
|
134
|
+
0, 0, (2 * far * near) / (near - far), 0,
|
|
135
|
+
];
|
|
136
|
+
}
|
|
137
|
+
/** The projection of an eye that sees everything at the size it is, which maps
|
|
138
|
+
* the named box onto the frame and leaves the fourth coordinate at one. */
|
|
139
|
+
function orthographic({ left, right, bottom, top, near, far }) {
|
|
140
|
+
return [
|
|
141
|
+
2 / (right - left), 0, 0, 0,
|
|
142
|
+
0, 2 / (top - bottom), 0, 0,
|
|
143
|
+
0, 0, -2 / (far - near), 0,
|
|
144
|
+
-(right + left) / (right - left),
|
|
145
|
+
-(top + bottom) / (top - bottom),
|
|
146
|
+
-(far + near) / (far - near),
|
|
147
|
+
1,
|
|
148
|
+
];
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Applies the matrix to a point, taking the translation with it and dividing by
|
|
152
|
+
* the fourth coordinate the matrix gives it.
|
|
153
|
+
*
|
|
154
|
+
* That divide is why a point through `multiply(a, b)` matches the same point
|
|
155
|
+
* through `b` and then through `a` for matrices that do not touch the fourth
|
|
156
|
+
* coordinate and not for a perspective matrix: dividing halfway throws away the
|
|
157
|
+
* fourth coordinate the outer matrix still needed. A fourth coordinate of zero is
|
|
158
|
+
* a point on the plane through the eye, which has no place on the page at all, so
|
|
159
|
+
* the divide is skipped and the caller is left to notice.
|
|
160
|
+
*/
|
|
161
|
+
function transformPoint(m, v) {
|
|
162
|
+
const w = m[3] * v.x + m[7] * v.y + m[11] * v.z + m[15];
|
|
163
|
+
const divisor = w === 0 ? 1 : w;
|
|
164
|
+
return {
|
|
165
|
+
x: (m[0] * v.x + m[4] * v.y + m[8] * v.z + m[12]) / divisor,
|
|
166
|
+
y: (m[1] * v.x + m[5] * v.y + m[9] * v.z + m[13]) / divisor,
|
|
167
|
+
z: (m[2] * v.x + m[6] * v.y + m[10] * v.z + m[14]) / divisor,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
/** Applies the rotation and scale and neither the translation nor the divide,
|
|
171
|
+
* which is what a direction wants: moving the world must not move where an arrow
|
|
172
|
+
* points, and a direction has no distance for a perspective to shrink. */
|
|
173
|
+
function transformDirection(m, v) {
|
|
174
|
+
return {
|
|
175
|
+
x: m[0] * v.x + m[4] * v.y + m[8] * v.z,
|
|
176
|
+
y: m[1] * v.x + m[5] * v.y + m[9] * v.z,
|
|
177
|
+
z: m[2] * v.x + m[6] * v.y + m[10] * v.z,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
export const mat4 = {
|
|
181
|
+
IDENTITY,
|
|
182
|
+
multiply,
|
|
183
|
+
translation,
|
|
184
|
+
scaling,
|
|
185
|
+
rotationX,
|
|
186
|
+
rotationY,
|
|
187
|
+
rotationZ,
|
|
188
|
+
lookAt,
|
|
189
|
+
perspective,
|
|
190
|
+
orthographic,
|
|
191
|
+
transformPoint,
|
|
192
|
+
transformDirection,
|
|
193
|
+
};
|
package/package.json
CHANGED