autumnplot-gl 3.1.0 → 4.0.0-beta
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 +6 -11
- package/dist/110.autumnplot-gl.js +1 -1
- package/dist/110.autumnplot-gl.js.map +1 -1
- 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 +53 -5
- package/lib/AutumnTypes.js +25 -1
- package/lib/Barbs.d.ts +23 -6
- package/lib/Barbs.js +20 -18
- package/lib/BillboardCollection.d.ts +16 -8
- package/lib/BillboardCollection.js +107 -59
- package/lib/Color.d.ts +57 -0
- package/lib/Color.js +163 -0
- package/lib/ColorBar.d.ts +12 -1
- package/lib/ColorBar.js +9 -7
- package/lib/Colormap.d.ts +19 -18
- package/lib/Colormap.js +84 -23
- package/lib/Contour.d.ts +42 -11
- package/lib/Contour.js +67 -58
- package/lib/ContourCreator.d.ts +4 -0
- package/lib/ContourCreator.js +2 -1
- package/lib/Fill.d.ts +27 -16
- package/lib/Fill.js +105 -83
- package/lib/Grid.d.ts +125 -29
- package/lib/Grid.js +303 -95
- package/lib/Hodographs.d.ts +24 -6
- package/lib/Hodographs.js +28 -24
- package/lib/Map.js +1 -1
- package/lib/Paintball.d.ts +6 -5
- package/lib/Paintball.js +38 -32
- package/lib/ParticleTracer.d.ts +19 -0
- package/lib/ParticleTracer.js +37 -0
- package/lib/PlotComponent.d.ts +6 -7
- package/lib/PlotComponent.js +17 -7
- package/lib/PlotLayer.d.ts +4 -4
- package/lib/PlotLayer.worker.d.ts +1 -2
- package/lib/PlotLayer.worker.js +22 -57
- package/lib/PolylineCollection.d.ts +18 -9
- package/lib/PolylineCollection.js +124 -89
- package/lib/RawField.d.ts +76 -23
- package/lib/RawField.js +138 -29
- package/lib/ShaderManager.d.ts +12 -0
- package/lib/ShaderManager.js +58 -0
- package/lib/StationPlot.d.ts +145 -0
- package/lib/StationPlot.js +205 -0
- package/lib/TextCollection.d.ts +12 -8
- package/lib/TextCollection.js +113 -71
- 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 +7 -4
- package/lib/index.js +5 -3
- package/lib/utils.d.ts +5 -8
- package/lib/utils.js +12 -83
- package/package.json +2 -2
|
Binary file
|
package/lib/AutumnTypes.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Float16Array } from "@petamoriken/float16";
|
|
2
2
|
interface WindProfile {
|
|
3
|
-
lat: number;
|
|
4
|
-
lon: number;
|
|
5
3
|
jlat: number;
|
|
6
4
|
ilon: number;
|
|
7
5
|
smu: number;
|
|
@@ -34,7 +32,57 @@ type Polyline = {
|
|
|
34
32
|
};
|
|
35
33
|
type WebGLAnyRenderingContext = WebGLRenderingContext | WebGL2RenderingContext;
|
|
36
34
|
declare function isWebGL2Ctx(gl: WebGLAnyRenderingContext): gl is WebGL2RenderingContext;
|
|
37
|
-
type TypedArray = Float16Array | Float32Array;
|
|
35
|
+
type TypedArray = Float16Array | Float32Array | Uint8Array;
|
|
36
|
+
type TypedArrayStr = 'float16' | 'float32' | 'uint8';
|
|
38
37
|
type ContourData = Record<number, [number, number][][]>;
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
type mat4 = number[] | Float32Array | Float64Array;
|
|
39
|
+
type RenderShaderData = {
|
|
40
|
+
vertexShaderPrelude: string;
|
|
41
|
+
define: string;
|
|
42
|
+
variantName: string;
|
|
43
|
+
};
|
|
44
|
+
type MapLibreRendererDataProjection = {
|
|
45
|
+
clippingPlane: [number, number, number, number];
|
|
46
|
+
fallbackMatrix: mat4;
|
|
47
|
+
mainMatrix: mat4;
|
|
48
|
+
projectionTransition: number;
|
|
49
|
+
tileMercatorCoords: [number, number, number, number];
|
|
50
|
+
};
|
|
51
|
+
type MapLibreRendererDataShader = RenderShaderData;
|
|
52
|
+
type MapLibreRendererData = {
|
|
53
|
+
defaultProjectionData: MapLibreRendererDataProjection;
|
|
54
|
+
farZ: number;
|
|
55
|
+
fov: number;
|
|
56
|
+
modelViewProjectionMatrix: mat4;
|
|
57
|
+
nearZ: number;
|
|
58
|
+
projectionMatrix: mat4;
|
|
59
|
+
shaderData: MapLibreRendererDataShader;
|
|
60
|
+
};
|
|
61
|
+
type RenderMethodArg = mat4 | MapLibreRendererData;
|
|
62
|
+
type RendererDataProjection = {
|
|
63
|
+
clippingPlane: number[];
|
|
64
|
+
fallbackMatrix: number[];
|
|
65
|
+
mainMatrix: number[];
|
|
66
|
+
projectionTransition: number;
|
|
67
|
+
tileMercatorCoords: number[];
|
|
68
|
+
};
|
|
69
|
+
type RendererDataShader = RenderShaderData;
|
|
70
|
+
type RendererDataMapLibre = {
|
|
71
|
+
type: 'maplibre';
|
|
72
|
+
defaultProjectionData: RendererDataProjection;
|
|
73
|
+
farZ: number;
|
|
74
|
+
fov: number;
|
|
75
|
+
modelViewProjectionMatrix: number[];
|
|
76
|
+
nearZ: number;
|
|
77
|
+
projectionMatrix: number[];
|
|
78
|
+
shaderData: RendererDataShader;
|
|
79
|
+
};
|
|
80
|
+
type RendererDataAutumn = {
|
|
81
|
+
type: 'autumn';
|
|
82
|
+
mainMatrix: number[];
|
|
83
|
+
shaderData: null;
|
|
84
|
+
};
|
|
85
|
+
type RendererData = RendererDataMapLibre | RendererDataAutumn;
|
|
86
|
+
declare function getRendererData(arg: RenderMethodArg): RendererData;
|
|
87
|
+
export { isWebGL2Ctx, getRendererData };
|
|
88
|
+
export type { WindProfile, BillboardSpec, Polyline, LineData, WebGLAnyRenderingContext, TypedArray, TypedArrayStr, ContourData, RenderMethodArg, RendererData, RenderShaderData };
|
package/lib/AutumnTypes.js
CHANGED
|
@@ -1,4 +1,28 @@
|
|
|
1
1
|
function isWebGL2Ctx(gl) {
|
|
2
2
|
return gl.getParameter(gl.VERSION).includes('WebGL 2.0');
|
|
3
3
|
}
|
|
4
|
-
|
|
4
|
+
function isMapLibreRenderArg(obj) {
|
|
5
|
+
return 'modelViewProjectionMatrix' in obj && 'defaultProjectionData' in obj && 'mainMatrix' in obj.defaultProjectionData;
|
|
6
|
+
}
|
|
7
|
+
function getRendererData(arg) {
|
|
8
|
+
if (isMapLibreRenderArg(arg)) {
|
|
9
|
+
return {
|
|
10
|
+
type: 'maplibre',
|
|
11
|
+
defaultProjectionData: {
|
|
12
|
+
clippingPlane: [...arg.defaultProjectionData.clippingPlane],
|
|
13
|
+
fallbackMatrix: [...arg.defaultProjectionData.fallbackMatrix],
|
|
14
|
+
mainMatrix: [...arg.defaultProjectionData.mainMatrix],
|
|
15
|
+
projectionTransition: arg.defaultProjectionData.projectionTransition,
|
|
16
|
+
tileMercatorCoords: [...arg.defaultProjectionData.tileMercatorCoords]
|
|
17
|
+
},
|
|
18
|
+
farZ: arg.farZ,
|
|
19
|
+
fov: arg.fov,
|
|
20
|
+
modelViewProjectionMatrix: [...arg.modelViewProjectionMatrix],
|
|
21
|
+
nearZ: arg.nearZ,
|
|
22
|
+
projectionMatrix: [...arg.projectionMatrix],
|
|
23
|
+
shaderData: arg.shaderData
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
return { type: 'autumn', mainMatrix: [...arg], shaderData: null };
|
|
27
|
+
}
|
|
28
|
+
export { isWebGL2Ctx, getRendererData };
|
package/lib/Barbs.d.ts
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
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
|
+
import { ColorMap } from "./Colormap";
|
|
6
|
+
import { Grid } from "./Grid";
|
|
5
7
|
interface BarbsOptions {
|
|
6
8
|
/**
|
|
7
9
|
* The color to use for the barbs as a hex color string;.
|
|
8
10
|
* @default '#000000'
|
|
9
11
|
*/
|
|
10
12
|
color?: string;
|
|
13
|
+
/**
|
|
14
|
+
* A color map to use to color the barbs by magnitude. Specifying cmap overrides the color argument.
|
|
15
|
+
*/
|
|
16
|
+
cmap?: ColorMap | null;
|
|
17
|
+
/**
|
|
18
|
+
* The width of the lines to use for the barbs
|
|
19
|
+
* @default 2
|
|
20
|
+
*/
|
|
21
|
+
line_width?: number;
|
|
22
|
+
/**
|
|
23
|
+
* A multiplier for the barb size
|
|
24
|
+
* @default 1
|
|
25
|
+
*/
|
|
26
|
+
barb_size_multiplier?: number;
|
|
11
27
|
/**
|
|
12
28
|
* How much to thin the barbs at zoom level 1 on the map. This effectively means to plot every `n`th barb in the i and j directions, where `n` =
|
|
13
29
|
* `thin_fac`. `thin_fac` should be a power of 2.
|
|
@@ -23,23 +39,24 @@ interface BarbsOptions {
|
|
|
23
39
|
* const vector_field = new RawVectorField(grid, u_data, v_data);
|
|
24
40
|
* const barbs = new Barbs(vector_field, {color: '#000000', thin_fac: 16});
|
|
25
41
|
*/
|
|
26
|
-
declare class Barbs<ArrayType extends TypedArray, MapType extends MapLikeType> extends PlotComponent<MapType> {
|
|
42
|
+
declare class Barbs<ArrayType extends TypedArray, GridType extends Grid, MapType extends MapLikeType> extends PlotComponent<MapType> {
|
|
27
43
|
/** The vector field */
|
|
28
44
|
private fields;
|
|
29
45
|
readonly opts: Required<BarbsOptions>;
|
|
30
|
-
private readonly
|
|
46
|
+
private readonly color;
|
|
31
47
|
private gl_elems;
|
|
48
|
+
private barb_texture;
|
|
32
49
|
/**
|
|
33
50
|
* Create a field of wind barbs
|
|
34
51
|
* @param fields - The vector field to plot as barbs
|
|
35
52
|
* @param opts - Options for creating the wind barbs
|
|
36
53
|
*/
|
|
37
|
-
constructor(fields: RawVectorField<ArrayType>, opts: BarbsOptions);
|
|
54
|
+
constructor(fields: RawVectorField<ArrayType, GridType>, opts: BarbsOptions);
|
|
38
55
|
/**
|
|
39
56
|
* Update the field displayed as barbs
|
|
40
57
|
* @param fields - The new field to display as barbs
|
|
41
58
|
*/
|
|
42
|
-
updateField(fields: RawVectorField<ArrayType>): Promise<void>;
|
|
59
|
+
updateField(fields: RawVectorField<ArrayType, GridType>): Promise<void>;
|
|
43
60
|
/**
|
|
44
61
|
* @internal
|
|
45
62
|
* Add the barb field to a map
|
|
@@ -49,7 +66,7 @@ declare class Barbs<ArrayType extends TypedArray, MapType extends MapLikeType> e
|
|
|
49
66
|
* @internal
|
|
50
67
|
* Render the barb field
|
|
51
68
|
*/
|
|
52
|
-
render(gl: WebGLAnyRenderingContext, matrix:
|
|
69
|
+
render(gl: WebGLAnyRenderingContext, matrix: RenderMethodArg): void;
|
|
53
70
|
}
|
|
54
71
|
export default Barbs;
|
|
55
72
|
export type { BarbsOptions };
|
package/lib/Barbs.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { PlotComponent } from "./PlotComponent";
|
|
2
2
|
import { BillboardCollection } from './BillboardCollection';
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import { normalizeOptions } from './utils';
|
|
4
|
+
import { Color } from "./Color";
|
|
5
|
+
const BASE_BARB_DIMS = {
|
|
5
6
|
BB_WIDTH: 85,
|
|
6
7
|
BB_HEIGHT: 256,
|
|
7
8
|
BB_TEX_WIDTH: 1024,
|
|
@@ -10,12 +11,13 @@ const BARB_DIMS = {
|
|
|
10
11
|
BB_MAG_WRAP: 60,
|
|
11
12
|
BB_MAG_BIN_SIZE: 5,
|
|
12
13
|
};
|
|
13
|
-
|
|
14
|
+
const LINE_WIDTH_MULTIPLIER = 4;
|
|
15
|
+
function createBarbTexture(dimensions, line_width) {
|
|
14
16
|
let canvas = document.createElement('canvas');
|
|
15
|
-
canvas.width =
|
|
16
|
-
canvas.height =
|
|
17
|
+
canvas.width = dimensions.BB_TEX_WIDTH;
|
|
18
|
+
canvas.height = dimensions.BB_TEX_HEIGHT;
|
|
17
19
|
function drawWindBarb(ctx, tipx, tipy, mag) {
|
|
18
|
-
const elem_full_size =
|
|
20
|
+
const elem_full_size = dimensions.BB_WIDTH / 2 - 4;
|
|
19
21
|
const elem_spacing = elem_full_size / 2;
|
|
20
22
|
if (mag < 2.5) {
|
|
21
23
|
ctx.beginPath();
|
|
@@ -87,18 +89,20 @@ function _createBarbTexture() {
|
|
|
87
89
|
if (ctx === null) {
|
|
88
90
|
throw "Could not get rendering context for the wind barb canvas";
|
|
89
91
|
}
|
|
90
|
-
ctx.lineWidth =
|
|
92
|
+
ctx.lineWidth = line_width;
|
|
91
93
|
ctx.miterLimit = 4;
|
|
92
|
-
for (let ibarb = 0; ibarb <=
|
|
93
|
-
const x_pos = (ibarb %
|
|
94
|
-
const y_pos = Math.floor(ibarb /
|
|
94
|
+
for (let ibarb = 0; ibarb <= dimensions.BB_MAG_MAX; ibarb += dimensions.BB_MAG_BIN_SIZE) {
|
|
95
|
+
const x_pos = (ibarb % dimensions.BB_MAG_WRAP) / dimensions.BB_MAG_BIN_SIZE * dimensions.BB_WIDTH + dimensions.BB_WIDTH / 2;
|
|
96
|
+
const y_pos = Math.floor(ibarb / dimensions.BB_MAG_WRAP) * dimensions.BB_HEIGHT + dimensions.BB_WIDTH / 2;
|
|
95
97
|
drawWindBarb(ctx, x_pos, y_pos, ibarb);
|
|
96
98
|
}
|
|
97
99
|
return canvas;
|
|
98
100
|
}
|
|
99
|
-
let BARB_TEXTURE = null;
|
|
100
101
|
const barb_opt_defaults = {
|
|
101
102
|
color: '#000000',
|
|
103
|
+
cmap: null,
|
|
104
|
+
line_width: 2,
|
|
105
|
+
barb_size_multiplier: 1,
|
|
102
106
|
thin_fac: 1
|
|
103
107
|
};
|
|
104
108
|
/**
|
|
@@ -119,8 +123,8 @@ class Barbs extends PlotComponent {
|
|
|
119
123
|
super();
|
|
120
124
|
this.fields = fields;
|
|
121
125
|
this.opts = normalizeOptions(opts, barb_opt_defaults);
|
|
122
|
-
|
|
123
|
-
this.
|
|
126
|
+
this.color = Color.fromHex(this.opts.color);
|
|
127
|
+
this.barb_texture = createBarbTexture(BASE_BARB_DIMS, this.opts.line_width / this.opts.barb_size_multiplier * LINE_WIDTH_MULTIPLIER);
|
|
124
128
|
this.gl_elems = null;
|
|
125
129
|
}
|
|
126
130
|
/**
|
|
@@ -142,11 +146,9 @@ class Barbs extends PlotComponent {
|
|
|
142
146
|
gl.getExtension('OES_texture_float');
|
|
143
147
|
gl.getExtension('OES_texture_float_linear');
|
|
144
148
|
const map_max_zoom = map.getMaxZoom();
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
const barb_image = { format: gl.RGBA, type: gl.UNSIGNED_BYTE, image: BARB_TEXTURE, mag_filter: gl.NEAREST };
|
|
149
|
-
const barb_billboards = new BillboardCollection(this.fields, this.opts.thin_fac, map_max_zoom, barb_image, BARB_DIMS, this.color_rgb, 0.1);
|
|
149
|
+
const barb_image = { format: gl.RGBA, type: gl.UNSIGNED_BYTE, image: this.barb_texture, mag_filter: gl.NEAREST };
|
|
150
|
+
const cmap = this.opts.cmap === null ? undefined : this.opts.cmap;
|
|
151
|
+
const barb_billboards = new BillboardCollection(this.fields, this.opts.thin_fac, map_max_zoom, barb_image, BASE_BARB_DIMS, 0.1 * this.opts.barb_size_multiplier, { color: this.color, cmap: cmap });
|
|
150
152
|
await barb_billboards.setup(gl);
|
|
151
153
|
this.gl_elems = {
|
|
152
154
|
map: map, barb_billboards: barb_billboards
|
|
@@ -1,21 +1,29 @@
|
|
|
1
|
-
import { BillboardSpec, TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
1
|
+
import { BillboardSpec, RenderMethodArg, TypedArray, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
2
|
+
import { Color } from "./Color";
|
|
3
|
+
import { ColorMap } from "./Colormap";
|
|
4
|
+
import { Grid } from "./Grid";
|
|
2
5
|
import { RawVectorField } from "./RawField";
|
|
3
6
|
import { WGLTextureSpec } from "autumn-wgl";
|
|
4
|
-
|
|
7
|
+
interface BillboardCollectionOpts {
|
|
8
|
+
color?: Color;
|
|
9
|
+
cmap?: ColorMap;
|
|
10
|
+
rotate_with_map?: boolean;
|
|
11
|
+
}
|
|
12
|
+
declare class BillboardCollection<ArrayType extends TypedArray, GridType extends Grid> {
|
|
5
13
|
private field;
|
|
6
14
|
readonly spec: BillboardSpec;
|
|
7
|
-
readonly color:
|
|
15
|
+
readonly color: Color;
|
|
16
|
+
readonly cmap: ColorMap | null;
|
|
17
|
+
readonly rotate_with_map: boolean;
|
|
8
18
|
readonly size_multiplier: number;
|
|
9
19
|
readonly thin_fac: number;
|
|
10
20
|
readonly max_zoom: number;
|
|
11
21
|
readonly billboard_image: WGLTextureSpec;
|
|
12
22
|
private gl_elems;
|
|
13
23
|
private wind_textures;
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
constructor(field: RawVectorField<ArrayType>, thin_fac: number, max_zoom: number, billboard_image: WGLTextureSpec, billboard_spec: BillboardSpec, billboard_color: [number, number, number], billboard_size_mult: number);
|
|
17
|
-
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;
|
|
18
26
|
setup(gl: WebGLAnyRenderingContext): Promise<void>;
|
|
19
|
-
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;
|
|
20
28
|
}
|
|
21
29
|
export { BillboardCollection };
|
|
@@ -1,25 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { getRendererData } from "./AutumnTypes";
|
|
2
|
+
import { Color } from "./Color";
|
|
3
|
+
import { ColorMapGPUInterface } from "./Colormap";
|
|
4
|
+
import { WGLBuffer, WGLTexture } from "autumn-wgl";
|
|
5
|
+
import { ShaderProgramManager } from "./ShaderManager";
|
|
6
|
+
const billboard_vertex_shader_src = `#version 300 es
|
|
7
|
+
|
|
4
8
|
uniform int u_offset;
|
|
5
9
|
|
|
6
|
-
|
|
7
|
-
|
|
10
|
+
in vec2 a_pos;
|
|
11
|
+
in vec2 a_tex_coord;
|
|
12
|
+
in lowp float a_geom;
|
|
8
13
|
uniform lowp float u_bb_size;
|
|
9
14
|
uniform lowp float u_map_aspect;
|
|
10
15
|
uniform lowp float u_zoom;
|
|
11
|
-
uniform highp float u_map_bearing;
|
|
12
16
|
uniform lowp float u_bb_width;
|
|
13
17
|
uniform lowp float u_bb_height;
|
|
14
18
|
uniform highp float u_bb_mag_bin_size;
|
|
15
|
-
|
|
16
19
|
uniform highp float u_bb_mag_wrap;
|
|
20
|
+
uniform int u_rotate_with_map;
|
|
17
21
|
|
|
18
22
|
uniform sampler2D u_u_sampler;
|
|
19
23
|
uniform sampler2D u_v_sampler;
|
|
20
24
|
uniform sampler2D u_rot_sampler;
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
out highp vec2 v_tex_coord;
|
|
27
|
+
#ifdef COLORMAP
|
|
28
|
+
out highp float v_mag;
|
|
29
|
+
#endif
|
|
23
30
|
|
|
24
31
|
mat4 scalingMatrix(float x_scale, float y_scale, float z_scale) {
|
|
25
32
|
return mat4(x_scale, 0.0, 0.0, 0.0,
|
|
@@ -52,18 +59,34 @@ void main() {
|
|
|
52
59
|
float globe_width = 1.;
|
|
53
60
|
vec2 globe_offset = vec2(globe_width * float(u_offset), 0.);
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
+
}
|
|
73
|
+
|
|
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);
|
|
59
79
|
|
|
60
|
-
highp float u =
|
|
61
|
-
highp float v =
|
|
62
|
-
highp float rot =
|
|
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;
|
|
63
83
|
|
|
64
84
|
lowp float bb_aspect = u_bb_width / u_bb_height;
|
|
65
85
|
lowp float ang = (abs(u) < 1e-6 && abs(v) < 1e-6) ? 0. : atan(v, u) - 3.141592654 / 2.0;
|
|
66
86
|
highp float mag = length(vec2(u, v));
|
|
87
|
+
#ifdef COLORMAP
|
|
88
|
+
v_mag = mag;
|
|
89
|
+
#endif
|
|
67
90
|
mag = floor(mag / u_bb_mag_bin_size + 0.5) * u_bb_mag_bin_size;
|
|
68
91
|
|
|
69
92
|
vec4 offset = vec4(0.0, 0.0, 0.0, 0.0);
|
|
@@ -90,58 +113,62 @@ void main() {
|
|
|
90
113
|
texcoord = tex_loc + vec2(u_bb_width, u_bb_height);
|
|
91
114
|
}
|
|
92
115
|
|
|
93
|
-
mat4 barb_rotation = rotationZMatrix(ang
|
|
94
|
-
mat4 map_stretch_matrix = scalingMatrix(1.0, 1. / u_map_aspect, 1.0);
|
|
116
|
+
mat4 barb_rotation = rotationZMatrix(ang - globe_rotation - rot);
|
|
95
117
|
offset = map_stretch_matrix * barb_rotation * offset;
|
|
96
118
|
}
|
|
97
119
|
|
|
98
120
|
gl_Position = pivot_pos + offset;
|
|
99
121
|
v_tex_coord = texcoord;
|
|
100
122
|
}`
|
|
101
|
-
const billboard_fragment_shader_src =
|
|
123
|
+
const billboard_fragment_shader_src = `#version 300 es
|
|
124
|
+
|
|
125
|
+
in highp vec2 v_tex_coord;
|
|
126
|
+
|
|
127
|
+
#ifdef COLORMAP
|
|
128
|
+
in highp float v_mag;
|
|
129
|
+
#else
|
|
130
|
+
uniform lowp vec4 u_bb_color;
|
|
131
|
+
#endif
|
|
102
132
|
|
|
103
133
|
uniform sampler2D u_sampler;
|
|
104
|
-
|
|
134
|
+
|
|
135
|
+
out highp vec4 fragColor;
|
|
105
136
|
|
|
106
137
|
void main() {
|
|
107
|
-
lowp vec4 tex_color =
|
|
108
|
-
|
|
138
|
+
lowp vec4 tex_color = texture(u_sampler, v_tex_coord);
|
|
139
|
+
|
|
140
|
+
lowp vec4 color;
|
|
141
|
+
#ifdef COLORMAP
|
|
142
|
+
color = apply_colormap(v_mag);
|
|
143
|
+
#else
|
|
144
|
+
color = u_bb_color;
|
|
145
|
+
#endif
|
|
146
|
+
|
|
147
|
+
color.a *= tex_color.a;
|
|
148
|
+
fragColor = color;
|
|
109
149
|
}`
|
|
110
|
-
class BillboardCollectionGLElems {
|
|
111
|
-
}
|
|
112
150
|
class BillboardCollection {
|
|
113
|
-
constructor(field, thin_fac, max_zoom, billboard_image, billboard_spec,
|
|
151
|
+
constructor(field, thin_fac, max_zoom, billboard_image, billboard_spec, billboard_size_mult, opts) {
|
|
152
|
+
opts = opts === undefined ? {} : opts;
|
|
153
|
+
this.color = opts.color === undefined ? new Color([0, 0, 0, 1]) : opts.color;
|
|
154
|
+
this.cmap = opts.cmap === undefined ? null : opts.cmap;
|
|
155
|
+
this.rotate_with_map = opts.rotate_with_map === undefined ? true : opts.rotate_with_map;
|
|
114
156
|
this.field = field;
|
|
115
157
|
this.spec = billboard_spec;
|
|
116
|
-
this.color = billboard_color;
|
|
117
158
|
this.size_multiplier = billboard_size_mult;
|
|
118
159
|
this.thin_fac = thin_fac;
|
|
119
160
|
this.max_zoom = max_zoom;
|
|
120
161
|
this.billboard_image = billboard_image;
|
|
121
162
|
this.gl_elems = null;
|
|
122
163
|
this.wind_textures = null;
|
|
123
|
-
const n_density_tiers = Math.log2(thin_fac);
|
|
124
|
-
const n_inaccessible_tiers = Math.max(n_density_tiers + 1 - max_zoom, 0);
|
|
125
|
-
this.trim_inaccessible = Math.pow(2, n_inaccessible_tiers);
|
|
126
|
-
this.show_field = true;
|
|
127
164
|
}
|
|
128
165
|
updateField(field) {
|
|
129
166
|
this.field = field;
|
|
130
167
|
if (this.gl_elems === null)
|
|
131
168
|
return;
|
|
132
169
|
const gl = this.gl_elems.gl;
|
|
133
|
-
const data = this.field.getThinnedField(this.
|
|
134
|
-
const { u:
|
|
135
|
-
this.show_field = u_thin !== null;
|
|
136
|
-
const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, !(u_thin instanceof Float32Array));
|
|
137
|
-
const u_image = { 'format': format, 'type': type,
|
|
138
|
-
'width': data.grid.ni, 'height': data.grid.nj, 'image': u_thin,
|
|
139
|
-
'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
|
|
140
|
-
};
|
|
141
|
-
const v_image = { 'format': format, 'type': type,
|
|
142
|
-
'width': data.grid.ni, 'height': data.grid.nj, 'image': v_thin,
|
|
143
|
-
'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
|
|
144
|
-
};
|
|
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);
|
|
145
172
|
if (this.wind_textures === null) {
|
|
146
173
|
this.wind_textures = { u: new WGLTexture(gl, u_image), v: new WGLTexture(gl, v_image) };
|
|
147
174
|
}
|
|
@@ -151,34 +178,55 @@ class BillboardCollection {
|
|
|
151
178
|
}
|
|
152
179
|
}
|
|
153
180
|
async setup(gl) {
|
|
154
|
-
const
|
|
155
|
-
const
|
|
156
|
-
const
|
|
157
|
-
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');
|
|
158
186
|
const texture = new WGLTexture(gl, this.billboard_image);
|
|
159
|
-
|
|
187
|
+
const shader_defines = [];
|
|
188
|
+
let fragment_src = billboard_fragment_shader_src;
|
|
189
|
+
let cmap_gpu = null;
|
|
190
|
+
if (this.cmap !== null) {
|
|
191
|
+
fragment_src = ColorMapGPUInterface.applyShader(fragment_src);
|
|
192
|
+
cmap_gpu = new ColorMapGPUInterface(this.cmap);
|
|
193
|
+
cmap_gpu.setupShaderVariables(gl, gl.NEAREST);
|
|
194
|
+
shader_defines.push('COLORMAP');
|
|
195
|
+
}
|
|
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 };
|
|
160
199
|
}
|
|
161
|
-
render(gl,
|
|
162
|
-
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)
|
|
163
202
|
return;
|
|
164
|
-
|
|
165
|
-
|
|
203
|
+
const render_data = getRendererData(arg);
|
|
204
|
+
const program = this.gl_elems.shader_manager.getShaderProgram(gl, render_data.shaderData);
|
|
166
205
|
const gl_elems = this.gl_elems;
|
|
167
206
|
const bb_size = this.spec.BB_HEIGHT * (map_height / map_width) * this.size_multiplier;
|
|
168
207
|
const bb_width = this.spec.BB_WIDTH / this.spec.BB_TEX_WIDTH;
|
|
169
208
|
const bb_height = this.spec.BB_HEIGHT / this.spec.BB_TEX_HEIGHT;
|
|
170
|
-
|
|
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,
|
|
171
210
|
'u_bb_mag_bin_size': this.spec.BB_MAG_BIN_SIZE, 'u_bb_mag_wrap': this.spec.BB_MAG_WRAP, 'u_offset': 0,
|
|
172
|
-
'
|
|
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 });
|
|
213
|
+
if (gl_elems.cmap_gpu !== null) {
|
|
214
|
+
gl_elems.cmap_gpu.bindShaderVariables(program);
|
|
215
|
+
}
|
|
216
|
+
else {
|
|
217
|
+
program.setUniforms({ 'u_bb_color': this.color.toRGBATuple() });
|
|
218
|
+
}
|
|
173
219
|
gl.enable(gl.BLEND);
|
|
174
220
|
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
+
}
|
|
182
230
|
}
|
|
183
231
|
}
|
|
184
232
|
export { BillboardCollection };
|
package/lib/Color.d.ts
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
declare class Color {
|
|
2
|
+
private rgba;
|
|
3
|
+
/**
|
|
4
|
+
* Create a new color object
|
|
5
|
+
* @param rgba - An RGBA tuple of floats between 0 and 1
|
|
6
|
+
*/
|
|
7
|
+
constructor(rgba: [number, number, number, number]);
|
|
8
|
+
/**
|
|
9
|
+
* The red component of the color as a float value between 0 and 1
|
|
10
|
+
*/
|
|
11
|
+
get r(): number;
|
|
12
|
+
/**
|
|
13
|
+
* The green component of the color as a float value between 0 and 1
|
|
14
|
+
*/
|
|
15
|
+
get g(): number;
|
|
16
|
+
/**
|
|
17
|
+
* The blue component of the color as a float value between 0 and 1
|
|
18
|
+
*/
|
|
19
|
+
get b(): number;
|
|
20
|
+
/**
|
|
21
|
+
* The alpha component (opacity) of the color as a float value between 0 and 1
|
|
22
|
+
*/
|
|
23
|
+
get a(): number;
|
|
24
|
+
/**
|
|
25
|
+
* @param opacity - The new alpha component (opacity)
|
|
26
|
+
* @returns A new color with the alpha component set to opacity.
|
|
27
|
+
*/
|
|
28
|
+
withOpacity(opacity: number): Color;
|
|
29
|
+
/**
|
|
30
|
+
* @returns The color as an RGB hex string (e.g., '#dedbef')
|
|
31
|
+
*/
|
|
32
|
+
toRGBHex(): string;
|
|
33
|
+
/**
|
|
34
|
+
* @returns The color as an RGBA hex string (e.g., '#dedbefff')
|
|
35
|
+
*/
|
|
36
|
+
toRGBAHex(): string;
|
|
37
|
+
/**
|
|
38
|
+
* @returns The color as an RGBA float tuple
|
|
39
|
+
*/
|
|
40
|
+
toRGBATuple(): [number, number, number, number];
|
|
41
|
+
/**
|
|
42
|
+
* @returns The color as a tuple of HSV values
|
|
43
|
+
*/
|
|
44
|
+
toHSVTuple(): [number, number, number];
|
|
45
|
+
/**
|
|
46
|
+
* @param hex - An RGB or RGBA hex string to parse
|
|
47
|
+
* @returns a new Color object
|
|
48
|
+
*/
|
|
49
|
+
static fromHex(hex: string): Color;
|
|
50
|
+
/**
|
|
51
|
+
* @param hsv - A tuple of HSV values
|
|
52
|
+
* @returns a new Color object
|
|
53
|
+
*/
|
|
54
|
+
static fromHSVTuple(hsv: [number, number, number]): Color;
|
|
55
|
+
static normalizeColor(color: Color | string): Color;
|
|
56
|
+
}
|
|
57
|
+
export { Color };
|