autumnplot-gl 2.0.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/AutumnTypes.d.ts +3 -1
- package/lib/Barbs.d.ts +5 -11
- package/lib/BillboardCollection.d.ts +10 -10
- package/lib/BillboardCollection.js +11 -9
- package/lib/ColorBar.d.ts +5 -0
- package/lib/ColorBar.js +11 -4
- package/lib/Colormap.d.ts +2 -1
- package/lib/Colormap.js +18 -3
- package/lib/Contour.d.ts +5 -15
- package/lib/Contour.js +27 -25
- package/lib/Fill.d.ts +86 -0
- package/lib/{ContourFill.js → Fill.js} +86 -35
- package/lib/Hodographs.d.ts +2 -12
- package/lib/Map.d.ts +9 -1
- package/lib/Map.js +39 -1
- package/lib/Paintball.d.ts +5 -13
- package/lib/Paintball.js +13 -12
- package/lib/PlotComponent.d.ts +6 -1
- package/lib/PlotComponent.js +34 -1
- package/lib/PlotLayer.d.ts +6 -11
- package/lib/PlotLayer.js +5 -6
- package/lib/PolylineCollection.d.ts +8 -8
- package/lib/PolylineCollection.js +3 -1
- package/lib/RawField.d.ts +68 -44
- package/lib/RawField.js +116 -31
- package/lib/index.d.ts +5 -4
- package/lib/index.js +6 -5
- package/lib/utils.d.ts +8 -1
- package/lib/utils.js +33 -1
- package/package.json +3 -2
- package/lib/ContourFill.d.ts +0 -58
package/lib/RawField.d.ts
CHANGED
|
@@ -1,30 +1,18 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Float16Array } from "@petamoriken/float16";
|
|
2
|
+
import { TypedArray, WebGLAnyRenderingContext, WindProfile } from "./AutumnTypes";
|
|
2
3
|
import { WGLBuffer } from "autumn-wgl";
|
|
3
|
-
declare class Cache<A extends unknown[], R> {
|
|
4
|
-
cached_value: R | null;
|
|
5
|
-
compute_value: (...args: A) => R;
|
|
6
|
-
constructor(compute_value: (...args: A) => R);
|
|
7
|
-
getValue(...args: A): R;
|
|
8
|
-
}
|
|
9
4
|
interface Coords {
|
|
10
5
|
lons: Float32Array;
|
|
11
6
|
lats: Float32Array;
|
|
12
7
|
}
|
|
13
|
-
type GridType = 'latlon' | 'lcc';
|
|
8
|
+
type GridType = 'latlon' | 'latlonrot' | 'lcc';
|
|
14
9
|
declare abstract class Grid {
|
|
15
10
|
readonly type: GridType;
|
|
16
11
|
readonly ni: number;
|
|
17
12
|
readonly nj: number;
|
|
18
13
|
readonly is_conformal: boolean;
|
|
19
|
-
readonly
|
|
20
|
-
|
|
21
|
-
'texcoords': WGLBuffer;
|
|
22
|
-
'cellsize': WGLBuffer;
|
|
23
|
-
}>>;
|
|
24
|
-
readonly _billboard_buffer_cache: Cache<[WebGLAnyRenderingContext, number, number], Promise<{
|
|
25
|
-
'vertices': WGLBuffer;
|
|
26
|
-
'texcoords': WGLBuffer;
|
|
27
|
-
}>>;
|
|
14
|
+
private readonly buffer_cache;
|
|
15
|
+
private readonly billboard_buffer_cache;
|
|
28
16
|
constructor(type: GridType, is_conformal: boolean, ni: number, nj: number);
|
|
29
17
|
abstract copy(opts?: {
|
|
30
18
|
ni?: number;
|
|
@@ -51,8 +39,7 @@ declare class PlateCarreeGrid extends Grid {
|
|
|
51
39
|
readonly ll_lat: number;
|
|
52
40
|
readonly ur_lon: number;
|
|
53
41
|
readonly ur_lat: number;
|
|
54
|
-
|
|
55
|
-
readonly _ll_cache: Cache<[], Coords>;
|
|
42
|
+
private readonly ll_cache;
|
|
56
43
|
/**
|
|
57
44
|
* Create a plate carree grid
|
|
58
45
|
* @param ni - The number of grid points in the i (longitude) direction
|
|
@@ -80,6 +67,47 @@ declare class PlateCarreeGrid extends Grid {
|
|
|
80
67
|
}): [number, number];
|
|
81
68
|
getThinnedGrid(thin_x: number, thin_y: number): PlateCarreeGrid;
|
|
82
69
|
}
|
|
70
|
+
/** A rotated lat-lon (plate carree) grid with uniform grid spacing */
|
|
71
|
+
declare class PlateCarreeRotatedGrid extends Grid {
|
|
72
|
+
readonly np_lon: number;
|
|
73
|
+
readonly np_lat: number;
|
|
74
|
+
readonly lon_shift: number;
|
|
75
|
+
readonly ll_lon: number;
|
|
76
|
+
readonly ll_lat: number;
|
|
77
|
+
readonly ur_lon: number;
|
|
78
|
+
readonly ur_lat: number;
|
|
79
|
+
private readonly llrot;
|
|
80
|
+
private readonly ll_cache;
|
|
81
|
+
/**
|
|
82
|
+
* Create a Lambert conformal conic grid
|
|
83
|
+
* @param ni - The number of grid points in the i (longitude) direction
|
|
84
|
+
* @param nj - The number of grid points in the j (latitude) direction
|
|
85
|
+
* @param np_lon - The longitude of the north pole for the rotated grid
|
|
86
|
+
* @param np_lat - The latitude of the north pole for the rotated grid
|
|
87
|
+
* @param lon_shift - The angle around the rotated north pole to shift the central meridian
|
|
88
|
+
* @param ll_lon - The longitude of the lower left corner of the grid (on the rotated earth)
|
|
89
|
+
* @param ll_lat - The latitude of the lower left corner of the grid (on the rotated earth)
|
|
90
|
+
* @param ur_lon - The longitude of the upper right corner of the grid (on the rotated earth)
|
|
91
|
+
* @param ur_lat - The latitude of the upper right corner of the grid (on the rotated earth)
|
|
92
|
+
*/
|
|
93
|
+
constructor(ni: number, nj: number, np_lon: number, np_lat: number, lon_shift: number, ll_lon: number, ll_lat: number, ur_lon: number, ur_lat: number);
|
|
94
|
+
copy(opts?: {
|
|
95
|
+
ni?: number;
|
|
96
|
+
nj?: number;
|
|
97
|
+
ll_lon?: number;
|
|
98
|
+
ll_lat?: number;
|
|
99
|
+
ur_lon?: number;
|
|
100
|
+
ur_lat?: number;
|
|
101
|
+
}): PlateCarreeRotatedGrid;
|
|
102
|
+
/**
|
|
103
|
+
* Get a list of longitudes and latitudes on the grid (internal method)
|
|
104
|
+
*/
|
|
105
|
+
getCoords(): Coords;
|
|
106
|
+
transform(x: number, y: number, opts?: {
|
|
107
|
+
inverse?: boolean;
|
|
108
|
+
}): [number, number];
|
|
109
|
+
getThinnedGrid(thin_x: number, thin_y: number): PlateCarreeRotatedGrid;
|
|
110
|
+
}
|
|
83
111
|
/** A Lambert conformal conic grid with uniform grid spacing */
|
|
84
112
|
declare class LambertGrid extends Grid {
|
|
85
113
|
readonly lon_0: number;
|
|
@@ -89,12 +117,8 @@ declare class LambertGrid extends Grid {
|
|
|
89
117
|
readonly ll_y: number;
|
|
90
118
|
readonly ur_x: number;
|
|
91
119
|
readonly ur_y: number;
|
|
92
|
-
|
|
93
|
-
readonly
|
|
94
|
-
inverse: boolean;
|
|
95
|
-
}) => [number, number];
|
|
96
|
-
/** @private */
|
|
97
|
-
readonly _ll_cache: Cache<[], Coords>;
|
|
120
|
+
private readonly lcc;
|
|
121
|
+
private readonly ll_cache;
|
|
98
122
|
/**
|
|
99
123
|
* Create a Lambert conformal conic grid
|
|
100
124
|
* @param ni - The number of grid points in the i (longitude) direction
|
|
@@ -125,17 +149,21 @@ declare class LambertGrid extends Grid {
|
|
|
125
149
|
}): [number, number];
|
|
126
150
|
getThinnedGrid(thin_x: number, thin_y: number): LambertGrid;
|
|
127
151
|
}
|
|
152
|
+
type TextureDataType<ArrayType> = ArrayType extends Float32Array ? Float32Array : Uint16Array;
|
|
128
153
|
/** A class representing a raw 2D field of gridded data, such as height or u wind. */
|
|
129
|
-
declare class RawScalarField {
|
|
154
|
+
declare class RawScalarField<ArrayType extends TypedArray> {
|
|
130
155
|
readonly grid: Grid;
|
|
131
|
-
readonly data:
|
|
156
|
+
readonly data: ArrayType;
|
|
132
157
|
/**
|
|
133
158
|
* Create a data field.
|
|
134
159
|
* @param grid - The grid on which the data are defined
|
|
135
160
|
* @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.
|
|
136
161
|
*/
|
|
137
|
-
constructor(grid: Grid, data:
|
|
138
|
-
|
|
162
|
+
constructor(grid: Grid, data: ArrayType);
|
|
163
|
+
/** @internal */
|
|
164
|
+
getTextureData(): TextureDataType<ArrayType>;
|
|
165
|
+
isFloat16(): boolean;
|
|
166
|
+
getThinnedField(thin_x: number, thin_y: number): RawScalarField<ArrayType>;
|
|
139
167
|
/**
|
|
140
168
|
* Create a new field by aggregating a number of fields using a specific function
|
|
141
169
|
* @param func - A function that will be applied each element of the field. It should take the same number of arguments as fields you have and return a single number.
|
|
@@ -145,7 +173,7 @@ declare class RawScalarField {
|
|
|
145
173
|
* // Compute wind speed from u and v
|
|
146
174
|
* wind_speed_field = RawScalarField.aggreateFields(Math.hypot, u_field, v_field);
|
|
147
175
|
*/
|
|
148
|
-
static aggregateFields(func: (...args: number[]) => number, ...args: RawScalarField[]): RawScalarField
|
|
176
|
+
static aggregateFields<ArrayType extends TypedArray>(func: (...args: number[]) => number, ...args: RawScalarField<ArrayType>[]): RawScalarField<ArrayType>;
|
|
149
177
|
}
|
|
150
178
|
type VectorRelativeTo = 'earth' | 'grid';
|
|
151
179
|
interface RawVectorFieldOptions {
|
|
@@ -156,15 +184,11 @@ interface RawVectorFieldOptions {
|
|
|
156
184
|
relative_to?: VectorRelativeTo;
|
|
157
185
|
}
|
|
158
186
|
/** A class representing a 2D gridded field of vectors */
|
|
159
|
-
declare class RawVectorField {
|
|
160
|
-
readonly u: RawScalarField
|
|
161
|
-
readonly v: RawScalarField
|
|
187
|
+
declare class RawVectorField<ArrayType extends TypedArray> {
|
|
188
|
+
readonly u: RawScalarField<ArrayType>;
|
|
189
|
+
readonly v: RawScalarField<ArrayType>;
|
|
162
190
|
readonly relative_to: VectorRelativeTo;
|
|
163
|
-
|
|
164
|
-
readonly _rotate_cache: Cache<[], {
|
|
165
|
-
u: RawScalarField;
|
|
166
|
-
v: RawScalarField;
|
|
167
|
-
}>;
|
|
191
|
+
private readonly rotate_cache;
|
|
168
192
|
/**
|
|
169
193
|
* Create a vector field.
|
|
170
194
|
* @param grid - The grid on which the vector components are defined
|
|
@@ -172,10 +196,10 @@ declare class RawVectorField {
|
|
|
172
196
|
* @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
|
|
173
197
|
* @param opts - Options for creating the vector field.
|
|
174
198
|
*/
|
|
175
|
-
constructor(grid: Grid, u:
|
|
176
|
-
getThinnedField(thin_x: number, thin_y: number): RawVectorField
|
|
199
|
+
constructor(grid: Grid, u: ArrayType, v: ArrayType, opts?: RawVectorFieldOptions);
|
|
200
|
+
getThinnedField(thin_x: number, thin_y: number): RawVectorField<ArrayType>;
|
|
177
201
|
get grid(): Grid;
|
|
178
|
-
toEarthRelative(): RawVectorField
|
|
202
|
+
toEarthRelative(): RawVectorField<ArrayType>;
|
|
179
203
|
}
|
|
180
204
|
/** A class grid of wind profiles */
|
|
181
205
|
declare class RawProfileField {
|
|
@@ -188,7 +212,7 @@ declare class RawProfileField {
|
|
|
188
212
|
*/
|
|
189
213
|
constructor(grid: Grid, profiles: WindProfile[]);
|
|
190
214
|
/** Get the gridded storm motion vector field (internal method) */
|
|
191
|
-
getStormMotionGrid(): RawVectorField
|
|
215
|
+
getStormMotionGrid(): RawVectorField<Float16Array>;
|
|
192
216
|
}
|
|
193
|
-
export { RawScalarField, RawVectorField, RawProfileField, PlateCarreeGrid, LambertGrid, Grid };
|
|
194
|
-
export type { GridType, RawVectorFieldOptions, VectorRelativeTo };
|
|
217
|
+
export { RawScalarField, RawVectorField, RawProfileField, PlateCarreeGrid, PlateCarreeRotatedGrid, LambertGrid, Grid };
|
|
218
|
+
export type { GridType, RawVectorFieldOptions, VectorRelativeTo, TextureDataType };
|
package/lib/RawField.js
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
import {
|
|
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.
|
|
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.
|
|
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.
|
|
44
|
+
return await this.buffer_cache.getValue(gl);
|
|
56
45
|
}
|
|
57
46
|
async getWGLBillboardBuffers(gl, thin_fac, max_zoom) {
|
|
58
|
-
return await this.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
346
|
+
this.rotate_cache = new Cache(() => {
|
|
262
347
|
const grid = this.u.grid;
|
|
263
348
|
const coords = grid.getCoords();
|
|
264
|
-
const u_rot = new
|
|
265
|
-
const v_rot = new
|
|
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.
|
|
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
|
|
331
|
-
const v = new
|
|
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
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { PlotComponent } from "./PlotComponent";
|
|
2
2
|
import Contour, { ContourOptions } from "./Contour";
|
|
3
|
-
import ContourFill,
|
|
3
|
+
import { ContourFill, Raster, ContourFillOptions, RasterOptions } from "./Fill";
|
|
4
4
|
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;
|
|
@@ -18,5 +18,6 @@ declare const colormaps: {
|
|
|
18
18
|
pw_cape: ColorMap;
|
|
19
19
|
pw_t2m: ColorMap;
|
|
20
20
|
pw_td2m: ColorMap;
|
|
21
|
+
nws_storm_clear_refl: ColorMap;
|
|
21
22
|
};
|
|
22
|
-
export { PlotComponent, Barbs, BarbsOptions, Contour, ContourOptions, ContourFill, ContourFillOptions, 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
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { PlotComponent } from "./PlotComponent";
|
|
2
2
|
import Contour from "./Contour";
|
|
3
|
-
import ContourFill from "./
|
|
3
|
+
import { ContourFill, Raster } from "./Fill";
|
|
4
4
|
import Barbs from "./Barbs";
|
|
5
5
|
import Paintball from "./Paintball";
|
|
6
6
|
import Hodographs from './Hodographs';
|
|
7
7
|
import { PlotLayer, MultiPlotLayer } from './PlotLayer';
|
|
8
|
-
import { ColorMap, bluered, redblue, pw_speed500mb, pw_speed850mb, pw_cape, pw_t2m, pw_td2m } from './Colormap';
|
|
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,
|
|
@@ -15,6 +15,7 @@ const colormaps = {
|
|
|
15
15
|
pw_speed850mb: pw_speed850mb,
|
|
16
16
|
pw_cape: pw_cape,
|
|
17
17
|
pw_t2m: pw_t2m,
|
|
18
|
-
pw_td2m: pw_td2m
|
|
18
|
+
pw_td2m: pw_td2m,
|
|
19
|
+
nws_storm_clear_refl: nws_storm_clear_refl,
|
|
19
20
|
};
|
|
20
|
-
export { PlotComponent, Barbs, Contour, ContourFill, 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
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
"
|
|
34
|
+
"@petamoriken/float16": "^3.8.4",
|
|
35
|
+
"autumn-wgl": "^1.2.0",
|
|
35
36
|
"comlink": "^4.3.1"
|
|
36
37
|
}
|
|
37
38
|
}
|
package/lib/ContourFill.d.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
import { PlotComponent } from './PlotComponent';
|
|
2
|
-
import { ColorMap } from './Colormap';
|
|
3
|
-
import { WGLBuffer, WGLProgram, WGLTexture } from 'autumn-wgl';
|
|
4
|
-
import { RawScalarField } from './RawField';
|
|
5
|
-
import { MapType } from './Map';
|
|
6
|
-
import { WebGLAnyRenderingContext } from './AutumnTypes';
|
|
7
|
-
interface ContourFillOptions {
|
|
8
|
-
/** The color map to use when creating the fills */
|
|
9
|
-
cmap: ColorMap;
|
|
10
|
-
/**
|
|
11
|
-
* The opacity for the filled contours
|
|
12
|
-
* @default 1
|
|
13
|
-
*/
|
|
14
|
-
opacity?: number;
|
|
15
|
-
}
|
|
16
|
-
interface ContourFillGLElems {
|
|
17
|
-
program: WGLProgram;
|
|
18
|
-
vertices: WGLBuffer;
|
|
19
|
-
fill_texture: WGLTexture;
|
|
20
|
-
texcoords: WGLBuffer;
|
|
21
|
-
cmap_texture: WGLTexture;
|
|
22
|
-
cmap_nonlin_texture: WGLTexture;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* A filled contoured field
|
|
26
|
-
* @example
|
|
27
|
-
* // Create a field of filled contours with the provided color map
|
|
28
|
-
* const fill = new ContourFill(wind_speed_field, {cmap: color_map});
|
|
29
|
-
*/
|
|
30
|
-
declare class ContourFill extends PlotComponent {
|
|
31
|
-
readonly field: RawScalarField;
|
|
32
|
-
readonly cmap: ColorMap;
|
|
33
|
-
readonly opacity: number;
|
|
34
|
-
/** @private */
|
|
35
|
-
readonly cmap_image: HTMLCanvasElement;
|
|
36
|
-
/** @private */
|
|
37
|
-
readonly index_map: Float32Array;
|
|
38
|
-
/** @private */
|
|
39
|
-
gl_elems: ContourFillGLElems | null;
|
|
40
|
-
/**
|
|
41
|
-
* Create a filled contoured field
|
|
42
|
-
* @param field - The field to create filled contours from
|
|
43
|
-
* @param opts - Options for creating the filled contours
|
|
44
|
-
*/
|
|
45
|
-
constructor(field: RawScalarField, opts: ContourFillOptions);
|
|
46
|
-
/**
|
|
47
|
-
* @internal
|
|
48
|
-
* Add the filled contours to a map
|
|
49
|
-
*/
|
|
50
|
-
onAdd(map: MapType, gl: WebGLAnyRenderingContext): Promise<void>;
|
|
51
|
-
/**
|
|
52
|
-
* @internal
|
|
53
|
-
* Render the filled contours
|
|
54
|
-
*/
|
|
55
|
-
render(gl: WebGLAnyRenderingContext, matrix: number[]): void;
|
|
56
|
-
}
|
|
57
|
-
export default ContourFill;
|
|
58
|
-
export type { ContourFillOptions };
|