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.
Files changed (59) hide show
  1. package/README.md +11 -207
  2. package/dist/983.autumnplot-gl.js +2 -0
  3. package/dist/983.autumnplot-gl.js.map +1 -0
  4. package/dist/autumnplot-gl.js +1 -1
  5. package/dist/autumnplot-gl.js.map +1 -1
  6. package/dist/marchingsquares.wasm +0 -0
  7. package/lib/AutumnTypes.d.ts +85 -6
  8. package/lib/AutumnTypes.js +28 -1
  9. package/lib/Barbs.d.ts +7 -5
  10. package/lib/BillboardCollection.d.ts +8 -7
  11. package/lib/BillboardCollection.js +69 -58
  12. package/lib/Color.d.ts +2 -0
  13. package/lib/Color.js +4 -0
  14. package/lib/ColorBar.d.ts +19 -0
  15. package/lib/ColorBar.js +9 -6
  16. package/lib/Colormap.d.ts +1 -0
  17. package/lib/Colormap.js +8 -8
  18. package/lib/Contour.d.ts +28 -8
  19. package/lib/Contour.js +27 -54
  20. package/lib/ContourCreator.d.ts +9 -1
  21. package/lib/ContourCreator.js +5 -4
  22. package/lib/Fill.d.ts +28 -14
  23. package/lib/Fill.js +97 -50
  24. package/lib/Grid.d.ts +132 -30
  25. package/lib/Grid.js +355 -99
  26. package/lib/Hodographs.d.ts +15 -8
  27. package/lib/Hodographs.js +48 -30
  28. package/lib/Map.d.ts +14 -1
  29. package/lib/Map.js +60 -4
  30. package/lib/Paintball.d.ts +7 -5
  31. package/lib/Paintball.js +36 -31
  32. package/lib/ParticleTracer.d.ts +19 -0
  33. package/lib/ParticleTracer.js +37 -0
  34. package/lib/PlotComponent.d.ts +7 -7
  35. package/lib/PlotComponent.js +9 -3
  36. package/lib/PlotLayer.d.ts +5 -5
  37. package/lib/PlotLayer.js +2 -2
  38. package/lib/PlotLayer.worker.d.ts +1 -2
  39. package/lib/PlotLayer.worker.js +22 -51
  40. package/lib/PolylineCollection.d.ts +5 -3
  41. package/lib/PolylineCollection.js +60 -37
  42. package/lib/RawField.d.ts +78 -23
  43. package/lib/RawField.js +147 -31
  44. package/lib/ShaderManager.d.ts +12 -0
  45. package/lib/ShaderManager.js +58 -0
  46. package/lib/StationPlot.d.ts +187 -25
  47. package/lib/StationPlot.js +209 -60
  48. package/lib/TextCollection.d.ts +9 -6
  49. package/lib/TextCollection.js +97 -62
  50. package/lib/cpp/marchingsquares.js +483 -585
  51. package/lib/cpp/marchingsquares.wasm +0 -0
  52. package/lib/cpp/marchingsquares_embind.d.ts +23 -3
  53. package/lib/index.d.ts +12 -5
  54. package/lib/index.js +8 -5
  55. package/lib/utils.d.ts +4 -1
  56. package/lib/utils.js +12 -1
  57. package/package.json +3 -3
  58. package/dist/110.autumnplot-gl.js +0 -2
  59. package/dist/110.autumnplot-gl.js.map +0 -1
