@pirireis/webglobeplugins 0.6.49-a → 0.7.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.
@@ -0,0 +1,155 @@
1
+ import { densityToLegendProgramCache } from "../programs/data2legend/density-to-legend";
2
+ import { pointToDensityTextureCache } from "../programs/data2legend/point-to-density-texture";
3
+ import { textureOnCanvasProgramCache } from "../util/programs/draw-texture-on-canvas";
4
+ import { defaultblendfunction } from "../util/webglobe/gldefaultstates";
5
+ class PointHeatmapFlow {
6
+
7
+ constructor(globe) {
8
+ this.globe = null;
9
+ this.gl = null;
10
+ this.program = null;
11
+ this.densityToLegendProgram = null;
12
+ this.globe = globe;
13
+ this.gl = globe.gl;
14
+ this.pointToDensityProgram = pointToDensityTextureCache.get(globe);
15
+ this.densityToLegendProgram = densityToLegendProgramCache.get(globe);
16
+ this.testTextureProgram = textureOnCanvasProgramCache.get(globe);
17
+ this._lookInfo = globe.api_GetCurrentLookInfo();
18
+ const { gl } = this;
19
+ {
20
+ this.buffer = gl.createBuffer();
21
+ this.vao2D = this.pointToDensityProgram.createVAO(this.buffer, 2);
22
+ this.vao3D = this.pointToDensityProgram.createVAO(this.buffer, 3);
23
+ }
24
+ { // framebuffer and texture
25
+ this.framebuffer = gl.createFramebuffer();
26
+ this.densityTexture = this._createDensityTexture();
27
+ this._bindTextureToFramebuffer();
28
+
29
+ }
30
+ }
31
+
32
+ _bindTextureToFramebuffer() {
33
+ const { gl, densityTexture, framebuffer } = this;
34
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
35
+ gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, densityTexture, 0);
36
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
37
+ }
38
+
39
+
40
+ draw(legendTexture, pointSize, opacity = 1.0) {
41
+ const { gl, globe, framebuffer } = this;
42
+ if (this._drawDensityRequired || this._isVisionChanged()) {
43
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
44
+ gl.clearColor(0, 0, 0, 0);
45
+ gl.viewport(
46
+ 0, 0,
47
+ Math.floor(globe.api_ScrW()), Math.floor(globe.api_ScrH())
48
+ );
49
+ gl.clear(gl.COLOR_BUFFER_BIT);
50
+ this._drawDensity(pointSize);
51
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
52
+ }
53
+ defaultblendfunction(gl);
54
+ gl.viewport(0, 0, 400, 400);
55
+ this.testTextureProgram.draw(legendTexture, 1.0);
56
+ gl.viewport(0, 400, 400, 400);
57
+ this.testTextureProgram.draw(this.densityTexture, 1.0);
58
+ gl.viewport(0, 0, globe.api_ScrW(), globe.api_ScrH());
59
+ this._drawLegend(legendTexture, opacity);
60
+ }
61
+
62
+
63
+ resize() {
64
+ const { gl, densityTexture } = this;
65
+ gl.deleteTexture(densityTexture);
66
+ this.densityTexture = this._createDensityTexture();
67
+ this._bindTextureToFramebuffer();
68
+ this._drawDensityRequired = true;
69
+ }
70
+
71
+
72
+ // USER API
73
+
74
+ /**
75
+ * @param {Float32Array} data
76
+ * @format [x, y, z, height] x,y,z is normalized 3d cartesian coordinates. Height in kilometers. Set 6371.137 for ground level.
77
+ */
78
+ setData(data) {
79
+ const { gl, buffer } = this;
80
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
81
+ gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
82
+ // use program
83
+ this.dataLength = data.length;
84
+ this._drawDensityRequired = true;
85
+ this.globe.DrawRender();
86
+ }
87
+
88
+ // implicit Methods
89
+
90
+ _createDensityTexture() {
91
+ const { gl, globe } = this;
92
+ const width = Math.floor(globe.api_ScrW())
93
+ const height = Math.floor(globe.api_ScrH());
94
+ const texture = gl.createTexture();
95
+ gl.bindTexture(gl.TEXTURE_2D, texture);
96
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
97
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
98
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
99
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
100
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
101
+ return texture;
102
+ }
103
+
104
+
105
+ _drawDensity(pointSize) {
106
+ const { gl, globe, pointToDensityProgram, vao2D, vao3D, dataLength } = this;
107
+ const is3D = globe.api_GetCurrentGeometry() === 0;
108
+ const vao = is3D ? vao3D : vao2D;
109
+ const length = dataLength / (is3D ? 3 : 2);
110
+ gl.blendEquation(gl.FUNC_ADD);
111
+ gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE, gl.SRC_ALPHA, gl.ONE);
112
+ pointToDensityProgram.draw(vao, length, pointSize);
113
+
114
+ this._drawDensityRequired = false;
115
+ }
116
+
117
+
118
+ _drawLegend(legendTexture, opacity) {
119
+ const { densityToLegendProgram, densityTexture } = this;
120
+ densityToLegendProgram.draw(densityTexture, legendTexture, opacity);
121
+ }
122
+
123
+
124
+ _isVisionChanged() {
125
+ const currentLookInfo = this.globe.api_GetCurrentLookInfo();
126
+ const _lookInfo = this._lookInfo;
127
+ if (
128
+ currentLookInfo.CenterLong !== _lookInfo.CenterLong ||
129
+ currentLookInfo.CenterLat !== _lookInfo.CenterLat ||
130
+ currentLookInfo.Distance !== _lookInfo.Distance ||
131
+ currentLookInfo.Tilt !== _lookInfo.Tilt ||
132
+ currentLookInfo.NorthAng !== _lookInfo.NorthAng
133
+ ) {
134
+ this._lookInfo = currentLookInfo;
135
+ return true;
136
+ }
137
+ return false;
138
+ }
139
+
140
+
141
+ free() {
142
+ if (this._isFreed) return;
143
+ this._isFreed = true;
144
+ densityToLegendProgramCache.release(this.globe);
145
+ pointToDensityTextureCache.release(this.globe);
146
+ this.gl.deleteTexture(this.densityTexture);
147
+ this.gl.deleteFramebuffer(this.framebuffer);
148
+ this.gl.deleteBuffer(this.buffer);
149
+ this.gl.deleteVertexArray(this.vao2D);
150
+ this.gl.deleteVertexArray(this.vao3D);
151
+ }
152
+ }
153
+
154
+
155
+ export { PointHeatmapFlow };
@@ -0,0 +1,15 @@
1
+ # Content
2
+
3
+ point-heat-map/
4
+ ├── plugin.js
5
+ └── point-to-heat-flow.js
6
+
7
+ ## plugin.js
8
+
9
+ Contains plugin plugin that calculates data on main thread.
10
+
11
+ ## point-to-heat-flow.js
12
+
13
+ Contains a wrapper around point-to-density and density-to-color-ramp programs.
14
+
15
+ The reason behind seperation of program flow and plugin is to explore web-worker version of interpolation and compare it with main thread version.
@@ -0,0 +1,115 @@
1
+ import { createProgram } from "../../util/";
2
+ import { noRegisterGlobeProgramCache } from "../programcache";
3
+
4
+
5
+ const vs = `#version 300 es
6
+ precision highp float;
7
+
8
+ uniform sampler2D u_density_texture;
9
+ in vec2 a_position;
10
+
11
+ out vec2 v_texcoord;
12
+
13
+ void main() {
14
+ gl_Position = vec4(a_position, 0.0, 1.0);
15
+ v_texcoord = a_position * 0.5 + 0.5;
16
+ }`;
17
+
18
+
19
+ const fs = `#version 300 es
20
+ precision highp float;
21
+
22
+ uniform sampler2D u_legend_texture;
23
+ uniform sampler2D u_density_texture;
24
+
25
+ uniform float u_opacity;
26
+ in vec2 v_texcoord;
27
+ out vec4 fragColor;
28
+
29
+ void main() {
30
+ float density = texture(u_density_texture, v_texcoord).r;
31
+ fragColor = texture(u_legend_texture, vec2(density, 0.5));
32
+ fragColor.a *= u_opacity * sqrt(density);
33
+ }`;
34
+
35
+
36
+
37
+
38
+ class DensityToLegendProgram {
39
+ constructor(globe) {
40
+ this.globe = globe;
41
+ this.gl = globe.gl;
42
+ this.program = createProgram(globe.gl, vs, fs);
43
+ const { gl, program } = this;
44
+ this.uniforms = {
45
+ densityTexture: gl.getUniformLocation(program, "u_density_texture"),
46
+ legendTexture: gl.getUniformLocation(program, "u_legend_texture"),
47
+ opacity: gl.getUniformLocation(program, "u_opacity"),
48
+ }
49
+ { // assign attribute locations
50
+ gl.bindAttribLocation(program, 0, "a_position");
51
+ }
52
+ {
53
+ this.vao = gl.createVertexArray();
54
+ const a_positionLocation = gl.getAttribLocation(program, "a_position");
55
+ gl.bindVertexArray(this.vao);
56
+
57
+ const buffer = gl.createBuffer();
58
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
59
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
60
+ -1, -1,
61
+ 1, -1,
62
+ 1, 1,
63
+ -1, 1,
64
+ ]), gl.STATIC_DRAW);
65
+ gl.enableVertexAttribArray(a_positionLocation);
66
+ gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
67
+ gl.bindVertexArray(null);
68
+ // gl.bindBuffer(gl.ARRAY_BUFFER, null);
69
+ this._buffer = buffer;
70
+ }
71
+
72
+ {
73
+ this._lastOpacity = 1;
74
+ const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM);
75
+ gl.useProgram(program);
76
+ gl.uniform1f(this.uniforms.opacity, this._lastOpacity);
77
+ gl.useProgram(currentProgram);
78
+ }
79
+ }
80
+
81
+
82
+ draw(densityTexture, legendTexture, opacity) {
83
+ const { gl, program, uniforms } = this;
84
+ gl.useProgram(program);
85
+ gl.bindVertexArray(this.vao);
86
+ gl.activeTexture(gl.TEXTURE1);
87
+ gl.bindTexture(gl.TEXTURE_2D, legendTexture);
88
+ gl.uniform1i(uniforms.legendTexture, 1);
89
+ gl.activeTexture(gl.TEXTURE0);
90
+ gl.bindTexture(gl.TEXTURE_2D, densityTexture);
91
+ gl.uniform1i(uniforms.densityTexture, 0);
92
+ if (this._lastOpacity !== opacity) {
93
+ gl.uniform1f(uniforms.opacity, opacity);
94
+ this._lastOpacity = opacity;
95
+ }
96
+ gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
97
+ gl.bindVertexArray(null);
98
+ }
99
+
100
+
101
+ free() {
102
+ const gl = this.gl;
103
+ gl.deleteVertexArray(this.vao);
104
+ gl.deleteBuffer(this._buffer);
105
+ gl.deleteProgram(this.program);
106
+ }
107
+ }
108
+
109
+
110
+ const densityToLegendProgramCache = {
111
+ get: (globe) => noRegisterGlobeProgramCache.getProgram(globe, DensityToLegendProgram),
112
+ release: (globe) => noRegisterGlobeProgramCache.releaseProgram(globe, DensityToLegendProgram)
113
+ }
114
+
115
+ export { densityToLegendProgramCache };
@@ -0,0 +1,114 @@
1
+ import { createProgram } from "../../util/";
2
+ import { noRegisterGlobeProgramCache } from "../programcache";
3
+ import { CameraUniformBlockTotemCache, CameraUniformBlockString } from "../totems/camerauniformblock";
4
+ import { mercatorXYToGLPosition, cartesian3DToGLPosition } from "../../util/shaderfunctions/geometrytransformations";
5
+
6
+
7
+ const vs = `#version 300 es
8
+ precision highp float;
9
+
10
+ ${CameraUniformBlockString}
11
+ ${mercatorXYToGLPosition}
12
+ ${cartesian3DToGLPosition}
13
+
14
+ in vec3 position;
15
+ uniform float pointSize;
16
+
17
+ void main() {
18
+ if (is3D) {
19
+ gl_Position = cartesian3DToGLPosition(position);
20
+ } else {
21
+ gl_Position = mercatorXYToGLPosition(position.xy);
22
+ }
23
+ gl_PointSize = pointSize;
24
+ }
25
+ `;
26
+
27
+
28
+ const fs = `#version 300 es
29
+ precision highp float;
30
+ out vec4 fragColor;
31
+
32
+ void main() {
33
+ float r = length(gl_PointCoord - 0.5) * 2.0;
34
+ if (r > 1.0) discard;
35
+ // float density = smoothstep(0.1, 1.0, 1.0 - r);
36
+ fragColor = vec4((15.0/16.0)*sqrt(1.0-sqrt(r)));
37
+ }`;
38
+
39
+
40
+
41
+ class PointHeatmapProgram {
42
+
43
+ constructor(globe) {
44
+ this.globe = globe;
45
+ this.gl = globe.gl;
46
+ this._isFreed = false;
47
+ this.program = createProgram(globe.gl, vs, fs);
48
+
49
+ const { gl, program } = this;
50
+ this.uniforms = {
51
+ pointSize: gl.getUniformLocation(this.program, "pointSize"),
52
+ }
53
+ { // assign attribute locations
54
+ gl.bindAttribLocation(program, 0, "position");
55
+ }
56
+
57
+ { // arrange camera uniform block
58
+ this.cameraBlockBingingPoint = 0;
59
+ this.cameraBlockTotem = CameraUniformBlockTotemCache.get(globe);
60
+ const cameraBlockIndex = gl.getUniformBlockIndex(program, "CameraUniformBlock");
61
+ gl.uniformBlockBinding(program, cameraBlockIndex, this.cameraBlockBingingPoint);
62
+ }
63
+
64
+ { // last values
65
+ this._lastPointSize = 0;
66
+
67
+ const currentProgram = gl.getParameter(gl.CURRENT_PROGRAM);
68
+ gl.useProgram(program);
69
+ gl.uniform1f(this.uniforms.pointSize, this._lastPointSize);
70
+ gl.useProgram(currentProgram);
71
+ }
72
+ }
73
+
74
+
75
+ createVAO(positionBuffer, vectorSize) {
76
+ const gl = this.gl;
77
+ const vao = gl.createVertexArray();
78
+ gl.bindVertexArray(vao);
79
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
80
+ gl.enableVertexAttribArray(0);
81
+ gl.vertexAttribPointer(0, vectorSize, gl.FLOAT, false, 0, 0);
82
+ gl.bindVertexArray(null);
83
+ return vao;
84
+ }
85
+
86
+ draw(vao, length, pointSize = 5.0) {
87
+ const gl = this.gl;
88
+ gl.useProgram(this.program);
89
+ if (pointSize !== this._lastPointSize) {
90
+ gl.uniform1f(this.uniforms.pointSize, pointSize);
91
+ this._lastPointSize = pointSize;
92
+ }
93
+ gl.bindVertexArray(vao);
94
+ this.cameraBlockTotem.bind(this.cameraBlockBingingPoint);
95
+ gl.drawArrays(gl.POINTS, 0, length);
96
+ this.cameraBlockTotem.unbind(this.cameraBlockBingingPoint);
97
+ gl.bindVertexArray(null);
98
+ }
99
+
100
+ free() {
101
+ if (this._isFreed) return;
102
+ const { gl, globe } = this;
103
+ CameraUniformBlockTotemCache.release(globe);
104
+ gl.deleteProgram(this.program);
105
+ this._isFreed = true;
106
+ }
107
+ }
108
+
109
+ const pointToDensityTextureCache = {
110
+ get: (globe) => noRegisterGlobeProgramCache.getProgram(globe, PointHeatmapProgram),
111
+ release: (globe) => noRegisterGlobeProgramCache.releaseProgram(globe, PointHeatmapProgram)
112
+ }
113
+
114
+ export { pointToDensityTextureCache };
@@ -19,7 +19,7 @@ import {
19
19
  * center_position is too small or doenst loaded as expected.
20
20
  */
21
21
 
22
- const INITIAL_EDGE_COUNT = 360;
22
+ const INITIAL_EDGE_COUNT = 720;
23
23
 
24
24
  const vertexShaderSource = `#version 300 es
25
25
  precision highp float;
@@ -86,7 +86,7 @@ class Logic {
86
86
  this.gl = globe.gl;
87
87
  this._lastOpacity = 1.0;
88
88
  this._lastEdgeCount = INITIAL_EDGE_COUNT;
89
- this._lastStepAngle = 360 / INITIAL_EDGE_COUNT;
89
+ this._lastStepAngle = 720 / INITIAL_EDGE_COUNT;
90
90
  this._lastZAlphaMode = Z_ALPHA_MODE.ON;
91
91
  this.program = createProgram(this.gl, vertexShaderSource, fragmentShaderSource);
92
92
 
@@ -103,7 +103,7 @@ class Logic {
103
103
  gl.useProgram(program);
104
104
  gl.uniform1f(program.uniforms.opacity, 1.0);
105
105
  gl.uniform1f(program.uniforms.edgeCount, INITIAL_EDGE_COUNT * 2);
106
- gl.uniform1f(program.uniforms.stepAngle, this._lastStepAngle * Math.PI / 180);
106
+ gl.uniform1f(program.uniforms.stepAngle, this._lastStepAngle * Math.PI / 360);
107
107
  gl.uniform1i(program.uniforms.zAlphaMode, Z_ALPHA_MODE.ON);
108
108
  gl.useProgram(currentProgram);
109
109
  }
@@ -162,7 +162,7 @@ class Logic {
162
162
  this._lastEdgeCount = edgeCount;
163
163
  }
164
164
  if (this._lastStepAngle !== stepAngle) {
165
- gl.uniform1f(program.uniforms.stepAngle, stepAngle * Math.PI / 180);
165
+ gl.uniform1f(program.uniforms.stepAngle, stepAngle * Math.PI / 360);
166
166
  this._lastStepAngle = stepAngle;
167
167
  }
168
168
  if (this._lastZAlphaMode !== zAlphaMode) {
@@ -69,7 +69,7 @@ function fillSliceOfFloat32ArrayLineStrip(floatArray, offset, coordinates, times
69
69
  }
70
70
 
71
71
  function addCuttingPointLineStrip(floatArray, offset) {
72
- floatArray.set([0, 0, 0, 0, -1.0, -1.0, -1.0, 0, 0], offset);
72
+ floatArray.set(new Float32Array(9).fill(NaN), offset);
73
73
  return offset + 9;
74
74
  }
75
75
 
@@ -628,7 +628,7 @@ void main() {
628
628
  gl.uniform3fv(_lineProgram.uTranslate, uTranslate);
629
629
 
630
630
  gl.bindVertexArray(_lineProgram.vao);
631
- gl.drawArrays(gl.LINE_STRIP, 0, this._totalLength); // TODO: line_strip with thombstone to reduce buffer size in half
631
+ gl.drawArrays(gl.LINE_STRIP, 0, this._totalLength);
632
632
  gl.drawBuffers([
633
633
  gl.COLOR_ATTACHMENT0,
634
634
  gl.NONE
@@ -786,7 +786,7 @@ void main() {
786
786
  gl.uniform3fv(_lineProgram.uTranslate, uTranslate);
787
787
 
788
788
  gl.bindVertexArray(_lineProgram.vao);
789
- gl.drawArrays(gl.LINES, 0, this._totalLength); // TODO: line_strip with thombstone to reduce buffer size in half
789
+ gl.drawArrays(gl.LINES, 0, this._totalLength);
790
790
  gl.drawBuffers([
791
791
  gl.COLOR_ATTACHMENT0,
792
792
  gl.NONE
@@ -78,7 +78,7 @@ export default class {
78
78
  {
79
79
  const { gl, _globalsbuffer } = this;
80
80
  gl.bindBuffer(gl.UNIFORM_BUFFER, _globalsbuffer);
81
- gl.bufferData(gl.UNIFORM_BUFFER, 12, gl.STREAM_DRAW); // TODO: sperate head time to make it dynamic maybe?
81
+ gl.bufferData(gl.UNIFORM_BUFFER, 12, gl.STREAM_DRAW);
82
82
  gl.bufferSubData(gl.UNIFORM_BUFFER, 0, new Float32Array([0, options.opacity, options.pointSize]));
83
83
  gl.bindBufferBase(gl.UNIFORM_BUFFER, this._globalsBlockBindingPoint, _globalsbuffer);
84
84
  gl.bindBuffer(gl.UNIFORM_BUFFER, null);
@@ -71,7 +71,7 @@ export default class {
71
71
  {
72
72
  const { gl, _globalsbuffer } = this;
73
73
  gl.bindBuffer(gl.UNIFORM_BUFFER, _globalsbuffer);
74
- gl.bufferData(gl.UNIFORM_BUFFER, 12, gl.STREAM_DRAW); // TODO: sperate head time to make it dynamic maybe?
74
+ gl.bufferData(gl.UNIFORM_BUFFER, 12, gl.STREAM_DRAW);
75
75
  gl.bufferSubData(gl.UNIFORM_BUFFER, 0, new Float32Array([0, options.opacity, options.pointSize]));
76
76
  gl.bindBufferBase(gl.UNIFORM_BUFFER, this._globalsBlockBindingPoint, _globalsbuffer);
77
77
  gl.bindBuffer(gl.UNIFORM_BUFFER, null);
@@ -0,0 +1 @@
1
+ TODO: delete program, programpoint, maybe adaptors. which are related to the old version of this plugin.
File without changes
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @typedef {Array<number>} ListLike
3
+ * @typedef {number || null} Index
4
+ */
5
+
6
+ /**
7
+ * @param {ListLike} container
8
+ * @param {number} value
9
+ * @returns {Index}
10
+ */
11
+ const findFirstIndexInRange = (container, value) => {
12
+ let start = 0;
13
+ let end = container.length - 1;
14
+ let mid = 0;
15
+ while (start <= end) {
16
+ mid = Math.floor((start + end) / 2);
17
+ if (container[mid] <= value && value <= container[mid + 1]) return mid;
18
+ if (container[mid] < value) start = mid + 1;
19
+ else end = mid - 1;
20
+ }
21
+ return null;
22
+ }
23
+
24
+
25
+ export { findFirstIndexInRange };
26
+
File without changes
File without changes
@@ -0,0 +1,89 @@
1
+ import { findFirstIndexInRange } from '../../algorithms/search-binary';
2
+ import {
3
+ sphericalLinearInterpolation_Cartesian3d,
4
+ sphericalLinearInterpolation_Mercator,
5
+ } from '../../../Math/methods';
6
+
7
+
8
+ /**
9
+ * @typedef {Array<number>} vec3 [x, y, z]
10
+ * @typedef {Array<number>} vec2 [x, y]
11
+ * @typedef {Array<number>} vec4 [x, y, z, w]
12
+ * @typedef {number} fraction a number between 0 and 1
13
+ * @typedef {Array<number>} wgs84 [long, lat]
14
+ */
15
+
16
+ const GEOMETRY = Object.freeze({
17
+ CARTESIAN3D: 0,
18
+ MERCATOR: 1,
19
+ });
20
+
21
+ class TimeTrackInterpolator {
22
+ /**
23
+ * @typedef Timetrack
24
+ * @property {Array<vec4>}} coordinates [x,y,z, length]
25
+ * @property {Array<Number>} times
26
+ * @param {Array<Timetrack>} timeTracks
27
+ */
28
+ constructor({ timeTracks, bbox = null, geometry = GEOMETRY.CARTESIAN3D } = {}) {
29
+ this.timeTracks = null;
30
+ this.timeTracksStartTimes = null;
31
+ this.geometry = geometry;
32
+ if (timeTracks) this.setTimetracks(timeTracks);
33
+ if (bbox) this.setBbox(bbox);
34
+ }
35
+
36
+
37
+ setGeometry(geometry) {
38
+ if (geometry !== GEOMETRY.CARTESIAN3D && geometry !== GEOMETRY.MERCATOR) {
39
+ throw new Error('Invalid geometry');
40
+ }
41
+ this.geometry = geometry;
42
+ }
43
+
44
+ setTimetracks(timeTracks) {
45
+ console.log("timetracks:", timeTracks);
46
+ this.timeTracks = timeTracks;
47
+ }
48
+
49
+
50
+ interpolate(time) {
51
+ const { timeTracks, geometry } = this;
52
+ if (!timeTracks) { return null; }
53
+ const resultArray = [];
54
+ const info = {
55
+ outOfRange: 0,
56
+ processed: 0,
57
+ }
58
+ for (let i = 0; i < timeTracks.length; i++) {
59
+ const { times, coordinates } = timeTracks[i];
60
+
61
+ if (times[times.length - 1] < time) continue;
62
+ info.processed++;
63
+ const timeIndex = findFirstIndexInRange(times, time);
64
+ if (timeIndex === null) { info.outOfRange++; continue; }
65
+ const timeFraction = (time - times[timeIndex]) / (times[timeIndex + 1] - times[timeIndex]);
66
+ const interpolated = (geometry === GEOMETRY.CARTESIAN3D) ?
67
+ sphericalLinearInterpolation_Cartesian3d(coordinates[timeIndex], coordinates[timeIndex + 1], timeFraction) :
68
+ sphericalLinearInterpolation_Mercator(coordinates[timeIndex], coordinates[timeIndex + 1], timeFraction);
69
+ resultArray.push(...interpolated);
70
+ }
71
+ return new Float32Array(resultArray);
72
+ }
73
+
74
+
75
+ // implicit methods
76
+
77
+ _orderTimeTracks() {
78
+ this.timeTracks.sort((a, b) => a.times[0] - b.times[0]);
79
+ }
80
+
81
+ _setStartTimes() {
82
+ this.timeTracksStartTimes = this.timeTracks.map(tt => tt.times[0]);
83
+ }
84
+
85
+
86
+ }
87
+
88
+
89
+ export { TimeTrackInterpolator, GEOMETRY };
@@ -0,0 +1,46 @@
1
+ import { TimeTrackInterpolator, GEOMETRY } from './timetrack-interpolator';
2
+
3
+
4
+ const interpolator = new TimeTrackInterpolator({ geometry: GEOMETRY.CARTESIAN3D });
5
+
6
+ /* eslint-disable-next-line no-restricted-globals */
7
+ self.onmessage = function (e) {
8
+
9
+ const { geometry = null, timeTracks = null, time = null } = e.data;
10
+
11
+ if (geometry !== null) {
12
+ try {
13
+ interpolator.setGeometry(geometry);
14
+ } catch (error) {
15
+ /* eslint-disable-next-line no-restricted-globals */
16
+ self.postMessage({ error: error.message });
17
+ return;
18
+ }
19
+ }
20
+
21
+ if (timeTracks !== null) {
22
+ try {
23
+ interpolator.setTimetracks(timeTracks);
24
+ } catch (error) {
25
+ /* eslint-disable-next-line no-restricted-globals */
26
+ self.postMessage({ error: error.message });
27
+ return;
28
+ }
29
+ }
30
+
31
+ if (time !== null) {
32
+ try {
33
+ const result = interpolator.interpolate(time);
34
+ /* eslint-disable-next-line no-restricted-globals */
35
+ self.postMessage(result, [result.buffer]);
36
+ return;
37
+ } catch (error) {
38
+ /* eslint-disable-next-line no-restricted-globals */
39
+ self.postMessage({ error: error.message });
40
+ return;
41
+ }
42
+ }
43
+ /* eslint-disable-next-line no-restricted-globals */
44
+ self.postMessage(true);
45
+ }
46
+