autumnplot-gl 4.0.0-beta → 4.1.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 +13 -207
- package/dist/812.autumnplot-gl.js +2 -0
- package/dist/812.autumnplot-gl.js.map +1 -0
- package/dist/983.autumnplot-gl.js +2 -0
- package/dist/983.autumnplot-gl.js.map +1 -0
- package/dist/autumnplot-gl.js +1 -1
- package/dist/autumnplot-gl.js.map +1 -1
- package/dist/marchingsquares.wasm +0 -0
- package/lib/AutumnTypes.d.ts +38 -5
- package/lib/AutumnTypes.js +7 -1
- package/lib/Barbs.d.ts +12 -2
- package/lib/Barbs.js +9 -0
- package/lib/BillboardCollection.d.ts +2 -2
- package/lib/BillboardCollection.js +14 -14
- package/lib/Color.d.ts +1 -0
- package/lib/Color.js +1 -0
- package/lib/ColorBar.d.ts +14 -0
- package/lib/ColorBar.js +15 -8
- package/lib/Colormap.d.ts +9 -1
- package/lib/Colormap.js +24 -1
- package/lib/Contour.d.ts +26 -1
- package/lib/Contour.js +24 -2
- package/lib/ContourCreator.worker.d.ts +25 -0
- package/lib/{ContourCreator.js → ContourCreator.worker.js} +15 -14
- package/lib/Fill.d.ts +31 -11
- package/lib/Fill.js +38 -18
- package/lib/Hodographs.d.ts +19 -3
- package/lib/Hodographs.js +45 -20
- package/lib/Map.d.ts +13 -1
- package/lib/Map.js +62 -8
- package/lib/Paintball.d.ts +14 -5
- package/lib/Paintball.js +96 -46
- package/lib/PlotComponent.d.ts +9 -3
- package/lib/PlotComponent.js +36 -1
- package/lib/PlotLayer.d.ts +2 -2
- package/lib/PlotLayer.js +2 -2
- package/lib/PlotLayer.worker.js +9 -3
- package/lib/RawField.d.ts +223 -27
- package/lib/RawField.js +413 -59
- package/lib/StationPlot.d.ts +78 -11
- package/lib/StationPlot.js +113 -30
- package/lib/TextCollection.d.ts +5 -0
- package/lib/TextCollection.js +82 -9
- package/lib/WasmInterface.d.ts +7 -0
- package/lib/WasmInterface.js +11 -0
- package/lib/WorkerPool.d.ts +8 -0
- package/lib/WorkerPool.js +77 -0
- package/lib/cpp/marchingsquares.js +127 -13
- package/lib/cpp/marchingsquares.wasm +0 -0
- package/lib/cpp/marchingsquares_embind.d.ts +16 -3
- package/lib/grids/AutoZoom.d.ts +21 -0
- package/lib/grids/AutoZoom.js +63 -0
- package/lib/grids/DomainBuffer.d.ts +14 -0
- package/lib/grids/DomainBuffer.js +16 -0
- package/lib/grids/Geostationary.d.ts +35 -0
- package/lib/grids/Geostationary.js +47 -0
- package/lib/grids/Grid.d.ts +36 -0
- package/lib/grids/Grid.js +12 -0
- package/lib/grids/GridCoordinates.d.ts +10 -0
- package/lib/grids/GridCoordinates.js +64 -0
- package/lib/grids/LambertGrid.d.ts +73 -0
- package/lib/grids/LambertGrid.js +92 -0
- package/lib/grids/PlateCarreeGrid.d.ts +46 -0
- package/lib/grids/PlateCarreeGrid.js +55 -0
- package/lib/grids/PlateCarreeRotatedGrid.d.ts +53 -0
- package/lib/grids/PlateCarreeRotatedGrid.js +65 -0
- package/lib/grids/RadarSweepGrid.d.ts +46 -0
- package/lib/grids/RadarSweepGrid.js +74 -0
- package/lib/grids/StructuredGrid.d.ts +49 -0
- package/lib/grids/StructuredGrid.js +103 -0
- package/lib/grids/UnstructuredGrid.d.ts +56 -0
- package/lib/grids/UnstructuredGrid.js +102 -0
- package/lib/index.d.ts +23 -6
- package/lib/index.js +18 -8
- package/lib/utils.d.ts +11 -2
- package/lib/utils.js +63 -1
- package/package.json +4 -3
- package/dist/110.autumnplot-gl.js +0 -2
- package/dist/110.autumnplot-gl.js.map +0 -1
- package/lib/ContourCreator.d.ts +0 -22
- package/lib/Grid.d.ts +0 -263
- package/lib/Grid.js +0 -547
- package/lib/ParticleTracer.d.ts +0 -19
- package/lib/ParticleTracer.js +0 -37
package/lib/Paintball.js
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
import { getRendererData } from "./AutumnTypes";
|
|
2
2
|
import { Color } from "./Color";
|
|
3
|
-
import { PlotComponent } from "./PlotComponent";
|
|
3
|
+
import { PlotComponent, getGLFormatTypeAlignment } from "./PlotComponent";
|
|
4
4
|
import { ShaderProgramManager } from "./ShaderManager";
|
|
5
|
-
import { normalizeOptions } from "./utils";
|
|
6
|
-
import { WGLTexture } from "autumn-wgl";
|
|
7
|
-
const
|
|
5
|
+
import { applySamplerCodeScalar, normalizeOptions } from "./utils";
|
|
6
|
+
import { WGLBuffer, WGLFramebuffer, WGLProgram, WGLTexture } from "autumn-wgl";
|
|
7
|
+
const paintball_step1_vertex_shader_src = `#version 300 es
|
|
8
|
+
|
|
9
|
+
in vec2 a_pos;
|
|
10
|
+
|
|
11
|
+
out highp vec2 v_tex_coord;
|
|
12
|
+
|
|
13
|
+
void main() {
|
|
14
|
+
gl_Position = vec4(a_pos.xy, 0., 1.);
|
|
15
|
+
v_tex_coord = 0.5 * a_pos.xy + vec2(0.5, 0.5);
|
|
16
|
+
}`
|
|
17
|
+
const paintball_step2_vertex_shader_src = `#version 300 es
|
|
8
18
|
|
|
9
19
|
uniform int u_offset;
|
|
10
20
|
|
|
@@ -20,15 +30,34 @@ void main() {
|
|
|
20
30
|
gl_Position = projectTile(a_pos.xy + globe_offset);
|
|
21
31
|
v_tex_coord = a_tex_coord;
|
|
22
32
|
}`
|
|
23
|
-
const
|
|
33
|
+
const paintball_step1_fragment_shader_src = `#version 300 es
|
|
34
|
+
|
|
35
|
+
in highp vec2 v_tex_coord;
|
|
36
|
+
|
|
37
|
+
uniform int u_imem;
|
|
38
|
+
|
|
39
|
+
out highp vec4 fragColor;
|
|
40
|
+
|
|
41
|
+
void main() {
|
|
42
|
+
uint fill_val = uint(get_field_value(v_tex_coord));
|
|
43
|
+
|
|
44
|
+
if (fill_val < uint(1)) {
|
|
45
|
+
discard;
|
|
46
|
+
}
|
|
24
47
|
|
|
25
|
-
|
|
48
|
+
lowp vec4 off_color = vec4(0., 0., 0., 1.);
|
|
49
|
+
lowp vec4 on_color = vec4(1., 1., 1., 1.);
|
|
50
|
+
|
|
51
|
+
uint mask = uint(1) << u_imem;
|
|
52
|
+
lowp float mem_active = float((fill_val & mask) > uint(0));
|
|
53
|
+
fragColor = mix(off_color, on_color, mem_active);
|
|
54
|
+
}`
|
|
55
|
+
const paintball_step2_fragment_shader_src = `#version 300 es
|
|
26
56
|
|
|
27
57
|
in highp vec2 v_tex_coord;
|
|
28
58
|
|
|
29
59
|
uniform sampler2D u_fill_sampler;
|
|
30
|
-
uniform lowp vec4
|
|
31
|
-
uniform int u_num_colors;
|
|
60
|
+
uniform lowp vec4 u_color;
|
|
32
61
|
uniform highp float u_opacity;
|
|
33
62
|
|
|
34
63
|
out highp vec4 fragColor;
|
|
@@ -36,19 +65,11 @@ out highp vec4 fragColor;
|
|
|
36
65
|
void main() {
|
|
37
66
|
highp float fill_val = texture(u_fill_sampler, v_tex_coord).r;
|
|
38
67
|
|
|
39
|
-
if (fill_val < 0.
|
|
68
|
+
if (fill_val < 0.4) {
|
|
40
69
|
discard;
|
|
41
70
|
}
|
|
42
71
|
|
|
43
|
-
lowp vec4 color =
|
|
44
|
-
|
|
45
|
-
for (int nclr = 0; nclr < MAX_N_COLORS ; nclr++) {
|
|
46
|
-
if (nclr >= u_num_colors || fill_val < 0.99) { break; }
|
|
47
|
-
|
|
48
|
-
lowp float mem_active = mod(fill_val, 2.);
|
|
49
|
-
color = mix(color, u_colors[nclr], mem_active);
|
|
50
|
-
fill_val = floor(fill_val / 2.);
|
|
51
|
-
}
|
|
72
|
+
lowp vec4 color = u_color;
|
|
52
73
|
|
|
53
74
|
color.a = color.a * u_opacity;
|
|
54
75
|
fragColor = color;
|
|
@@ -63,6 +84,14 @@ const paintball_opt_defaults = {
|
|
|
63
84
|
* the data for the paintball plot is given as a single field with the objects from each member encoded as "bits" in the field. Because the field is made up
|
|
64
85
|
* of single-precision floats, this works for up to 24 members. (Technically speaking, I don't need the quotes around "bits", as they're bits of the
|
|
65
86
|
* significand of an IEEE 754 float.)
|
|
87
|
+
*
|
|
88
|
+
* ## Grid Compatibility
|
|
89
|
+
* - :white_check_mark: `PlateCarreeGrid`
|
|
90
|
+
* - :white_check_mark: `PlateCarreeRotatedGrid`
|
|
91
|
+
* - :white_check_mark: `LambertGrid`
|
|
92
|
+
* - :x: `UnstructuredGrid`
|
|
93
|
+
* - :white_check_mark: `RadarSweepGrid`
|
|
94
|
+
* - :white_check_mark: `Geostationary`
|
|
66
95
|
*/
|
|
67
96
|
class Paintball extends PlotComponent {
|
|
68
97
|
/**
|
|
@@ -76,7 +105,7 @@ class Paintball extends PlotComponent {
|
|
|
76
105
|
super();
|
|
77
106
|
this.field = field;
|
|
78
107
|
this.opts = normalizeOptions(opts, paintball_opt_defaults);
|
|
79
|
-
this.color_components =
|
|
108
|
+
this.color_components = this.opts.colors.map(color => Color.fromHex(color).toRGBATuple());
|
|
80
109
|
this.gl_elems = null;
|
|
81
110
|
this.fill_texture = null;
|
|
82
111
|
}
|
|
@@ -90,13 +119,7 @@ class Paintball extends PlotComponent {
|
|
|
90
119
|
return;
|
|
91
120
|
const gl = this.gl_elems.gl;
|
|
92
121
|
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 2);
|
|
93
|
-
|
|
94
|
-
if (this.fill_texture === null) {
|
|
95
|
-
this.fill_texture = new WGLTexture(gl, fill_image);
|
|
96
|
-
}
|
|
97
|
-
else {
|
|
98
|
-
this.fill_texture.setImageData(fill_image);
|
|
99
|
-
}
|
|
122
|
+
this.fill_texture = this.field.updateTexImageData(gl, gl.NEAREST, this.fill_texture);
|
|
100
123
|
}
|
|
101
124
|
/**
|
|
102
125
|
* @internal
|
|
@@ -104,12 +127,23 @@ class Paintball extends PlotComponent {
|
|
|
104
127
|
*/
|
|
105
128
|
async onAdd(map, gl) {
|
|
106
129
|
gl.getExtension('OES_texture_float');
|
|
107
|
-
const
|
|
108
|
-
const vertices =
|
|
109
|
-
const
|
|
110
|
-
const
|
|
130
|
+
const vertices_step1 = new WGLBuffer(gl, new Float32Array([-1., -1., 1., -1., -1., 1., 1., 1.]), 2, gl.TRIANGLE_STRIP);
|
|
131
|
+
const { vertices: vertices_step2, texcoords: texcoords_step2 } = await this.field.grid.getDomainBuffers(gl);
|
|
132
|
+
const sampler_keys = this.field.getSamplerIds();
|
|
133
|
+
const sampler_expression = this.field.getExpression();
|
|
134
|
+
const dtypes = this.field.dtypes;
|
|
135
|
+
const step1_frag_shader_src = applySamplerCodeScalar(paintball_step1_fragment_shader_src, sampler_keys, sampler_expression, dtypes);
|
|
136
|
+
const shader_program_step1 = new WGLProgram(gl, paintball_step1_vertex_shader_src, step1_frag_shader_src);
|
|
137
|
+
const shader_manager_step2 = new ShaderProgramManager(paintball_step2_vertex_shader_src, paintball_step2_fragment_shader_src, []);
|
|
138
|
+
const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, 'float16');
|
|
139
|
+
const fb_texture = new WGLTexture(gl, { format: format, type: type,
|
|
140
|
+
width: this.field.grid.ni, height: this.field.grid.nj, image: null,
|
|
141
|
+
mag_filter: gl.LINEAR, row_alignment: row_alignment });
|
|
142
|
+
const fb = new WGLFramebuffer(gl, fb_texture);
|
|
111
143
|
this.gl_elems = {
|
|
112
|
-
gl: gl,
|
|
144
|
+
gl: gl, map: map, shader_program_1: shader_program_step1, shader_manager_2: shader_manager_step2,
|
|
145
|
+
vertices_step1: vertices_step1, vertices_step2: vertices_step2, texcoords_step2: texcoords_step2,
|
|
146
|
+
framebuffer: fb
|
|
113
147
|
};
|
|
114
148
|
this.updateField(this.field);
|
|
115
149
|
}
|
|
@@ -121,22 +155,38 @@ class Paintball extends PlotComponent {
|
|
|
121
155
|
if (this.gl_elems === null || this.fill_texture === null)
|
|
122
156
|
return;
|
|
123
157
|
const gl_elems = this.gl_elems;
|
|
158
|
+
const fill_texture = this.fill_texture;
|
|
159
|
+
const map = gl_elems.map;
|
|
160
|
+
const viewport_width = map.getCanvas().width;
|
|
161
|
+
const viewport_height = map.getCanvas().height;
|
|
124
162
|
const render_data = getRendererData(arg);
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
163
|
+
const program_step1 = this.gl_elems.shader_program_1;
|
|
164
|
+
const program_step2 = this.gl_elems.shader_manager_2.getShaderProgram(gl, render_data.shaderData);
|
|
165
|
+
const samplers = Object.fromEntries([...this.fill_texture.entries()]);
|
|
166
|
+
this.color_components.forEach((color, icolor) => {
|
|
167
|
+
// Render to framebuffer to pull out an individual member from the packed field
|
|
168
|
+
program_step1.use({ 'a_pos': gl_elems.vertices_step1 }, { 'u_imem': icolor }, samplers);
|
|
169
|
+
gl_elems.framebuffer.clear([0, 0, 0, 1]);
|
|
170
|
+
gl_elems.framebuffer.renderTo(0, 0, this.field.grid.ni, this.field.grid.nj);
|
|
171
|
+
gl.enable(gl.BLEND);
|
|
172
|
+
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
173
|
+
program_step1.draw();
|
|
174
|
+
// Now render the framebuffer as a filled contour
|
|
175
|
+
program_step2.use({ 'a_pos': gl_elems.vertices_step2, 'a_tex_coord': gl_elems.texcoords_step2 }, { 'u_opacity': this.opts.opacity, 'u_color': color, 'u_offset': 0,
|
|
176
|
+
...gl_elems.shader_manager_2.getShaderUniforms(render_data) }, { 'u_fill_sampler': gl_elems.framebuffer.texture });
|
|
177
|
+
WGLFramebuffer.screen(gl).renderTo(0, 0, viewport_width, viewport_height);
|
|
178
|
+
gl.enable(gl.BLEND);
|
|
179
|
+
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
180
|
+
program_step2.draw();
|
|
181
|
+
if (render_data.type != 'maplibre' || !render_data.shaderData.define.includes('GLOBE')) {
|
|
182
|
+
program_step2.setUniforms({ 'u_offset': -2 });
|
|
183
|
+
program_step2.draw();
|
|
184
|
+
program_step2.setUniforms({ 'u_offset': -1 });
|
|
185
|
+
program_step2.draw();
|
|
186
|
+
program_step2.setUniforms({ 'u_offset': 1 });
|
|
187
|
+
program_step2.draw();
|
|
188
|
+
}
|
|
189
|
+
});
|
|
140
190
|
}
|
|
141
191
|
}
|
|
142
192
|
export default Paintball;
|
package/lib/PlotComponent.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
2
|
import { MapLikeType } from './Map';
|
|
3
3
|
import { RenderMethodArg, TypedArrayStr, WebGLAnyRenderingContext } from './AutumnTypes';
|
|
4
|
+
import { WorkerPool } from './WorkerPool';
|
|
4
5
|
declare const layer_worker: Comlink.Remote<{
|
|
5
6
|
makeBBElements: (field_lats: Float32Array, field_lons: Float32Array, min_zoom: Uint8Array, field_ni: number, field_nj: number, map_max_zoom: number) => {
|
|
6
7
|
pts: Float32Array;
|
|
@@ -12,13 +13,18 @@ declare const layer_worker: Comlink.Remote<{
|
|
|
12
13
|
};
|
|
13
14
|
makePolyLines: (lines: import("./AutumnTypes").LineData[]) => import("./AutumnTypes").Polyline;
|
|
14
15
|
}>;
|
|
16
|
+
declare function getContourWorkerPool(wasm_base_url: string | undefined, n_workers: number): WorkerPool<{
|
|
17
|
+
contourCreator: (data: import("./AutumnTypes").ContourableTypedArray, grid_coords: import("./grids/Grid").GridCoords, opts: import("./ContourCreator.worker").FieldContourOpts) => Promise<import("./AutumnTypes").ContourData>;
|
|
18
|
+
init: (wasm_base_url: string | undefined) => Promise<void>;
|
|
19
|
+
}>;
|
|
20
|
+
/** Base class for all plot components */
|
|
15
21
|
declare abstract class PlotComponent<MapType extends MapLikeType> {
|
|
16
22
|
abstract onAdd(map: MapType, gl: WebGLAnyRenderingContext): Promise<void>;
|
|
17
23
|
abstract render(gl: WebGLAnyRenderingContext, arg: RenderMethodArg): void;
|
|
18
24
|
}
|
|
19
25
|
declare function getGLFormatTypeAlignment(gl: WebGLAnyRenderingContext, array_dtype: TypedArrayStr): {
|
|
20
|
-
format: 33321 | 33325 | 33326 | 6409;
|
|
21
|
-
type: 36193 | 5131 | 5121 | 5126;
|
|
26
|
+
format: 33321 | 33325 | 33326 | 33331 | 33332 | 33333 | 33334 | 6409;
|
|
27
|
+
type: 36193 | 5131 | 5121 | 5122 | 5123 | 5124 | 5125 | 5126;
|
|
22
28
|
row_alignment: number;
|
|
23
29
|
};
|
|
24
|
-
export { PlotComponent, layer_worker, getGLFormatTypeAlignment };
|
|
30
|
+
export { PlotComponent, layer_worker, getContourWorkerPool, getGLFormatTypeAlignment };
|
package/lib/PlotComponent.js
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
2
|
import { getOS } from "./utils";
|
|
3
3
|
import { isWebGL2Ctx } from './AutumnTypes';
|
|
4
|
+
import { createWorkerPool } from './WorkerPool';
|
|
4
5
|
const worker = new Worker(new URL('./PlotLayer.worker', import.meta.url));
|
|
5
6
|
const layer_worker = Comlink.wrap(worker);
|
|
7
|
+
let c_worker_pool = null;
|
|
8
|
+
function getContourWorkerPool(wasm_base_url, n_workers) {
|
|
9
|
+
if (c_worker_pool !== null) {
|
|
10
|
+
return c_worker_pool;
|
|
11
|
+
}
|
|
12
|
+
const c_workers = [];
|
|
13
|
+
for (let iw = 0; iw < n_workers; iw++) {
|
|
14
|
+
c_workers.push(new Worker(new URL('./ContourCreator.worker', import.meta.url)));
|
|
15
|
+
}
|
|
16
|
+
const pool = createWorkerPool(c_workers, wkr => wkr.init(wasm_base_url));
|
|
17
|
+
c_worker_pool = pool;
|
|
18
|
+
return pool;
|
|
19
|
+
}
|
|
20
|
+
/** Base class for all plot components */
|
|
6
21
|
class PlotComponent {
|
|
7
22
|
}
|
|
8
23
|
function getGLFormatTypeAlignment(gl, array_dtype) {
|
|
@@ -39,6 +54,26 @@ function getGLFormatTypeAlignment(gl, array_dtype) {
|
|
|
39
54
|
type = gl.FLOAT;
|
|
40
55
|
row_alignment = 4;
|
|
41
56
|
}
|
|
57
|
+
else if (array_dtype == 'uint16') {
|
|
58
|
+
format = is_webgl2 ? gl.R16UI : gl.LUMINANCE;
|
|
59
|
+
type = gl.UNSIGNED_SHORT;
|
|
60
|
+
row_alignment = 2;
|
|
61
|
+
}
|
|
62
|
+
else if (array_dtype == 'uint32') {
|
|
63
|
+
format = is_webgl2 ? gl.R32UI : gl.LUMINANCE;
|
|
64
|
+
type = gl.UNSIGNED_INT;
|
|
65
|
+
row_alignment = 4;
|
|
66
|
+
}
|
|
67
|
+
else if (array_dtype == 'int16') {
|
|
68
|
+
format = is_webgl2 ? gl.R16I : gl.LUMINANCE;
|
|
69
|
+
type = gl.SHORT;
|
|
70
|
+
row_alignment = 2;
|
|
71
|
+
}
|
|
72
|
+
else if (array_dtype == 'int32') {
|
|
73
|
+
format = is_webgl2 ? gl.R32I : gl.LUMINANCE;
|
|
74
|
+
type = gl.INT;
|
|
75
|
+
row_alignment = 4;
|
|
76
|
+
}
|
|
42
77
|
else {
|
|
43
78
|
format = is_webgl2 ? gl.R8 : gl.LUMINANCE;
|
|
44
79
|
type = gl.UNSIGNED_BYTE;
|
|
@@ -46,4 +81,4 @@ function getGLFormatTypeAlignment(gl, array_dtype) {
|
|
|
46
81
|
}
|
|
47
82
|
return { format: format, type: type, row_alignment: row_alignment };
|
|
48
83
|
}
|
|
49
|
-
export { PlotComponent, layer_worker, getGLFormatTypeAlignment };
|
|
84
|
+
export { PlotComponent, layer_worker, getContourWorkerPool, getGLFormatTypeAlignment };
|
package/lib/PlotLayer.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ declare abstract class PlotLayerBase<MapType extends MapLikeType> {
|
|
|
11
11
|
protected repaint(): void;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
* A static map layer. The data are assumed to be static in time. If the data have a time component (e.g., a model forecast),
|
|
14
|
+
* A static map layer. The data are assumed to be static in time. If the data have a time component (e.g., a model forecast), a {@link MultiPlotLayer}
|
|
15
15
|
* may be more appropriate.
|
|
16
16
|
* @example
|
|
17
17
|
* // Create map layers from provided fields
|
|
@@ -39,7 +39,7 @@ declare class PlotLayer<MapType extends MapLikeType> extends PlotLayerBase<MapTy
|
|
|
39
39
|
render(gl: WebGLAnyRenderingContext, matrix: RenderMethodArg): void;
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
* A varying map layer. If the data don't have a varying component, such as over time, it might be easier to use
|
|
42
|
+
* A varying map layer. If the data don't have a varying component, such as over time, it might be easier to use a {@link PlotLayer} instead.
|
|
43
43
|
* @example
|
|
44
44
|
* // Create a varying map layer
|
|
45
45
|
* height_layer = new MultiPlotLayer('height-contours');
|
package/lib/PlotLayer.js
CHANGED
|
@@ -11,7 +11,7 @@ class PlotLayerBase {
|
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
|
-
* A static map layer. The data are assumed to be static in time. If the data have a time component (e.g., a model forecast),
|
|
14
|
+
* A static map layer. The data are assumed to be static in time. If the data have a time component (e.g., a model forecast), a {@link MultiPlotLayer}
|
|
15
15
|
* may be more appropriate.
|
|
16
16
|
* @example
|
|
17
17
|
* // Create map layers from provided fields
|
|
@@ -46,7 +46,7 @@ class PlotLayer extends PlotLayerBase {
|
|
|
46
46
|
}
|
|
47
47
|
}
|
|
48
48
|
/**
|
|
49
|
-
* A varying map layer. If the data don't have a varying component, such as over time, it might be easier to use
|
|
49
|
+
* A varying map layer. If the data don't have a varying component, such as over time, it might be easier to use a {@link PlotLayer} instead.
|
|
50
50
|
* @example
|
|
51
51
|
* // Create a varying map layer
|
|
52
52
|
* height_layer = new MultiPlotLayer('height-contours');
|
package/lib/PlotLayer.worker.js
CHANGED
|
@@ -21,7 +21,10 @@ function makeBBElements(field_lats, field_lons, min_zoom, field_ni, field_nj, ma
|
|
|
21
21
|
const pt_ll = new LngLat(lon, lat).toMercatorCoord();
|
|
22
22
|
pts[istart_pts + 0] = pt_ll.x;
|
|
23
23
|
pts[istart_pts + 1] = pt_ll.y;
|
|
24
|
-
|
|
24
|
+
// Pack the min zoom in with the texture coordinates; only works because the min zoom is always an integer
|
|
25
|
+
// Another gotcha is that if the i texcoord is 1, then that bump up the zoom that gets unpacked on the GPU, which causes may cause the last column of billboards to
|
|
26
|
+
// disappear. To fix this, cap the texcoord at 0.99999, which should be good for textures up to 10^5 pixels in size.
|
|
27
|
+
tex_coords[istart_tc + 0] = Math.min(ilon / (field_ni - 1), 0.99999) + zoom;
|
|
25
28
|
tex_coords[istart_tc + 1] = ilat / (field_nj - 1);
|
|
26
29
|
istart_pts += n_coords_per_pt_pts;
|
|
27
30
|
istart_tc += n_coords_per_pt_tc;
|
|
@@ -204,7 +207,7 @@ function makePolylinesMiter(lines) {
|
|
|
204
207
|
}
|
|
205
208
|
*/
|
|
206
209
|
function makePolylines(lines) {
|
|
207
|
-
if (lines.length == 0) {
|
|
210
|
+
if (lines.length == 0 || lines[0].vertices.length == 0) {
|
|
208
211
|
return { vertices: new Float32Array([]), extrusion: new Float32Array([]) };
|
|
209
212
|
}
|
|
210
213
|
const n_points_per_vert = Object.fromEntries(Object.entries(lines[0]).map(([k, v]) => {
|
|
@@ -252,6 +255,9 @@ function makePolylines(lines) {
|
|
|
252
255
|
const v_ll = new LngLat(...v).toMercatorCoord();
|
|
253
256
|
return [v_ll.x, v_ll.y];
|
|
254
257
|
});
|
|
258
|
+
if (line.vertices.length == 0) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
255
261
|
const has_offsets = line.offsets !== undefined;
|
|
256
262
|
const extrusion_verts = line.offsets !== undefined ? line.offsets : verts;
|
|
257
263
|
let pt_prev, pt_this = verts[0], pt_next = verts[1];
|
|
@@ -342,6 +348,6 @@ function makePolylines(lines) {
|
|
|
342
348
|
const ep_interface = {
|
|
343
349
|
'makeBBElements': makeBBElements,
|
|
344
350
|
'makeDomainVerticesAndTexCoords': makeDomainVerticesAndTexCoords,
|
|
345
|
-
'makePolyLines': makePolylines
|
|
351
|
+
'makePolyLines': makePolylines,
|
|
346
352
|
};
|
|
347
353
|
Comlink.expose(ep_interface);
|