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.
package/lib/RawField.js CHANGED
@@ -1,19 +1,8 @@
1
- import { lambertConformalConic } from "./Map";
1
+ import { Float16Array } from "@petamoriken/float16";
2
+ import { lambertConformalConic, rotateSphere } from "./Map";
2
3
  import { layer_worker } from "./PlotComponent";
3
- import { zip } from "./utils";
4
+ import { Cache, zip } from "./utils";
4
5
  import { WGLBuffer } from "autumn-wgl";
5
- class Cache {
6
- constructor(compute_value) {
7
- this.cached_value = null;
8
- this.compute_value = compute_value;
9
- }
10
- getValue(...args) {
11
- if (this.cached_value === null) {
12
- this.cached_value = this.compute_value(...args);
13
- }
14
- return this.cached_value;
15
- }
16
- }
17
6
  async function makeWGLDomainBuffers(gl, grid, native_grid) {
18
7
  native_grid = native_grid !== undefined ? native_grid : grid;
19
8
  const texcoord_margin_r = 1 / (2 * native_grid.ni);
@@ -42,20 +31,20 @@ class Grid {
42
31
  this.is_conformal = is_conformal;
43
32
  this.ni = ni;
44
33
  this.nj = nj;
45
- this._buffer_cache = new Cache((gl) => {
34
+ this.buffer_cache = new Cache((gl) => {
46
35
  const new_ni = Math.max(Math.floor(this.ni / 50), 20);
47
36
  const new_nj = Math.max(Math.floor(this.nj / 50), 20);
48
37
  return makeWGLDomainBuffers(gl, this.copy({ ni: new_ni, nj: new_nj }), this);
49
38
  });
50
- this._billboard_buffer_cache = new Cache((gl, thin_fac, max_zoom) => {
39
+ this.billboard_buffer_cache = new Cache((gl, thin_fac, max_zoom) => {
51
40
  return makeWGLBillboardBuffers(gl, this, thin_fac, max_zoom);
52
41
  });
53
42
  }
54
43
  async getWGLBuffers(gl) {
55
- return await this._buffer_cache.getValue(gl);
44
+ return await this.buffer_cache.getValue(gl);
56
45
  }
57
46
  async getWGLBillboardBuffers(gl, thin_fac, max_zoom) {
58
- return await this._billboard_buffer_cache.getValue(gl, thin_fac, max_zoom);
47
+ return await this.billboard_buffer_cache.getValue(gl, thin_fac, max_zoom);
59
48
  }
60
49
  }
61
50
  /** A plate carree (a.k.a. lat/lon) grid with uniform grid spacing */
@@ -75,7 +64,7 @@ class PlateCarreeGrid extends Grid {
75
64
  this.ll_lat = ll_lat;
76
65
  this.ur_lon = ur_lon;
77
66
  this.ur_lat = ur_lat;
78
- this._ll_cache = new Cache(() => {
67
+ this.ll_cache = new Cache(() => {
79
68
  const dlon = (this.ur_lon - this.ll_lon) / (this.ni - 1);
80
69
  const dlat = (this.ur_lat - this.ll_lat) / (this.nj - 1);
81
70
  const lons = new Float32Array(this.ni * this.nj);
@@ -104,7 +93,7 @@ class PlateCarreeGrid extends Grid {
104
93
  * Get a list of longitudes and latitudes on the grid (internal method)
105
94
  */
106
95
  getCoords() {
107
- return this._ll_cache.getValue();
96
+ return this.ll_cache.getValue();
108
97
  }
109
98
  transform(x, y, opts) {
110
99
  return [x, y];
@@ -123,6 +112,81 @@ class PlateCarreeGrid extends Grid {
123
112
  return new PlateCarreeGrid(ni, nj, ll_lon, ll_lat, ur_lon, ur_lat);
124
113
  }
125
114
  }
115
+ /** A rotated lat-lon (plate carree) grid with uniform grid spacing */
116
+ class PlateCarreeRotatedGrid extends Grid {
117
+ /**
118
+ * Create a Lambert conformal conic grid
119
+ * @param ni - The number of grid points in the i (longitude) direction
120
+ * @param nj - The number of grid points in the j (latitude) direction
121
+ * @param np_lon - The longitude of the north pole for the rotated grid
122
+ * @param np_lat - The latitude of the north pole for the rotated grid
123
+ * @param lon_shift - The angle around the rotated north pole to shift the central meridian
124
+ * @param ll_lon - The longitude of the lower left corner of the grid (on the rotated earth)
125
+ * @param ll_lat - The latitude of the lower left corner of the grid (on the rotated earth)
126
+ * @param ur_lon - The longitude of the upper right corner of the grid (on the rotated earth)
127
+ * @param ur_lat - The latitude of the upper right corner of the grid (on the rotated earth)
128
+ */
129
+ constructor(ni, nj, np_lon, np_lat, lon_shift, ll_lon, ll_lat, ur_lon, ur_lat) {
130
+ super('latlonrot', true, ni, nj);
131
+ this.np_lon = np_lon;
132
+ this.np_lat = np_lat;
133
+ this.lon_shift = lon_shift;
134
+ this.ll_lon = ll_lon;
135
+ this.ll_lat = ll_lat;
136
+ this.ur_lon = ur_lon;
137
+ this.ur_lat = ur_lat;
138
+ this.llrot = rotateSphere({ np_lon: np_lon, np_lat: np_lat, lon_shift: lon_shift });
139
+ this.ll_cache = new Cache(() => {
140
+ const lons = new Float32Array(this.ni * this.nj);
141
+ const lats = new Float32Array(this.ni * this.nj);
142
+ for (let i = 0; i < this.ni; i++) {
143
+ const lon_p = this.ll_lon + (this.ur_lon - this.ll_lon) * i / (this.ni - 1);
144
+ for (let j = 0; j < this.nj; j++) {
145
+ const lat_p = this.ll_lat + (this.ur_lat - this.ll_lat) * j / (this.nj - 1);
146
+ const [lon, lat] = this.llrot(lon_p, lat_p);
147
+ const idx = i + j * this.ni;
148
+ lons[idx] = lon;
149
+ lats[idx] = lat;
150
+ }
151
+ }
152
+ return { lons: lons, lats: lats };
153
+ });
154
+ }
155
+ copy(opts) {
156
+ opts = opts !== undefined ? opts : {};
157
+ const ni = opts.ni !== undefined ? opts.ni : this.ni;
158
+ const nj = opts.nj !== undefined ? opts.nj : this.nj;
159
+ const ll_lon = opts.ll_lon !== undefined ? opts.ll_lon : this.ll_lon;
160
+ const ll_lat = opts.ll_lat !== undefined ? opts.ll_lat : this.ll_lat;
161
+ const ur_lon = opts.ur_lon !== undefined ? opts.ur_lon : this.ur_lon;
162
+ const ur_lat = opts.ur_lat !== undefined ? opts.ur_lat : this.ur_lat;
163
+ return new PlateCarreeRotatedGrid(ni, nj, this.np_lon, this.np_lat, this.lon_shift, ll_lon, ll_lat, ur_lon, ur_lat);
164
+ }
165
+ /**
166
+ * Get a list of longitudes and latitudes on the grid (internal method)
167
+ */
168
+ getCoords() {
169
+ return this.ll_cache.getValue();
170
+ }
171
+ transform(x, y, opts) {
172
+ opts = opts === undefined ? {} : opts;
173
+ const inverse = 'inverse' in opts ? opts.inverse : false;
174
+ return this.llrot(x, y, { inverse: !inverse });
175
+ }
176
+ getThinnedGrid(thin_x, thin_y) {
177
+ const dlon = (this.ur_lon - this.ll_lon) / this.ni;
178
+ const dlat = (this.ur_lat - this.ll_lat) / this.nj;
179
+ const ni = Math.ceil(this.ni / thin_x);
180
+ const nj = Math.ceil(this.nj / thin_y);
181
+ const ni_remove = (this.ni - 1) % thin_x;
182
+ const nj_remove = (this.nj - 1) % thin_y;
183
+ const ll_lon = this.ll_lon;
184
+ const ll_lat = this.ll_lat;
185
+ const ur_lon = this.ur_lon - ni_remove * dlon;
186
+ const ur_lat = this.ur_lat - nj_remove * dlat;
187
+ return new PlateCarreeRotatedGrid(ni, nj, this.np_lon, this.np_lat, this.lon_shift, ll_lon, ll_lat, ur_lon, ur_lat);
188
+ }
189
+ }
126
190
  /** A Lambert conformal conic grid with uniform grid spacing */
127
191
  class LambertGrid extends Grid {
128
192
  /**
@@ -147,7 +211,7 @@ class LambertGrid extends Grid {
147
211
  this.ur_x = ur_x;
148
212
  this.ur_y = ur_y;
149
213
  this.lcc = lambertConformalConic({ lon_0: lon_0, lat_0: lat_0, lat_std: lat_std });
150
- this._ll_cache = new Cache(() => {
214
+ this.ll_cache = new Cache(() => {
151
215
  const lons = new Float32Array(this.ni * this.nj);
152
216
  const lats = new Float32Array(this.ni * this.nj);
153
217
  for (let i = 0; i < this.ni; i++) {
@@ -177,7 +241,7 @@ class LambertGrid extends Grid {
177
241
  * Get a list of longitudes and latitudes on the grid (internal method)
178
242
  */
179
243
  getCoords() {
180
- return this._ll_cache.getValue();
244
+ return this.ll_cache.getValue();
181
245
  }
182
246
  transform(x, y, opts) {
183
247
  opts = opts === undefined ? {} : opts;
@@ -198,6 +262,9 @@ class LambertGrid extends Grid {
198
262
  return new LambertGrid(ni, nj, this.lon_0, this.lat_0, this.lat_std, ll_x, ll_y, ur_x, ur_y);
199
263
  }
200
264
  }
265
+ function getArrayConstructor(ary) {
266
+ return ary.constructor;
267
+ }
201
268
  /** A class representing a raw 2D field of gridded data, such as height or u wind. */
202
269
  class RawScalarField {
203
270
  /**
@@ -212,9 +279,25 @@ class RawScalarField {
212
279
  throw `Data size (${data.length}) doesn't match the grid dimensions (${grid.ni} x ${grid.nj}; expected ${grid.ni * grid.nj} points)`;
213
280
  }
214
281
  }
282
+ /** @internal */
283
+ getTextureData() {
284
+ // Need to give float16 data as uint16s to make WebGL happy: https://github.com/petamoriken/float16/issues/105
285
+ let data;
286
+ if (this.data instanceof Float32Array) {
287
+ data = this.data;
288
+ }
289
+ else {
290
+ data = new Uint16Array(this.data.buffer);
291
+ }
292
+ return data;
293
+ }
294
+ isFloat16() {
295
+ return !(this.data instanceof Float32Array);
296
+ }
215
297
  getThinnedField(thin_x, thin_y) {
298
+ const arrayType = getArrayConstructor(this.data);
216
299
  const new_grid = this.grid.getThinnedGrid(thin_x, thin_y);
217
- const new_data = new Float32Array(new_grid.ni * new_grid.nj);
300
+ const new_data = new arrayType(new_grid.ni * new_grid.nj);
218
301
  for (let i = 0; i < new_grid.ni; i++) {
219
302
  for (let j = 0; j < new_grid.nj; j++) {
220
303
  const idx_old = i * thin_x + this.grid.ni * j * thin_y;
@@ -239,8 +322,9 @@ class RawScalarField {
239
322
  yield func(elem);
240
323
  }
241
324
  }
325
+ const arrayType = getArrayConstructor(args[0].data);
242
326
  const zipped_args = zip(...args.map(a => a.data));
243
- const agg_data = new Float32Array(mapGenerator(zipped_args, (a) => func(...a)));
327
+ const agg_data = new arrayType(mapGenerator(zipped_args, (a) => func(...a)));
244
328
  return new RawScalarField(args[0].grid, agg_data);
245
329
  }
246
330
  }
@@ -255,14 +339,15 @@ class RawVectorField {
255
339
  */
256
340
  constructor(grid, u, v, opts) {
257
341
  opts = opts === undefined ? {} : opts;
342
+ const arrayType = getArrayConstructor(u);
258
343
  this.u = new RawScalarField(grid, u);
259
344
  this.v = new RawScalarField(grid, v);
260
345
  this.relative_to = opts.relative_to === undefined ? 'grid' : opts.relative_to;
261
- this._rotate_cache = new Cache(() => {
346
+ this.rotate_cache = new Cache(() => {
262
347
  const grid = this.u.grid;
263
348
  const coords = grid.getCoords();
264
- const u_rot = new Float32Array(coords.lats.length);
265
- const v_rot = new Float32Array(coords.lats.length);
349
+ const u_rot = new arrayType(coords.lats.length);
350
+ const v_rot = new arrayType(coords.lats.length);
266
351
  for (let icd = 0; icd < coords.lats.length; icd++) {
267
352
  const lon = coords.lons[icd];
268
353
  const lat = coords.lats[icd];
@@ -307,7 +392,7 @@ class RawVectorField {
307
392
  v = this.v;
308
393
  }
309
394
  else {
310
- const { u: u_, v: v_ } = this._rotate_cache.getValue();
395
+ const { u: u_, v: v_ } = this.rotate_cache.getValue();
311
396
  u = u_;
312
397
  v = v_;
313
398
  }
@@ -327,8 +412,8 @@ class RawProfileField {
327
412
  }
328
413
  /** Get the gridded storm motion vector field (internal method) */
329
414
  getStormMotionGrid() {
330
- const u = new Float32Array(this.grid.ni * this.grid.nj);
331
- const v = new Float32Array(this.grid.ni * this.grid.nj);
415
+ const u = new Float16Array(this.grid.ni * this.grid.nj);
416
+ const v = new Float16Array(this.grid.ni * this.grid.nj);
332
417
  this.profiles.forEach(prof => {
333
418
  const idx = prof.ilon + this.grid.ni * prof.jlat;
334
419
  u[idx] = prof.smu;
@@ -337,4 +422,4 @@ class RawProfileField {
337
422
  return new RawVectorField(this.grid, u, v, { relative_to: 'grid' });
338
423
  }
339
424
  }
340
- export { RawScalarField, RawVectorField, RawProfileField, PlateCarreeGrid, LambertGrid, Grid };
425
+ export { RawScalarField, RawVectorField, RawProfileField, PlateCarreeGrid, PlateCarreeRotatedGrid, LambertGrid, Grid };
package/lib/index.d.ts CHANGED
@@ -5,11 +5,11 @@ import Barbs, { BarbsOptions } from "./Barbs";
5
5
  import Paintball, { PaintballOptions } from "./Paintball";
6
6
  import Hodographs, { HodographOptions } from './Hodographs';
7
7
  import { PlotLayer, MultiPlotLayer } from './PlotLayer';
8
- import { WindProfile, WebGLAnyRenderingContext } from "./AutumnTypes";
8
+ import { WindProfile, WebGLAnyRenderingContext, TypedArray } from "./AutumnTypes";
9
9
  import { MapType } from "./Map";
10
10
  import { ColorMap, Color } from './Colormap';
11
11
  import { makeColorBar, makePaintballKey, ColorbarOrientation, ColorbarTickDirection, ColorBarOptions, PaintballKeyOptions } from "./ColorBar";
12
- import { RawScalarField, RawVectorField, RawProfileField, Grid, GridType, VectorRelativeTo, RawVectorFieldOptions, PlateCarreeGrid, LambertGrid } from "./RawField";
12
+ import { RawScalarField, RawVectorField, RawProfileField, Grid, GridType, VectorRelativeTo, RawVectorFieldOptions, PlateCarreeGrid, PlateCarreeRotatedGrid, LambertGrid } from "./RawField";
13
13
  declare const colormaps: {
14
14
  bluered: (level_min: number, level_max: number, n_colors: number) => ColorMap;
15
15
  redblue: (level_min: number, level_max: number, n_colors: number) => ColorMap;
@@ -20,4 +20,4 @@ declare const colormaps: {
20
20
  pw_td2m: ColorMap;
21
21
  nws_storm_clear_refl: ColorMap;
22
22
  };
23
- export { PlotComponent, Barbs, BarbsOptions, Contour, ContourOptions, ContourFill, Raster, ContourFillOptions, RasterOptions, Paintball, PaintballOptions, Hodographs, HodographOptions, WindProfile, PlotLayer, MultiPlotLayer, MapType, ColorMap, colormaps, makeColorBar, makePaintballKey, Color, ColorbarOrientation, ColorbarTickDirection, ColorBarOptions, PaintballKeyOptions, RawScalarField, RawVectorField, RawProfileField, Grid, GridType, VectorRelativeTo, RawVectorFieldOptions, PlateCarreeGrid, LambertGrid, WebGLAnyRenderingContext };
23
+ export { PlotComponent, Barbs, BarbsOptions, Contour, ContourOptions, ContourFill, Raster, ContourFillOptions, RasterOptions, Paintball, PaintballOptions, Hodographs, HodographOptions, WindProfile, PlotLayer, MultiPlotLayer, MapType, ColorMap, colormaps, makeColorBar, makePaintballKey, Color, ColorbarOrientation, ColorbarTickDirection, ColorBarOptions, PaintballKeyOptions, RawScalarField, RawVectorField, RawProfileField, Grid, GridType, VectorRelativeTo, RawVectorFieldOptions, PlateCarreeGrid, PlateCarreeRotatedGrid, LambertGrid, WebGLAnyRenderingContext, TypedArray };
package/lib/index.js CHANGED
@@ -7,7 +7,7 @@ import Hodographs from './Hodographs';
7
7
  import { PlotLayer, MultiPlotLayer } from './PlotLayer';
8
8
  import { ColorMap, bluered, redblue, pw_speed500mb, pw_speed850mb, pw_cape, pw_t2m, pw_td2m, nws_storm_clear_refl } from './Colormap';
9
9
  import { makeColorBar, makePaintballKey } from "./ColorBar";
10
- import { RawScalarField, RawVectorField, RawProfileField, Grid, PlateCarreeGrid, LambertGrid } from "./RawField";
10
+ import { RawScalarField, RawVectorField, RawProfileField, Grid, PlateCarreeGrid, PlateCarreeRotatedGrid, LambertGrid } from "./RawField";
11
11
  const colormaps = {
12
12
  bluered: bluered,
13
13
  redblue: redblue,
@@ -18,4 +18,4 @@ const colormaps = {
18
18
  pw_td2m: pw_td2m,
19
19
  nws_storm_clear_refl: nws_storm_clear_refl,
20
20
  };
21
- export { PlotComponent, Barbs, Contour, ContourFill, Raster, Paintball, Hodographs, PlotLayer, MultiPlotLayer, ColorMap, colormaps, makeColorBar, makePaintballKey, RawScalarField, RawVectorField, RawProfileField, Grid, PlateCarreeGrid, LambertGrid };
21
+ export { PlotComponent, Barbs, Contour, ContourFill, Raster, Paintball, Hodographs, PlotLayer, MultiPlotLayer, ColorMap, colormaps, makeColorBar, makePaintballKey, RawScalarField, RawVectorField, RawProfileField, Grid, PlateCarreeGrid, PlateCarreeRotatedGrid, LambertGrid };
package/lib/utils.d.ts CHANGED
@@ -6,4 +6,11 @@ declare const rgb2hsv: (rgb: [number, number, number]) => [number, number, numbe
6
6
  declare const hsv2rgb: (hsv: [number, number, number]) => [number, number, number];
7
7
  declare function getMinZoom(jlat: number, ilon: number, thin_fac_base: number): number;
8
8
  declare function zip(...args: any[]): Generator<any[], void, unknown>;
9
- export { hex2rgba, rgba2hex, hex2rgb, rgb2hex, rgb2hsv, hsv2rgb, zip, getMinZoom };
9
+ declare function getOS(): string;
10
+ declare class Cache<A extends unknown[], R> {
11
+ private cached_value;
12
+ private readonly compute_value;
13
+ constructor(compute_value: (...args: A) => R);
14
+ getValue(...args: A): R;
15
+ }
16
+ export { hex2rgba, rgba2hex, hex2rgb, rgb2hex, rgb2hsv, hsv2rgb, zip, getMinZoom, getOS, Cache };
package/lib/utils.js CHANGED
@@ -100,4 +100,36 @@ function* zip(...args) {
100
100
  yield current.map(x => x.value);
101
101
  }
102
102
  }
103
- export { hex2rgba, rgba2hex, hex2rgb, rgb2hex, rgb2hsv, hsv2rgb, zip, getMinZoom };
103
+ function getOS() {
104
+ const userAgent = window.navigator.userAgent, platform = window.navigator.platform, macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'], windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'], iosPlatforms = ['iPhone', 'iPad', 'iPod'];
105
+ let os = null;
106
+ if (macosPlatforms.indexOf(platform) !== -1 && navigator.maxTouchPoints <= 1) {
107
+ os = 'Mac OS';
108
+ }
109
+ else if (iosPlatforms.indexOf(platform) !== -1 || (macosPlatforms.indexOf(platform) !== -1 && navigator.maxTouchPoints > 1)) {
110
+ os = 'iOS';
111
+ }
112
+ else if (windowsPlatforms.indexOf(platform) !== -1) {
113
+ os = 'Windows';
114
+ }
115
+ else if (/Android/.test(userAgent)) {
116
+ os = 'Android';
117
+ }
118
+ else if (/Linux/.test(platform)) {
119
+ os = 'Linux';
120
+ }
121
+ return os;
122
+ }
123
+ class Cache {
124
+ constructor(compute_value) {
125
+ this.cached_value = null;
126
+ this.compute_value = compute_value;
127
+ }
128
+ getValue(...args) {
129
+ if (this.cached_value === null) {
130
+ this.cached_value = this.compute_value(...args);
131
+ }
132
+ return this.cached_value;
133
+ }
134
+ }
135
+ export { hex2rgba, rgba2hex, hex2rgb, rgb2hex, rgb2hsv, hsv2rgb, zip, getMinZoom, getOS, Cache };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autumnplot-gl",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -31,7 +31,8 @@
31
31
  "webpack-glsl-loader": "^1.0.1"
32
32
  },
33
33
  "dependencies": {
34
- "autumn-wgl": "^1.1.0",
34
+ "@petamoriken/float16": "^3.8.4",
35
+ "autumn-wgl": "^1.2.0",
35
36
  "comlink": "^4.3.1"
36
37
  }
37
38
  }