autumnplot-gl 3.2.0 → 4.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/README.md +11 -207
- 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 +85 -6
- package/lib/AutumnTypes.js +28 -1
- package/lib/Barbs.d.ts +7 -5
- package/lib/BillboardCollection.d.ts +8 -7
- package/lib/BillboardCollection.js +69 -58
- package/lib/Color.d.ts +2 -0
- package/lib/Color.js +4 -0
- package/lib/ColorBar.d.ts +19 -0
- package/lib/ColorBar.js +9 -6
- package/lib/Colormap.d.ts +1 -0
- package/lib/Colormap.js +8 -8
- package/lib/Contour.d.ts +28 -8
- package/lib/Contour.js +27 -54
- package/lib/ContourCreator.d.ts +9 -1
- package/lib/ContourCreator.js +5 -4
- package/lib/Fill.d.ts +28 -14
- package/lib/Fill.js +97 -50
- package/lib/Grid.d.ts +132 -30
- package/lib/Grid.js +355 -99
- package/lib/Hodographs.d.ts +15 -8
- package/lib/Hodographs.js +48 -30
- package/lib/Map.d.ts +14 -1
- package/lib/Map.js +60 -4
- package/lib/Paintball.d.ts +7 -5
- package/lib/Paintball.js +36 -31
- package/lib/ParticleTracer.d.ts +19 -0
- package/lib/ParticleTracer.js +37 -0
- package/lib/PlotComponent.d.ts +7 -7
- package/lib/PlotComponent.js +9 -3
- package/lib/PlotLayer.d.ts +5 -5
- package/lib/PlotLayer.js +2 -2
- package/lib/PlotLayer.worker.d.ts +1 -2
- package/lib/PlotLayer.worker.js +22 -51
- package/lib/PolylineCollection.d.ts +5 -3
- package/lib/PolylineCollection.js +60 -37
- package/lib/RawField.d.ts +78 -23
- package/lib/RawField.js +147 -31
- package/lib/ShaderManager.d.ts +12 -0
- package/lib/ShaderManager.js +58 -0
- package/lib/StationPlot.d.ts +187 -25
- package/lib/StationPlot.js +209 -60
- package/lib/TextCollection.d.ts +9 -6
- package/lib/TextCollection.js +97 -62
- package/lib/cpp/marchingsquares.js +483 -585
- package/lib/cpp/marchingsquares.wasm +0 -0
- package/lib/cpp/marchingsquares_embind.d.ts +23 -3
- package/lib/index.d.ts +12 -5
- package/lib/index.js +8 -5
- package/lib/utils.d.ts +4 -1
- package/lib/utils.js +12 -1
- package/package.json +3 -3
- package/dist/110.autumnplot-gl.js +0 -2
- package/dist/110.autumnplot-gl.js.map +0 -1
package/lib/PlotLayer.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WebGLAnyRenderingContext } from './AutumnTypes';
|
|
1
|
+
import { RenderMethodArg, WebGLAnyRenderingContext } from './AutumnTypes';
|
|
2
2
|
import { MapLikeType } from './Map';
|
|
3
3
|
import { PlotComponent } from './PlotComponent';
|
|
4
4
|
declare abstract class PlotLayerBase<MapType extends MapLikeType> {
|
|
@@ -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
|
|
@@ -36,10 +36,10 @@ declare class PlotLayer<MapType extends MapLikeType> extends PlotLayerBase<MapTy
|
|
|
36
36
|
* @internal
|
|
37
37
|
* Render this layer
|
|
38
38
|
*/
|
|
39
|
-
render(gl: WebGLAnyRenderingContext, matrix:
|
|
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');
|
|
@@ -70,7 +70,7 @@ declare class MultiPlotLayer<MapType extends MapLikeType> extends PlotLayerBase<
|
|
|
70
70
|
* @internal
|
|
71
71
|
* Render this layer
|
|
72
72
|
*/
|
|
73
|
-
render(gl: WebGLAnyRenderingContext, matrix:
|
|
73
|
+
render(gl: WebGLAnyRenderingContext, matrix: RenderMethodArg): void;
|
|
74
74
|
/**
|
|
75
75
|
* Set the active key
|
|
76
76
|
* @param key - The new key. The field with that key is plotted immediately.
|
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');
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { LineData, Polyline } from "./AutumnTypes";
|
|
2
|
-
declare function makeBBElements(field_lats: Float32Array, field_lons: Float32Array,
|
|
2
|
+
declare function makeBBElements(field_lats: Float32Array, field_lons: Float32Array, min_zoom: Uint8Array, field_ni: number, field_nj: number, map_max_zoom: number): {
|
|
3
3
|
pts: Float32Array;
|
|
4
4
|
tex_coords: Float32Array;
|
|
5
5
|
};
|
|
6
6
|
declare function makeDomainVerticesAndTexCoords(field_lats: Float32Array, field_lons: Float32Array, field_ni: number, field_nj: number, texcoord_margin_r: number, texcoord_margin_s: number): {
|
|
7
7
|
vertices: Float32Array;
|
|
8
8
|
tex_coords: Float32Array;
|
|
9
|
-
grid_cell_size: Float32Array;
|
|
10
9
|
};
|
|
11
10
|
declare function makePolylines(lines: LineData[]): Polyline;
|
|
12
11
|
declare const ep_interface: {
|
package/lib/PlotLayer.worker.js
CHANGED
|
@@ -1,17 +1,11 @@
|
|
|
1
|
-
import { getMinZoom } from "./utils";
|
|
2
1
|
import * as Comlink from 'comlink';
|
|
3
2
|
import { LngLat } from "./Map";
|
|
4
|
-
function makeBBElements(field_lats, field_lons, field_ni, field_nj,
|
|
5
|
-
const
|
|
6
|
-
const n_coords_per_pt_pts = 3;
|
|
3
|
+
function makeBBElements(field_lats, field_lons, min_zoom, field_ni, field_nj, map_max_zoom) {
|
|
4
|
+
const n_coords_per_pt_pts = 2;
|
|
7
5
|
const n_coords_per_pt_tc = 2;
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const
|
|
11
|
-
const field_ni_access = Math.floor((field_ni - 1) / trim_inaccessible) + 1;
|
|
12
|
-
const field_nj_access = Math.floor((field_nj - 1) / trim_inaccessible) + 1;
|
|
13
|
-
const n_elems_pts = field_ni_access * field_nj_access * n_pts_per_poly * n_coords_per_pt_pts;
|
|
14
|
-
const n_elems_tc = field_ni_access * field_nj_access * n_pts_per_poly * n_coords_per_pt_tc;
|
|
6
|
+
const field_n_access = min_zoom.filter(mz => mz <= map_max_zoom).length;
|
|
7
|
+
const n_elems_pts = field_n_access * n_coords_per_pt_pts;
|
|
8
|
+
const n_elems_tc = field_n_access * n_coords_per_pt_tc;
|
|
15
9
|
let pts = new Float32Array(n_elems_pts);
|
|
16
10
|
let tex_coords = new Float32Array(n_elems_tc);
|
|
17
11
|
let istart_pts = 0;
|
|
@@ -21,22 +15,19 @@ function makeBBElements(field_lats, field_lons, field_ni, field_nj, thin_fac_bas
|
|
|
21
15
|
const idx = ilat * field_ni + ilon;
|
|
22
16
|
const lat = field_lats[idx];
|
|
23
17
|
const lon = field_lons[idx];
|
|
24
|
-
const zoom =
|
|
25
|
-
if (zoom >
|
|
26
|
-
continue;
|
|
18
|
+
const zoom = min_zoom[idx];
|
|
19
|
+
if (zoom > map_max_zoom || lon === undefined || lat === undefined)
|
|
20
|
+
continue; // TAS: Adding the checks for lat/lon here may be a bug waiting to happen? Not sure.
|
|
27
21
|
const pt_ll = new LngLat(lon, lat).toMercatorCoord();
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
istart_pts += (n_pts_per_poly * n_coords_per_pt_pts);
|
|
39
|
-
istart_tc += (n_pts_per_poly * n_coords_per_pt_tc);
|
|
22
|
+
pts[istart_pts + 0] = pt_ll.x;
|
|
23
|
+
pts[istart_pts + 1] = pt_ll.y;
|
|
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;
|
|
28
|
+
tex_coords[istart_tc + 1] = ilat / (field_nj - 1);
|
|
29
|
+
istart_pts += n_coords_per_pt_pts;
|
|
30
|
+
istart_tc += n_coords_per_pt_tc;
|
|
40
31
|
}
|
|
41
32
|
}
|
|
42
33
|
return { 'pts': pts, 'tex_coords': tex_coords };
|
|
@@ -44,7 +35,6 @@ function makeBBElements(field_lats, field_lons, field_ni, field_nj, thin_fac_bas
|
|
|
44
35
|
function makeDomainVerticesAndTexCoords(field_lats, field_lons, field_ni, field_nj, texcoord_margin_r, texcoord_margin_s) {
|
|
45
36
|
const verts = new Float32Array(2 * 2 * (field_ni - 1) * (field_nj + 1)).fill(0);
|
|
46
37
|
const tex_coords = new Float32Array(2 * 2 * (field_ni - 1) * (field_nj + 1)).fill(0);
|
|
47
|
-
const grid_cell_size = new Float32Array(1 * 2 * (field_ni - 1) * (field_nj + 1)).fill(0);
|
|
48
38
|
let ivert = 0;
|
|
49
39
|
let itexcoord = 0;
|
|
50
40
|
for (let i = 0; i < field_ni - 1; i++) {
|
|
@@ -83,29 +73,7 @@ function makeDomainVerticesAndTexCoords(field_lats, field_lons, field_ni, field_
|
|
|
83
73
|
}
|
|
84
74
|
}
|
|
85
75
|
}
|
|
86
|
-
|
|
87
|
-
for (let i = 0; i < field_ni - 1; i++) {
|
|
88
|
-
for (let j = 0; j < field_nj - 1; j++) {
|
|
89
|
-
const ivert = j == 0 ? 2 * (igcs + 1) : 2 * igcs;
|
|
90
|
-
const x_ll = verts[ivert], y_ll = verts[ivert + 1], x_lr = verts[ivert + 2], y_lr = verts[ivert + 3], x_ul = verts[ivert + 4], y_ul = verts[ivert + 5], x_ur = verts[ivert + 6], y_ur = verts[ivert + 7];
|
|
91
|
-
const area = 0.5 * Math.abs(x_ll * (y_lr - y_ul) + x_lr * (y_ul - y_ll) + x_ul * (y_ll - y_lr) +
|
|
92
|
-
x_ur * (y_ul - y_lr) + x_ul * (y_lr - y_ur) + x_lr * (y_ur - y_ul));
|
|
93
|
-
if (j == 0) {
|
|
94
|
-
grid_cell_size[igcs] = area;
|
|
95
|
-
igcs += 1;
|
|
96
|
-
}
|
|
97
|
-
grid_cell_size[igcs] = area;
|
|
98
|
-
grid_cell_size[igcs + 1] = area;
|
|
99
|
-
igcs += 2;
|
|
100
|
-
if (j == field_nj - 2) {
|
|
101
|
-
grid_cell_size[igcs] = area;
|
|
102
|
-
grid_cell_size[igcs + 1] = area;
|
|
103
|
-
grid_cell_size[igcs + 2] = area;
|
|
104
|
-
igcs += 3;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
return { 'vertices': verts, 'tex_coords': tex_coords, 'grid_cell_size': grid_cell_size };
|
|
76
|
+
return { 'vertices': verts, 'tex_coords': tex_coords };
|
|
109
77
|
}
|
|
110
78
|
/*
|
|
111
79
|
function makePolylinesMiter(lines) {
|
|
@@ -239,7 +207,7 @@ function makePolylinesMiter(lines) {
|
|
|
239
207
|
}
|
|
240
208
|
*/
|
|
241
209
|
function makePolylines(lines) {
|
|
242
|
-
if (lines.length == 0) {
|
|
210
|
+
if (lines.length == 0 || lines[0].vertices.length == 0) {
|
|
243
211
|
return { vertices: new Float32Array([]), extrusion: new Float32Array([]) };
|
|
244
212
|
}
|
|
245
213
|
const n_points_per_vert = Object.fromEntries(Object.entries(lines[0]).map(([k, v]) => {
|
|
@@ -287,6 +255,9 @@ function makePolylines(lines) {
|
|
|
287
255
|
const v_ll = new LngLat(...v).toMercatorCoord();
|
|
288
256
|
return [v_ll.x, v_ll.y];
|
|
289
257
|
});
|
|
258
|
+
if (line.vertices.length == 0) {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
290
261
|
const has_offsets = line.offsets !== undefined;
|
|
291
262
|
const extrusion_verts = line.offsets !== undefined ? line.offsets : verts;
|
|
292
263
|
let pt_prev, pt_this = verts[0], pt_next = verts[1];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { LineData, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
1
|
+
import { LineData, WebGLAnyRenderingContext, RenderMethodArg } from "./AutumnTypes";
|
|
2
2
|
import { ColorMap } from "./Colormap";
|
|
3
3
|
/**
|
|
4
4
|
* A style to use to draw lines. The possible options are '-' for a solid line, '--' for a dashed line, ':' for a
|
|
@@ -9,6 +9,7 @@ type LineStyle = "-" | "--" | ":" | "-." | number[];
|
|
|
9
9
|
declare function isLineStyle(obj: any): obj is LineStyle;
|
|
10
10
|
interface PolylineCollectionOpts {
|
|
11
11
|
offset_scale?: number;
|
|
12
|
+
offset_rotates_with_map?: boolean;
|
|
12
13
|
color?: string;
|
|
13
14
|
cmap?: ColorMap;
|
|
14
15
|
line_width?: number;
|
|
@@ -17,7 +18,7 @@ interface PolylineCollectionOpts {
|
|
|
17
18
|
declare class PolylineCollection {
|
|
18
19
|
readonly width: number;
|
|
19
20
|
readonly scale: number | null;
|
|
20
|
-
private readonly
|
|
21
|
+
private readonly shader_manager;
|
|
21
22
|
private readonly vertices;
|
|
22
23
|
private readonly extrusion;
|
|
23
24
|
private readonly offset;
|
|
@@ -25,11 +26,12 @@ declare class PolylineCollection {
|
|
|
25
26
|
private readonly line_data;
|
|
26
27
|
private readonly color;
|
|
27
28
|
private readonly cmap_gpu;
|
|
29
|
+
private readonly offset_rotates_with_map;
|
|
28
30
|
private readonly dash_texture;
|
|
29
31
|
private readonly n_dash;
|
|
30
32
|
private constructor();
|
|
31
33
|
static make(gl: WebGLAnyRenderingContext, lines: LineData[], opts?: PolylineCollectionOpts): Promise<PolylineCollection>;
|
|
32
|
-
render(gl: WebGLAnyRenderingContext,
|
|
34
|
+
render(gl: WebGLAnyRenderingContext, arg: RenderMethodArg, [map_width, map_height]: [number, number], map_zoom: number, map_bearing: number, map_pitch: number): void;
|
|
33
35
|
}
|
|
34
36
|
export { PolylineCollection, isLineStyle };
|
|
35
37
|
export type { PolylineCollectionOpts, LineStyle };
|
|
@@ -1,42 +1,45 @@
|
|
|
1
|
-
import { WGLBuffer,
|
|
2
|
-
import { isWebGL2Ctx } from "./AutumnTypes";
|
|
1
|
+
import { WGLBuffer, WGLTexture } from "autumn-wgl";
|
|
2
|
+
import { isWebGL2Ctx, getRendererData } from "./AutumnTypes";
|
|
3
3
|
import { ColorMap, ColorMapGPUInterface } from "./Colormap";
|
|
4
4
|
import { Color } from "./Color";
|
|
5
5
|
import { layer_worker } from "./PlotComponent";
|
|
6
|
-
|
|
6
|
+
import { ShaderProgramManager } from "./ShaderManager";
|
|
7
|
+
const polyline_vertex_src = `#version 300 es
|
|
8
|
+
|
|
7
9
|
uniform int u_offset;
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
in vec3 a_pos;
|
|
12
|
+
in vec2 a_extrusion;
|
|
13
|
+
in float a_data;
|
|
12
14
|
|
|
13
15
|
#ifdef ZOOM
|
|
14
|
-
|
|
16
|
+
in float a_min_zoom;
|
|
15
17
|
#endif
|
|
16
18
|
|
|
17
19
|
#ifdef OFFSET
|
|
18
|
-
|
|
20
|
+
in vec2 a_offset;
|
|
19
21
|
#endif
|
|
20
22
|
|
|
21
23
|
uniform lowp float u_line_width;
|
|
22
24
|
uniform lowp float u_map_width;
|
|
23
25
|
uniform lowp float u_map_height;
|
|
24
|
-
|
|
26
|
+
|
|
25
27
|
|
|
26
28
|
#ifdef ZOOM
|
|
27
29
|
uniform lowp float u_zoom;
|
|
28
30
|
#endif
|
|
29
31
|
|
|
30
32
|
#ifdef OFFSET
|
|
33
|
+
uniform int u_offset_rotates_with_map;
|
|
31
34
|
uniform lowp float u_offset_scale;
|
|
32
35
|
#endif
|
|
33
36
|
|
|
34
37
|
#ifdef DATA
|
|
35
|
-
|
|
38
|
+
out highp float v_data;
|
|
36
39
|
#endif
|
|
37
40
|
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
out highp float v_dist;
|
|
42
|
+
out lowp float v_cross;
|
|
40
43
|
|
|
41
44
|
mat4 scalingMatrix(float x_scale, float y_scale, float z_scale) {
|
|
42
45
|
return mat4(x_scale, 0.0, 0.0, 0.0,
|
|
@@ -71,7 +74,7 @@ void main() {
|
|
|
71
74
|
|
|
72
75
|
v_dist = abs(a_pos.z);
|
|
73
76
|
v_cross = sign(a_pos.z);
|
|
74
|
-
vec4 center_pos =
|
|
77
|
+
vec4 center_pos = projectTile(a_pos.xy + globe_offset);
|
|
75
78
|
vec4 offset = vec4(0.0, 0.0, 0.0, 0.0);
|
|
76
79
|
|
|
77
80
|
#ifdef ZOOM
|
|
@@ -81,13 +84,26 @@ void main() {
|
|
|
81
84
|
vec2 offset_ext = u_line_width * 2. * a_extrusion;
|
|
82
85
|
|
|
83
86
|
mat4 map_stretch_matrix = scalingMatrix(u_map_height / u_map_width, 1., 1.);
|
|
84
|
-
|
|
87
|
+
|
|
88
|
+
vec4 center_pos_ihat = projectTile(a_pos.xy + globe_offset + vec2(1e-5, 0.));
|
|
89
|
+
|
|
90
|
+
vec2 center_east = normalize((inverse(map_stretch_matrix) * (center_pos_ihat - center_pos)).xy);
|
|
91
|
+
float globe_rotation = atan(center_east.x, center_east.y) - 3.141592654 / 2.0;
|
|
92
|
+
mat4 rotation_matrix = rotationZMatrix(-globe_rotation);
|
|
93
|
+
|
|
85
94
|
offset = map_stretch_matrix * rotation_matrix * vec4(offset_ext, 0., 0.);
|
|
86
95
|
|
|
87
96
|
#ifdef OFFSET
|
|
88
|
-
|
|
97
|
+
mat4 offset_matrix = scalingMatrix(1., u_map_width / u_map_height, 1.);
|
|
98
|
+
if (u_offset_rotates_with_map == 1) {
|
|
99
|
+
offset_matrix = offset_matrix * rotation_matrix;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
offset = map_stretch_matrix * vec4(offset_ext, 0., 0.);
|
|
103
|
+
}
|
|
104
|
+
|
|
89
105
|
vec2 offset_offset = u_offset_scale * a_offset;
|
|
90
|
-
offset +=
|
|
106
|
+
offset += offset_matrix * vec4(offset_offset, 0., 0.);
|
|
91
107
|
#endif
|
|
92
108
|
|
|
93
109
|
#ifdef ZOOM
|
|
@@ -100,7 +116,8 @@ void main() {
|
|
|
100
116
|
v_data = a_data;
|
|
101
117
|
#endif
|
|
102
118
|
}`
|
|
103
|
-
const polyline_fragment_src =
|
|
119
|
+
const polyline_fragment_src = `#version 300 es
|
|
120
|
+
|
|
104
121
|
uniform sampler2D u_dash_sampler;
|
|
105
122
|
|
|
106
123
|
#ifndef DATA
|
|
@@ -112,15 +129,17 @@ uniform lowp float u_zoom;
|
|
|
112
129
|
uniform int u_dash_pattern_length;
|
|
113
130
|
|
|
114
131
|
#ifdef DATA
|
|
115
|
-
|
|
132
|
+
in highp float v_data;
|
|
116
133
|
#endif
|
|
117
134
|
|
|
118
|
-
|
|
119
|
-
|
|
135
|
+
in highp float v_dist;
|
|
136
|
+
in lowp float v_cross;
|
|
137
|
+
|
|
138
|
+
out highp vec4 fragColor;
|
|
120
139
|
|
|
121
140
|
void main() {
|
|
122
141
|
lowp float dash_x = fract(v_dist * 2e2 * pow(2., floor(u_zoom)) / float(u_dash_pattern_length));
|
|
123
|
-
lowp float dash =
|
|
142
|
+
lowp float dash = texture(u_dash_sampler, vec2(dash_x, 0.5)).r;
|
|
124
143
|
|
|
125
144
|
lowp vec4 color;
|
|
126
145
|
#ifdef DATA
|
|
@@ -132,7 +151,7 @@ void main() {
|
|
|
132
151
|
lowp float feather = clamp((1. - abs(v_cross)) * u_line_width, 0., 1.);
|
|
133
152
|
color.a *= (dash >= 1. ? 1. : 0.) * feather;
|
|
134
153
|
|
|
135
|
-
|
|
154
|
+
fragColor = color;
|
|
136
155
|
}`
|
|
137
156
|
const dash_arrays = {
|
|
138
157
|
"-": [1],
|
|
@@ -162,6 +181,7 @@ class PolylineCollection {
|
|
|
162
181
|
this.color = Color.fromHex(color_hex);
|
|
163
182
|
const line_width = opts.line_width === undefined ? 1 : opts.line_width;
|
|
164
183
|
const line_style = opts.line_style === undefined ? '-' : opts.line_style;
|
|
184
|
+
this.offset_rotates_with_map = opts.offset_rotates_with_map === undefined ? true : opts.offset_rotates_with_map;
|
|
165
185
|
this.width = line_width;
|
|
166
186
|
const shader_defines = [];
|
|
167
187
|
this.vertices = new WGLBuffer(gl, polyline['vertices'], 3, gl.TRIANGLE_STRIP);
|
|
@@ -196,24 +216,25 @@ class PolylineCollection {
|
|
|
196
216
|
this.cmap_gpu = null;
|
|
197
217
|
}
|
|
198
218
|
[this.n_dash, this.dash_texture] = makeDashTexture(gl, line_style);
|
|
199
|
-
this.
|
|
219
|
+
this.shader_manager = new ShaderProgramManager(polyline_vertex_src, fragment_src, shader_defines);
|
|
200
220
|
}
|
|
201
221
|
static async make(gl, lines, opts) {
|
|
202
222
|
const polylines = await layer_worker.makePolyLines(lines);
|
|
203
223
|
return new PolylineCollection(gl, polylines, opts);
|
|
204
224
|
}
|
|
205
|
-
render(gl,
|
|
206
|
-
|
|
207
|
-
|
|
225
|
+
render(gl, arg, [map_width, map_height], map_zoom, map_bearing, map_pitch) {
|
|
226
|
+
const render_data = getRendererData(arg);
|
|
227
|
+
const program = this.shader_manager.getShaderProgram(gl, render_data.shaderData);
|
|
208
228
|
const attributes = { 'a_pos': this.vertices, 'a_extrusion': this.extrusion };
|
|
209
229
|
const uniforms = {
|
|
210
|
-
'
|
|
211
|
-
'u_dash_pattern_length': this.n_dash
|
|
230
|
+
'u_line_width': this.width, 'u_map_width': map_width, 'u_map_height': map_height, 'u_offset': 0, 'u_zoom': map_zoom,
|
|
231
|
+
'u_dash_pattern_length': this.n_dash, ...this.shader_manager.getShaderUniforms(render_data)
|
|
212
232
|
};
|
|
213
233
|
const textures = { 'u_dash_sampler': this.dash_texture };
|
|
214
234
|
if (this.offset !== null && this.scale !== null) {
|
|
215
235
|
attributes['a_offset'] = this.offset;
|
|
216
236
|
uniforms['u_offset_scale'] = this.scale * (map_height / map_width);
|
|
237
|
+
uniforms['u_offset_rotates_with_map'] = this.offset_rotates_with_map ? 1 : 0;
|
|
217
238
|
}
|
|
218
239
|
if (this.min_zoom !== null) {
|
|
219
240
|
attributes['a_min_zoom'] = this.min_zoom;
|
|
@@ -224,19 +245,21 @@ class PolylineCollection {
|
|
|
224
245
|
else {
|
|
225
246
|
uniforms['u_color'] = this.color.toRGBATuple();
|
|
226
247
|
}
|
|
227
|
-
|
|
248
|
+
program.use(attributes, uniforms, textures);
|
|
228
249
|
if (this.cmap_gpu !== null) {
|
|
229
|
-
this.cmap_gpu.bindShaderVariables(
|
|
250
|
+
this.cmap_gpu.bindShaderVariables(program);
|
|
230
251
|
}
|
|
231
252
|
gl.enable(gl.BLEND);
|
|
232
253
|
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
254
|
+
program.draw();
|
|
255
|
+
if (render_data.type != 'maplibre' || !render_data.shaderData.define.includes('GLOBE')) {
|
|
256
|
+
program.setUniforms({ 'u_offset': -2 });
|
|
257
|
+
program.draw();
|
|
258
|
+
program.setUniforms({ 'u_offset': -1 });
|
|
259
|
+
program.draw();
|
|
260
|
+
program.setUniforms({ 'u_offset': 1 });
|
|
261
|
+
program.draw();
|
|
262
|
+
}
|
|
240
263
|
}
|
|
241
264
|
}
|
|
242
265
|
export { PolylineCollection, isLineStyle };
|
package/lib/RawField.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Float16Array } from "@petamoriken/float16";
|
|
2
|
-
import { ContourData, TypedArray, WindProfile } from "./AutumnTypes";
|
|
2
|
+
import { ContourData, TypedArray, WebGLAnyRenderingContext, WindProfile } from "./AutumnTypes";
|
|
3
3
|
import { FieldContourOpts } from "./ContourCreator";
|
|
4
4
|
import { Grid } from "./Grid";
|
|
5
|
-
|
|
5
|
+
import { WGLTextureSpec } from "autumn-wgl";
|
|
6
|
+
type TextureDataType<ArrayType> = ArrayType extends Float32Array ? Float32Array : (ArrayType extends Uint8Array ? Uint8Array : Uint16Array);
|
|
6
7
|
/** A class representing a raw 2D field of gridded data, such as height or u wind. */
|
|
7
|
-
declare class RawScalarField<ArrayType extends TypedArray> {
|
|
8
|
-
readonly grid:
|
|
8
|
+
declare class RawScalarField<ArrayType extends TypedArray, GridType extends Grid> {
|
|
9
|
+
readonly grid: GridType;
|
|
9
10
|
readonly data: ArrayType;
|
|
10
11
|
private readonly contour_cache;
|
|
11
12
|
/**
|
|
@@ -13,9 +14,15 @@ declare class RawScalarField<ArrayType extends TypedArray> {
|
|
|
13
14
|
* @param grid - The grid on which the data are defined
|
|
14
15
|
* @param data - The data, which should be given as a 1D array in row-major order, with the first element being at the lower-left corner of the grid.
|
|
15
16
|
*/
|
|
16
|
-
constructor(grid:
|
|
17
|
+
constructor(grid: GridType, data: ArrayType);
|
|
17
18
|
/** @internal */
|
|
18
|
-
getTextureData
|
|
19
|
+
private getTextureData;
|
|
20
|
+
getWGLTextureSpec(gl: WebGLAnyRenderingContext, image_mag_filter: number): WGLTextureSpec;
|
|
21
|
+
/**
|
|
22
|
+
* Get contour data as an object with each contour level being a separate property.
|
|
23
|
+
* @param opts - Options for doing the contouring
|
|
24
|
+
* @returns contour data as an object
|
|
25
|
+
*/
|
|
19
26
|
getContours(opts: FieldContourOpts): Promise<ContourData>;
|
|
20
27
|
/**
|
|
21
28
|
* Create a new field by aggregating a number of fields using a specific function
|
|
@@ -26,9 +33,12 @@ declare class RawScalarField<ArrayType extends TypedArray> {
|
|
|
26
33
|
* // Compute wind speed from u and v
|
|
27
34
|
* wind_speed_field = RawScalarField.aggreateFields(Math.hypot, u_field, v_field);
|
|
28
35
|
*/
|
|
29
|
-
static aggregateFields<ArrayType extends TypedArray>(func: (...args: number[]) => number, ...args: RawScalarField<ArrayType>[]): RawScalarField<ArrayType>;
|
|
36
|
+
static aggregateFields<ArrayType extends TypedArray, GridType extends Grid>(func: (...args: number[]) => number, ...args: RawScalarField<ArrayType, GridType>[]): RawScalarField<ArrayType, GridType>;
|
|
37
|
+
sampleField(lon: number, lat: number): number;
|
|
30
38
|
}
|
|
39
|
+
/** The basis vectors for vector fields (i.e, whether vectors a relative to Earth or the grid) */
|
|
31
40
|
type VectorRelativeTo = 'earth' | 'grid';
|
|
41
|
+
/** Options for {@link RawVectorField}s */
|
|
32
42
|
interface RawVectorFieldOptions {
|
|
33
43
|
/**
|
|
34
44
|
* Whether the vectors are relative to the grid ('grid') or Earth ('earth')
|
|
@@ -37,9 +47,9 @@ interface RawVectorFieldOptions {
|
|
|
37
47
|
relative_to?: VectorRelativeTo;
|
|
38
48
|
}
|
|
39
49
|
/** A class representing a 2D gridded field of vectors */
|
|
40
|
-
declare class RawVectorField<ArrayType extends TypedArray> {
|
|
41
|
-
readonly u: RawScalarField<ArrayType>;
|
|
42
|
-
readonly v: RawScalarField<ArrayType>;
|
|
50
|
+
declare class RawVectorField<ArrayType extends TypedArray, GridType extends Grid> {
|
|
51
|
+
readonly u: RawScalarField<ArrayType, GridType>;
|
|
52
|
+
readonly v: RawScalarField<ArrayType, GridType>;
|
|
43
53
|
readonly relative_to: VectorRelativeTo;
|
|
44
54
|
/**
|
|
45
55
|
* Create a vector field.
|
|
@@ -48,26 +58,71 @@ declare class RawVectorField<ArrayType extends TypedArray> {
|
|
|
48
58
|
* @param v - The v (north/south) component of the vectors, which should be given as a 1D array in row-major order, with the first element being at the lower-left corner of the grid
|
|
49
59
|
* @param opts - Options for creating the vector field.
|
|
50
60
|
*/
|
|
51
|
-
constructor(grid:
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
61
|
+
constructor(grid: GridType, u: ArrayType, v: ArrayType, opts?: RawVectorFieldOptions);
|
|
62
|
+
/** @internal */
|
|
63
|
+
private getTextureData;
|
|
64
|
+
getWGLTextureSpecs(gl: WebGLAnyRenderingContext, mag_filter: number): {
|
|
65
|
+
u: WGLTextureSpec;
|
|
66
|
+
v: WGLTextureSpec;
|
|
55
67
|
};
|
|
56
|
-
|
|
57
|
-
|
|
68
|
+
/** @internal */
|
|
69
|
+
getThinnedField(thin_fac: number, map_max_zoom: number): RawVectorField<ArrayType, Grid>;
|
|
70
|
+
/** @internal */
|
|
71
|
+
get grid(): GridType;
|
|
72
|
+
sampleField(lon: number, lat: number): [number, number];
|
|
58
73
|
}
|
|
59
74
|
/** A class grid of wind profiles */
|
|
60
|
-
declare class RawProfileField {
|
|
75
|
+
declare class RawProfileField<GridType extends Grid> {
|
|
61
76
|
readonly profiles: WindProfile[];
|
|
62
|
-
readonly grid:
|
|
77
|
+
readonly grid: GridType;
|
|
63
78
|
/**
|
|
64
79
|
* Create a grid of wind profiles
|
|
65
80
|
* @param grid - The grid on which the profiles are defined
|
|
66
81
|
* @param profiles - The wind profiles themselves, which should be given as a 1D array in row-major order, with the first profile being at the lower-left corner of the grid
|
|
67
82
|
*/
|
|
68
|
-
constructor(grid:
|
|
69
|
-
/**
|
|
70
|
-
|
|
83
|
+
constructor(grid: GridType, profiles: WindProfile[]);
|
|
84
|
+
/**
|
|
85
|
+
* @internal
|
|
86
|
+
* Get the gridded storm motion vector field
|
|
87
|
+
*/
|
|
88
|
+
getStormMotionGrid(): RawVectorField<Float16Array, GridType>;
|
|
89
|
+
/** @internal */
|
|
90
|
+
getProfileCoords(): {
|
|
91
|
+
lats: Float32Array;
|
|
92
|
+
lons: Float32Array;
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Type for an observation data point
|
|
97
|
+
* @example
|
|
98
|
+
* const obs : ObsRawData<'t' | 'td'> = {'t': 71, 'td': 66};
|
|
99
|
+
*/
|
|
100
|
+
type ObsRawData<ObsFieldName extends string> = Record<ObsFieldName, string | number | [number, number] | null>;
|
|
101
|
+
/** Raw observation data, given as a list of objects */
|
|
102
|
+
declare class RawObsField<GridType extends Grid, ObsFieldName extends string> {
|
|
103
|
+
readonly grid: GridType;
|
|
104
|
+
readonly data: ObsRawData<ObsFieldName>[];
|
|
105
|
+
/**
|
|
106
|
+
* Create a field of observations
|
|
107
|
+
* @param grid - The grid on which the obs are defined (can be either a structured or unstructured grid)
|
|
108
|
+
* @param data - The observation data. Conceptually, obs are given as a list of individual observations.
|
|
109
|
+
*/
|
|
110
|
+
constructor(grid: GridType, data: ObsRawData<ObsFieldName>[]);
|
|
111
|
+
/**
|
|
112
|
+
* @internal
|
|
113
|
+
* Get observation element as a list of scalar numbers
|
|
114
|
+
*/
|
|
115
|
+
getScalar(key: ObsFieldName): (number | null)[];
|
|
116
|
+
/**
|
|
117
|
+
* @internal
|
|
118
|
+
* Get observed element as a list of strings (internal method)
|
|
119
|
+
*/
|
|
120
|
+
getStrings(key: ObsFieldName): (string | null)[];
|
|
121
|
+
/**
|
|
122
|
+
* @internal
|
|
123
|
+
* Get observed element as a list of vectors (internal method)
|
|
124
|
+
*/
|
|
125
|
+
getVector(key: ObsFieldName): RawVectorField<Float16Array, GridType>;
|
|
71
126
|
}
|
|
72
|
-
export { RawScalarField, RawVectorField, RawProfileField };
|
|
73
|
-
export type { RawVectorFieldOptions, VectorRelativeTo, TextureDataType };
|
|
127
|
+
export { RawScalarField, RawVectorField, RawProfileField, RawObsField };
|
|
128
|
+
export type { RawVectorFieldOptions, VectorRelativeTo, TextureDataType, ObsRawData };
|