tela.js 1.0.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/.eslintrc.yml +8 -0
- package/LICENSE +201 -0
- package/README.md +54 -0
- package/assets/bunny.obj +7474 -0
- package/assets/expand.svg +1 -0
- package/assets/great.jpg +0 -0
- package/assets/kakashi.jpg +0 -0
- package/assets/spot.obj +11999 -0
- package/assets/spot.png +0 -0
- package/assets/torus.obj +3137 -0
- package/assets/x.svg +1 -0
- package/bun.lockb +0 -0
- package/bundle.js +39 -0
- package/dist/node/index.js +37048 -0
- package/dist/web/index.js +1511 -0
- package/index.css +129 -0
- package/index.html +19 -0
- package/index.js +534 -0
- package/package.json +40 -0
- package/src/Animation/Animation.js +61 -0
- package/src/Box/Box.js +105 -0
- package/src/Camera/Camera.js +133 -0
- package/src/Canvas/Canvas.js +203 -0
- package/src/Canvas/README.md +83 -0
- package/src/Color/Color.js +77 -0
- package/src/DomBuilder/DomBuilder.js +126 -0
- package/src/IO/IO.js +120 -0
- package/src/Image/Image.js +138 -0
- package/src/Image/README.md +33 -0
- package/src/Monads/Monads.js +28 -0
- package/src/Ray/Ray.js +7 -0
- package/src/Scene/Mesh.js +103 -0
- package/src/Scene/NaiveScene.js +77 -0
- package/src/Scene/Point.js +109 -0
- package/src/Scene/PointCloud.js +51 -0
- package/src/Scene/Scene.js +200 -0
- package/src/Stream/Stream.js +10 -0
- package/src/Utils/Constants.js +1 -0
- package/src/Utils/Math.js +65 -0
- package/src/Utils/Utils.js +39 -0
- package/src/Vector/Vector.js +495 -0
- package/src/index.js +32 -0
- package/src/index.node.js +5 -0
- package/test/node/amazing_shader.js +56 -0
- package/test/node/bunny.js +55 -0
- package/test/node/bunny_parallel.js +102 -0
- package/test/node/image2rgb.js +57 -0
- package/test/node/image_test.js +38 -0
- package/test/node/lorentz.js +0 -0
- package/test/web/amazing_shader.js +60 -0
- package/test/web/amazing_shader_2.js +54 -0
- package/test/web/bunny.js +72 -0
- package/test/web/image2rgb.js +77 -0
- package/test/web/interactive_wave.js +108 -0
- package/test/web/lorenz.js +60 -0
- package/test/web/mandelbrot.js +59 -0
- package/test/web/rotating_grid.js +62 -0
- package/test/web/signed_bunny.js +139 -0
- package/test/web/signed_distance.js +95 -0
- package/test/web/simple_animation.js +39 -0
- package/test/web/simple_shader.js +14 -0
- package/test/web/six_spheres.js +102 -0
- package/test/web/wave_equation.js +93 -0
- package/vs-monaco/package/LICENSE +21 -0
- package/vs-monaco/package/ThirdPartyNotices.txt +448 -0
- package/vs-monaco/package/min/vs/base/browser/ui/codicons/codicon/codicon.ttf +0 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.de.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.es.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.fr.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.it.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.ja.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.ko.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.ru.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.zh-cn.js +8 -0
- package/vs-monaco/package/min/vs/base/common/worker/simpleWorker.nls.zh-tw.js +8 -0
- package/vs-monaco/package/min/vs/base/worker/workerMain.js +27 -0
- package/vs-monaco/package/min/vs/basic-languages/abap/abap.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/apex/apex.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/azcli/azcli.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/bat/bat.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/bicep/bicep.js +11 -0
- package/vs-monaco/package/min/vs/basic-languages/cameligo/cameligo.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/clojure/clojure.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/coffee/coffee.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/cpp/cpp.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/csharp/csharp.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/csp/csp.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/css/css.js +12 -0
- package/vs-monaco/package/min/vs/basic-languages/cypher/cypher.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/dart/dart.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/dockerfile/dockerfile.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/ecl/ecl.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/elixir/elixir.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/flow9/flow9.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/freemarker2/freemarker2.js +12 -0
- package/vs-monaco/package/min/vs/basic-languages/fsharp/fsharp.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/go/go.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/graphql/graphql.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/handlebars/handlebars.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/hcl/hcl.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/html/html.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/ini/ini.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/java/java.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/javascript/javascript.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/julia/julia.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/kotlin/kotlin.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/less/less.js +11 -0
- package/vs-monaco/package/min/vs/basic-languages/lexon/lexon.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/liquid/liquid.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/lua/lua.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/m3/m3.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/markdown/markdown.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/mdx/mdx.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/mips/mips.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/msdax/msdax.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/mysql/mysql.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/objective-c/objective-c.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/pascal/pascal.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/pascaligo/pascaligo.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/perl/perl.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/pgsql/pgsql.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/php/php.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/pla/pla.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/postiats/postiats.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/powerquery/powerquery.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/powershell/powershell.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/protobuf/protobuf.js +11 -0
- package/vs-monaco/package/min/vs/basic-languages/pug/pug.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/python/python.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/qsharp/qsharp.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/r/r.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/razor/razor.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/redis/redis.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/redshift/redshift.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/restructuredtext/restructuredtext.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/ruby/ruby.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/rust/rust.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/sb/sb.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/scala/scala.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/scheme/scheme.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/scss/scss.js +12 -0
- package/vs-monaco/package/min/vs/basic-languages/shell/shell.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/solidity/solidity.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/sophia/sophia.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/sparql/sparql.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/sql/sql.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/st/st.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/swift/swift.js +13 -0
- package/vs-monaco/package/min/vs/basic-languages/systemverilog/systemverilog.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/tcl/tcl.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/twig/twig.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/typescript/typescript.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/vb/vb.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/wgsl/wgsl.js +307 -0
- package/vs-monaco/package/min/vs/basic-languages/xml/xml.js +10 -0
- package/vs-monaco/package/min/vs/basic-languages/yaml/yaml.js +10 -0
- package/vs-monaco/package/min/vs/editor/editor.main.css +6 -0
- package/vs-monaco/package/min/vs/editor/editor.main.js +745 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.de.js +31 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.es.js +31 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.fr.js +29 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.it.js +29 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.ja.js +31 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.js +29 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.ko.js +29 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.ru.js +31 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.zh-cn.js +31 -0
- package/vs-monaco/package/min/vs/editor/editor.main.nls.zh-tw.js +29 -0
- package/vs-monaco/package/min/vs/language/css/cssMode.js +13 -0
- package/vs-monaco/package/min/vs/language/css/cssWorker.js +81 -0
- package/vs-monaco/package/min/vs/language/html/htmlMode.js +13 -0
- package/vs-monaco/package/min/vs/language/html/htmlWorker.js +453 -0
- package/vs-monaco/package/min/vs/language/json/jsonMode.js +15 -0
- package/vs-monaco/package/min/vs/language/json/jsonWorker.js +36 -0
- package/vs-monaco/package/min/vs/language/typescript/tsMode.js +20 -0
- package/vs-monaco/package/min/vs/language/typescript/tsWorker.js +37016 -0
- package/vs-monaco/package/min/vs/loader.js +11 -0
|
@@ -0,0 +1,1511 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, {
|
|
5
|
+
get: all[name],
|
|
6
|
+
enumerable: true,
|
|
7
|
+
configurable: true,
|
|
8
|
+
set: (newValue) => all[name] = () => newValue
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/Ray/Ray.jstants.
|
|
13
|
+
class Stream {
|
|
14
|
+
constructor(initialState, updateStateFunction) {
|
|
15
|
+
this._head = initialState;
|
|
16
|
+
this._tail = updateStateFunction;
|
|
17
|
+
}
|
|
18
|
+
get head() {
|
|
19
|
+
return this._head;
|
|
20
|
+
}
|
|
21
|
+
get tail() {
|
|
22
|
+
return new Stream(this._tail(this._head), this._tail);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// src/Ray/Ray.jstants.jsser.
|
|
27
|
+
class Animation {
|
|
28
|
+
constructor(state, next, doWhile) {
|
|
29
|
+
this.animation = new Stream(state, next);
|
|
30
|
+
this.while = doWhile;
|
|
31
|
+
this.requestAnimeId = null;
|
|
32
|
+
}
|
|
33
|
+
play(stream = this.animation) {
|
|
34
|
+
this.requestAnimeId = requestAnimationFrame(() => {
|
|
35
|
+
if (!this.while(stream.head))
|
|
36
|
+
return this.stop();
|
|
37
|
+
this.play(stream.tail);
|
|
38
|
+
});
|
|
39
|
+
Animation.globalAnimationIds.push(this.requestAnimeId);
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
stop() {
|
|
43
|
+
cancelAnimationFrame(this.requestAnimeId);
|
|
44
|
+
return this;
|
|
45
|
+
}
|
|
46
|
+
static globalAnimationIds = [];
|
|
47
|
+
static builder() {
|
|
48
|
+
return new AnimationBuilder;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
class AnimationBuilder {
|
|
53
|
+
constructor() {
|
|
54
|
+
this._state = null;
|
|
55
|
+
this._next = null;
|
|
56
|
+
this._end = null;
|
|
57
|
+
}
|
|
58
|
+
initialState(state) {
|
|
59
|
+
this._state = state;
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
nextState(next) {
|
|
63
|
+
this._next = next;
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
while(end) {
|
|
67
|
+
this._end = end;
|
|
68
|
+
return this;
|
|
69
|
+
}
|
|
70
|
+
build() {
|
|
71
|
+
const someAreEmpty = [this._state, this._next, this._end].some((x) => x === null || x === undefined);
|
|
72
|
+
if (someAreEmpty)
|
|
73
|
+
throw new Error("Animation properties are missing");
|
|
74
|
+
return new Animation(this._state, this._next, this._end);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/Ray/Ray.jstant
|
|
79
|
+
var MAX_8BIT = 255;
|
|
80
|
+
|
|
81
|
+
class Color {
|
|
82
|
+
constructor(rbg) {
|
|
83
|
+
this.rgb = rbg;
|
|
84
|
+
}
|
|
85
|
+
getRGB() {
|
|
86
|
+
return this.rgb;
|
|
87
|
+
}
|
|
88
|
+
get red() {
|
|
89
|
+
return this.rgb[0];
|
|
90
|
+
}
|
|
91
|
+
get green() {
|
|
92
|
+
return this.rgb[1];
|
|
93
|
+
}
|
|
94
|
+
get blue() {
|
|
95
|
+
return this.rgb[2];
|
|
96
|
+
}
|
|
97
|
+
add(color) {
|
|
98
|
+
return Color.ofRGB(this.rgb[0] + color.red, this.rgb[1] + color.green, this.rgb[2] + color.blue);
|
|
99
|
+
}
|
|
100
|
+
scale(r) {
|
|
101
|
+
const ans = this.rgb.map((c) => Math.min(1, Math.max(0, c * r)));
|
|
102
|
+
return new Color(ans);
|
|
103
|
+
}
|
|
104
|
+
equals(color) {
|
|
105
|
+
return this.rgb[0] === color.rgb[0] && this.rgb[1] === color.rgb[1] && this.rgb[2] === color.rgb[2];
|
|
106
|
+
}
|
|
107
|
+
static ofRGB(red = 0, green = 0, blue = 0) {
|
|
108
|
+
const rgb = new Float64Array(3);
|
|
109
|
+
rgb[0] = red;
|
|
110
|
+
rgb[1] = green;
|
|
111
|
+
rgb[2] = blue;
|
|
112
|
+
return new Color(rgb);
|
|
113
|
+
}
|
|
114
|
+
static ofRGBRaw(red = 0, green = 0, blue = 0) {
|
|
115
|
+
const rgb = new Float64Array(3);
|
|
116
|
+
rgb[0] = red / MAX_8BIT;
|
|
117
|
+
rgb[1] = green / MAX_8BIT;
|
|
118
|
+
rgb[2] = blue / MAX_8BIT;
|
|
119
|
+
return new Color(rgb);
|
|
120
|
+
}
|
|
121
|
+
static random() {
|
|
122
|
+
const r = () => Math.random();
|
|
123
|
+
return Color.ofRGB(r(), r(), r());
|
|
124
|
+
}
|
|
125
|
+
static RED = Color.ofRGB(1, 0, 0);
|
|
126
|
+
static GREEN = Color.ofRGB(0, 1, 0);
|
|
127
|
+
static BLUE = Color.ofRGB(0, 0, 1);
|
|
128
|
+
static BLACK = Color.ofRGB(0, 0, 0);
|
|
129
|
+
static WHITE = Color.ofRGB(1, 1, 1);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/Ray/Ray.jstants.js
|
|
133
|
+
var MAX_8BIT2 = 255;
|
|
134
|
+
|
|
135
|
+
// src/Ray/Ray.jstan
|
|
136
|
+
function smin(a, b, k = 32) {
|
|
137
|
+
const res = Math.exp(-k * a) + Math.exp(-k * b);
|
|
138
|
+
return -Math.log(res) / k;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/Ray/Ray.jstants.
|
|
142
|
+
var handleMouse = function(canvas, lambda) {
|
|
143
|
+
return (event) => {
|
|
144
|
+
const h = canvas.height;
|
|
145
|
+
const w = canvas.width;
|
|
146
|
+
const rect = canvas._canvas.getBoundingClientRect();
|
|
147
|
+
const mx = (event.clientX - rect.left) / rect.width, my = (event.clientY - rect.top) / rect.height;
|
|
148
|
+
const x = Math.floor(mx * w);
|
|
149
|
+
const y = Math.floor(h - 1 - my * h);
|
|
150
|
+
return lambda(x, y);
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
class Canvas {
|
|
155
|
+
constructor(canvas) {
|
|
156
|
+
this._canvas = canvas;
|
|
157
|
+
this._width = canvas.width;
|
|
158
|
+
this._height = canvas.height;
|
|
159
|
+
this._ctx = this._canvas.getContext("2d", { willReadFrequently: true });
|
|
160
|
+
this._imageData = this._ctx.getImageData(0, 0, this._width, this._height);
|
|
161
|
+
this._image = this._imageData.data;
|
|
162
|
+
}
|
|
163
|
+
get width() {
|
|
164
|
+
return this._canvas.width;
|
|
165
|
+
}
|
|
166
|
+
get height() {
|
|
167
|
+
return this._canvas.height;
|
|
168
|
+
}
|
|
169
|
+
get DOM() {
|
|
170
|
+
return this._canvas;
|
|
171
|
+
}
|
|
172
|
+
fill(color) {
|
|
173
|
+
return this.map(() => color);
|
|
174
|
+
}
|
|
175
|
+
map(lambda) {
|
|
176
|
+
const n = this._image.length;
|
|
177
|
+
const w = this._width;
|
|
178
|
+
const h = this._height;
|
|
179
|
+
for (let k = 0;k < n; k += 4) {
|
|
180
|
+
const i = Math.floor(k / (4 * w));
|
|
181
|
+
const j = Math.floor(k / 4 % w);
|
|
182
|
+
const x = j;
|
|
183
|
+
const y = h - 1 - i;
|
|
184
|
+
const color = lambda(x, y);
|
|
185
|
+
this._image[k] = color.red * MAX_8BIT2;
|
|
186
|
+
this._image[k + 1] = color.green * MAX_8BIT2;
|
|
187
|
+
this._image[k + 2] = color.blue * MAX_8BIT2;
|
|
188
|
+
this._image[k + 3] = MAX_8BIT2;
|
|
189
|
+
}
|
|
190
|
+
return this.paint();
|
|
191
|
+
}
|
|
192
|
+
setPxl(x, y, color) {
|
|
193
|
+
const w = this._width;
|
|
194
|
+
const h = this._height;
|
|
195
|
+
const i = h - 1 - y;
|
|
196
|
+
const j = x;
|
|
197
|
+
let index = 4 * (w * i + j);
|
|
198
|
+
this._image[index] = color.red * MAX_8BIT2;
|
|
199
|
+
this._image[index + 1] = color.green * MAX_8BIT2;
|
|
200
|
+
this._image[index + 2] = color.blue * MAX_8BIT2;
|
|
201
|
+
this._image[index + 3] = MAX_8BIT2;
|
|
202
|
+
return this;
|
|
203
|
+
}
|
|
204
|
+
getPxl(x, y) {
|
|
205
|
+
const w = this._width;
|
|
206
|
+
const h = this._height;
|
|
207
|
+
const i = h - 1 - y;
|
|
208
|
+
const j = x;
|
|
209
|
+
let index = 4 * (w * i + j);
|
|
210
|
+
return Color.ofRGBRaw(this._image[index], this._image[index + 1], this._image[index + 2]);
|
|
211
|
+
}
|
|
212
|
+
paint() {
|
|
213
|
+
this._ctx.putImageData(this._imageData, 0, 0);
|
|
214
|
+
return this;
|
|
215
|
+
}
|
|
216
|
+
onMouseDown(lambda) {
|
|
217
|
+
this._canvas.addEventListener("mousedown", handleMouse(this, lambda), false);
|
|
218
|
+
this._canvas.addEventListener("touchstart", handleMouse(this, lambda), false);
|
|
219
|
+
return this;
|
|
220
|
+
}
|
|
221
|
+
onMouseUp(lambda) {
|
|
222
|
+
this._canvas.addEventListener("mouseup", handleMouse(this, lambda), false);
|
|
223
|
+
this._canvas.addEventListener("touchend", handleMouse(this, lambda), false);
|
|
224
|
+
return this;
|
|
225
|
+
}
|
|
226
|
+
onMouseMove(lambda) {
|
|
227
|
+
this._canvas.addEventListener("mousemove", handleMouse(this, lambda), false);
|
|
228
|
+
this._canvas.addEventListener("touchmove", handleMouse(this, lambda), false);
|
|
229
|
+
return this;
|
|
230
|
+
}
|
|
231
|
+
onMouseWheel(lambda) {
|
|
232
|
+
this._canvas.addEventListener("wheel", lambda, false);
|
|
233
|
+
}
|
|
234
|
+
resize(width, height) {
|
|
235
|
+
this._canvas.width = width;
|
|
236
|
+
this._canvas.height = height;
|
|
237
|
+
this._width = this._canvas.width;
|
|
238
|
+
this._height = this._canvas.height;
|
|
239
|
+
this._ctx = this._canvas.getContext("2d", { willReadFrequently: true });
|
|
240
|
+
this._imageData = this._ctx.getImageData(0, 0, this._width, this._height);
|
|
241
|
+
this._image = this._imageData.data;
|
|
242
|
+
}
|
|
243
|
+
startVideoRecorder() {
|
|
244
|
+
let responseBlob;
|
|
245
|
+
const canvasSnapshots = [];
|
|
246
|
+
const stream = this._canvas.captureStream();
|
|
247
|
+
const recorder = new MediaRecorder(stream);
|
|
248
|
+
recorder.addEventListener("dataavailable", (e) => canvasSnapshots.push(e.data));
|
|
249
|
+
recorder.start();
|
|
250
|
+
recorder.onstop = () => responseBlob = new Blob(canvasSnapshots, { type: "video/webm" });
|
|
251
|
+
return {
|
|
252
|
+
stop: () => new Promise((re) => {
|
|
253
|
+
recorder.stop();
|
|
254
|
+
setTimeout(() => re(responseBlob));
|
|
255
|
+
})
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
static ofSize(width, height) {
|
|
259
|
+
const canvas = document.createElement("canvas");
|
|
260
|
+
canvas.setAttribute("width", width);
|
|
261
|
+
canvas.setAttribute("height", height);
|
|
262
|
+
return new Canvas(canvas);
|
|
263
|
+
}
|
|
264
|
+
static ofDOM(canvasDOM) {
|
|
265
|
+
return new Canvas(canvasDOM);
|
|
266
|
+
}
|
|
267
|
+
static ofCanvas(canvas) {
|
|
268
|
+
return new Canvas(canvas._canvas);
|
|
269
|
+
}
|
|
270
|
+
static ofUrl(url) {
|
|
271
|
+
return new Promise((resolve) => {
|
|
272
|
+
const img = document.createElement("img");
|
|
273
|
+
img.src = url;
|
|
274
|
+
img.onload = function() {
|
|
275
|
+
const canvas = document.createElement("canvas");
|
|
276
|
+
canvas.width = img.width;
|
|
277
|
+
canvas.height = img.height;
|
|
278
|
+
const ctx = canvas.getContext("2d");
|
|
279
|
+
ctx.drawImage(img, 0, 0);
|
|
280
|
+
resolve(Canvas.ofDOM(canvas));
|
|
281
|
+
};
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
static ofImage(image) {
|
|
285
|
+
const w = image.width;
|
|
286
|
+
const h = image.height;
|
|
287
|
+
return Canvas.ofSize(w, h).map((x, y) => {
|
|
288
|
+
return image.get(x, y);
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// src/Ray/Ray.jstants.jsser.js
|
|
294
|
+
var isElement = function(o) {
|
|
295
|
+
return typeof HTMLElement === "object" ? o instanceof HTMLElement : o && typeof o === "object" && o !== null && o.nodeType === 1 && typeof o.nodeName === "string";
|
|
296
|
+
};
|
|
297
|
+
var isPromise = function(o) {
|
|
298
|
+
return o instanceof Promise;
|
|
299
|
+
};
|
|
300
|
+
var SVG_URL = "http://www.w3.org/2000/svg";
|
|
301
|
+
var SVG_TAGS = [
|
|
302
|
+
"svg",
|
|
303
|
+
"g",
|
|
304
|
+
"circle",
|
|
305
|
+
"ellipse",
|
|
306
|
+
"line",
|
|
307
|
+
"path",
|
|
308
|
+
"polygon",
|
|
309
|
+
"polyline",
|
|
310
|
+
"rect"
|
|
311
|
+
];
|
|
312
|
+
|
|
313
|
+
class DomBuilder {
|
|
314
|
+
constructor(element) {
|
|
315
|
+
this.element = element;
|
|
316
|
+
}
|
|
317
|
+
attr(name, value) {
|
|
318
|
+
this.element.setAttribute(name, value);
|
|
319
|
+
return this;
|
|
320
|
+
}
|
|
321
|
+
style(styleStr) {
|
|
322
|
+
this.element.setAttribute("style", styleStr);
|
|
323
|
+
return this;
|
|
324
|
+
}
|
|
325
|
+
appendChild(...elements) {
|
|
326
|
+
elements.forEach((e) => {
|
|
327
|
+
if (isElement(e)) {
|
|
328
|
+
this.element.appendChild(e);
|
|
329
|
+
} else if (isPromise(e)) {
|
|
330
|
+
e.then((actualElem) => this.appendChild(actualElem));
|
|
331
|
+
} else {
|
|
332
|
+
this.element.appendChild(e.build());
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
return this;
|
|
336
|
+
}
|
|
337
|
+
inner(value) {
|
|
338
|
+
if (isPromise(value)) {
|
|
339
|
+
value.then((v) => this.element.innerHTML = v);
|
|
340
|
+
} else {
|
|
341
|
+
this.element.innerHTML = value;
|
|
342
|
+
}
|
|
343
|
+
return this;
|
|
344
|
+
}
|
|
345
|
+
removeChildren() {
|
|
346
|
+
while (this.element.firstChild) {
|
|
347
|
+
this.element.removeChild(this.element.lastChild);
|
|
348
|
+
}
|
|
349
|
+
return this;
|
|
350
|
+
}
|
|
351
|
+
html(value) {
|
|
352
|
+
return this.inner(value);
|
|
353
|
+
}
|
|
354
|
+
event(eventName, lambda) {
|
|
355
|
+
this.element.addEventListener(eventName, lambda);
|
|
356
|
+
return this;
|
|
357
|
+
}
|
|
358
|
+
build() {
|
|
359
|
+
return this.element;
|
|
360
|
+
}
|
|
361
|
+
addClass(className) {
|
|
362
|
+
if (!className || className === "")
|
|
363
|
+
return this;
|
|
364
|
+
this.element.classList.add(...className.split(" "));
|
|
365
|
+
return this;
|
|
366
|
+
}
|
|
367
|
+
removeClass(className) {
|
|
368
|
+
this.element.classList.remove(className);
|
|
369
|
+
return this;
|
|
370
|
+
}
|
|
371
|
+
static of(elem) {
|
|
372
|
+
if (isElement(elem)) {
|
|
373
|
+
return new DomBuilder(elem);
|
|
374
|
+
}
|
|
375
|
+
const isSvg = SVG_TAGS.includes(elem);
|
|
376
|
+
const element = isSvg ? document.createElementNS(SVG_URL, elem) : document.createElement(elem);
|
|
377
|
+
return new DomBuilder(element);
|
|
378
|
+
}
|
|
379
|
+
static ofId(id) {
|
|
380
|
+
return new DomBuilder(document.getElementById(id));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
var DomBuilder_default = DomBuilder;
|
|
384
|
+
|
|
385
|
+
// src/Ray/Ray.jstants.
|
|
386
|
+
var _sanitize_input = function(arrayIn, arrayOut) {
|
|
387
|
+
for (let i = 0;i < arrayIn.length; i++) {
|
|
388
|
+
const z = arrayIn[i];
|
|
389
|
+
const zIsNumber = z !== null && z !== undefined && typeof z === "number";
|
|
390
|
+
arrayOut[i] = zIsNumber ? z : 0;
|
|
391
|
+
}
|
|
392
|
+
return arrayOut;
|
|
393
|
+
};
|
|
394
|
+
var sameSizeOrError = function(a, b) {
|
|
395
|
+
if (a.n === b.n) {
|
|
396
|
+
return true;
|
|
397
|
+
}
|
|
398
|
+
throw new VectorException("Vector must have same size");
|
|
399
|
+
};
|
|
400
|
+
var ARRAY_TYPES = {
|
|
401
|
+
Float32Array,
|
|
402
|
+
Float64Array
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
class Vec {
|
|
406
|
+
constructor(array) {
|
|
407
|
+
this._vec = array;
|
|
408
|
+
this._n = this._vec.length;
|
|
409
|
+
}
|
|
410
|
+
get n() {
|
|
411
|
+
return this._n;
|
|
412
|
+
}
|
|
413
|
+
get dim() {
|
|
414
|
+
return this._n;
|
|
415
|
+
}
|
|
416
|
+
size = () => this._n;
|
|
417
|
+
shape = () => [this._n];
|
|
418
|
+
clone() {
|
|
419
|
+
return new Vec(COPY_VEC(this._vec));
|
|
420
|
+
}
|
|
421
|
+
get(i) {
|
|
422
|
+
return this._vec[i];
|
|
423
|
+
}
|
|
424
|
+
toArray() {
|
|
425
|
+
return COPY_VEC(this._vec);
|
|
426
|
+
}
|
|
427
|
+
toString() {
|
|
428
|
+
return "[" + this._vec.join(", ") + "]";
|
|
429
|
+
}
|
|
430
|
+
serialize() {
|
|
431
|
+
return this._vec.join(", ");
|
|
432
|
+
}
|
|
433
|
+
add(u) {
|
|
434
|
+
return this.op(u, (a, b) => a + b);
|
|
435
|
+
}
|
|
436
|
+
sub(u) {
|
|
437
|
+
return this.op(u, (a, b) => a - b);
|
|
438
|
+
}
|
|
439
|
+
mul(u) {
|
|
440
|
+
return this.op(u, (a, b) => a * b);
|
|
441
|
+
}
|
|
442
|
+
div(u) {
|
|
443
|
+
return this.op(u, (a, b) => a / b);
|
|
444
|
+
}
|
|
445
|
+
dot(u) {
|
|
446
|
+
let acc = 0;
|
|
447
|
+
for (let i = 0;i < this._n; i++) {
|
|
448
|
+
acc += this._vec[i] * u._vec[i];
|
|
449
|
+
}
|
|
450
|
+
return acc;
|
|
451
|
+
}
|
|
452
|
+
squareLength() {
|
|
453
|
+
return this.dot(this);
|
|
454
|
+
}
|
|
455
|
+
length() {
|
|
456
|
+
return Math.sqrt(this.dot(this));
|
|
457
|
+
}
|
|
458
|
+
normalize() {
|
|
459
|
+
return this.scale(1 / this.length());
|
|
460
|
+
}
|
|
461
|
+
scale(r) {
|
|
462
|
+
return this.map((z) => z * r);
|
|
463
|
+
}
|
|
464
|
+
map(lambda) {
|
|
465
|
+
const ans = BUILD_VEC(this._n);
|
|
466
|
+
for (let i = 0;i < this._n; i++) {
|
|
467
|
+
ans[i] = lambda(this._vec[i], i);
|
|
468
|
+
}
|
|
469
|
+
return new Vec(ans);
|
|
470
|
+
}
|
|
471
|
+
op(u, operation) {
|
|
472
|
+
sameSizeOrError(this, u);
|
|
473
|
+
const ans = BUILD_VEC(this._n);
|
|
474
|
+
for (let i = 0;i < this._n; i++) {
|
|
475
|
+
ans[i] = operation(this._vec[i], u._vec[i]);
|
|
476
|
+
}
|
|
477
|
+
return new Vec(ans);
|
|
478
|
+
}
|
|
479
|
+
reduce(fold, init = 0) {
|
|
480
|
+
let acc = init;
|
|
481
|
+
for (let i = 0;i < this._n; i++) {
|
|
482
|
+
acc = fold(acc, this._vec[i], i);
|
|
483
|
+
}
|
|
484
|
+
return acc;
|
|
485
|
+
}
|
|
486
|
+
fold = this.reduce;
|
|
487
|
+
foldLeft = this.fold;
|
|
488
|
+
equals(u, precision = 0.00001) {
|
|
489
|
+
if (!(u instanceof Vec))
|
|
490
|
+
return false;
|
|
491
|
+
return this.sub(u).length() < precision;
|
|
492
|
+
}
|
|
493
|
+
take(n = 0, m = this._vec.length) {
|
|
494
|
+
return new Vec(this._vec.slice(n, m));
|
|
495
|
+
}
|
|
496
|
+
findIndex(predicate) {
|
|
497
|
+
for (let i = 0;i < this._n; i++) {
|
|
498
|
+
if (predicate(this._vec[i]))
|
|
499
|
+
return i;
|
|
500
|
+
}
|
|
501
|
+
return -1;
|
|
502
|
+
}
|
|
503
|
+
static fromArray(array) {
|
|
504
|
+
if (array.length === 2)
|
|
505
|
+
return Vector2.fromArray(array);
|
|
506
|
+
if (array.length === 3)
|
|
507
|
+
return Vector3.fromArray(array);
|
|
508
|
+
return new Vec(_sanitize_input(array, BUILD_VEC(array.length)));
|
|
509
|
+
}
|
|
510
|
+
static of(...values) {
|
|
511
|
+
if (values.length === 2)
|
|
512
|
+
return Vector2.of(...values);
|
|
513
|
+
if (values.length === 3)
|
|
514
|
+
return Vector3.of(...values);
|
|
515
|
+
return new Vec(_sanitize_input(values, BUILD_VEC(values.length)));
|
|
516
|
+
}
|
|
517
|
+
static ZERO = (n) => n === 3 ? new Vector3 : n === 2 ? new Vector2 : new Vec(BUILD_VEC(n));
|
|
518
|
+
static ONES = (n) => {
|
|
519
|
+
if (n === 2)
|
|
520
|
+
return Vector2.ONES;
|
|
521
|
+
if (n === 3)
|
|
522
|
+
return Vector3.ONES;
|
|
523
|
+
return Vec.ZERO(n).map(() => 1);
|
|
524
|
+
};
|
|
525
|
+
static e = (n) => (i) => {
|
|
526
|
+
if (n === 2)
|
|
527
|
+
return Vector2.e(i);
|
|
528
|
+
if (n === 3)
|
|
529
|
+
return Vector3.e(i);
|
|
530
|
+
const vec = BUILD_VEC(n);
|
|
531
|
+
if (i >= 0 && i < n) {
|
|
532
|
+
vec[i] = 1;
|
|
533
|
+
}
|
|
534
|
+
return new Vec(vec);
|
|
535
|
+
};
|
|
536
|
+
static RANDOM = (n) => {
|
|
537
|
+
if (n === 2)
|
|
538
|
+
return Vector2.RANDOM();
|
|
539
|
+
if (n === 3)
|
|
540
|
+
return Vector3.RANDOM();
|
|
541
|
+
const v = BUILD_VEC(n);
|
|
542
|
+
for (let i = 0;i < n; i++) {
|
|
543
|
+
v[i] = Math.random();
|
|
544
|
+
}
|
|
545
|
+
return new Vec(v);
|
|
546
|
+
};
|
|
547
|
+
}
|
|
548
|
+
var BUILD_VEC = (n) => new ARRAY_TYPES.Float64Array(n);
|
|
549
|
+
var COPY_VEC = (array) => ARRAY_TYPES.Float64Array.from(array);
|
|
550
|
+
|
|
551
|
+
class VectorException extends Error {
|
|
552
|
+
}
|
|
553
|
+
var Vec3 = (x = 0, y = 0, z = 0) => new Vector3(x, y, z);
|
|
554
|
+
var Vec2 = (x = 0, y = 0) => new Vector2(x, y);
|
|
555
|
+
|
|
556
|
+
class Vector3 {
|
|
557
|
+
constructor(x = 0, y = 0, z = 0) {
|
|
558
|
+
this.x = x;
|
|
559
|
+
this.y = y;
|
|
560
|
+
this.z = z;
|
|
561
|
+
}
|
|
562
|
+
get n() {
|
|
563
|
+
return 3;
|
|
564
|
+
}
|
|
565
|
+
get dim() {
|
|
566
|
+
return 3;
|
|
567
|
+
}
|
|
568
|
+
size = () => 3;
|
|
569
|
+
shape = () => [3];
|
|
570
|
+
clone() {
|
|
571
|
+
return new Vector3(this.x, this.y, this.z);
|
|
572
|
+
}
|
|
573
|
+
get(i) {
|
|
574
|
+
return [this.x, this.y, this.z][i];
|
|
575
|
+
}
|
|
576
|
+
toArray() {
|
|
577
|
+
return [this.x, this.y, this.z];
|
|
578
|
+
}
|
|
579
|
+
toString() {
|
|
580
|
+
return "[" + this.toArray().join(", ") + "]";
|
|
581
|
+
}
|
|
582
|
+
serialize() {
|
|
583
|
+
return this.toArray().join(", ");
|
|
584
|
+
}
|
|
585
|
+
add(u) {
|
|
586
|
+
return this.op(u, (a, b) => a + b);
|
|
587
|
+
}
|
|
588
|
+
sub(u) {
|
|
589
|
+
return this.op(u, (a, b) => a - b);
|
|
590
|
+
}
|
|
591
|
+
mul(u) {
|
|
592
|
+
return this.op(u, (a, b) => a * b);
|
|
593
|
+
}
|
|
594
|
+
div(u) {
|
|
595
|
+
return this.op(u, (a, b) => a / b);
|
|
596
|
+
}
|
|
597
|
+
dot(u) {
|
|
598
|
+
return this.x * u.x + this.y * u.y + this.z * u.z;
|
|
599
|
+
}
|
|
600
|
+
squareLength() {
|
|
601
|
+
return this.dot(this);
|
|
602
|
+
}
|
|
603
|
+
length() {
|
|
604
|
+
return Math.sqrt(this.dot(this));
|
|
605
|
+
}
|
|
606
|
+
normalize() {
|
|
607
|
+
return this.scale(1 / this.length());
|
|
608
|
+
}
|
|
609
|
+
scale(r) {
|
|
610
|
+
return this.map((z) => z * r);
|
|
611
|
+
}
|
|
612
|
+
map(lambda) {
|
|
613
|
+
return new Vector3(lambda(this.x, 0), lambda(this.y, 1), lambda(this.z, 2));
|
|
614
|
+
}
|
|
615
|
+
op(u, operation) {
|
|
616
|
+
return new Vector3(operation(this.x, u.x), operation(this.y, u.y), operation(this.z, u.z));
|
|
617
|
+
}
|
|
618
|
+
reduce(fold, init = 0) {
|
|
619
|
+
let acc = init;
|
|
620
|
+
acc = fold(acc, this.x);
|
|
621
|
+
acc = fold(acc, this.y);
|
|
622
|
+
acc = fold(acc, this.z);
|
|
623
|
+
return acc;
|
|
624
|
+
}
|
|
625
|
+
fold = this.reduce;
|
|
626
|
+
foldLeft = this.fold;
|
|
627
|
+
equals(u, precision = 0.00001) {
|
|
628
|
+
if (!(u instanceof Vector3))
|
|
629
|
+
return false;
|
|
630
|
+
return this.sub(u).length() < precision;
|
|
631
|
+
}
|
|
632
|
+
take(n = 0, m = 3) {
|
|
633
|
+
const array = [this.x, this.y, this.z].slice(n, m);
|
|
634
|
+
if (array.length === 2)
|
|
635
|
+
return Vector2.fromArray(array);
|
|
636
|
+
if (array.length === 3)
|
|
637
|
+
return Vector3.fromArray(array);
|
|
638
|
+
return Vec.fromArray(array);
|
|
639
|
+
}
|
|
640
|
+
findIndex(predicate) {
|
|
641
|
+
if (predicate(this.x))
|
|
642
|
+
return 0;
|
|
643
|
+
if (predicate(this.y))
|
|
644
|
+
return 1;
|
|
645
|
+
if (predicate(this.z))
|
|
646
|
+
return 2;
|
|
647
|
+
return -1;
|
|
648
|
+
}
|
|
649
|
+
static fromArray(array) {
|
|
650
|
+
return new Vector3(...array);
|
|
651
|
+
}
|
|
652
|
+
static of(...values) {
|
|
653
|
+
return new Vector3(...values);
|
|
654
|
+
}
|
|
655
|
+
static e = (i) => {
|
|
656
|
+
if (i === 0)
|
|
657
|
+
return new Vector3(1, 0, 0);
|
|
658
|
+
if (i === 1)
|
|
659
|
+
return new Vector3(0, 1, 0);
|
|
660
|
+
if (i === 2)
|
|
661
|
+
return new Vector3(0, 0, 1);
|
|
662
|
+
return new Vec3;
|
|
663
|
+
};
|
|
664
|
+
static RANDOM = () => {
|
|
665
|
+
return new Vector3(Math.random(), Math.random(), Math.random());
|
|
666
|
+
};
|
|
667
|
+
static ONES = new Vector3(1, 1, 1);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
class Vector2 {
|
|
671
|
+
constructor(x = 0, y = 0) {
|
|
672
|
+
this.x = x;
|
|
673
|
+
this.y = y;
|
|
674
|
+
}
|
|
675
|
+
get n() {
|
|
676
|
+
return 2;
|
|
677
|
+
}
|
|
678
|
+
get dim() {
|
|
679
|
+
return 2;
|
|
680
|
+
}
|
|
681
|
+
size = () => 2;
|
|
682
|
+
shape = () => [2];
|
|
683
|
+
clone() {
|
|
684
|
+
return new Vector2(this.x, this.y);
|
|
685
|
+
}
|
|
686
|
+
get(i) {
|
|
687
|
+
return [this.x, this.y][i];
|
|
688
|
+
}
|
|
689
|
+
toArray() {
|
|
690
|
+
return [this.x, this.y];
|
|
691
|
+
}
|
|
692
|
+
toString() {
|
|
693
|
+
return "[" + this.toArray().join(", ") + "]";
|
|
694
|
+
}
|
|
695
|
+
serialize() {
|
|
696
|
+
return this.toArray().join(", ");
|
|
697
|
+
}
|
|
698
|
+
add(u) {
|
|
699
|
+
return this.op(u, (a, b) => a + b);
|
|
700
|
+
}
|
|
701
|
+
sub(u) {
|
|
702
|
+
return this.op(u, (a, b) => a - b);
|
|
703
|
+
}
|
|
704
|
+
mul(u) {
|
|
705
|
+
return this.op(u, (a, b) => a * b);
|
|
706
|
+
}
|
|
707
|
+
div(u) {
|
|
708
|
+
return this.op(u, (a, b) => a / b);
|
|
709
|
+
}
|
|
710
|
+
dot(u) {
|
|
711
|
+
return this.x * u.x + this.y * u.y;
|
|
712
|
+
}
|
|
713
|
+
squareLength() {
|
|
714
|
+
return this.dot(this);
|
|
715
|
+
}
|
|
716
|
+
length() {
|
|
717
|
+
return Math.sqrt(this.dot(this));
|
|
718
|
+
}
|
|
719
|
+
normalize() {
|
|
720
|
+
return this.scale(1 / this.length());
|
|
721
|
+
}
|
|
722
|
+
scale(r) {
|
|
723
|
+
return this.map((z) => z * r);
|
|
724
|
+
}
|
|
725
|
+
map(lambda) {
|
|
726
|
+
return new Vector2(lambda(this.x, 0), lambda(this.y, 1));
|
|
727
|
+
}
|
|
728
|
+
op(u, operation) {
|
|
729
|
+
return new Vector2(operation(this.x, u.x), operation(this.y, u.y));
|
|
730
|
+
}
|
|
731
|
+
reduce(fold, init = 0) {
|
|
732
|
+
let acc = init;
|
|
733
|
+
acc = fold(acc, this.x);
|
|
734
|
+
acc = fold(acc, this.y);
|
|
735
|
+
return acc;
|
|
736
|
+
}
|
|
737
|
+
fold = this.reduce;
|
|
738
|
+
foldLeft = this.fold;
|
|
739
|
+
equals(u, precision = 0.00001) {
|
|
740
|
+
if (!(u instanceof Vector2))
|
|
741
|
+
return false;
|
|
742
|
+
return this.sub(u).length() < precision;
|
|
743
|
+
}
|
|
744
|
+
take(n = 0, m = 2) {
|
|
745
|
+
const array = [this.x, this.y].slice(n, m);
|
|
746
|
+
if (array.length === 2)
|
|
747
|
+
return Vector2.fromArray(array);
|
|
748
|
+
return Vec.fromArray(array);
|
|
749
|
+
}
|
|
750
|
+
findIndex(predicate) {
|
|
751
|
+
if (predicate(this.x))
|
|
752
|
+
return 0;
|
|
753
|
+
if (predicate(this.y))
|
|
754
|
+
return 1;
|
|
755
|
+
return -1;
|
|
756
|
+
}
|
|
757
|
+
static fromArray(array) {
|
|
758
|
+
return new Vector2(...array);
|
|
759
|
+
}
|
|
760
|
+
static of(...values) {
|
|
761
|
+
return new Vector2(...values);
|
|
762
|
+
}
|
|
763
|
+
static e = (i) => {
|
|
764
|
+
if (i === 0)
|
|
765
|
+
return new Vector2(1, 0);
|
|
766
|
+
if (i === 1)
|
|
767
|
+
return new Vector2(0, 1);
|
|
768
|
+
return new Vector2;
|
|
769
|
+
};
|
|
770
|
+
static RANDOM = () => {
|
|
771
|
+
return new Vector2(Math.random(), Math.random());
|
|
772
|
+
};
|
|
773
|
+
static ONES = new Vector2(1, 1);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// src/Ray/Ray.js
|
|
777
|
+
function Ray(init, dir) {
|
|
778
|
+
const ans = {};
|
|
779
|
+
ans.init = init;
|
|
780
|
+
ans.dir = dir;
|
|
781
|
+
ans.trace = (t) => init.add(dir.scale(t));
|
|
782
|
+
return ans;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
// src/Ray/Ray.jstants.
|
|
786
|
+
class Camera {
|
|
787
|
+
constructor(props = {
|
|
788
|
+
sphericalCoords: Vec3(2, 0, 0),
|
|
789
|
+
focalPoint: Vec3(0, 0, 0),
|
|
790
|
+
distanceToPlane: 1
|
|
791
|
+
}) {
|
|
792
|
+
const { sphericalCoords, focalPoint, distanceToPlane } = props;
|
|
793
|
+
this.sphericalCoords = sphericalCoords || Vec3(2, 0, 0);
|
|
794
|
+
this.focalPoint = focalPoint || Vec3(0, 0, 0);
|
|
795
|
+
this.distanceToPlane = distanceToPlane || 1;
|
|
796
|
+
this.orbit();
|
|
797
|
+
}
|
|
798
|
+
orbit() {
|
|
799
|
+
const [rho, theta, phi] = this.sphericalCoords.toArray();
|
|
800
|
+
const cosT = Math.cos(theta);
|
|
801
|
+
const sinT = Math.sin(theta);
|
|
802
|
+
const cosP = Math.cos(phi);
|
|
803
|
+
const sinP = Math.sin(phi);
|
|
804
|
+
this.basis = [];
|
|
805
|
+
this.basis[2] = Vec3(-cosP * cosT, -cosP * sinT, -sinP);
|
|
806
|
+
this.basis[1] = Vec3(-sinP * cosT, -sinP * sinT, cosP);
|
|
807
|
+
this.basis[0] = Vec3(-sinT, cosT, 0);
|
|
808
|
+
const sphereCoordinates = Vec3(rho * cosP * cosT, rho * cosP * sinT, rho * sinP);
|
|
809
|
+
this.eye = sphereCoordinates.add(this.focalPoint);
|
|
810
|
+
return this;
|
|
811
|
+
}
|
|
812
|
+
rayShot(lambdaWithRays) {
|
|
813
|
+
return {
|
|
814
|
+
to: (canvas) => {
|
|
815
|
+
const w = canvas.width;
|
|
816
|
+
const h = canvas.height;
|
|
817
|
+
return canvas.map((x, y) => {
|
|
818
|
+
const dirInLocal = [
|
|
819
|
+
2 * (x / w) - 1,
|
|
820
|
+
2 * (y / h) - 1,
|
|
821
|
+
1
|
|
822
|
+
];
|
|
823
|
+
const dir = this.basis[0].scale(dirInLocal[0]).add(this.basis[1].scale(dirInLocal[1])).add(this.basis[2].scale(dirInLocal[2])).normalize();
|
|
824
|
+
return lambdaWithRays(Ray(this.eye, dir));
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
};
|
|
828
|
+
}
|
|
829
|
+
sceneShot(scene) {
|
|
830
|
+
const lambda = (ray) => {
|
|
831
|
+
return scene.interceptWith(ray).map(([pos, normal]) => {
|
|
832
|
+
return Color.ofRGB((normal.get(0) + 1) / 2, (normal.get(1) + 1) / 2, (normal.get(2) + 1) / 2);
|
|
833
|
+
}).orElse(() => {
|
|
834
|
+
return Color.BLACK;
|
|
835
|
+
});
|
|
836
|
+
};
|
|
837
|
+
return this.rayShot(lambda);
|
|
838
|
+
}
|
|
839
|
+
reverseShot(scene) {
|
|
840
|
+
return {
|
|
841
|
+
to: (canvas) => {
|
|
842
|
+
canvas.fill(Color.BLACK);
|
|
843
|
+
const w = canvas.width;
|
|
844
|
+
const h = canvas.height;
|
|
845
|
+
const zBuffer = new Float64Array(w * h).fill(Number.MAX_VALUE);
|
|
846
|
+
scene.getElements().forEach((point) => {
|
|
847
|
+
let pointInCamCoord = point.position.sub(this.eye);
|
|
848
|
+
pointInCamCoord = Vec3(this.basis[0].dot(pointInCamCoord), this.basis[1].dot(pointInCamCoord), this.basis[2].dot(pointInCamCoord));
|
|
849
|
+
const z = pointInCamCoord.get(2);
|
|
850
|
+
if (z < this.distanceToPlane)
|
|
851
|
+
return;
|
|
852
|
+
const projectedPoint = pointInCamCoord.scale(this.distanceToPlane / z);
|
|
853
|
+
let x = w / 2 + projectedPoint.get(0) * w;
|
|
854
|
+
let y = h / 2 + projectedPoint.get(1) * h;
|
|
855
|
+
x = Math.floor(x);
|
|
856
|
+
y = Math.floor(y);
|
|
857
|
+
if (x < 0 || x >= w || y < 0 || y >= h)
|
|
858
|
+
return;
|
|
859
|
+
const radius = Math.floor(Math.max(1, Math.min(10, 10 - z)));
|
|
860
|
+
for (let k = -radius;k < radius; k++) {
|
|
861
|
+
for (let l = -radius;l < radius; l++) {
|
|
862
|
+
const xl = Math.max(0, Math.min(w - 1, x + k));
|
|
863
|
+
const yl = Math.floor(y + l);
|
|
864
|
+
const j = xl;
|
|
865
|
+
const i = h - 1 - yl;
|
|
866
|
+
const zBufferIndex = Math.floor(w * i + j);
|
|
867
|
+
if (z < zBuffer[zBufferIndex]) {
|
|
868
|
+
zBuffer[zBufferIndex] = z;
|
|
869
|
+
canvas.setPxl(xl, yl, point.color);
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
canvas.paint();
|
|
875
|
+
return canvas;
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
// src/Ray/Ray.jstants.
|
|
882
|
+
var exports_Monads = {};
|
|
883
|
+
__export(exports_Monads, {
|
|
884
|
+
some: () => {
|
|
885
|
+
{
|
|
886
|
+
return some;
|
|
887
|
+
}
|
|
888
|
+
},
|
|
889
|
+
none: () => {
|
|
890
|
+
{
|
|
891
|
+
return none;
|
|
892
|
+
}
|
|
893
|
+
},
|
|
894
|
+
maybe: () => {
|
|
895
|
+
{
|
|
896
|
+
return maybe;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
});
|
|
900
|
+
function some(x) {
|
|
901
|
+
const object = {
|
|
902
|
+
map: (f) => maybe(f(x)),
|
|
903
|
+
orElse: () => x,
|
|
904
|
+
forEach: (f) => f(x),
|
|
905
|
+
flatMap: (f) => f(x),
|
|
906
|
+
isSome: () => true
|
|
907
|
+
};
|
|
908
|
+
return object;
|
|
909
|
+
}
|
|
910
|
+
function none() {
|
|
911
|
+
const object = {
|
|
912
|
+
map: () => object,
|
|
913
|
+
orElse: (f = () => {
|
|
914
|
+
}) => f(),
|
|
915
|
+
forEach: () => {
|
|
916
|
+
},
|
|
917
|
+
flatMap: () => object,
|
|
918
|
+
isSome: () => false
|
|
919
|
+
};
|
|
920
|
+
return object;
|
|
921
|
+
}
|
|
922
|
+
function maybe(x) {
|
|
923
|
+
if (x) {
|
|
924
|
+
return some(x);
|
|
925
|
+
}
|
|
926
|
+
return none(x);
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
// src/Ray/Ray.js
|
|
930
|
+
var maxComp = function(u) {
|
|
931
|
+
return u.fold((e, x) => Math.max(e, x), -Number.MAX_VALUE);
|
|
932
|
+
};
|
|
933
|
+
|
|
934
|
+
class Box {
|
|
935
|
+
constructor(min, max) {
|
|
936
|
+
this.isEmpty = min === undefined || max === undefined;
|
|
937
|
+
if (this.isEmpty)
|
|
938
|
+
return this;
|
|
939
|
+
this.min = min.op(max, Math.min);
|
|
940
|
+
this.max = max.op(min, Math.max);
|
|
941
|
+
this.center = min.add(max).scale(1 / 2);
|
|
942
|
+
this.diagonal = max.sub(min);
|
|
943
|
+
}
|
|
944
|
+
add(box) {
|
|
945
|
+
if (this.isEmpty)
|
|
946
|
+
return box;
|
|
947
|
+
const { min, max } = this;
|
|
948
|
+
return new Box(min.op(box.min, Math.min), max.op(box.max, Math.max));
|
|
949
|
+
}
|
|
950
|
+
union = this.add;
|
|
951
|
+
sub(box) {
|
|
952
|
+
if (this.isEmpty)
|
|
953
|
+
return Box.EMPTY;
|
|
954
|
+
const { min, max } = this;
|
|
955
|
+
const newMin = min.op(box.min, Math.max);
|
|
956
|
+
const newMax = max.op(box.max, Math.min);
|
|
957
|
+
const newDiag = newMax.sub(newMin);
|
|
958
|
+
const isAllPositive = newDiag.data.every((x) => x >= 0);
|
|
959
|
+
return !isAllPositive ? Box.EMPTY : new Box(newMin, newMax);
|
|
960
|
+
}
|
|
961
|
+
intersection = this.sub;
|
|
962
|
+
interceptWith(ray) {
|
|
963
|
+
const maxIte = 100;
|
|
964
|
+
const epsilon = 0.001;
|
|
965
|
+
let p = ray.init;
|
|
966
|
+
let t = this.distanceToPoint(p);
|
|
967
|
+
let minT = t;
|
|
968
|
+
for (let i = 0;i < maxIte; i++) {
|
|
969
|
+
p = ray.trace(t);
|
|
970
|
+
const d = this.distanceToPoint(p);
|
|
971
|
+
t += d;
|
|
972
|
+
if (d < epsilon) {
|
|
973
|
+
return some(p);
|
|
974
|
+
}
|
|
975
|
+
if (d > minT) {
|
|
976
|
+
break;
|
|
977
|
+
}
|
|
978
|
+
minT = d;
|
|
979
|
+
}
|
|
980
|
+
return none();
|
|
981
|
+
}
|
|
982
|
+
scale(r) {
|
|
983
|
+
return new Box(this.min.sub(this.center).scale(r), this.max.sub(this.center).scale(r)).move(this.center);
|
|
984
|
+
}
|
|
985
|
+
move(v) {
|
|
986
|
+
return new Box(this.min.add(v), this.max.add(v));
|
|
987
|
+
}
|
|
988
|
+
equals(box) {
|
|
989
|
+
if (!(box instanceof Box))
|
|
990
|
+
return false;
|
|
991
|
+
if (this == Box.EMPTY)
|
|
992
|
+
return true;
|
|
993
|
+
return this.min.equals(box.min) && this.max.equals(box.max);
|
|
994
|
+
}
|
|
995
|
+
distanceToBox(box) {
|
|
996
|
+
return this.min.sub(box.min).length() + this.max.sub(box.max).length();
|
|
997
|
+
}
|
|
998
|
+
distanceToPoint(pointVec) {
|
|
999
|
+
const p = pointVec.sub(this.center);
|
|
1000
|
+
const r = this.max.sub(this.center);
|
|
1001
|
+
const q = p.map(Math.abs).sub(r);
|
|
1002
|
+
return q.map((x) => Math.max(x, 0)).length() + Math.min(0, maxComp(q));
|
|
1003
|
+
}
|
|
1004
|
+
estimateNormal(pointVec) {
|
|
1005
|
+
const epsilon = 0.001;
|
|
1006
|
+
const n = pointVec.dim;
|
|
1007
|
+
const grad = [];
|
|
1008
|
+
const d = this.distanceToPoint(pointVec);
|
|
1009
|
+
for (let i = 0;i < n; i++) {
|
|
1010
|
+
grad.push(this.distanceToPoint(pointVec.add(Vec.e(n)(i).scale(epsilon))) - d);
|
|
1011
|
+
}
|
|
1012
|
+
return Vec.fromArray(grad).scale(Math.sign(d)).normalize();
|
|
1013
|
+
}
|
|
1014
|
+
toString() {
|
|
1015
|
+
return `{
|
|
1016
|
+
min:${this.min.toString()},
|
|
1017
|
+
max:${this.max.toString()}
|
|
1018
|
+
}`;
|
|
1019
|
+
}
|
|
1020
|
+
static EMPTY = new Box;
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// src/Ray/Ray.jstant
|
|
1024
|
+
var exports_Utils = {};
|
|
1025
|
+
__export(exports_Utils, {
|
|
1026
|
+
or: () => {
|
|
1027
|
+
{
|
|
1028
|
+
return or;
|
|
1029
|
+
}
|
|
1030
|
+
},
|
|
1031
|
+
measureTimeWithResult: () => {
|
|
1032
|
+
{
|
|
1033
|
+
return measureTimeWithResult;
|
|
1034
|
+
}
|
|
1035
|
+
},
|
|
1036
|
+
measureTime: () => {
|
|
1037
|
+
{
|
|
1038
|
+
return measureTime;
|
|
1039
|
+
}
|
|
1040
|
+
},
|
|
1041
|
+
compose: () => {
|
|
1042
|
+
{
|
|
1043
|
+
return compose;
|
|
1044
|
+
}
|
|
1045
|
+
},
|
|
1046
|
+
argmin: () => {
|
|
1047
|
+
{
|
|
1048
|
+
return argmin;
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
});
|
|
1052
|
+
function measureTime(lambda) {
|
|
1053
|
+
const t = performance.now();
|
|
1054
|
+
lambda();
|
|
1055
|
+
return 0.001 * (performance.now() - t);
|
|
1056
|
+
}
|
|
1057
|
+
function measureTimeWithResult(lambda) {
|
|
1058
|
+
const t = performance.now();
|
|
1059
|
+
const result = lambda();
|
|
1060
|
+
return { result, time: 0.001 * (performance.now() - t) };
|
|
1061
|
+
}
|
|
1062
|
+
function compose(f, g) {
|
|
1063
|
+
return (x) => f(g(x));
|
|
1064
|
+
}
|
|
1065
|
+
function or(...lambdas) {
|
|
1066
|
+
for (let i = 0;i < lambdas.length; i++) {
|
|
1067
|
+
try {
|
|
1068
|
+
return lambdas[i]();
|
|
1069
|
+
} catch (err) {
|
|
1070
|
+
continue;
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
function argmin(array, costFunction = (x) => x) {
|
|
1075
|
+
let argminIndex = -1;
|
|
1076
|
+
let cost = Number.MAX_VALUE;
|
|
1077
|
+
for (let i = 0;i < array.length; i++) {
|
|
1078
|
+
const newCost = costFunction(array[i]);
|
|
1079
|
+
if (newCost < cost) {
|
|
1080
|
+
cost = newCost;
|
|
1081
|
+
argminIndex = i;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
return argminIndex;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
// src/Ray/Ray.jstant
|
|
1088
|
+
var sphereInterception = function(point, ray) {
|
|
1089
|
+
const { init, dir } = ray;
|
|
1090
|
+
const diff = init.sub(point.position);
|
|
1091
|
+
const b = 2 * dir.dot(diff);
|
|
1092
|
+
const c = diff.squareLength() - point.radius * point.radius;
|
|
1093
|
+
const discriminant = b * b - 4 * c;
|
|
1094
|
+
if (discriminant < 0)
|
|
1095
|
+
return none();
|
|
1096
|
+
const sqrt = Math.sqrt(discriminant);
|
|
1097
|
+
const [t1, t2] = [(-b - sqrt) / 2, (-b + sqrt) / 2];
|
|
1098
|
+
const t = Math.min(t1, t2);
|
|
1099
|
+
if (t1 * t2 < 0)
|
|
1100
|
+
return some(t);
|
|
1101
|
+
return t1 >= 0 && t2 >= 0 ? some(t) : none();
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
class Point {
|
|
1105
|
+
constructor({ name, position, normal, color, radius }) {
|
|
1106
|
+
this.name = name;
|
|
1107
|
+
this.color = color;
|
|
1108
|
+
this.normal = normal;
|
|
1109
|
+
this.radius = radius;
|
|
1110
|
+
this.position = position;
|
|
1111
|
+
}
|
|
1112
|
+
distanceToPoint(p) {
|
|
1113
|
+
return this.position.sub(p).length() - this.radius;
|
|
1114
|
+
}
|
|
1115
|
+
interceptWith(ray) {
|
|
1116
|
+
return sphereInterception(this, ray).map((t) => {
|
|
1117
|
+
const pointOnSphere = ray.trace(t);
|
|
1118
|
+
const normal = pointOnSphere.sub(this.position).normalize();
|
|
1119
|
+
return [pointOnSphere, normal];
|
|
1120
|
+
});
|
|
1121
|
+
}
|
|
1122
|
+
getBoundingBox() {
|
|
1123
|
+
if (this.boundingBox)
|
|
1124
|
+
return this.boundingBox;
|
|
1125
|
+
const n = this.position.dim;
|
|
1126
|
+
this.boundingBox = new Box(this.position.add(Vec.ONES(n).scale(-this.radius)), this.position.add(Vec.ONES(n).scale(this.radius)));
|
|
1127
|
+
return this.boundingBox;
|
|
1128
|
+
}
|
|
1129
|
+
static builder() {
|
|
1130
|
+
return new PointBuilder;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
class PointBuilder {
|
|
1135
|
+
constructor() {
|
|
1136
|
+
this._name;
|
|
1137
|
+
this._color = Color.WHITE;
|
|
1138
|
+
this._radius = 1;
|
|
1139
|
+
this._normal = Vec3(1, 0, 0);
|
|
1140
|
+
this._position = Vec3(0, 0, 0);
|
|
1141
|
+
}
|
|
1142
|
+
name(name) {
|
|
1143
|
+
this._name = name;
|
|
1144
|
+
return this;
|
|
1145
|
+
}
|
|
1146
|
+
color(color) {
|
|
1147
|
+
this._color = color;
|
|
1148
|
+
return this;
|
|
1149
|
+
}
|
|
1150
|
+
radius(radius) {
|
|
1151
|
+
this._radius = radius;
|
|
1152
|
+
return this;
|
|
1153
|
+
}
|
|
1154
|
+
normal(normal) {
|
|
1155
|
+
this._normal = normal;
|
|
1156
|
+
return this;
|
|
1157
|
+
}
|
|
1158
|
+
position(posVec3) {
|
|
1159
|
+
this._position = posVec3;
|
|
1160
|
+
return this;
|
|
1161
|
+
}
|
|
1162
|
+
build() {
|
|
1163
|
+
const attrs = {
|
|
1164
|
+
name: this._name,
|
|
1165
|
+
color: this._color,
|
|
1166
|
+
radius: this._radius,
|
|
1167
|
+
normal: this._normal,
|
|
1168
|
+
position: this._position
|
|
1169
|
+
};
|
|
1170
|
+
if (Object.values(attrs).some((x) => x === undefined)) {
|
|
1171
|
+
throw new Error("Point is incomplete");
|
|
1172
|
+
}
|
|
1173
|
+
return new Point(attrs);
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
var Point_default = Point;
|
|
1177
|
+
|
|
1178
|
+
// src/Ray/Ray.jstant
|
|
1179
|
+
class Scene {
|
|
1180
|
+
constructor() {
|
|
1181
|
+
this.id2ElemMap = {};
|
|
1182
|
+
this.sceneElements = [];
|
|
1183
|
+
this.boundingBoxScene = new Node;
|
|
1184
|
+
}
|
|
1185
|
+
add(...elements) {
|
|
1186
|
+
return this.addList(elements);
|
|
1187
|
+
}
|
|
1188
|
+
addList(elements) {
|
|
1189
|
+
for (let i = 0;i < elements.length; i++) {
|
|
1190
|
+
const elem = elements[i];
|
|
1191
|
+
const classes = [Point_default];
|
|
1192
|
+
if (!classes.some((c) => elem instanceof c))
|
|
1193
|
+
return this;
|
|
1194
|
+
const { name } = elem;
|
|
1195
|
+
this.id2ElemMap[name] = elem;
|
|
1196
|
+
this.sceneElements.push(elem);
|
|
1197
|
+
this.boundingBoxScene.add(elem);
|
|
1198
|
+
}
|
|
1199
|
+
return this;
|
|
1200
|
+
}
|
|
1201
|
+
clear() {
|
|
1202
|
+
this.id2ElemMap = {};
|
|
1203
|
+
this.sceneElements = [];
|
|
1204
|
+
this.boundingBoxScene = new Node;
|
|
1205
|
+
}
|
|
1206
|
+
getElements() {
|
|
1207
|
+
return this.sceneElements;
|
|
1208
|
+
}
|
|
1209
|
+
interceptWith(ray, level) {
|
|
1210
|
+
return this.boundingBoxScene.interceptWith(ray, level);
|
|
1211
|
+
}
|
|
1212
|
+
distanceToPoint(p) {
|
|
1213
|
+
return this.boundingBoxScene.distanceToPoint(p);
|
|
1214
|
+
}
|
|
1215
|
+
estimateNormal(p) {
|
|
1216
|
+
const epsilon = 0.001;
|
|
1217
|
+
const n = p.dim;
|
|
1218
|
+
const grad = [];
|
|
1219
|
+
const d = this.distanceToPoint(p);
|
|
1220
|
+
for (let i = 0;i < n; i++) {
|
|
1221
|
+
grad.push(this.distanceToPoint(p.add(Vec.e(n)(i).scale(epsilon))) - d);
|
|
1222
|
+
}
|
|
1223
|
+
return Vec.fromArray(grad).scale(Math.sign(d)).normalize();
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
|
|
1227
|
+
class Node {
|
|
1228
|
+
isLeaf = false;
|
|
1229
|
+
numberOfLeafs = 0;
|
|
1230
|
+
leafs = [];
|
|
1231
|
+
constructor() {
|
|
1232
|
+
this.box = Box.EMPTY;
|
|
1233
|
+
}
|
|
1234
|
+
add(element) {
|
|
1235
|
+
this.numberOfLeafs += 1;
|
|
1236
|
+
this.leafs.push(element);
|
|
1237
|
+
const elemBox = element.getBoundingBox();
|
|
1238
|
+
this.box = this.box.add(elemBox);
|
|
1239
|
+
if (!this.left) {
|
|
1240
|
+
this.left = new Leaf(element);
|
|
1241
|
+
} else if (!this.right) {
|
|
1242
|
+
this.right = new Leaf(element);
|
|
1243
|
+
} else {
|
|
1244
|
+
this._addElementWhenTreeIsFull(element, elemBox);
|
|
1245
|
+
}
|
|
1246
|
+
return this;
|
|
1247
|
+
}
|
|
1248
|
+
distanceToPoint(p) {
|
|
1249
|
+
if (this.numberOfLeafs <= 2) {
|
|
1250
|
+
return this.getElements().reduce((e, leaf) => smin(e, leaf.distanceToPoint(p)), 1000);
|
|
1251
|
+
}
|
|
1252
|
+
const children = [this.left, this.right];
|
|
1253
|
+
const index = argmin(children, (c) => c.box.distanceToPoint(p));
|
|
1254
|
+
return children[index].distanceToPoint(p);
|
|
1255
|
+
}
|
|
1256
|
+
getElements() {
|
|
1257
|
+
return this.leafs;
|
|
1258
|
+
}
|
|
1259
|
+
getRandomLeaf() {
|
|
1260
|
+
return Math.random() < 0.5 ? this.left.getRandomLeaf() : this.right.getRandomLeaf();
|
|
1261
|
+
}
|
|
1262
|
+
interceptWith(ray, depth = 1) {
|
|
1263
|
+
if (this.numberOfLeafs === 5) {
|
|
1264
|
+
return this.box.interceptWith(ray).map((p) => [p, this.box.estimateNormal(p)]);
|
|
1265
|
+
}
|
|
1266
|
+
return this.box.interceptWith(ray).flatMap((p) => {
|
|
1267
|
+
const children = [this.left, this.right].filter((x) => x);
|
|
1268
|
+
const hits = [];
|
|
1269
|
+
for (let i = 0;i < children.length; i++) {
|
|
1270
|
+
const maybeHit = children[i].interceptWith(ray, depth + 1);
|
|
1271
|
+
if (maybeHit.isSome())
|
|
1272
|
+
hits.push(maybeHit.orElse());
|
|
1273
|
+
}
|
|
1274
|
+
const minIndex = argmin(hits, ([point]) => point.sub(ray.init).length());
|
|
1275
|
+
if (minIndex === -1)
|
|
1276
|
+
return none();
|
|
1277
|
+
return some(hits[minIndex]);
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
_addElementWhenTreeIsFull(element, elemBox) {
|
|
1281
|
+
if (this.left.isLeaf && this.right.isLeaf) {
|
|
1282
|
+
this._addWithLeafs(element);
|
|
1283
|
+
} else {
|
|
1284
|
+
const minIndex = argmin([
|
|
1285
|
+
this.left.box.distanceToBox(elemBox),
|
|
1286
|
+
this.right.box.distanceToBox(elemBox)
|
|
1287
|
+
]);
|
|
1288
|
+
this._updateChildren(minIndex, element);
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
_updateChildren(minIndex, element) {
|
|
1292
|
+
let child = [this.left, this.right][minIndex];
|
|
1293
|
+
if (!child.isLeaf) {
|
|
1294
|
+
child.add(element);
|
|
1295
|
+
} else {
|
|
1296
|
+
const aux = child.element;
|
|
1297
|
+
if (minIndex === 0)
|
|
1298
|
+
this.left = new Node().add(aux).add(element);
|
|
1299
|
+
if (minIndex === 1)
|
|
1300
|
+
this.right = new Node().add(aux).add(element);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
_addWithLeafs(element) {
|
|
1304
|
+
const elemBox = element.getBoundingBox();
|
|
1305
|
+
const distances = [
|
|
1306
|
+
elemBox.distanceToBox(this.left.box),
|
|
1307
|
+
elemBox.distanceToBox(this.right.box),
|
|
1308
|
+
this.left.box.distanceToBox(this.right.box)
|
|
1309
|
+
];
|
|
1310
|
+
const index = argmin(distances);
|
|
1311
|
+
const index2Action = {
|
|
1312
|
+
0: () => {
|
|
1313
|
+
const aux = this.left;
|
|
1314
|
+
this.left = new Node;
|
|
1315
|
+
this.left.add(aux.element).add(element);
|
|
1316
|
+
},
|
|
1317
|
+
1: () => {
|
|
1318
|
+
const aux = this.right;
|
|
1319
|
+
this.right = new Node;
|
|
1320
|
+
this.right.add(aux.element).add(element);
|
|
1321
|
+
},
|
|
1322
|
+
2: () => {
|
|
1323
|
+
const aux = this.left;
|
|
1324
|
+
this.left = new Node;
|
|
1325
|
+
this.left.add(aux.element).add(this.right.element);
|
|
1326
|
+
this.right = new Leaf(element);
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
index2Action[index]();
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
class Leaf {
|
|
1334
|
+
isLeaf = true;
|
|
1335
|
+
constructor(element) {
|
|
1336
|
+
this.element = element;
|
|
1337
|
+
this.box = element.getBoundingBox();
|
|
1338
|
+
}
|
|
1339
|
+
distanceToPoint(x) {
|
|
1340
|
+
return this.element.distanceToPoint(x);
|
|
1341
|
+
}
|
|
1342
|
+
getLeafs() {
|
|
1343
|
+
return [this];
|
|
1344
|
+
}
|
|
1345
|
+
getRandomLeaf() {
|
|
1346
|
+
return this;
|
|
1347
|
+
}
|
|
1348
|
+
interceptWith(ray, depth) {
|
|
1349
|
+
return this.element.interceptWith(ray);
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
|
|
1353
|
+
// src/Ray/Ray.jstants.jss
|
|
1354
|
+
class NaiveScene {
|
|
1355
|
+
constructor() {
|
|
1356
|
+
this.id2ElemMap = {};
|
|
1357
|
+
this.sceneElements = [];
|
|
1358
|
+
}
|
|
1359
|
+
add(...elements) {
|
|
1360
|
+
return this.addList(elements);
|
|
1361
|
+
}
|
|
1362
|
+
addList(elements) {
|
|
1363
|
+
for (let i = 0;i < elements.length; i++) {
|
|
1364
|
+
const elem = elements[i];
|
|
1365
|
+
const classes = [Point_default];
|
|
1366
|
+
if (!classes.some((c) => elem instanceof c))
|
|
1367
|
+
return this;
|
|
1368
|
+
const { name } = elem;
|
|
1369
|
+
this.id2ElemMap[name] = elem;
|
|
1370
|
+
this.sceneElements.push(elem);
|
|
1371
|
+
}
|
|
1372
|
+
return this;
|
|
1373
|
+
}
|
|
1374
|
+
clear() {
|
|
1375
|
+
this.id2ElemMap = {};
|
|
1376
|
+
this.sceneElements = [];
|
|
1377
|
+
}
|
|
1378
|
+
getElements() {
|
|
1379
|
+
return this.sceneElements;
|
|
1380
|
+
}
|
|
1381
|
+
distanceToPoint(p) {
|
|
1382
|
+
const elements = this.sceneElements;
|
|
1383
|
+
let distance = Number.MAX_VALUE;
|
|
1384
|
+
for (let i = 0;i < elements.length; i++) {
|
|
1385
|
+
distance = smin(distance, elements[i].distanceToPoint(p));
|
|
1386
|
+
}
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
estimateNormal(p) {
|
|
1390
|
+
const epsilon = 0.001;
|
|
1391
|
+
const n = p.dim;
|
|
1392
|
+
const grad = [];
|
|
1393
|
+
const d = this.distanceToPoint(p);
|
|
1394
|
+
for (let i = 0;i < n; i++) {
|
|
1395
|
+
grad.push(this.distanceToPoint(p.add(Vec.e(n)(i).scale(epsilon))) - d);
|
|
1396
|
+
}
|
|
1397
|
+
return Vec.fromArray(grad).scale(Math.sign(d)).normalize();
|
|
1398
|
+
}
|
|
1399
|
+
interceptWith(ray) {
|
|
1400
|
+
const points = this.sceneElements;
|
|
1401
|
+
let closestDistance = Number.MAX_VALUE;
|
|
1402
|
+
let closest = none();
|
|
1403
|
+
for (let i = 0;i < points.length; i++) {
|
|
1404
|
+
points[i].interceptWith(ray).map(([pos, normal]) => {
|
|
1405
|
+
const distance = ray.init.sub(pos).length();
|
|
1406
|
+
if (distance < closestDistance) {
|
|
1407
|
+
closest = some([pos, normal]);
|
|
1408
|
+
closestDistance = distance;
|
|
1409
|
+
}
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
return closest;
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// src/Ray/Ray.jstan
|
|
1417
|
+
var RADIUS = 0.001;
|
|
1418
|
+
|
|
1419
|
+
class Mesh {
|
|
1420
|
+
constructor({ vertices, normals, textureCoords, faces, colors }) {
|
|
1421
|
+
this.vertices = vertices || [];
|
|
1422
|
+
this.normals = normals || [];
|
|
1423
|
+
this.textureCoords = textureCoords || [];
|
|
1424
|
+
this.faces = faces || [];
|
|
1425
|
+
this.colors = colors || [];
|
|
1426
|
+
}
|
|
1427
|
+
mapVertices(lambda) {
|
|
1428
|
+
const newVertices = [];
|
|
1429
|
+
for (let i = 0;i < this.vertices.length; i++) {
|
|
1430
|
+
newVertices.push(lambda(this.vertices[i]));
|
|
1431
|
+
}
|
|
1432
|
+
return new Mesh({
|
|
1433
|
+
vertices: newVertices,
|
|
1434
|
+
normals: this.normals,
|
|
1435
|
+
textureCoords: this.textureCoords,
|
|
1436
|
+
faces: this.faces
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
mapColors(lambda) {
|
|
1440
|
+
const newColors = [];
|
|
1441
|
+
for (let i = 0;i < this.vertices.length; i++) {
|
|
1442
|
+
newColors.push(lambda(this.vertices[i]));
|
|
1443
|
+
}
|
|
1444
|
+
return new Mesh({
|
|
1445
|
+
vertices: this.vertices,
|
|
1446
|
+
normals: this.normals,
|
|
1447
|
+
textureCoords: this.textureCoords,
|
|
1448
|
+
faces: this.faces,
|
|
1449
|
+
colors: newColors
|
|
1450
|
+
});
|
|
1451
|
+
}
|
|
1452
|
+
getBoundingBox() {
|
|
1453
|
+
if (this.boundingBox)
|
|
1454
|
+
return this.boundingBox;
|
|
1455
|
+
this.boundingBox = new Box;
|
|
1456
|
+
for (let i = 0;i < this.vertices.length; i++) {
|
|
1457
|
+
this.boundingBox = this.boundingBox.add(new Box(this.vertices[i].add(Vec3(1, 1, 1).scale(RADIUS)), this.vertices[i].add(Vec3(1, 1, 1).scale(RADIUS))));
|
|
1458
|
+
}
|
|
1459
|
+
return this.boundingBox;
|
|
1460
|
+
}
|
|
1461
|
+
asPoints(name, radius = RADIUS) {
|
|
1462
|
+
const points = [];
|
|
1463
|
+
for (let i = 0;i < this.vertices.length; i++) {
|
|
1464
|
+
points.push(Point_default.builder().radius(radius).name(`${name}_${i}`).color(this.colors[i]).position(this.vertices[i]).normal(this.normals[i] || Vec3(1, 0, 0)).build());
|
|
1465
|
+
}
|
|
1466
|
+
return points;
|
|
1467
|
+
}
|
|
1468
|
+
static readObj(objFile) {
|
|
1469
|
+
const vertices = [];
|
|
1470
|
+
const normals = [];
|
|
1471
|
+
const texture = [];
|
|
1472
|
+
const faces = [];
|
|
1473
|
+
objFile.split("\n").forEach((lines) => {
|
|
1474
|
+
const spaces = lines.split(" ");
|
|
1475
|
+
const type = spaces[0];
|
|
1476
|
+
if (type === "v") {
|
|
1477
|
+
const v = spaces.slice(1, 4).map((x) => Number.parseFloat(x));
|
|
1478
|
+
vertices.push(Vec3(...v));
|
|
1479
|
+
}
|
|
1480
|
+
if (type === "vn") {
|
|
1481
|
+
const v = spaces.slice(1, 4).map((x) => Number.parseFloat(x));
|
|
1482
|
+
normals.push(Vec3(...v));
|
|
1483
|
+
}
|
|
1484
|
+
if (type === "vt") {
|
|
1485
|
+
const v = spaces.slice(1, 3).map((x) => Number.parseFloat(x));
|
|
1486
|
+
texture.push(Vec2(...v));
|
|
1487
|
+
}
|
|
1488
|
+
if (type === "f") {
|
|
1489
|
+
}
|
|
1490
|
+
});
|
|
1491
|
+
return new Mesh({ vertices, normals, texture, faces });
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
export {
|
|
1495
|
+
Vec3,
|
|
1496
|
+
Vec2,
|
|
1497
|
+
Vec,
|
|
1498
|
+
exports_Utils as Utils,
|
|
1499
|
+
Stream,
|
|
1500
|
+
Scene,
|
|
1501
|
+
Point_default as Point,
|
|
1502
|
+
NaiveScene,
|
|
1503
|
+
exports_Monads as Monads,
|
|
1504
|
+
Mesh,
|
|
1505
|
+
DomBuilder_default as DOM,
|
|
1506
|
+
Color,
|
|
1507
|
+
Canvas,
|
|
1508
|
+
Camera,
|
|
1509
|
+
Box,
|
|
1510
|
+
Animation
|
|
1511
|
+
};
|