autumnplot-gl 3.2.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -207
- package/dist/983.autumnplot-gl.js +2 -0
- package/dist/983.autumnplot-gl.js.map +1 -0
- package/dist/autumnplot-gl.js +1 -1
- package/dist/autumnplot-gl.js.map +1 -1
- package/dist/marchingsquares.wasm +0 -0
- package/lib/AutumnTypes.d.ts +85 -6
- package/lib/AutumnTypes.js +28 -1
- package/lib/Barbs.d.ts +7 -5
- package/lib/BillboardCollection.d.ts +8 -7
- package/lib/BillboardCollection.js +69 -58
- package/lib/Color.d.ts +2 -0
- package/lib/Color.js +4 -0
- package/lib/ColorBar.d.ts +19 -0
- package/lib/ColorBar.js +9 -6
- package/lib/Colormap.d.ts +1 -0
- package/lib/Colormap.js +8 -8
- package/lib/Contour.d.ts +28 -8
- package/lib/Contour.js +27 -54
- package/lib/ContourCreator.d.ts +9 -1
- package/lib/ContourCreator.js +5 -4
- package/lib/Fill.d.ts +28 -14
- package/lib/Fill.js +97 -50
- package/lib/Grid.d.ts +132 -30
- package/lib/Grid.js +355 -99
- package/lib/Hodographs.d.ts +15 -8
- package/lib/Hodographs.js +48 -30
- package/lib/Map.d.ts +14 -1
- package/lib/Map.js +60 -4
- package/lib/Paintball.d.ts +7 -5
- package/lib/Paintball.js +36 -31
- package/lib/ParticleTracer.d.ts +19 -0
- package/lib/ParticleTracer.js +37 -0
- package/lib/PlotComponent.d.ts +7 -7
- package/lib/PlotComponent.js +9 -3
- package/lib/PlotLayer.d.ts +5 -5
- package/lib/PlotLayer.js +2 -2
- package/lib/PlotLayer.worker.d.ts +1 -2
- package/lib/PlotLayer.worker.js +22 -51
- package/lib/PolylineCollection.d.ts +5 -3
- package/lib/PolylineCollection.js +60 -37
- package/lib/RawField.d.ts +78 -23
- package/lib/RawField.js +147 -31
- package/lib/ShaderManager.d.ts +12 -0
- package/lib/ShaderManager.js +58 -0
- package/lib/StationPlot.d.ts +187 -25
- package/lib/StationPlot.js +209 -60
- package/lib/TextCollection.d.ts +9 -6
- package/lib/TextCollection.js +97 -62
- package/lib/cpp/marchingsquares.js +483 -585
- package/lib/cpp/marchingsquares.wasm +0 -0
- package/lib/cpp/marchingsquares_embind.d.ts +23 -3
- package/lib/index.d.ts +12 -5
- package/lib/index.js +8 -5
- package/lib/utils.d.ts +4 -1
- package/lib/utils.js +12 -1
- package/package.json +3 -3
- package/dist/110.autumnplot-gl.js +0 -2
- package/dist/110.autumnplot-gl.js.map +0 -1
|
Binary file
|
package/lib/AutumnTypes.d.ts
CHANGED
|
@@ -1,15 +1,37 @@
|
|
|
1
1
|
import { Float16Array } from "@petamoriken/float16";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
/** A wind profile with a storm-motion for plotting storm-relative hodographs */
|
|
3
|
+
interface StormRelativeWindProfile {
|
|
4
|
+
/** The grid index in the j direction (ignored for unstructured grids) */
|
|
5
5
|
jlat: number;
|
|
6
|
+
/** The grid index in the i direction */
|
|
6
7
|
ilon: number;
|
|
8
|
+
/** u component of storm motion in kts */
|
|
7
9
|
smu: number;
|
|
10
|
+
/** v component of storm motion in kts */
|
|
8
11
|
smv: number;
|
|
12
|
+
/** Ground-relative u winds in kts (will be converted to storm-relative during plotting) */
|
|
9
13
|
u: Float32Array;
|
|
14
|
+
/** Ground-relative v winds in kts (will be converted to storm-relative during plotting) */
|
|
10
15
|
v: Float32Array;
|
|
16
|
+
/** Height of each data point in km */
|
|
11
17
|
z: Float32Array;
|
|
12
18
|
}
|
|
19
|
+
/** A wind profile without a storm motion for plotting ground-relative hodographs */
|
|
20
|
+
interface GroundRelativeWindProfile {
|
|
21
|
+
/** The grid index in the j direction (ignored for unstructured grids) */
|
|
22
|
+
jlat: number;
|
|
23
|
+
/** The grid index in the i direction */
|
|
24
|
+
ilon: number;
|
|
25
|
+
/** Ground-relative u winds in kts */
|
|
26
|
+
u: Float32Array;
|
|
27
|
+
/** Ground-relative v winds in kts */
|
|
28
|
+
v: Float32Array;
|
|
29
|
+
/** Height of each data point in km */
|
|
30
|
+
z: Float32Array;
|
|
31
|
+
}
|
|
32
|
+
/** Different types of wind profiles for {@link Hodographs} components */
|
|
33
|
+
type WindProfile = StormRelativeWindProfile | GroundRelativeWindProfile;
|
|
34
|
+
declare function isStormRelativeWindProfile(obj: any): obj is StormRelativeWindProfile;
|
|
13
35
|
interface BillboardSpec {
|
|
14
36
|
BB_WIDTH: number;
|
|
15
37
|
BB_HEIGHT: number;
|
|
@@ -32,9 +54,66 @@ type Polyline = {
|
|
|
32
54
|
data?: Float32Array;
|
|
33
55
|
zoom?: Float32Array;
|
|
34
56
|
};
|
|
57
|
+
/** WebGL rendering contexts (either WebGL1 or WebGL2) */
|
|
35
58
|
type WebGLAnyRenderingContext = WebGLRenderingContext | WebGL2RenderingContext;
|
|
36
59
|
declare function isWebGL2Ctx(gl: WebGLAnyRenderingContext): gl is WebGL2RenderingContext;
|
|
37
|
-
|
|
60
|
+
/** Javascript typed arrays for use in raw fields */
|
|
61
|
+
type TypedArray = Float16Array | Float32Array | Uint8Array;
|
|
62
|
+
type TypedArrayStr = 'float16' | 'float32' | 'uint8';
|
|
63
|
+
/**
|
|
64
|
+
* The result of contouring a field
|
|
65
|
+
*
|
|
66
|
+
* Each property is a different contour level giving an array of contours, and each contour is an array of [longitude, latitude].
|
|
67
|
+
*/
|
|
38
68
|
type ContourData = Record<number, [number, number][][]>;
|
|
39
|
-
|
|
40
|
-
|
|
69
|
+
type mat4 = number[] | Float32Array | Float64Array;
|
|
70
|
+
type RenderShaderData = {
|
|
71
|
+
vertexShaderPrelude: string;
|
|
72
|
+
define: string;
|
|
73
|
+
variantName: string;
|
|
74
|
+
};
|
|
75
|
+
type MapLibreRendererDataProjection = {
|
|
76
|
+
clippingPlane: [number, number, number, number];
|
|
77
|
+
fallbackMatrix: mat4;
|
|
78
|
+
mainMatrix: mat4;
|
|
79
|
+
projectionTransition: number;
|
|
80
|
+
tileMercatorCoords: [number, number, number, number];
|
|
81
|
+
};
|
|
82
|
+
type MapLibreRendererDataShader = RenderShaderData;
|
|
83
|
+
type MapLibreRendererData = {
|
|
84
|
+
defaultProjectionData: MapLibreRendererDataProjection;
|
|
85
|
+
farZ: number;
|
|
86
|
+
fov: number;
|
|
87
|
+
modelViewProjectionMatrix: mat4;
|
|
88
|
+
nearZ: number;
|
|
89
|
+
projectionMatrix: mat4;
|
|
90
|
+
shaderData: MapLibreRendererDataShader;
|
|
91
|
+
};
|
|
92
|
+
type RenderMethodArg = mat4 | MapLibreRendererData;
|
|
93
|
+
type RendererDataProjection = {
|
|
94
|
+
clippingPlane: number[];
|
|
95
|
+
fallbackMatrix: number[];
|
|
96
|
+
mainMatrix: number[];
|
|
97
|
+
projectionTransition: number;
|
|
98
|
+
tileMercatorCoords: number[];
|
|
99
|
+
};
|
|
100
|
+
type RendererDataShader = RenderShaderData;
|
|
101
|
+
type RendererDataMapLibre = {
|
|
102
|
+
type: 'maplibre';
|
|
103
|
+
defaultProjectionData: RendererDataProjection;
|
|
104
|
+
farZ: number;
|
|
105
|
+
fov: number;
|
|
106
|
+
modelViewProjectionMatrix: number[];
|
|
107
|
+
nearZ: number;
|
|
108
|
+
projectionMatrix: number[];
|
|
109
|
+
shaderData: RendererDataShader;
|
|
110
|
+
};
|
|
111
|
+
type RendererDataAutumn = {
|
|
112
|
+
type: 'autumn';
|
|
113
|
+
mainMatrix: number[];
|
|
114
|
+
shaderData: null;
|
|
115
|
+
};
|
|
116
|
+
type RendererData = RendererDataMapLibre | RendererDataAutumn;
|
|
117
|
+
declare function getRendererData(arg: RenderMethodArg): RendererData;
|
|
118
|
+
export { isWebGL2Ctx, getRendererData, isStormRelativeWindProfile };
|
|
119
|
+
export type { WindProfile, StormRelativeWindProfile, GroundRelativeWindProfile, BillboardSpec, Polyline, LineData, WebGLAnyRenderingContext, TypedArray, TypedArrayStr, ContourData, RenderMethodArg, RendererData, RenderShaderData };
|
package/lib/AutumnTypes.js
CHANGED
|
@@ -1,4 +1,31 @@
|
|
|
1
|
+
function isStormRelativeWindProfile(obj) {
|
|
2
|
+
return 'smu' in obj && 'smv' in obj;
|
|
3
|
+
}
|
|
1
4
|
function isWebGL2Ctx(gl) {
|
|
2
5
|
return gl.getParameter(gl.VERSION).includes('WebGL 2.0');
|
|
3
6
|
}
|
|
4
|
-
|
|
7
|
+
function isMapLibreRenderArg(obj) {
|
|
8
|
+
return 'modelViewProjectionMatrix' in obj && 'defaultProjectionData' in obj && 'mainMatrix' in obj.defaultProjectionData;
|
|
9
|
+
}
|
|
10
|
+
function getRendererData(arg) {
|
|
11
|
+
if (isMapLibreRenderArg(arg)) {
|
|
12
|
+
return {
|
|
13
|
+
type: 'maplibre',
|
|
14
|
+
defaultProjectionData: {
|
|
15
|
+
clippingPlane: [...arg.defaultProjectionData.clippingPlane],
|
|
16
|
+
fallbackMatrix: [...arg.defaultProjectionData.fallbackMatrix],
|
|
17
|
+
mainMatrix: [...arg.defaultProjectionData.mainMatrix],
|
|
18
|
+
projectionTransition: arg.defaultProjectionData.projectionTransition,
|
|
19
|
+
tileMercatorCoords: [...arg.defaultProjectionData.tileMercatorCoords]
|
|
20
|
+
},
|
|
21
|
+
farZ: arg.farZ,
|
|
22
|
+
fov: arg.fov,
|
|
23
|
+
modelViewProjectionMatrix: [...arg.modelViewProjectionMatrix],
|
|
24
|
+
nearZ: arg.nearZ,
|
|
25
|
+
projectionMatrix: [...arg.projectionMatrix],
|
|
26
|
+
shaderData: arg.shaderData
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return { type: 'autumn', mainMatrix: [...arg], shaderData: null };
|
|
30
|
+
}
|
|
31
|
+
export { isWebGL2Ctx, getRendererData, isStormRelativeWindProfile };
|
package/lib/Barbs.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { PlotComponent } from "./PlotComponent";
|
|
2
2
|
import { RawVectorField } from "./RawField";
|
|
3
3
|
import { MapLikeType } from "./Map";
|
|
4
|
-
import { TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
4
|
+
import { RenderMethodArg, TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
5
5
|
import { ColorMap } from "./Colormap";
|
|
6
|
+
import { Grid } from "./Grid";
|
|
7
|
+
/** Options for {@link Barbs} components */
|
|
6
8
|
interface BarbsOptions {
|
|
7
9
|
/**
|
|
8
10
|
* The color to use for the barbs as a hex color string;.
|
|
@@ -38,7 +40,7 @@ interface BarbsOptions {
|
|
|
38
40
|
* const vector_field = new RawVectorField(grid, u_data, v_data);
|
|
39
41
|
* const barbs = new Barbs(vector_field, {color: '#000000', thin_fac: 16});
|
|
40
42
|
*/
|
|
41
|
-
declare class Barbs<ArrayType extends TypedArray, MapType extends MapLikeType> extends PlotComponent<MapType> {
|
|
43
|
+
declare class Barbs<ArrayType extends TypedArray, GridType extends Grid, MapType extends MapLikeType> extends PlotComponent<MapType> {
|
|
42
44
|
/** The vector field */
|
|
43
45
|
private fields;
|
|
44
46
|
readonly opts: Required<BarbsOptions>;
|
|
@@ -50,12 +52,12 @@ declare class Barbs<ArrayType extends TypedArray, MapType extends MapLikeType> e
|
|
|
50
52
|
* @param fields - The vector field to plot as barbs
|
|
51
53
|
* @param opts - Options for creating the wind barbs
|
|
52
54
|
*/
|
|
53
|
-
constructor(fields: RawVectorField<ArrayType>, opts: BarbsOptions);
|
|
55
|
+
constructor(fields: RawVectorField<ArrayType, GridType>, opts: BarbsOptions);
|
|
54
56
|
/**
|
|
55
57
|
* Update the field displayed as barbs
|
|
56
58
|
* @param fields - The new field to display as barbs
|
|
57
59
|
*/
|
|
58
|
-
updateField(fields: RawVectorField<ArrayType>): Promise<void>;
|
|
60
|
+
updateField(fields: RawVectorField<ArrayType, GridType>): Promise<void>;
|
|
59
61
|
/**
|
|
60
62
|
* @internal
|
|
61
63
|
* Add the barb field to a map
|
|
@@ -65,7 +67,7 @@ declare class Barbs<ArrayType extends TypedArray, MapType extends MapLikeType> e
|
|
|
65
67
|
* @internal
|
|
66
68
|
* Render the barb field
|
|
67
69
|
*/
|
|
68
|
-
render(gl: WebGLAnyRenderingContext, matrix:
|
|
70
|
+
render(gl: WebGLAnyRenderingContext, matrix: RenderMethodArg): void;
|
|
69
71
|
}
|
|
70
72
|
export default Barbs;
|
|
71
73
|
export type { BarbsOptions };
|
|
@@ -1,28 +1,29 @@
|
|
|
1
|
-
import { BillboardSpec, TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
1
|
+
import { BillboardSpec, RenderMethodArg, TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
2
2
|
import { Color } from "./Color";
|
|
3
3
|
import { ColorMap } from "./Colormap";
|
|
4
|
+
import { Grid } from "./Grid";
|
|
4
5
|
import { RawVectorField } from "./RawField";
|
|
5
6
|
import { WGLTextureSpec } from "autumn-wgl";
|
|
6
7
|
interface BillboardCollectionOpts {
|
|
7
8
|
color?: Color;
|
|
8
9
|
cmap?: ColorMap;
|
|
10
|
+
rotate_with_map?: boolean;
|
|
9
11
|
}
|
|
10
|
-
declare class BillboardCollection<ArrayType extends TypedArray> {
|
|
12
|
+
declare class BillboardCollection<ArrayType extends TypedArray, GridType extends Grid> {
|
|
11
13
|
private field;
|
|
12
14
|
readonly spec: BillboardSpec;
|
|
13
15
|
readonly color: Color;
|
|
14
16
|
readonly cmap: ColorMap | null;
|
|
17
|
+
readonly rotate_with_map: boolean;
|
|
15
18
|
readonly size_multiplier: number;
|
|
16
19
|
readonly thin_fac: number;
|
|
17
20
|
readonly max_zoom: number;
|
|
18
21
|
readonly billboard_image: WGLTextureSpec;
|
|
19
22
|
private gl_elems;
|
|
20
23
|
private wind_textures;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
constructor(field: RawVectorField<ArrayType>, thin_fac: number, max_zoom: number, billboard_image: WGLTextureSpec, billboard_spec: BillboardSpec, billboard_size_mult: number, opts?: BillboardCollectionOpts);
|
|
24
|
-
updateField(field: RawVectorField<ArrayType>): void;
|
|
24
|
+
constructor(field: RawVectorField<ArrayType, GridType>, thin_fac: number, max_zoom: number, billboard_image: WGLTextureSpec, billboard_spec: BillboardSpec, billboard_size_mult: number, opts?: BillboardCollectionOpts);
|
|
25
|
+
updateField(field: RawVectorField<ArrayType, GridType>): void;
|
|
25
26
|
setup(gl: WebGLAnyRenderingContext): Promise<void>;
|
|
26
|
-
render(gl: WebGLAnyRenderingContext,
|
|
27
|
+
render(gl: WebGLAnyRenderingContext, arg: RenderMethodArg, [map_width, map_height]: [number, number], map_zoom: number, map_bearing: number, map_pitch: number): void;
|
|
27
28
|
}
|
|
28
29
|
export { BillboardCollection };
|
|
@@ -1,29 +1,31 @@
|
|
|
1
|
+
import { getRendererData } from "./AutumnTypes";
|
|
1
2
|
import { Color } from "./Color";
|
|
2
3
|
import { ColorMapGPUInterface } from "./Colormap";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
const billboard_vertex_shader_src =
|
|
4
|
+
import { WGLBuffer, WGLTexture } from "autumn-wgl";
|
|
5
|
+
import { ShaderProgramManager } from "./ShaderManager";
|
|
6
|
+
const billboard_vertex_shader_src = `#version 300 es
|
|
7
|
+
|
|
6
8
|
uniform int u_offset;
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
in vec2 a_pos;
|
|
11
|
+
in vec2 a_tex_coord;
|
|
12
|
+
in lowp float a_geom;
|
|
10
13
|
uniform lowp float u_bb_size;
|
|
11
14
|
uniform lowp float u_map_aspect;
|
|
12
15
|
uniform lowp float u_zoom;
|
|
13
|
-
uniform highp float u_map_bearing;
|
|
14
16
|
uniform lowp float u_bb_width;
|
|
15
17
|
uniform lowp float u_bb_height;
|
|
16
18
|
uniform highp float u_bb_mag_bin_size;
|
|
17
|
-
|
|
18
19
|
uniform highp float u_bb_mag_wrap;
|
|
20
|
+
uniform int u_rotate_with_map;
|
|
19
21
|
|
|
20
22
|
uniform sampler2D u_u_sampler;
|
|
21
23
|
uniform sampler2D u_v_sampler;
|
|
22
24
|
uniform sampler2D u_rot_sampler;
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
out highp vec2 v_tex_coord;
|
|
25
27
|
#ifdef COLORMAP
|
|
26
|
-
|
|
28
|
+
out highp float v_mag;
|
|
27
29
|
#endif
|
|
28
30
|
|
|
29
31
|
mat4 scalingMatrix(float x_scale, float y_scale, float z_scale) {
|
|
@@ -57,14 +59,27 @@ void main() {
|
|
|
57
59
|
float globe_width = 1.;
|
|
58
60
|
vec2 globe_offset = vec2(globe_width * float(u_offset), 0.);
|
|
59
61
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
mat4 map_stretch_matrix = scalingMatrix(1.0, 1. / u_map_aspect, 1.0);
|
|
63
|
+
|
|
64
|
+
vec4 pivot_pos = projectTile(a_pos.xy + globe_offset);
|
|
65
|
+
float globe_rotation = 0.0;
|
|
66
|
+
|
|
67
|
+
if (u_rotate_with_map == 1) {
|
|
68
|
+
vec4 pivot_pos_ihat = projectTile(a_pos.xy + globe_offset + vec2(1e-5, 0.));
|
|
69
|
+
|
|
70
|
+
vec2 pivot_east = normalize((inverse(map_stretch_matrix) * (pivot_pos_ihat - pivot_pos)).xy);
|
|
71
|
+
globe_rotation = atan(pivot_east.x, pivot_east.y) - 3.141592654 / 2.0;
|
|
72
|
+
}
|
|
64
73
|
|
|
65
|
-
highp float
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
highp float min_zoom = floor(a_tex_coord.x);
|
|
75
|
+
lowp float corner = a_geom;
|
|
76
|
+
|
|
77
|
+
vec2 data_texcoord = a_tex_coord;
|
|
78
|
+
data_texcoord.x = fract(data_texcoord.x);
|
|
79
|
+
|
|
80
|
+
highp float u = texture(u_u_sampler, data_texcoord).r;
|
|
81
|
+
highp float v = texture(u_v_sampler, data_texcoord).r;
|
|
82
|
+
highp float rot = texture(u_rot_sampler, data_texcoord).r;
|
|
68
83
|
|
|
69
84
|
lowp float bb_aspect = u_bb_width / u_bb_height;
|
|
70
85
|
lowp float ang = (abs(u) < 1e-6 && abs(v) < 1e-6) ? 0. : atan(v, u) - 3.141592654 / 2.0;
|
|
@@ -98,26 +113,29 @@ void main() {
|
|
|
98
113
|
texcoord = tex_loc + vec2(u_bb_width, u_bb_height);
|
|
99
114
|
}
|
|
100
115
|
|
|
101
|
-
mat4 barb_rotation = rotationZMatrix(ang
|
|
102
|
-
mat4 map_stretch_matrix = scalingMatrix(1.0, 1. / u_map_aspect, 1.0);
|
|
116
|
+
mat4 barb_rotation = rotationZMatrix(ang - globe_rotation - rot);
|
|
103
117
|
offset = map_stretch_matrix * barb_rotation * offset;
|
|
104
118
|
}
|
|
105
119
|
|
|
106
120
|
gl_Position = pivot_pos + offset;
|
|
107
121
|
v_tex_coord = texcoord;
|
|
108
122
|
}`
|
|
109
|
-
const billboard_fragment_shader_src =
|
|
123
|
+
const billboard_fragment_shader_src = `#version 300 es
|
|
124
|
+
|
|
125
|
+
in highp vec2 v_tex_coord;
|
|
110
126
|
|
|
111
127
|
#ifdef COLORMAP
|
|
112
|
-
|
|
128
|
+
in highp float v_mag;
|
|
113
129
|
#else
|
|
114
130
|
uniform lowp vec4 u_bb_color;
|
|
115
131
|
#endif
|
|
116
132
|
|
|
117
133
|
uniform sampler2D u_sampler;
|
|
118
134
|
|
|
135
|
+
out highp vec4 fragColor;
|
|
136
|
+
|
|
119
137
|
void main() {
|
|
120
|
-
lowp vec4 tex_color =
|
|
138
|
+
lowp vec4 tex_color = texture(u_sampler, v_tex_coord);
|
|
121
139
|
|
|
122
140
|
lowp vec4 color;
|
|
123
141
|
#ifdef COLORMAP
|
|
@@ -127,13 +145,14 @@ void main() {
|
|
|
127
145
|
#endif
|
|
128
146
|
|
|
129
147
|
color.a *= tex_color.a;
|
|
130
|
-
|
|
148
|
+
fragColor = color;
|
|
131
149
|
}`
|
|
132
150
|
class BillboardCollection {
|
|
133
151
|
constructor(field, thin_fac, max_zoom, billboard_image, billboard_spec, billboard_size_mult, opts) {
|
|
134
152
|
opts = opts === undefined ? {} : opts;
|
|
135
153
|
this.color = opts.color === undefined ? new Color([0, 0, 0, 1]) : opts.color;
|
|
136
154
|
this.cmap = opts.cmap === undefined ? null : opts.cmap;
|
|
155
|
+
this.rotate_with_map = opts.rotate_with_map === undefined ? true : opts.rotate_with_map;
|
|
137
156
|
this.field = field;
|
|
138
157
|
this.spec = billboard_spec;
|
|
139
158
|
this.size_multiplier = billboard_size_mult;
|
|
@@ -142,28 +161,14 @@ class BillboardCollection {
|
|
|
142
161
|
this.billboard_image = billboard_image;
|
|
143
162
|
this.gl_elems = null;
|
|
144
163
|
this.wind_textures = null;
|
|
145
|
-
const n_density_tiers = Math.log2(thin_fac);
|
|
146
|
-
const n_inaccessible_tiers = Math.max(n_density_tiers + 1 - max_zoom, 0);
|
|
147
|
-
this.trim_inaccessible = Math.pow(2, n_inaccessible_tiers);
|
|
148
|
-
this.show_field = true;
|
|
149
164
|
}
|
|
150
165
|
updateField(field) {
|
|
151
166
|
this.field = field;
|
|
152
167
|
if (this.gl_elems === null)
|
|
153
168
|
return;
|
|
154
169
|
const gl = this.gl_elems.gl;
|
|
155
|
-
const data = this.field.getThinnedField(this.
|
|
156
|
-
const { u:
|
|
157
|
-
this.show_field = u_thin !== null;
|
|
158
|
-
const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, !(u_thin instanceof Float32Array));
|
|
159
|
-
const u_image = { 'format': format, 'type': type,
|
|
160
|
-
'width': data.grid.ni, 'height': data.grid.nj, 'image': u_thin,
|
|
161
|
-
'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
|
|
162
|
-
};
|
|
163
|
-
const v_image = { 'format': format, 'type': type,
|
|
164
|
-
'width': data.grid.ni, 'height': data.grid.nj, 'image': v_thin,
|
|
165
|
-
'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
|
|
166
|
-
};
|
|
170
|
+
const data = this.field.getThinnedField(this.thin_fac, this.max_zoom);
|
|
171
|
+
const { u: u_image, v: v_image } = data.getWGLTextureSpecs(gl, gl.NEAREST);
|
|
167
172
|
if (this.wind_textures === null) {
|
|
168
173
|
this.wind_textures = { u: new WGLTexture(gl, u_image), v: new WGLTexture(gl, v_image) };
|
|
169
174
|
}
|
|
@@ -173,9 +178,11 @@ class BillboardCollection {
|
|
|
173
178
|
}
|
|
174
179
|
}
|
|
175
180
|
async setup(gl) {
|
|
176
|
-
const
|
|
177
|
-
const
|
|
178
|
-
const
|
|
181
|
+
const thinned_grid = this.field.grid.getThinnedGrid(this.thin_fac, this.max_zoom);
|
|
182
|
+
const geom_verts = new Float32Array([0., 1., 2., 3.]);
|
|
183
|
+
const geom_buffer = new WGLBuffer(gl, geom_verts, 1, gl.TRIANGLE_STRIP);
|
|
184
|
+
const { vertices, texcoords } = await thinned_grid.getWGLBillboardBuffers(gl, this.thin_fac, this.max_zoom);
|
|
185
|
+
const { rotation: proj_rotation_tex } = thinned_grid.getVectorRotationTexture(gl, this.field.relative_to == 'earth');
|
|
179
186
|
const texture = new WGLTexture(gl, this.billboard_image);
|
|
180
187
|
const shader_defines = [];
|
|
181
188
|
let fragment_src = billboard_fragment_shader_src;
|
|
@@ -186,36 +193,40 @@ class BillboardCollection {
|
|
|
186
193
|
cmap_gpu.setupShaderVariables(gl, gl.NEAREST);
|
|
187
194
|
shader_defines.push('COLORMAP');
|
|
188
195
|
}
|
|
189
|
-
const
|
|
190
|
-
this.gl_elems = { gl: gl,
|
|
196
|
+
const shader_manager = new ShaderProgramManager(billboard_vertex_shader_src, fragment_src, shader_defines);
|
|
197
|
+
this.gl_elems = { gl: gl, shader_manager: shader_manager, geom_vertices: geom_buffer, vertices: vertices, texcoords: texcoords, texture: texture,
|
|
198
|
+
proj_rot_texture: proj_rotation_tex, cmap_gpu: cmap_gpu };
|
|
191
199
|
}
|
|
192
|
-
render(gl,
|
|
193
|
-
if (this.gl_elems === null || this.wind_textures === null
|
|
200
|
+
render(gl, arg, [map_width, map_height], map_zoom, map_bearing, map_pitch) {
|
|
201
|
+
if (this.gl_elems === null || this.wind_textures === null)
|
|
194
202
|
return;
|
|
195
|
-
|
|
196
|
-
|
|
203
|
+
const render_data = getRendererData(arg);
|
|
204
|
+
const program = this.gl_elems.shader_manager.getShaderProgram(gl, render_data.shaderData);
|
|
197
205
|
const gl_elems = this.gl_elems;
|
|
198
206
|
const bb_size = this.spec.BB_HEIGHT * (map_height / map_width) * this.size_multiplier;
|
|
199
207
|
const bb_width = this.spec.BB_WIDTH / this.spec.BB_TEX_WIDTH;
|
|
200
208
|
const bb_height = this.spec.BB_HEIGHT / this.spec.BB_TEX_HEIGHT;
|
|
201
|
-
|
|
209
|
+
program.use({ 'a_geom': gl_elems.geom_vertices, 'a_pos': gl_elems.vertices, 'a_tex_coord': gl_elems.texcoords }, { 'u_bb_size': bb_size, 'u_bb_width': bb_width, 'u_bb_height': bb_height,
|
|
202
210
|
'u_bb_mag_bin_size': this.spec.BB_MAG_BIN_SIZE, 'u_bb_mag_wrap': this.spec.BB_MAG_WRAP, 'u_offset': 0,
|
|
203
|
-
'
|
|
211
|
+
'u_map_aspect': map_height / map_width, 'u_zoom': map_zoom, 'u_rotate_with_map': this.rotate_with_map ? 1 : 0,
|
|
212
|
+
...this.gl_elems.shader_manager.getShaderUniforms(render_data) }, { 'u_sampler': gl_elems.texture, 'u_u_sampler': this.wind_textures.u, 'u_v_sampler': this.wind_textures.v, 'u_rot_sampler': gl_elems.proj_rot_texture });
|
|
204
213
|
if (gl_elems.cmap_gpu !== null) {
|
|
205
|
-
gl_elems.cmap_gpu.bindShaderVariables(
|
|
214
|
+
gl_elems.cmap_gpu.bindShaderVariables(program);
|
|
206
215
|
}
|
|
207
216
|
else {
|
|
208
|
-
|
|
217
|
+
program.setUniforms({ 'u_bb_color': this.color.toRGBATuple() });
|
|
209
218
|
}
|
|
210
219
|
gl.enable(gl.BLEND);
|
|
211
220
|
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
221
|
+
program.draw();
|
|
222
|
+
if (render_data.type != 'maplibre' || !render_data.shaderData.define.includes('GLOBE')) {
|
|
223
|
+
program.setUniforms({ 'u_offset': -2 });
|
|
224
|
+
program.draw();
|
|
225
|
+
program.setUniforms({ 'u_offset': -1 });
|
|
226
|
+
program.draw();
|
|
227
|
+
program.setUniforms({ 'u_offset': 1 });
|
|
228
|
+
program.draw();
|
|
229
|
+
}
|
|
219
230
|
}
|
|
220
231
|
}
|
|
221
232
|
export { BillboardCollection };
|
package/lib/Color.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/** A class for handling colors and translations between different color spaces */
|
|
1
2
|
declare class Color {
|
|
2
3
|
private rgba;
|
|
3
4
|
/**
|
|
@@ -52,5 +53,6 @@ declare class Color {
|
|
|
52
53
|
* @returns a new Color object
|
|
53
54
|
*/
|
|
54
55
|
static fromHSVTuple(hsv: [number, number, number]): Color;
|
|
56
|
+
static normalizeColor(color: Color | string): Color;
|
|
55
57
|
}
|
|
56
58
|
export { Color };
|
package/lib/Color.js
CHANGED
|
@@ -78,6 +78,7 @@ const hsv2rgb = (hsv) => {
|
|
|
78
78
|
}
|
|
79
79
|
return [r_prime + m, g_prime + m, b_prime + m];
|
|
80
80
|
};
|
|
81
|
+
/** A class for handling colors and translations between different color spaces */
|
|
81
82
|
class Color {
|
|
82
83
|
/**
|
|
83
84
|
* Create a new color object
|
|
@@ -156,5 +157,8 @@ class Color {
|
|
|
156
157
|
const rgb = hsv2rgb(hsv);
|
|
157
158
|
return new Color([rgb[0], rgb[1], rgb[2], 1]);
|
|
158
159
|
}
|
|
160
|
+
static normalizeColor(color) {
|
|
161
|
+
return color instanceof Color ? color : Color.fromHex(color);
|
|
162
|
+
}
|
|
159
163
|
}
|
|
160
164
|
export { Color };
|
package/lib/ColorBar.d.ts
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import { ColorMap } from "./Colormap";
|
|
2
2
|
import { Color } from "./Color";
|
|
3
|
+
/** The orientation for color bars (horizontal or vertical) */
|
|
3
4
|
type ColorbarOrientation = 'horizontal' | 'vertical';
|
|
5
|
+
/** Which side of a color bar the ticks are on */
|
|
4
6
|
type ColorbarTickDirection = 'top' | 'bottom' | 'left' | 'right';
|
|
7
|
+
/** Options for {@link ColorBar}s */
|
|
5
8
|
interface ColorBarOptions {
|
|
6
9
|
/** The label to place along the color bar */
|
|
7
10
|
label?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The size in pixels along the long axis of the colorbar
|
|
13
|
+
* @default 600
|
|
14
|
+
*/
|
|
15
|
+
size_long?: number;
|
|
16
|
+
/**
|
|
17
|
+
* The size in pixels along the short axis of the colorbar
|
|
18
|
+
* @default size_long / 9
|
|
19
|
+
*/
|
|
20
|
+
size_short?: number;
|
|
8
21
|
/**
|
|
9
22
|
* An array of numbers to use as the tick locations.
|
|
10
23
|
* @default Use all the levels in the color map provided to {@link makeColorBar}.
|
|
@@ -31,6 +44,11 @@ interface ColorBarOptions {
|
|
|
31
44
|
* @default 12
|
|
32
45
|
*/
|
|
33
46
|
ticklabelsize?: number;
|
|
47
|
+
/**
|
|
48
|
+
* The color for the color bar outline and the text
|
|
49
|
+
* @default '#000000'
|
|
50
|
+
*/
|
|
51
|
+
outline_and_text_color?: string;
|
|
34
52
|
}
|
|
35
53
|
/**
|
|
36
54
|
* Make an SVG containing a color bar. The color bar can either be oriented horizontal or vertical, and a label can be provided.
|
|
@@ -46,6 +64,7 @@ interface ColorBarOptions {
|
|
|
46
64
|
* document.getElementById('colorbar-container').appendChild(svg);
|
|
47
65
|
*/
|
|
48
66
|
declare function makeColorBar(colormap: ColorMap, opts: ColorBarOptions): SVGElement;
|
|
67
|
+
/** Options for {@link makePaintballKey | makePaintballKey()} */
|
|
49
68
|
interface PaintballKeyOptions {
|
|
50
69
|
/**
|
|
51
70
|
* The number of columns of entries in the key
|
package/lib/ColorBar.js
CHANGED
|
@@ -30,6 +30,9 @@ function makeColorBar(colormap, opts) {
|
|
|
30
30
|
const orientation = opts.orientation || 'vertical';
|
|
31
31
|
const fontface = opts.fontface || 'sans-serif';
|
|
32
32
|
const tickfontsize = opts.ticklabelsize || 12;
|
|
33
|
+
const size_long = opts.size_long || 600;
|
|
34
|
+
const size_short = opts.size_short || size_long / 9;
|
|
35
|
+
const outline_and_text_color = opts.outline_and_text_color || '#000000';
|
|
33
36
|
const tick_dir = opts.tick_direction || (orientation == 'vertical' ? 'left' : 'bottom');
|
|
34
37
|
if (orientation == 'vertical' && (tick_dir == 'top' || tick_dir == 'bottom') ||
|
|
35
38
|
orientation == 'horizontal' && (tick_dir == 'left' || tick_dir == 'right')) {
|
|
@@ -41,8 +44,8 @@ function makeColorBar(colormap, opts) {
|
|
|
41
44
|
const chars_left = getNChar(ticks[0]);
|
|
42
45
|
const chars_right = getNChar(ticks[ticks.length - 1]);
|
|
43
46
|
const need_overflow = colormap.underflow_color !== null || colormap.overflow_color !== null;
|
|
44
|
-
const bar_long_size =
|
|
45
|
-
const bar_cross_size =
|
|
47
|
+
const bar_long_size = size_long;
|
|
48
|
+
const bar_cross_size = size_short;
|
|
46
49
|
const bar_long_pad = Math.max(orientation == 'horizontal' ? Math.max(chars_left, chars_right) * 6 : 8, need_overflow ? bar_cross_size / (2 * Math.sqrt(3)) : 0);
|
|
47
50
|
const bar_cross_pad = 3;
|
|
48
51
|
const bar_thickness = 10;
|
|
@@ -141,7 +144,7 @@ function makeColorBar(colormap, opts) {
|
|
|
141
144
|
else {
|
|
142
145
|
lineattrs = tick_dir == 'bottom' ? { y2: 6 } : { y2: -6 };
|
|
143
146
|
}
|
|
144
|
-
createElement('line', { ...lineattrs, stroke:
|
|
147
|
+
createElement('line', { ...lineattrs, stroke: outline_and_text_color, 'stroke-width': 1.5 }, gtick);
|
|
145
148
|
let textattrs;
|
|
146
149
|
if (orientation == 'vertical') {
|
|
147
150
|
textattrs = tick_dir == 'left' ? { x: -9, dy: '0.32em' } : { x: 9, dy: '0.32em' };
|
|
@@ -149,7 +152,7 @@ function makeColorBar(colormap, opts) {
|
|
|
149
152
|
else {
|
|
150
153
|
textattrs = tick_dir == 'bottom' ? { y: 9, dy: '0.8em' } : { y: -9, dy: '0em' };
|
|
151
154
|
}
|
|
152
|
-
const text = createElement('text', { ...textattrs, fill:
|
|
155
|
+
const text = createElement('text', { ...textattrs, fill: outline_and_text_color, style: `font-family: ${fontface}; font-size: ${tickfontsize}pt` }, gtick);
|
|
153
156
|
text.textContent = level.toString();
|
|
154
157
|
});
|
|
155
158
|
// Draw the outline
|
|
@@ -164,7 +167,7 @@ function makeColorBar(colormap, opts) {
|
|
|
164
167
|
}
|
|
165
168
|
const outline_attrs = {
|
|
166
169
|
points: point_list,
|
|
167
|
-
stroke:
|
|
170
|
+
stroke: outline_and_text_color,
|
|
168
171
|
'stroke-width': 1.5,
|
|
169
172
|
fill: 'none'
|
|
170
173
|
};
|
|
@@ -177,7 +180,7 @@ function makeColorBar(colormap, opts) {
|
|
|
177
180
|
else {
|
|
178
181
|
labelattrs = tick_dir == 'bottom' ? { transform: `translate(${width / 2}, ${height - 5})` } : { transform: `translate(${width / 2}, 15)` };
|
|
179
182
|
}
|
|
180
|
-
const label_elem = createElement('text', { ...labelattrs, fill:
|
|
183
|
+
const label_elem = createElement('text', { ...labelattrs, fill: outline_and_text_color, 'text-anchor': 'middle', style: `font-family: ${fontface};` }, root);
|
|
181
184
|
label_elem.textContent = label;
|
|
182
185
|
return root;
|
|
183
186
|
}
|
package/lib/Colormap.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { WGLProgram, WGLTexture } from "autumn-wgl";
|
|
2
2
|
import { WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
3
3
|
import { Color } from "./Color";
|
|
4
|
+
/** Options for {@link ColorMap}s */
|
|
4
5
|
interface ColorMapOptions {
|
|
5
6
|
/** The color to use for areas where the value is above the highest value in the color map */
|
|
6
7
|
overflow_color?: Color | string;
|
package/lib/Colormap.js
CHANGED
|
@@ -8,6 +8,7 @@ import { Float16Array } from "@petamoriken/float16";
|
|
|
8
8
|
import { WGLTexture } from "autumn-wgl";
|
|
9
9
|
import { getGLFormatTypeAlignment } from "./PlotComponent";
|
|
10
10
|
import { Color } from "./Color";
|
|
11
|
+
import { mergeShaderCode } from "./utils";
|
|
11
12
|
const colormap_shader_src = `
|
|
12
13
|
uniform sampler2D u_cmap_sampler;
|
|
13
14
|
uniform sampler2D u_cmap_nonlin_sampler;
|
|
@@ -30,8 +31,8 @@ lowp vec4 apply_colormap(highp float value) {
|
|
|
30
31
|
else {
|
|
31
32
|
lowp float index_buffer = 1. / (2. * float(u_n_index));
|
|
32
33
|
normed_val = index_buffer + normed_val * (1. - 2. * index_buffer);
|
|
33
|
-
highp float nonlin_val =
|
|
34
|
-
color =
|
|
34
|
+
highp float nonlin_val = texture(u_cmap_nonlin_sampler, vec2(normed_val, 0.5)).r;
|
|
35
|
+
color = texture(u_cmap_sampler, vec2(nonlin_val, 0.5));
|
|
35
36
|
}
|
|
36
37
|
|
|
37
38
|
return color;
|
|
@@ -48,12 +49,11 @@ class ColorMap {
|
|
|
48
49
|
if (levels.length != colors.length + 1) {
|
|
49
50
|
throw `Mismatch between number of levels (${levels.length}) and number of colors (${colors.length}; expected ${levels.length - 1})`;
|
|
50
51
|
}
|
|
51
|
-
const normalizeColor = (c) => c instanceof Color ? c : Color.fromHex(c);
|
|
52
52
|
this.levels = levels;
|
|
53
|
-
this.colors = colors.map(c => normalizeColor(c));
|
|
53
|
+
this.colors = colors.map(c => Color.normalizeColor(c));
|
|
54
54
|
opts = opts === undefined ? {} : opts;
|
|
55
|
-
this.overflow_color = opts.overflow_color === undefined ? null : normalizeColor(opts.overflow_color);
|
|
56
|
-
this.underflow_color = opts.underflow_color === undefined ? null : normalizeColor(opts.underflow_color);
|
|
55
|
+
this.overflow_color = opts.overflow_color === undefined ? null : Color.normalizeColor(opts.overflow_color);
|
|
56
|
+
this.underflow_color = opts.underflow_color === undefined ? null : Color.normalizeColor(opts.underflow_color);
|
|
57
57
|
}
|
|
58
58
|
/**
|
|
59
59
|
* @returns an array of hex color strings
|
|
@@ -195,12 +195,12 @@ class ColorMapGPUInterface {
|
|
|
195
195
|
this.gl_elems = null;
|
|
196
196
|
}
|
|
197
197
|
static applyShader(shader_src) {
|
|
198
|
-
return colormap_shader_src
|
|
198
|
+
return mergeShaderCode(colormap_shader_src, shader_src);
|
|
199
199
|
}
|
|
200
200
|
setupShaderVariables(gl, mag_filter) {
|
|
201
201
|
const index_map = makeIndexMap(this.colormap);
|
|
202
202
|
const cmap_image = makeTextureImage(this.colormap);
|
|
203
|
-
const { format: format_nonlin, type: type_nonlin, row_alignment: row_alignment_nonlin } = getGLFormatTypeAlignment(gl,
|
|
203
|
+
const { format: format_nonlin, type: type_nonlin, row_alignment: row_alignment_nonlin } = getGLFormatTypeAlignment(gl, 'float16');
|
|
204
204
|
const cmap_image_spec = { 'format': gl.RGBA, 'type': gl.UNSIGNED_BYTE, 'image': cmap_image, 'mag_filter': mag_filter };
|
|
205
205
|
const cmap_texture = new WGLTexture(gl, cmap_image_spec);
|
|
206
206
|
const cmap_nonlin_image = { 'format': format_nonlin, 'type': type_nonlin,
|