autumnplot-gl 2.1.0 → 2.2.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.
@@ -1,3 +1,4 @@
1
+ import { Float16Array } from "@petamoriken/float16";
1
2
  interface WindProfile {
2
3
  lat: number;
3
4
  lon: number;
@@ -33,5 +34,6 @@ interface LineSpec {
33
34
  }
34
35
  type WebGLAnyRenderingContext = WebGLRenderingContext | WebGL2RenderingContext;
35
36
  declare function isWebGL2Ctx(gl: WebGLAnyRenderingContext): gl is WebGL2RenderingContext;
37
+ type TypedArray = Float16Array | Float32Array;
36
38
  export { isWebGL2Ctx };
37
- export type { WindProfile, BillboardSpec, PolylineSpec, LineSpec, WebGLAnyRenderingContext };
39
+ export type { WindProfile, BillboardSpec, PolylineSpec, LineSpec, WebGLAnyRenderingContext, TypedArray };
package/lib/Barbs.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { PlotComponent } from "./PlotComponent";
2
- import { BillboardCollection } from './BillboardCollection';
3
2
  import { RawVectorField } from "./RawField";
4
3
  import { MapType } from "./Map";
5
- import { WebGLAnyRenderingContext } from "./AutumnTypes";
4
+ import { TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
6
5
  interface BarbsOptions {
7
6
  /**
8
7
  * The color to use for the barbs as a hex color string;.
@@ -16,10 +15,6 @@ interface BarbsOptions {
16
15
  */
17
16
  thin_fac?: number;
18
17
  }
19
- interface BarbsGLElems {
20
- map: MapType | null;
21
- barb_billboards: BillboardCollection | null;
22
- }
23
18
  /**
24
19
  * A class representing a field of wind barbs. The barbs are automatically thinned based on the zoom level on the map; the user only has to provide a
25
20
  * thinning factor at zoom level 1.
@@ -28,19 +23,18 @@ interface BarbsGLElems {
28
23
  * const vector_field = new RawVectorField(grid, u_data, v_data);
29
24
  * const barbs = new Barbs(vector_field, {color: '#000000', thin_fac: 16});
30
25
  */
31
- declare class Barbs extends PlotComponent {
26
+ declare class Barbs<ArrayType extends TypedArray> extends PlotComponent {
32
27
  /** The vector field */
33
- readonly fields: RawVectorField;
28
+ private readonly fields;
34
29
  readonly color: [number, number, number];
35
30
  readonly thin_fac: number;
36
- /** @private */
37
- gl_elems: BarbsGLElems | null;
31
+ private gl_elems;
38
32
  /**
39
33
  * Create a field of wind barbs
40
34
  * @param fields - The vector field to plot as barbs
41
35
  * @param opts - Options for creating the wind barbs
42
36
  */
43
- constructor(fields: RawVectorField, opts: BarbsOptions);
37
+ constructor(fields: RawVectorField<ArrayType>, opts: BarbsOptions);
44
38
  /**
45
39
  * @internal
46
40
  * Add the barb field to a map
@@ -1,17 +1,17 @@
1
- import { BillboardSpec, WebGLAnyRenderingContext } from "./AutumnTypes";
1
+ import { BillboardSpec, TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
2
2
  import { RawVectorField } from "./RawField";
3
- import { WGLBuffer, WGLProgram, WGLTexture, WGLTextureSpec } from "autumn-wgl";
4
- declare class BillboardCollection {
3
+ import { WGLTextureSpec } from "autumn-wgl";
4
+ declare class BillboardCollection<ArrayType extends TypedArray> {
5
5
  readonly spec: BillboardSpec;
6
6
  readonly color: [number, number, number];
7
7
  readonly size_multiplier: number;
8
- readonly program: WGLProgram;
9
- vertices: WGLBuffer | null;
10
- texcoords: WGLBuffer | null;
11
- readonly texture: WGLTexture;
12
- readonly u_texture: WGLTexture;
13
- readonly v_texture: WGLTexture;
14
- constructor(gl: WebGLAnyRenderingContext, field: RawVectorField, thin_fac: number, max_zoom: number, billboard_image: WGLTextureSpec, billboard_spec: BillboardSpec, billboard_color: [number, number, number], billboard_size_mult: number);
8
+ private readonly program;
9
+ private vertices;
10
+ private texcoords;
11
+ private readonly texture;
12
+ private readonly u_texture;
13
+ private readonly v_texture;
14
+ constructor(gl: WebGLAnyRenderingContext, field: RawVectorField<ArrayType>, thin_fac: number, max_zoom: number, billboard_image: WGLTextureSpec, billboard_spec: BillboardSpec, billboard_color: [number, number, number], billboard_size_mult: number);
15
15
  render(gl: WebGLAnyRenderingContext, matrix: number[], [map_width, map_height]: [number, number], map_zoom: number, map_bearing: number, map_pitch: number): void;
16
16
  }
17
17
  export { BillboardCollection };
@@ -1,5 +1,6 @@
1
- import { isWebGL2Ctx } from "./AutumnTypes";
1
+ import { getGLFormatTypeAlignment } from "./PlotComponent";
2
2
  import { WGLProgram, WGLTexture } from "autumn-wgl";
3
+ import { Cache } from "./utils";
3
4
  const billboard_vertex_shader_src = `uniform mat4 u_matrix;
4
5
 
5
6
  attribute vec3 a_pos;
@@ -100,12 +101,13 @@ void main() {
100
101
  lowp vec4 tex_color = texture2D(u_sampler, v_tex_coord);
101
102
  gl_FragColor = vec4(u_bb_color, tex_color.a);
102
103
  }`
104
+ const program_cache = new Cache((gl) => new WGLProgram(gl, billboard_vertex_shader_src, billboard_fragment_shader_src));
103
105
  class BillboardCollection {
104
106
  constructor(gl, field, thin_fac, max_zoom, billboard_image, billboard_spec, billboard_color, billboard_size_mult) {
105
107
  this.spec = billboard_spec;
106
108
  this.color = billboard_color;
107
109
  this.size_multiplier = billboard_size_mult;
108
- this.program = new WGLProgram(gl, billboard_vertex_shader_src, billboard_fragment_shader_src);
110
+ this.program = program_cache.getValue(gl);
109
111
  this.vertices = null;
110
112
  this.texcoords = null;
111
113
  const n_density_tiers = Math.log2(thin_fac);
@@ -119,14 +121,14 @@ class BillboardCollection {
119
121
  this.vertices = vertices;
120
122
  this.texcoords = texcoords;
121
123
  })();
122
- const format = isWebGL2Ctx(gl) ? gl.R32F : gl.LUMINANCE;
123
- const u_image = { 'format': format, 'type': gl.FLOAT,
124
- 'width': u_thin.grid.ni, 'height': u_thin.grid.nj, 'image': u_thin.data,
125
- 'mag_filter': gl.NEAREST,
124
+ const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, u_thin.isFloat16());
125
+ const u_image = { 'format': format, 'type': type,
126
+ 'width': u_thin.grid.ni, 'height': u_thin.grid.nj, 'image': u_thin.getTextureData(),
127
+ 'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
126
128
  };
127
- const v_image = { 'format': format, 'type': gl.FLOAT,
128
- 'width': v_thin.grid.ni, 'height': v_thin.grid.nj, 'image': v_thin.data,
129
- 'mag_filter': gl.NEAREST,
129
+ const v_image = { 'format': format, 'type': type,
130
+ 'width': v_thin.grid.ni, 'height': v_thin.grid.nj, 'image': v_thin.getTextureData(),
131
+ 'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
130
132
  };
131
133
  this.texture = new WGLTexture(gl, billboard_image);
132
134
  this.u_texture = new WGLTexture(gl, u_image);
package/lib/Contour.d.ts CHANGED
@@ -1,8 +1,7 @@
1
- import { WebGLAnyRenderingContext } from './AutumnTypes';
1
+ import { TypedArray, WebGLAnyRenderingContext } from './AutumnTypes';
2
2
  import { MapType } from './Map';
3
3
  import { PlotComponent } from './PlotComponent';
4
4
  import { RawScalarField } from './RawField';
5
- import { WGLBuffer, WGLProgram, WGLTexture } from 'autumn-wgl';
6
5
  interface ContourOptions {
7
6
  /**
8
7
  * The color of the contours as a hex color string
@@ -26,14 +25,6 @@ interface ContourOptions {
26
25
  */
27
26
  thinner?: (zoom: number) => number;
28
27
  }
29
- interface ContourGLElems {
30
- map: MapType;
31
- program: WGLProgram;
32
- vertices: WGLBuffer;
33
- grid_cell_size: WGLBuffer;
34
- fill_texture: WGLTexture;
35
- texcoords: WGLBuffer;
36
- }
37
28
  /**
38
29
  * A field of contoured data. The contours can optionally be thinned based on map zoom level.
39
30
  * @example
@@ -42,20 +33,19 @@ interface ContourGLElems {
42
33
  * const contours = new Contour(height_field, {color: '#000000', interval: 30,
43
34
  * thinner: zoom => zoom < 5 ? 2 : 1});
44
35
  */
45
- declare class Contour extends PlotComponent {
46
- readonly field: RawScalarField;
36
+ declare class Contour<ArrayType extends TypedArray> extends PlotComponent {
37
+ private readonly field;
47
38
  readonly color: [number, number, number];
48
39
  readonly interval: number;
49
40
  readonly levels: number[];
50
41
  readonly thinner: (zoom: number) => number;
51
- /** @private */
52
- gl_elems: ContourGLElems | null;
42
+ private gl_elems;
53
43
  /**
54
44
  * Create a contoured field
55
45
  * @param field - The field to contour
56
46
  * @param opts - Options for creating the contours
57
47
  */
58
- constructor(field: RawScalarField, opts: ContourOptions);
48
+ constructor(field: RawScalarField<ArrayType>, opts: ContourOptions);
59
49
  /**
60
50
  * @internal
61
51
  * Add the contours to a map
package/lib/Contour.js CHANGED
@@ -1,6 +1,5 @@
1
- import { isWebGL2Ctx } from './AutumnTypes';
2
- import { PlotComponent } from './PlotComponent';
3
- import { hex2rgba } from './utils';
1
+ import { PlotComponent, getGLFormatTypeAlignment } from './PlotComponent';
2
+ import { Cache, hex2rgba } from './utils';
4
3
  import { WGLProgram, WGLTexture } from 'autumn-wgl';
5
4
  const contour_vertex_shader_src = `uniform mat4 u_matrix;
6
5
 
@@ -40,16 +39,20 @@ uniform lowp float u_zoom_fac;
40
39
  void main() {
41
40
  highp float field_val = texture2D(u_fill_sampler, v_tex_coord).r;
42
41
 
43
-
42
+ lowp vec2 grid_point = fract(v_tex_coord / u_step_size + vec2(0.5, 0.5));
43
+ highp vec2 grid_sw = v_tex_coord - grid_point * u_step_size;
44
+
44
45
  lowp vec2 ihat = vec2(u_step_size.x, 0.0);
45
46
  lowp vec2 jhat = vec2(0.0, u_step_size.y);
46
- highp float fv_xp1 = texture2D(u_fill_sampler, v_tex_coord + ihat).r;
47
- highp float fv_xm1 = texture2D(u_fill_sampler, v_tex_coord - ihat).r;
48
- highp float fv_yp1 = texture2D(u_fill_sampler, v_tex_coord + jhat).r;
49
- highp float fv_ym1 = texture2D(u_fill_sampler, v_tex_coord - jhat).r;
50
- highp float fwidth_field = sqrt(((fv_xp1 - fv_xm1) * (fv_xp1 - fv_xm1) + (fv_yp1 - fv_ym1) * (fv_yp1 - fv_ym1)) / (5e5 * v_grid_cell_size));
47
+ highp float fv_sw = texture2D(u_fill_sampler, grid_sw).r;
48
+ highp float fv_se = texture2D(u_fill_sampler, grid_sw + ihat).r;
49
+ highp float fv_nw = texture2D(u_fill_sampler, grid_sw + jhat).r;
50
+ highp float fv_ne = texture2D(u_fill_sampler, grid_sw + ihat + jhat).r;
51
+
52
+ highp float dfdx = mix(fv_se, fv_ne, grid_point.y) - mix(fv_sw, fv_nw, grid_point.y);
53
+ highp float dfdy = mix(fv_nw, fv_ne, grid_point.x) - mix(fv_sw, fv_se, grid_point.x);
54
+ highp float fwidth_field = sqrt((dfdx * dfdx + dfdy * dfdy) / (5e5 * v_grid_cell_size));
51
55
 
52
-
53
56
  lowp float plot_val;
54
57
 
55
58
  if (u_num_contours > 0) {
@@ -97,9 +100,10 @@ void main() {
97
100
 
98
101
  gl_FragColor = vec4(u_color, 1. - (plot_val * plot_val / (u_line_cutoff * u_line_cutoff)));
99
102
  }`
103
+ const program_cache = new Cache((gl) => new WGLProgram(gl, contour_vertex_shader_src, contour_fragment_shader_src));
100
104
  /**
101
105
  * A field of contoured data. The contours can optionally be thinned based on map zoom level.
102
- * &example
106
+ * @example
103
107
  * // Create a contoured height field, with black contours every 30 m (assuming the height field is in
104
108
  * // meters) and only using every other contour when the map zoom level is less than 5.
105
109
  * const contours = new Contour(height_field, {color: '#000000', interval: 30,
@@ -108,8 +112,8 @@ void main() {
108
112
  class Contour extends PlotComponent {
109
113
  /**
110
114
  * Create a contoured field
111
- * &param field - The field to contour
112
- * &param opts - Options for creating the contours
115
+ * @param field - The field to contour
116
+ * @param opts - Options for creating the contours
113
117
  */
114
118
  constructor(field, opts) {
115
119
  super();
@@ -122,23 +126,21 @@ class Contour extends PlotComponent {
122
126
  this.gl_elems = null;
123
127
  }
124
128
  /**
125
- * &internal
129
+ * @internal
126
130
  * Add the contours to a map
127
131
  */
128
132
  async onAdd(map, gl) {
129
133
  // Basic procedure for these contours from https://www.shadertoy.com/view/lltBWM
130
- gl.getExtension('OES_texture_float');
131
- gl.getExtension('OES_texture_float_linear');
132
- gl.getExtension('OES_standard_derivatives');
133
- const program = new WGLProgram(gl, contour_vertex_shader_src, contour_fragment_shader_src);
134
+ gl.getExtension("OES_standard_derivatives");
135
+ const program = program_cache.getValue(gl);
134
136
  const { vertices: verts_buf, texcoords: tex_coords_buf, cellsize: cellsize_buf } = await this.field.grid.getWGLBuffers(gl);
135
137
  const vertices = verts_buf;
136
138
  const texcoords = tex_coords_buf;
137
139
  const grid_cell_size = cellsize_buf;
138
- const format = isWebGL2Ctx(gl) ? gl.R32F : gl.LUMINANCE;
139
- const fill_image = { 'format': format, 'type': gl.FLOAT,
140
- 'width': this.field.grid.ni, 'height': this.field.grid.nj, 'image': this.field.data,
141
- 'mag_filter': gl.LINEAR,
140
+ const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, this.field.isFloat16());
141
+ const fill_image = { 'format': format, 'type': type,
142
+ 'width': this.field.grid.ni, 'height': this.field.grid.nj, 'image': this.field.getTextureData(),
143
+ 'mag_filter': gl.LINEAR, 'row_alignment': row_alignment,
142
144
  };
143
145
  const fill_texture = new WGLTexture(gl, fill_image);
144
146
  this.gl_elems = {
@@ -146,7 +148,7 @@ class Contour extends PlotComponent {
146
148
  };
147
149
  }
148
150
  /**
149
- * &internal
151
+ * @internal
150
152
  * Render the contours
151
153
  */
152
154
  render(gl, matrix) {
@@ -155,8 +157,8 @@ class Contour extends PlotComponent {
155
157
  const gl_elems = this.gl_elems;
156
158
  const zoom = gl_elems.map.getZoom();
157
159
  const intv = this.thinner(zoom) * this.interval;
158
- const cutoff = 0.5 / intv;
159
- const step_size = [0.25 / this.field.grid.ni, 0.25 / this.field.grid.nj];
160
+ const cutoff = 0.3 / intv;
161
+ const step_size = [1 / this.field.grid.ni, 1 / this.field.grid.nj];
160
162
  const zoom_fac = Math.pow(2, zoom);
161
163
  let uniforms = { 'u_contour_interval': intv, 'u_line_cutoff': cutoff, 'u_color': this.color, 'u_step_size': step_size, 'u_zoom_fac': zoom_fac,
162
164
  'u_matrix': matrix, 'u_num_contours': 0, 'u_contour_levels': [0] };
package/lib/Fill.d.ts CHANGED
@@ -1,9 +1,8 @@
1
1
  import { PlotComponent } from './PlotComponent';
2
2
  import { ColorMap } from './Colormap';
3
- import { WGLBuffer, WGLProgram, WGLTexture } from 'autumn-wgl';
4
3
  import { RawScalarField } from './RawField';
5
4
  import { MapType } from './Map';
6
- import { WebGLAnyRenderingContext } from './AutumnTypes';
5
+ import { TypedArray, WebGLAnyRenderingContext } from './AutumnTypes';
7
6
  interface ContourFillOptions {
8
7
  /** The color map to use when creating the fills */
9
8
  cmap: ColorMap;
@@ -22,27 +21,16 @@ interface RasterOptions {
22
21
  */
23
22
  opacity?: number;
24
23
  }
25
- interface PlotComponentFillGLElems {
26
- program: WGLProgram;
27
- vertices: WGLBuffer;
28
- fill_texture: WGLTexture;
29
- texcoords: WGLBuffer;
30
- cmap_texture: WGLTexture;
31
- cmap_nonlin_texture: WGLTexture;
32
- }
33
- declare class PlotComponentFill extends PlotComponent {
34
- readonly field: RawScalarField;
24
+ declare class PlotComponentFill<ArrayType extends TypedArray> extends PlotComponent {
25
+ private readonly field;
35
26
  readonly cmap: ColorMap;
36
27
  readonly opacity: number;
37
- /** @private */
38
- readonly cmap_image: HTMLCanvasElement;
39
- /** @private */
40
- readonly index_map: Float32Array;
41
- /** @private */
42
- gl_elems: PlotComponentFillGLElems | null;
43
- image_mag_filter: number | null;
44
- cmap_mag_filter: number | null;
45
- constructor(field: RawScalarField, opts: ContourFillOptions);
28
+ private readonly cmap_image;
29
+ private readonly index_map;
30
+ private gl_elems;
31
+ protected image_mag_filter: number | null;
32
+ protected cmap_mag_filter: number | null;
33
+ constructor(field: RawScalarField<ArrayType>, opts: ContourFillOptions);
46
34
  onAdd(map: MapType, gl: WebGLAnyRenderingContext): Promise<void>;
47
35
  render(gl: WebGLAnyRenderingContext, matrix: number[]): void;
48
36
  }
@@ -52,13 +40,13 @@ declare class PlotComponentFill extends PlotComponent {
52
40
  * // Create a raster plot with the provided color map
53
41
  * const raster = new Raster(wind_speed_field, {cmap: color_map});
54
42
  */
55
- declare class Raster extends PlotComponentFill {
43
+ declare class Raster<ArrayType extends TypedArray> extends PlotComponentFill<ArrayType> {
56
44
  /**
57
45
  * Create a raster plot
58
46
  * @param field - The field to create the raster plot from
59
47
  * @param opts - Options for creating the raster plot
60
48
  */
61
- constructor(field: RawScalarField, opts: RasterOptions);
49
+ constructor(field: RawScalarField<ArrayType>, opts: RasterOptions);
62
50
  /**
63
51
  * @internal
64
52
  * Add the raster plot to a map
@@ -76,13 +64,13 @@ declare class Raster extends PlotComponentFill {
76
64
  * // Create a field of filled contours with the provided color map
77
65
  * const fill = new ContourFill(wind_speed_field, {cmap: color_map});
78
66
  */
79
- declare class ContourFill extends PlotComponentFill {
67
+ declare class ContourFill<ArrayType extends TypedArray> extends PlotComponentFill<ArrayType> {
80
68
  /**
81
69
  * Create a filled contoured field
82
70
  * @param field - The field to create filled contours from
83
71
  * @param opts - Options for creating the filled contours
84
72
  */
85
- constructor(field: RawScalarField, opts: ContourFillOptions);
73
+ constructor(field: RawScalarField<ArrayType>, opts: ContourFillOptions);
86
74
  /**
87
75
  * @internal
88
76
  * Add the filled contours to a map
package/lib/Fill.js CHANGED
@@ -1,7 +1,8 @@
1
- import { PlotComponent } from './PlotComponent';
1
+ import { PlotComponent, getGLFormatTypeAlignment } from './PlotComponent';
2
2
  import { makeTextureImage } from './Colormap';
3
3
  import { WGLProgram, WGLTexture } from 'autumn-wgl';
4
- import { isWebGL2Ctx } from './AutumnTypes';
4
+ import { Float16Array } from '@petamoriken/float16';
5
+ import { Cache } from './utils';
5
6
  const contourfill_vertex_shader_src = `uniform mat4 u_matrix;
6
7
 
7
8
  attribute vec2 a_pos;
@@ -38,6 +39,7 @@ void main() {
38
39
  color.a = color.a * u_opacity;
39
40
  gl_FragColor = color;
40
41
  }`
42
+ const program_cache = new Cache((gl) => new WGLProgram(gl, contourfill_vertex_shader_src, contourfill_fragment_shader_src));
41
43
  class PlotComponentFill extends PlotComponent {
42
44
  constructor(field, opts) {
43
45
  super();
@@ -62,34 +64,33 @@ class PlotComponentFill extends PlotComponent {
62
64
  const alpha = (lev - cmap_norm[jlev]) / (cmap_norm[jlev + 1] - cmap_norm[jlev]);
63
65
  return input_norm[jlev] * (1 - alpha) + input_norm[jlev + 1] * alpha;
64
66
  });
65
- this.index_map = new Float32Array(inv_cmap_norm);
67
+ this.index_map = new Float16Array(inv_cmap_norm);
66
68
  this.gl_elems = null;
67
69
  this.image_mag_filter = null;
68
70
  this.cmap_mag_filter = null;
69
71
  }
70
72
  async onAdd(map, gl) {
71
73
  // Basic procedure for the filled contours inspired by https://blog.mbq.me/webgl-weather-globe/
72
- gl.getExtension('OES_texture_float');
73
- gl.getExtension('OES_texture_float_linear');
74
74
  if (this.image_mag_filter === null || this.cmap_mag_filter === null) {
75
75
  throw `Implement magnification filtes in a subclass`;
76
76
  }
77
- const program = new WGLProgram(gl, contourfill_vertex_shader_src, contourfill_fragment_shader_src);
77
+ const program = program_cache.getValue(gl);
78
78
  const { vertices: verts_buf, texcoords: tex_coords_buf } = await this.field.grid.getWGLBuffers(gl);
79
79
  const vertices = verts_buf;
80
80
  const texcoords = tex_coords_buf;
81
- const format = isWebGL2Ctx(gl) ? gl.R32F : gl.LUMINANCE;
82
- const fill_image = { 'format': format, 'type': gl.FLOAT,
83
- 'width': this.field.grid.ni, 'height': this.field.grid.nj, 'image': this.field.data,
84
- 'mag_filter': this.image_mag_filter,
81
+ const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, this.field.isFloat16());
82
+ const fill_image = { 'format': format, 'type': type,
83
+ 'width': this.field.grid.ni, 'height': this.field.grid.nj, 'image': this.field.getTextureData(),
84
+ 'mag_filter': this.image_mag_filter, 'row_alignment': row_alignment,
85
85
  };
86
86
  const fill_texture = new WGLTexture(gl, fill_image);
87
87
  const cmap_image = { 'format': gl.RGBA, 'type': gl.UNSIGNED_BYTE, 'image': this.cmap_image, 'mag_filter': this.cmap_mag_filter };
88
88
  const cmap_texture = new WGLTexture(gl, cmap_image);
89
- const cmap_nonlin_image = { 'format': format, 'type': gl.FLOAT,
89
+ const { format: format_nonlin, type: type_nonlin, row_alignment: row_alignment_nonlin } = getGLFormatTypeAlignment(gl, true);
90
+ const cmap_nonlin_image = { 'format': format_nonlin, 'type': type_nonlin,
90
91
  'width': this.index_map.length, 'height': 1,
91
- 'image': this.index_map,
92
- 'mag_filter': gl.LINEAR
92
+ 'image': new Uint16Array(this.index_map.buffer),
93
+ 'mag_filter': gl.LINEAR, 'row_alignment': row_alignment_nonlin,
93
94
  };
94
95
  const cmap_nonlin_texture = new WGLTexture(gl, cmap_nonlin_image);
95
96
  this.gl_elems = {
@@ -110,21 +111,21 @@ class PlotComponentFill extends PlotComponent {
110
111
  }
111
112
  /**
112
113
  * A raster (i.e. pixel) plot
113
- * &example
114
+ * @example
114
115
  * // Create a raster plot with the provided color map
115
116
  * const raster = new Raster(wind_speed_field, {cmap: color_map});
116
117
  */
117
118
  class Raster extends PlotComponentFill {
118
119
  /**
119
120
  * Create a raster plot
120
- * &param field - The field to create the raster plot from
121
- * &param opts - Options for creating the raster plot
121
+ * @param field - The field to create the raster plot from
122
+ * @param opts - Options for creating the raster plot
122
123
  */
123
124
  constructor(field, opts) {
124
125
  super(field, opts);
125
126
  }
126
127
  /**
127
- * &internal
128
+ * @internal
128
129
  * Add the raster plot to a map
129
130
  */
130
131
  async onAdd(map, gl) {
@@ -133,7 +134,7 @@ class Raster extends PlotComponentFill {
133
134
  super.onAdd(map, gl);
134
135
  }
135
136
  /**
136
- * &internal
137
+ * @internal
137
138
  * Render the raster plot
138
139
  */
139
140
  render(gl, matrix) {
@@ -142,21 +143,21 @@ class Raster extends PlotComponentFill {
142
143
  }
143
144
  /**
144
145
  * A filled contoured field
145
- * &example
146
+ * @example
146
147
  * // Create a field of filled contours with the provided color map
147
148
  * const fill = new ContourFill(wind_speed_field, {cmap: color_map});
148
149
  */
149
150
  class ContourFill extends PlotComponentFill {
150
151
  /**
151
152
  * Create a filled contoured field
152
- * &param field - The field to create filled contours from
153
- * &param opts - Options for creating the filled contours
153
+ * @param field - The field to create filled contours from
154
+ * @param opts - Options for creating the filled contours
154
155
  */
155
156
  constructor(field, opts) {
156
157
  super(field, opts);
157
158
  }
158
159
  /**
159
- * &internal
160
+ * @internal
160
161
  * Add the filled contours to a map
161
162
  */
162
163
  async onAdd(map, gl) {
@@ -165,7 +166,7 @@ class ContourFill extends PlotComponentFill {
165
166
  super.onAdd(map, gl);
166
167
  }
167
168
  /**
168
- * &internal
169
+ * @internal
169
170
  * Render the filled contours
170
171
  */
171
172
  render(gl, matrix) {
@@ -1,8 +1,5 @@
1
1
  /// <reference types="mapbox-gl" />
2
2
  import { PlotComponent } from "./PlotComponent";
3
- import { PolylineCollection } from "./PolylineCollection";
4
- import { BillboardCollection } from "./BillboardCollection";
5
- import { MapType } from "./Map";
6
3
  import { RawProfileField } from "./RawField";
7
4
  import { WebGLAnyRenderingContext } from "./AutumnTypes";
8
5
  interface HodographOptions {
@@ -17,19 +14,12 @@ interface HodographOptions {
17
14
  */
18
15
  thin_fac?: number;
19
16
  }
20
- interface HodographGLElems {
21
- map: MapType;
22
- bg_billboard: BillboardCollection | null;
23
- hodo_line: PolylineCollection | null;
24
- sm_line: PolylineCollection | null;
25
- }
26
17
  /** A class representing a a field of hodograph plots */
27
18
  declare class Hodographs extends PlotComponent {
28
- readonly profile_field: RawProfileField;
19
+ private readonly profile_field;
29
20
  readonly bgcolor: [number, number, number];
30
21
  readonly thin_fac: number;
31
- /** @private */
32
- gl_elems: HodographGLElems;
22
+ private gl_elems;
33
23
  /**
34
24
  * Create a field of hodographs
35
25
  * @param profile_field - The grid of profiles to plot
package/lib/Map.d.ts CHANGED
@@ -8,6 +8,14 @@ interface LambertConformalConicParameters {
8
8
  declare function lambertConformalConic(params: LambertConformalConicParameters): (a: number, b: number, opts?: {
9
9
  inverse: boolean;
10
10
  }) => [number, number];
11
+ interface RotateSphereParams {
12
+ np_lon: number;
13
+ np_lat: number;
14
+ lon_shift: number;
15
+ }
16
+ declare function rotateSphere(params: RotateSphereParams): (a: number, b: number, opts?: {
17
+ inverse: boolean;
18
+ }) => [number, number];
11
19
  /**
12
20
  * A `LngLat` object represents a given longitude and latitude coordinate, measured in degrees.
13
21
  * These coordinates are based on the [WGS84 (EPSG:4326) standard](https://en.wikipedia.org/wiki/World_Geodetic_System#WGS84).
@@ -30,5 +38,5 @@ declare class LngLat {
30
38
  y: number;
31
39
  };
32
40
  }
33
- export { LngLat, lambertConformalConic };
41
+ export { LngLat, lambertConformalConic, rotateSphere };
34
42
  export type { MapType };
package/lib/Map.js CHANGED
@@ -83,6 +83,44 @@ function lambertConformalConic(params) {
83
83
  return opts.inverse ? compute_lcc_inverse(a, b) : compute_lcc(a, b);
84
84
  };
85
85
  }
86
+ function rotateSphere(params) {
87
+ const radians = Math.PI / 180;
88
+ const np_lat = params.np_lat * radians;
89
+ const np_lon = params.np_lon * radians;
90
+ const lon_shift = params.lon_shift * radians;
91
+ const sin_np_lat = Math.sin(np_lat);
92
+ const cos_np_lat = Math.cos(np_lat);
93
+ const compute_rotation = (lon, lat) => {
94
+ lon *= radians;
95
+ lat *= radians;
96
+ const sin_lat = Math.sin(lat);
97
+ const cos_lat = Math.cos(lat);
98
+ const sin_lon_diff = Math.sin(lon - lon_shift);
99
+ const cos_lon_diff = Math.cos(lon - lon_shift);
100
+ const lat_p = Math.asin(sin_np_lat * sin_lat - cos_np_lat * cos_lat * cos_lon_diff);
101
+ let lon_p = np_lon + Math.atan2((cos_lat * sin_lon_diff), (sin_np_lat * cos_lat * cos_lon_diff + cos_np_lat * sin_lat));
102
+ if (lon_p > Math.PI)
103
+ lon_p -= 2 * Math.PI;
104
+ return [lon_p / radians, lat_p / radians];
105
+ };
106
+ const compute_rotation_inverse = (lon_p, lat_p) => {
107
+ lon_p *= radians;
108
+ lat_p *= radians;
109
+ const sin_lat_p = Math.sin(lat_p);
110
+ const cos_lat_p = Math.cos(lat_p);
111
+ const sin_lon_p_diff = Math.sin(lon_p - np_lon);
112
+ const cos_lon_p_diff = Math.cos(lon_p - np_lon);
113
+ const lat = Math.asin(sin_np_lat * sin_lat_p + cos_np_lat * cos_lat_p * cos_lon_p_diff);
114
+ let lon = lon_shift + Math.atan2((cos_lat_p * sin_lon_p_diff), (sin_np_lat * cos_lat_p * cos_lon_p_diff - cos_np_lat * sin_lat_p));
115
+ if (lon_p > Math.PI)
116
+ lon_p -= 2 * Math.PI;
117
+ return [lon / radians, lat / radians];
118
+ };
119
+ return (a, b, opts) => {
120
+ opts = opts === undefined ? { inverse: false } : opts;
121
+ return opts.inverse ? compute_rotation_inverse(a, b) : compute_rotation(a, b);
122
+ };
123
+ }
86
124
  function mercatorXfromLng(lng) {
87
125
  return (180 + lng) / 360;
88
126
  }
@@ -117,4 +155,4 @@ class LngLat {
117
155
  return { x: mercatorXfromLng(this.lng), y: mercatorYfromLat(this.lat) };
118
156
  }
119
157
  }
120
- export { LngLat, lambertConformalConic };
158
+ export { LngLat, lambertConformalConic, rotateSphere };
@@ -1,8 +1,7 @@
1
- import { WebGLAnyRenderingContext } from "./AutumnTypes";
1
+ import { TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
2
2
  import { MapType } from "./Map";
3
3
  import { PlotComponent } from "./PlotComponent";
4
4
  import { RawScalarField } from "./RawField";
5
- import { WGLBuffer, WGLProgram, WGLTexture } from "autumn-wgl";
6
5
  interface PaintballOptions {
7
6
  /**
8
7
  * The list of colors (as hex strings) to use for each member in the paintball plot. The first color corresponds to member 1, the second to member 2, etc.
@@ -14,12 +13,6 @@ interface PaintballOptions {
14
13
  */
15
14
  opacity?: number;
16
15
  }
17
- interface PaintballGLElems {
18
- program: WGLProgram;
19
- vertices: WGLBuffer;
20
- fill_texture: WGLTexture;
21
- texcoords: WGLBuffer;
22
- }
23
16
  /**
24
17
  * A class representing a paintball plot, which is a plot of objects in every member of an ensemble. Objects are usually defined by a single threshold on
25
18
  * a field (such as simulated reflectivity greater than 40 dBZ), but could in theory be defined by any arbitrarily complicated method. In autumnplot-gl,
@@ -27,12 +20,11 @@ interface PaintballGLElems {
27
20
  * 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
28
21
  * significand of an IEEE 754 float.)
29
22
  */
30
- declare class Paintball extends PlotComponent {
31
- readonly field: RawScalarField;
23
+ declare class Paintball<ArrayType extends TypedArray> extends PlotComponent {
24
+ private readonly field;
32
25
  readonly colors: number[];
33
26
  readonly opacity: number;
34
- /** @private */
35
- gl_elems: PaintballGLElems | null;
27
+ private gl_elems;
36
28
  /**
37
29
  * Create a paintball plot
38
30
  * @param field - A scalar field containing the member objects encoded as "bits." The numerical value of each grid point can be constructed like
@@ -40,7 +32,7 @@ declare class Paintball extends PlotComponent {
40
32
  * `M2` is the same thing for member 2, and `M3` and `M4` and up to `Mn` are the same thing for the rest of the members.
41
33
  * @param opts - Options for creating the paintball plot
42
34
  */
43
- constructor(field: RawScalarField, opts?: PaintballOptions);
35
+ constructor(field: RawScalarField<ArrayType>, opts?: PaintballOptions);
44
36
  /**
45
37
  * @internal
46
38
  * Add the paintball plot to a map.