@@ -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), an {@link MultiPlotLayer}
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: number[] | Float32Array): void;
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 an {@link PlotLayer} instead.
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: number[] | Float32Array): void;
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), an {@link MultiPlotLayer}
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 an {@link PlotLayer} instead.
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, field_ni: number, field_nj: number, thin_fac_base: number, max_zoom: number): {
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: {
@@ -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, thin_fac_base, max_zoom) {
5
- const n_pts_per_poly = 6;
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 n_density_tiers = Math.log2(thin_fac_base);
9
- const n_inaccessible_tiers = Math.max(n_density_tiers + 1 - max_zoom, 0);
10
- const trim_inaccessible = Math.pow(2, n_inaccessible_tiers);
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 = getMinZoom(ilat, ilon, thin_fac_base);
25
- if (zoom > max_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
- // These contain a degenerate triangle on either end to imitate primitive restarting
29
- // (see https://groups.google.com/g/webgl-dev-list/c/KLfiwj4jax0/m/cKiezrhRz8MJ?pli=1)
30
- for (let icrnr = 0; icrnr < n_pts_per_poly; icrnr++) {
31
- const actual_icrnr = Math.max(0, Math.min(icrnr - 1, 3));
32
- pts[istart_pts + icrnr * n_coords_per_pt_pts + 0] = pt_ll.x;
33
- pts[istart_pts + icrnr * n_coords_per_pt_pts + 1] = pt_ll.y;
34
- pts[istart_pts + icrnr * n_coords_per_pt_pts + 2] = zoom * 4 + actual_icrnr;
35
- tex_coords[istart_tc + icrnr * n_coords_per_pt_tc + 0] = ilon / (field_ni - 1);
36
- tex_coords[istart_tc + icrnr * n_coords_per_pt_tc + 1] = ilat / (field_nj - 1);
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
- let igcs = 0;
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 program;
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, matrix: number[] | Float32Array, [map_width, map_height]: [number, number], map_zoom: number, map_bearing: number, map_pitch: number): void;
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, WGLProgram, WGLTexture } from "autumn-wgl";
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
- const polyline_vertex_src = `uniform mat4 u_matrix;
6
+ import { ShaderProgramManager } from "./ShaderManager";
7
+ const polyline_vertex_src = `#version 300 es
8
+
7
9
  uniform int u_offset;
8
10
 
9
- attribute vec3 a_pos;
10
- attribute vec2 a_extrusion;
11
- attribute float a_data;
11
+ in vec3 a_pos;
12
+ in vec2 a_extrusion;
13
+ in float a_data;
12
14
 
13
15
  #ifdef ZOOM
14
- attribute float a_min_zoom;
16
+ in float a_min_zoom;
15
17
  #endif
16
18
 
17
19
  #ifdef OFFSET
18
- attribute vec2 a_offset;
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
- uniform highp float u_map_bearing;
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
- varying highp float v_data;
38
+ out highp float v_data;
36
39
  #endif
37
40
 
38
- varying highp float v_dist;
39
- varying lowp float v_cross;
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 = u_matrix * vec4(a_pos.xy + globe_offset, 0.0, 1.0);
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
- mat4 rotation_matrix = rotationZMatrix(radians(u_map_bearing));
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
- map_stretch_matrix = scalingMatrix(1., u_map_width / u_map_height, 1.);
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 += map_stretch_matrix * rotation_matrix * vec4(offset_offset, 0., 0.);
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
- varying highp float v_data;
132
+ in highp float v_data;
116
133
  #endif
117
134
 
118
- varying highp float v_dist;
119
- varying lowp float v_cross;
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 = texture2D(u_dash_sampler, vec2(dash_x, 0.5)).r;
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
- gl_FragColor = color;
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.program = new WGLProgram(gl, polyline_vertex_src, fragment_src, { define: shader_defines });
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, matrix, [map_width, map_height], map_zoom, map_bearing, map_pitch) {
206
- if (matrix instanceof Float32Array)
207
- matrix = [...matrix];
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
- 'u_matrix': matrix, 'u_line_width': this.width, 'u_map_width': map_width, 'u_map_height': map_height, 'u_map_bearing': map_bearing, 'u_offset': 0, 'u_zoom': map_zoom,
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
- this.program.use(attributes, uniforms, textures);
248
+ program.use(attributes, uniforms, textures);
228
249
  if (this.cmap_gpu !== null) {
229
- this.cmap_gpu.bindShaderVariables(this.program);
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
- this.program.draw();
234
- this.program.setUniforms({ 'u_offset': -2 });
235
- this.program.draw();
236
- this.program.setUniforms({ 'u_offset': -1 });
237
- this.program.draw();
238
- this.program.setUniforms({ 'u_offset': 1 });
239
- this.program.draw();
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
- type TextureDataType<ArrayType> = ArrayType extends Float32Array ? Float32Array : Uint16Array;
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: 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: Grid, data: ArrayType);
17
+ constructor(grid: GridType, data: ArrayType);
17
18
  /** @internal */
18
- getTextureData(): TextureDataType<ArrayType>;
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: Grid, u: ArrayType, v: ArrayType, opts?: RawVectorFieldOptions);
52
- getTextureData(): {
53
- u: TextureDataType<ArrayType>;
54
- v: TextureDataType<ArrayType>;
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
- getThinnedField(thin_x: number, thin_y: number): RawVectorField<ArrayType>;
57
- get grid(): Grid;
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: 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: Grid, profiles: WindProfile[]);
69
- /** Get the gridded storm motion vector field (internal method) */
70
- getStormMotionGrid(): RawVectorField<Float16Array>;
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 };