autumnplot-gl 2.2.3 → 3.1.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 +65 -8
- package/dist/110.autumnplot-gl.js +2 -0
- package/dist/110.autumnplot-gl.js.map +1 -0
- package/dist/autumnplot-gl.js +3 -0
- package/dist/autumnplot-gl.js.LICENSE.txt +12 -0
- package/dist/autumnplot-gl.js.map +1 -0
- package/dist/marchingsquares.wasm +0 -0
- package/lib/AutumnTypes.d.ts +14 -13
- package/lib/Barbs.d.ts +10 -5
- package/lib/Barbs.js +22 -5
- package/lib/BillboardCollection.d.ts +11 -7
- package/lib/BillboardCollection.js +52 -30
- package/lib/ColorBar.js +51 -7
- package/lib/Colormap.d.ts +14 -3
- package/lib/Colormap.js +63 -12
- package/lib/Contour.d.ts +73 -18
- package/lib/Contour.js +180 -148
- package/lib/ContourCreator.d.ts +18 -0
- package/lib/ContourCreator.js +23 -0
- package/lib/Fill.d.ts +18 -7
- package/lib/Fill.js +73 -41
- package/lib/Grid.d.ts +167 -0
- package/lib/Grid.js +339 -0
- package/lib/Hodographs.d.ts +13 -6
- package/lib/Hodographs.js +58 -71
- package/lib/Map.d.ts +14 -3
- package/lib/Map.js +9 -0
- package/lib/Paintball.d.ts +11 -5
- package/lib/Paintball.js +35 -15
- package/lib/PlotComponent.d.ts +5 -5
- package/lib/PlotLayer.d.ts +12 -12
- package/lib/PlotLayer.js +16 -14
- package/lib/PlotLayer.worker.d.ts +2 -2
- package/lib/PlotLayer.worker.js +105 -66
- package/lib/PolylineCollection.d.ts +20 -9
- package/lib/PolylineCollection.js +158 -32
- package/lib/RawField.d.ts +11 -167
- package/lib/RawField.js +37 -383
- package/lib/TextCollection.d.ts +31 -0
- package/lib/TextCollection.js +295 -0
- package/lib/cpp/marchingsquares.d.ts +6 -0
- package/lib/cpp/marchingsquares.js +3449 -0
- package/lib/cpp/marchingsquares.wasm +0 -0
- package/lib/cpp/marchingsquares_embind.d.ts +6 -0
- package/lib/index.d.ts +13 -6
- package/lib/index.js +12 -3
- package/lib/utils.d.ts +5 -3
- package/lib/utils.js +17 -6
- package/package.json +14 -9
package/lib/Paintball.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PlotComponent, getGLFormatTypeAlignment } from "./PlotComponent";
|
|
2
|
-
import { hex2rgba } from "./utils";
|
|
2
|
+
import { hex2rgba, normalizeOptions } from "./utils";
|
|
3
3
|
import { WGLProgram, WGLTexture } from "autumn-wgl";
|
|
4
4
|
const paintball_vertex_shader_src = `uniform mat4 u_matrix;
|
|
5
5
|
uniform int u_offset;
|
|
@@ -45,6 +45,10 @@ void main() {
|
|
|
45
45
|
color.a = color.a * u_opacity;
|
|
46
46
|
gl_FragColor = color;
|
|
47
47
|
}`
|
|
48
|
+
const paintball_opt_defaults = {
|
|
49
|
+
colors: ['#000000'],
|
|
50
|
+
opacity: 1
|
|
51
|
+
};
|
|
48
52
|
/**
|
|
49
53
|
* A class representing a paintball plot, which is a plot of objects in every member of an ensemble. Objects are usually defined by a single threshold on
|
|
50
54
|
* a field (such as simulated reflectivity greater than 40 dBZ), but could in theory be defined by any arbitrarily complicated method. In autumnplot-gl,
|
|
@@ -63,11 +67,33 @@ class Paintball extends PlotComponent {
|
|
|
63
67
|
constructor(field, opts) {
|
|
64
68
|
super();
|
|
65
69
|
this.field = field;
|
|
66
|
-
opts = opts
|
|
67
|
-
|
|
68
|
-
this.colors = colors.reverse().map(color => hex2rgba(color)).flat();
|
|
69
|
-
this.opacity = opts.opacity !== undefined ? opts.opacity : 1.;
|
|
70
|
+
this.opts = normalizeOptions(opts, paintball_opt_defaults);
|
|
71
|
+
this.color_components = [...this.opts.colors].reverse().map(color => hex2rgba(color)).flat();
|
|
70
72
|
this.gl_elems = null;
|
|
73
|
+
this.fill_texture = null;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Update the field displayed as a paintball plot
|
|
77
|
+
* @param field - The new field to display as a paintball plot
|
|
78
|
+
*/
|
|
79
|
+
async updateField(field) {
|
|
80
|
+
this.field = field;
|
|
81
|
+
if (this.gl_elems === null)
|
|
82
|
+
return;
|
|
83
|
+
const gl = this.gl_elems.gl;
|
|
84
|
+
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 2);
|
|
85
|
+
const tex_data = this.field.getTextureData();
|
|
86
|
+
const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, !(tex_data instanceof Float32Array));
|
|
87
|
+
const fill_image = { 'format': format, 'type': type,
|
|
88
|
+
'width': this.field.grid.ni, 'height': this.field.grid.nj, 'image': tex_data,
|
|
89
|
+
'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
|
|
90
|
+
};
|
|
91
|
+
if (this.fill_texture === null) {
|
|
92
|
+
this.fill_texture = new WGLTexture(gl, fill_image);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
this.fill_texture.setImageData(fill_image);
|
|
96
|
+
}
|
|
71
97
|
}
|
|
72
98
|
/**
|
|
73
99
|
* @internal
|
|
@@ -79,29 +105,23 @@ class Paintball extends PlotComponent {
|
|
|
79
105
|
const { vertices: verts_buf, texcoords: tex_coords_buf } = await this.field.grid.getWGLBuffers(gl);
|
|
80
106
|
const vertices = verts_buf;
|
|
81
107
|
const texcoords = tex_coords_buf;
|
|
82
|
-
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 2);
|
|
83
|
-
const { format, type, row_alignment } = getGLFormatTypeAlignment(gl, this.field.isFloat16());
|
|
84
|
-
const fill_image = { 'format': format, 'type': type,
|
|
85
|
-
'width': this.field.grid.ni, 'height': this.field.grid.nj, 'image': this.field.getTextureData(),
|
|
86
|
-
'mag_filter': gl.NEAREST, 'row_alignment': row_alignment,
|
|
87
|
-
};
|
|
88
|
-
const fill_texture = new WGLTexture(gl, fill_image);
|
|
89
108
|
this.gl_elems = {
|
|
90
|
-
program: program, vertices: vertices,
|
|
109
|
+
gl: gl, program: program, vertices: vertices, texcoords: texcoords,
|
|
91
110
|
};
|
|
111
|
+
this.updateField(this.field);
|
|
92
112
|
}
|
|
93
113
|
/**
|
|
94
114
|
* @internal
|
|
95
115
|
* Render the paintball plot
|
|
96
116
|
*/
|
|
97
117
|
render(gl, matrix) {
|
|
98
|
-
if (this.gl_elems === null)
|
|
118
|
+
if (this.gl_elems === null || this.fill_texture === null)
|
|
99
119
|
return;
|
|
100
120
|
const gl_elems = this.gl_elems;
|
|
101
121
|
if (matrix instanceof Float32Array)
|
|
102
122
|
matrix = [...matrix];
|
|
103
123
|
// Render to framebuffer
|
|
104
|
-
gl_elems.program.use({ 'a_pos': gl_elems.vertices, 'a_tex_coord': gl_elems.texcoords }, { 'u_matrix': matrix, 'u_opacity': this.opacity, 'u_colors': this.
|
|
124
|
+
gl_elems.program.use({ 'a_pos': gl_elems.vertices, 'a_tex_coord': gl_elems.texcoords }, { 'u_matrix': matrix, 'u_opacity': this.opts.opacity, 'u_colors': this.color_components, 'u_num_colors': this.opts.colors.length, 'u_offset': 0 }, { 'u_fill_sampler': this.fill_texture });
|
|
105
125
|
gl.enable(gl.BLEND);
|
|
106
126
|
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
107
127
|
gl_elems.program.draw();
|
package/lib/PlotComponent.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Comlink from 'comlink';
|
|
2
|
-
import {
|
|
2
|
+
import { MapLikeType } from './Map';
|
|
3
3
|
import { WebGLAnyRenderingContext } from './AutumnTypes';
|
|
4
4
|
declare const layer_worker: Comlink.Remote<{
|
|
5
5
|
makeBBElements: (field_lats: Float32Array, field_lons: Float32Array, field_ni: number, field_nj: number, thin_fac_base: number, max_zoom: number) => {
|
|
@@ -11,15 +11,15 @@ declare const layer_worker: Comlink.Remote<{
|
|
|
11
11
|
tex_coords: Float32Array;
|
|
12
12
|
grid_cell_size: Float32Array;
|
|
13
13
|
};
|
|
14
|
-
makePolyLines: (lines: import("./AutumnTypes").
|
|
14
|
+
makePolyLines: (lines: import("./AutumnTypes").LineData[]) => import("./AutumnTypes").Polyline;
|
|
15
15
|
}>;
|
|
16
|
-
declare abstract class PlotComponent {
|
|
16
|
+
declare abstract class PlotComponent<MapType extends MapLikeType> {
|
|
17
17
|
abstract onAdd(map: MapType, gl: WebGLAnyRenderingContext): Promise<void>;
|
|
18
18
|
abstract render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
19
19
|
}
|
|
20
20
|
declare function getGLFormatTypeAlignment(gl: WebGLAnyRenderingContext, is_float16: boolean): {
|
|
21
|
-
format:
|
|
22
|
-
type:
|
|
21
|
+
format: 33325 | 33326 | 6409;
|
|
22
|
+
type: 36193 | 5131 | 5126;
|
|
23
23
|
row_alignment: number;
|
|
24
24
|
};
|
|
25
25
|
export { PlotComponent, layer_worker, getGLFormatTypeAlignment };
|
package/lib/PlotLayer.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { WebGLAnyRenderingContext } from './AutumnTypes';
|
|
2
|
-
import {
|
|
2
|
+
import { MapLikeType } from './Map';
|
|
3
3
|
import { PlotComponent } from './PlotComponent';
|
|
4
|
-
declare abstract class PlotLayerBase {
|
|
4
|
+
declare abstract class PlotLayerBase<MapType extends MapLikeType> {
|
|
5
5
|
readonly type: 'custom';
|
|
6
6
|
readonly id: string;
|
|
7
|
+
protected map: MapType;
|
|
7
8
|
constructor(id: string);
|
|
8
9
|
abstract onAdd(map: MapType, gl: WebGLAnyRenderingContext): void;
|
|
9
10
|
abstract render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
11
|
+
protected repaint(): void;
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* A static map layer. The data are assumed to be static in time. If the data have a time component (e.g., a model forecast), an {@link MultiPlotLayer}
|
|
@@ -17,19 +19,19 @@ declare abstract class PlotLayerBase {
|
|
|
17
19
|
* const wind_speed_layer = new PlotLayer('wind-speed-fill', wind_speed_fill);
|
|
18
20
|
* const barb_layer = new PlotLayer('barbs', wind_barbs);
|
|
19
21
|
*/
|
|
20
|
-
declare class PlotLayer extends PlotLayerBase {
|
|
22
|
+
declare class PlotLayer<MapType extends MapLikeType> extends PlotLayerBase<MapType> {
|
|
21
23
|
private readonly field;
|
|
22
24
|
/**
|
|
23
25
|
* Create a map layer from a field
|
|
24
26
|
* @param id - A unique id for this layer
|
|
25
27
|
* @param field - The field to plot in this layer
|
|
26
28
|
*/
|
|
27
|
-
constructor(id: string, field: PlotComponent);
|
|
29
|
+
constructor(id: string, field: PlotComponent<MapType>);
|
|
28
30
|
/**
|
|
29
31
|
* @internal
|
|
30
32
|
* Add this layer to a map
|
|
31
33
|
*/
|
|
32
|
-
onAdd(map: MapType, gl: WebGLAnyRenderingContext): void
|
|
34
|
+
onAdd(map: MapType, gl: WebGLAnyRenderingContext): Promise<void>;
|
|
33
35
|
/**
|
|
34
36
|
* @internal
|
|
35
37
|
* Render this layer
|
|
@@ -50,10 +52,9 @@ declare class PlotLayer extends PlotLayerBase {
|
|
|
50
52
|
* // Set the date/time in the map layer
|
|
51
53
|
* height_layer.setActiveKey('20230112_1200');
|
|
52
54
|
*/
|
|
53
|
-
declare class MultiPlotLayer extends PlotLayerBase {
|
|
55
|
+
declare class MultiPlotLayer<MapType extends MapLikeType> extends PlotLayerBase<MapType> {
|
|
54
56
|
private fields;
|
|
55
57
|
private field_key;
|
|
56
|
-
private map;
|
|
57
58
|
private gl;
|
|
58
59
|
/**
|
|
59
60
|
* Create a time-varying map layer
|
|
@@ -72,7 +73,7 @@ declare class MultiPlotLayer extends PlotLayerBase {
|
|
|
72
73
|
render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array): void;
|
|
73
74
|
/**
|
|
74
75
|
* Set the active key
|
|
75
|
-
* @param key - The new key
|
|
76
|
+
* @param key - The new key. The field with that key is plotted immediately.
|
|
76
77
|
*/
|
|
77
78
|
setActiveKey(key: string): void;
|
|
78
79
|
/**
|
|
@@ -81,11 +82,10 @@ declare class MultiPlotLayer extends PlotLayerBase {
|
|
|
81
82
|
*/
|
|
82
83
|
getKeys(): string[];
|
|
83
84
|
/**
|
|
84
|
-
* Add a field
|
|
85
|
+
* Add a field with a given key
|
|
85
86
|
* @param field - The field to add
|
|
86
|
-
* @param
|
|
87
|
+
* @param key - The key to associate with the field
|
|
87
88
|
*/
|
|
88
|
-
addField(field: PlotComponent
|
|
89
|
-
private repaintIfNecessary;
|
|
89
|
+
addField(field: PlotComponent<MapType>, key: string): void;
|
|
90
90
|
}
|
|
91
91
|
export { PlotLayer, MultiPlotLayer };
|
package/lib/PlotLayer.js
CHANGED
|
@@ -2,6 +2,12 @@ class PlotLayerBase {
|
|
|
2
2
|
constructor(id) {
|
|
3
3
|
this.type = 'custom';
|
|
4
4
|
this.id = id;
|
|
5
|
+
this.map = null;
|
|
6
|
+
}
|
|
7
|
+
repaint() {
|
|
8
|
+
if (this.map !== null) {
|
|
9
|
+
this.map.triggerRepaint();
|
|
10
|
+
}
|
|
5
11
|
}
|
|
6
12
|
}
|
|
7
13
|
/**
|
|
@@ -27,8 +33,9 @@ class PlotLayer extends PlotLayerBase {
|
|
|
27
33
|
* @internal
|
|
28
34
|
* Add this layer to a map
|
|
29
35
|
*/
|
|
30
|
-
onAdd(map, gl) {
|
|
31
|
-
this.
|
|
36
|
+
async onAdd(map, gl) {
|
|
37
|
+
this.map = map;
|
|
38
|
+
await this.field.onAdd(map, gl);
|
|
32
39
|
}
|
|
33
40
|
/**
|
|
34
41
|
* @internal
|
|
@@ -73,10 +80,10 @@ class MultiPlotLayer extends PlotLayerBase {
|
|
|
73
80
|
this.gl = gl;
|
|
74
81
|
Object.values(this.fields).forEach(field => {
|
|
75
82
|
field.onAdd(map, gl).then(res => {
|
|
76
|
-
this.
|
|
83
|
+
this.repaint();
|
|
77
84
|
});
|
|
78
85
|
});
|
|
79
|
-
this.
|
|
86
|
+
this.repaint();
|
|
80
87
|
}
|
|
81
88
|
/**
|
|
82
89
|
* @internal
|
|
@@ -90,12 +97,12 @@ class MultiPlotLayer extends PlotLayerBase {
|
|
|
90
97
|
}
|
|
91
98
|
/**
|
|
92
99
|
* Set the active key
|
|
93
|
-
* @param key - The new key
|
|
100
|
+
* @param key - The new key. The field with that key is plotted immediately.
|
|
94
101
|
*/
|
|
95
102
|
setActiveKey(key) {
|
|
96
103
|
const old_field_key = this.field_key;
|
|
97
104
|
this.field_key = key;
|
|
98
|
-
this.
|
|
105
|
+
this.repaint();
|
|
99
106
|
}
|
|
100
107
|
/**
|
|
101
108
|
* Get a list of all dates/times that have been added to the layer
|
|
@@ -105,15 +112,15 @@ class MultiPlotLayer extends PlotLayerBase {
|
|
|
105
112
|
return Object.keys(this.fields);
|
|
106
113
|
}
|
|
107
114
|
/**
|
|
108
|
-
* Add a field
|
|
115
|
+
* Add a field with a given key
|
|
109
116
|
* @param field - The field to add
|
|
110
|
-
* @param
|
|
117
|
+
* @param key - The key to associate with the field
|
|
111
118
|
*/
|
|
112
119
|
addField(field, key) {
|
|
113
120
|
const old_field_key = this.field_key;
|
|
114
121
|
if (this.map !== null && this.gl !== null && field !== null) {
|
|
115
122
|
field.onAdd(this.map, this.gl).then(res => {
|
|
116
|
-
this.
|
|
123
|
+
this.repaint();
|
|
117
124
|
});
|
|
118
125
|
}
|
|
119
126
|
this.fields[key] = field;
|
|
@@ -121,10 +128,5 @@ class MultiPlotLayer extends PlotLayerBase {
|
|
|
121
128
|
this.field_key = key;
|
|
122
129
|
}
|
|
123
130
|
}
|
|
124
|
-
repaintIfNecessary(old_field_key) {
|
|
125
|
-
if (this.map !== null && old_field_key !== this.field_key) {
|
|
126
|
-
this.map.triggerRepaint();
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
131
|
}
|
|
130
132
|
export { PlotLayer, MultiPlotLayer };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LineData, Polyline } from "./AutumnTypes";
|
|
2
2
|
declare function makeBBElements(field_lats: Float32Array, field_lons: Float32Array, field_ni: number, field_nj: number, thin_fac_base: number, max_zoom: number): {
|
|
3
3
|
pts: Float32Array;
|
|
4
4
|
tex_coords: Float32Array;
|
|
@@ -8,7 +8,7 @@ declare function makeDomainVerticesAndTexCoords(field_lats: Float32Array, field_
|
|
|
8
8
|
tex_coords: Float32Array;
|
|
9
9
|
grid_cell_size: Float32Array;
|
|
10
10
|
};
|
|
11
|
-
declare function makePolylines(lines:
|
|
11
|
+
declare function makePolylines(lines: LineData[]): Polyline;
|
|
12
12
|
declare const ep_interface: {
|
|
13
13
|
makeBBElements: typeof makeBBElements;
|
|
14
14
|
makeDomainVerticesAndTexCoords: typeof makeDomainVerticesAndTexCoords;
|
package/lib/PlotLayer.worker.js
CHANGED
|
@@ -239,13 +239,16 @@ function makePolylinesMiter(lines) {
|
|
|
239
239
|
}
|
|
240
240
|
*/
|
|
241
241
|
function makePolylines(lines) {
|
|
242
|
+
if (lines.length == 0) {
|
|
243
|
+
return { vertices: new Float32Array([]), extrusion: new Float32Array([]) };
|
|
244
|
+
}
|
|
242
245
|
const n_points_per_vert = Object.fromEntries(Object.entries(lines[0]).map(([k, v]) => {
|
|
243
246
|
let n_verts;
|
|
244
|
-
if (v
|
|
247
|
+
if (typeof v === 'number') {
|
|
245
248
|
n_verts = 1;
|
|
246
249
|
}
|
|
247
|
-
else if (v[0]
|
|
248
|
-
n_verts =
|
|
250
|
+
else if (typeof v[0] === 'number') {
|
|
251
|
+
n_verts = 1;
|
|
249
252
|
}
|
|
250
253
|
else {
|
|
251
254
|
n_verts = v[0].length;
|
|
@@ -253,85 +256,121 @@ function makePolylines(lines) {
|
|
|
253
256
|
return [k, n_verts];
|
|
254
257
|
}));
|
|
255
258
|
n_points_per_vert['extrusion'] = 2;
|
|
256
|
-
|
|
257
|
-
const
|
|
259
|
+
n_points_per_vert['vertices'] += 1;
|
|
260
|
+
const n_verts = lines.map(l => l.vertices.length).reduce((a, b) => a + b);
|
|
261
|
+
const n_out_verts = n_verts * 4 - lines.length * 2;
|
|
258
262
|
const ary_lens = Object.fromEntries(Object.entries(n_points_per_vert).map(([k, nppv]) => [k, n_out_verts * nppv]));
|
|
259
263
|
let ret = {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
'extrusion': new Float32Array(ary_lens['extrusion']),
|
|
263
|
-
'zoom': new Float32Array(ary_lens['zoom']),
|
|
264
|
-
'texcoords': new Float32Array(ary_lens['texcoords']),
|
|
264
|
+
vertices: new Float32Array(ary_lens['vertices']),
|
|
265
|
+
extrusion: new Float32Array(ary_lens['extrusion']),
|
|
265
266
|
};
|
|
267
|
+
if ('offsets' in lines[0]) {
|
|
268
|
+
ret.offsets = new Float32Array(ary_lens['offsets']);
|
|
269
|
+
}
|
|
270
|
+
if ('data' in lines[0]) {
|
|
271
|
+
ret.data = new Float32Array(ary_lens['data']);
|
|
272
|
+
}
|
|
273
|
+
if ('zoom' in lines[0]) {
|
|
274
|
+
ret.zoom = new Float32Array(ary_lens['zoom']);
|
|
275
|
+
}
|
|
266
276
|
let ilns = Object.fromEntries(Object.keys(ary_lens).map(k => [k, 0]));
|
|
267
|
-
const compute_normal_vec = (pt1, pt2) => {
|
|
277
|
+
const compute_normal_vec = (pt1, pt2, flip_y_coord) => {
|
|
268
278
|
const line_vec_x = pt2[0] - pt1[0];
|
|
269
279
|
const line_vec_y = pt2[1] - pt1[1];
|
|
270
280
|
const line_vec_mag = Math.hypot(line_vec_x, line_vec_y);
|
|
271
|
-
|
|
281
|
+
const ext_x = line_vec_y / line_vec_mag;
|
|
282
|
+
const ext_y = -line_vec_x / line_vec_mag;
|
|
283
|
+
return [ext_x, flip_y_coord ? -ext_y : ext_y];
|
|
272
284
|
};
|
|
273
285
|
lines.forEach(line => {
|
|
274
|
-
const verts = line
|
|
275
|
-
|
|
276
|
-
|
|
286
|
+
const verts = line.vertices.map(v => {
|
|
287
|
+
const v_ll = new LngLat(...v).toMercatorCoord();
|
|
288
|
+
return [v_ll.x, v_ll.y];
|
|
289
|
+
});
|
|
290
|
+
const has_offsets = line.offsets !== undefined;
|
|
291
|
+
const extrusion_verts = has_offsets ? line.offsets : verts;
|
|
277
292
|
let pt_prev, pt_this = verts[0], pt_next = verts[1];
|
|
278
|
-
let
|
|
279
|
-
let
|
|
280
|
-
|
|
281
|
-
ret[
|
|
282
|
-
ret[
|
|
283
|
-
ret[
|
|
284
|
-
ret[
|
|
285
|
-
ret[
|
|
293
|
+
let ept_prev, ept_this = extrusion_verts[0], ept_next = extrusion_verts[1];
|
|
294
|
+
let len_prev, len_this = 0;
|
|
295
|
+
let [ext_x, ext_y] = compute_normal_vec(ept_this, ept_next, !has_offsets);
|
|
296
|
+
ret.vertices[ilns.vertices++] = pt_this[0];
|
|
297
|
+
ret.vertices[ilns.vertices++] = pt_this[1];
|
|
298
|
+
ret.vertices[ilns.vertices++] = len_this;
|
|
299
|
+
ret.extrusion[ilns.extrusion++] = ext_x;
|
|
300
|
+
ret.extrusion[ilns.extrusion++] = ext_y;
|
|
286
301
|
for (let ivt = 1; ivt < verts.length; ivt++) {
|
|
287
302
|
pt_this = verts[ivt];
|
|
288
303
|
pt_prev = verts[ivt - 1];
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
[ext_x, ext_y] = compute_normal_vec(
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
ret[
|
|
295
|
-
ret[
|
|
296
|
-
ret[
|
|
297
|
-
ret[
|
|
298
|
-
ret[
|
|
299
|
-
ret[
|
|
300
|
-
ret[
|
|
301
|
-
ret[
|
|
302
|
-
ret[
|
|
303
|
-
ret[
|
|
304
|
-
ret[
|
|
305
|
-
ret[
|
|
306
|
-
ret[
|
|
307
|
-
ret[
|
|
308
|
-
ret[
|
|
309
|
-
ret[
|
|
310
|
-
ret[
|
|
311
|
-
ret[
|
|
312
|
-
ret[
|
|
313
|
-
ret[
|
|
314
|
-
ret['extrusion'][ary_ivt + 5] = ext_y;
|
|
315
|
-
ret['extrusion'][ary_ivt + 6] = -ext_x;
|
|
316
|
-
ret['extrusion'][ary_ivt + 7] = -ext_y;
|
|
304
|
+
ept_this = extrusion_verts[ivt];
|
|
305
|
+
ept_prev = extrusion_verts[ivt - 1];
|
|
306
|
+
[ext_x, ext_y] = compute_normal_vec(ept_prev, ept_this, !has_offsets);
|
|
307
|
+
len_prev = len_this;
|
|
308
|
+
len_this += Math.hypot(verts[ivt - 1][0] - verts[ivt][0], verts[ivt - 1][1] - verts[ivt][1]);
|
|
309
|
+
ret.vertices[ilns.vertices++] = pt_prev[0];
|
|
310
|
+
ret.vertices[ilns.vertices++] = pt_prev[1];
|
|
311
|
+
ret.vertices[ilns.vertices++] = len_prev;
|
|
312
|
+
ret.vertices[ilns.vertices++] = pt_prev[0];
|
|
313
|
+
ret.vertices[ilns.vertices++] = pt_prev[1];
|
|
314
|
+
ret.vertices[ilns.vertices++] = len_prev;
|
|
315
|
+
ret.vertices[ilns.vertices++] = pt_this[0];
|
|
316
|
+
ret.vertices[ilns.vertices++] = pt_this[1];
|
|
317
|
+
ret.vertices[ilns.vertices++] = len_this;
|
|
318
|
+
ret.vertices[ilns.vertices++] = pt_this[0];
|
|
319
|
+
ret.vertices[ilns.vertices++] = pt_this[1];
|
|
320
|
+
ret.vertices[ilns.vertices++] = len_this;
|
|
321
|
+
ret.extrusion[ilns.extrusion++] = ext_x;
|
|
322
|
+
ret.extrusion[ilns.extrusion++] = ext_y;
|
|
323
|
+
ret.extrusion[ilns.extrusion++] = -ext_x;
|
|
324
|
+
ret.extrusion[ilns.extrusion++] = -ext_y;
|
|
325
|
+
ret.extrusion[ilns.extrusion++] = ext_x;
|
|
326
|
+
ret.extrusion[ilns.extrusion++] = ext_y;
|
|
327
|
+
ret.extrusion[ilns.extrusion++] = -ext_x;
|
|
328
|
+
ret.extrusion[ilns.extrusion++] = -ext_y;
|
|
317
329
|
}
|
|
318
|
-
ret[
|
|
319
|
-
ret[
|
|
320
|
-
ret[
|
|
321
|
-
ret[
|
|
322
|
-
ret[
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
330
|
+
ret.vertices[ilns.vertices++] = pt_this[0];
|
|
331
|
+
ret.vertices[ilns.vertices++] = pt_this[1];
|
|
332
|
+
ret.vertices[ilns.vertices++] = len_this;
|
|
333
|
+
ret.extrusion[ilns.extrusion++] = -ext_x;
|
|
334
|
+
ret.extrusion[ilns.extrusion++] = -ext_y;
|
|
335
|
+
if ('offsets' in ret) {
|
|
336
|
+
const offsets = line.offsets;
|
|
337
|
+
let off_prev, off_this = offsets[0];
|
|
338
|
+
ret.offsets[ilns.offsets++] = off_this[0];
|
|
339
|
+
ret.offsets[ilns.offsets++] = off_this[1];
|
|
340
|
+
for (let ivt = 1; ivt < offsets.length; ivt++) {
|
|
341
|
+
off_this = offsets[ivt];
|
|
342
|
+
off_prev = offsets[ivt - 1];
|
|
343
|
+
ret.offsets[ilns.offsets++] = off_prev[0];
|
|
344
|
+
ret.offsets[ilns.offsets++] = off_prev[1];
|
|
345
|
+
ret.offsets[ilns.offsets++] = off_prev[0];
|
|
346
|
+
ret.offsets[ilns.offsets++] = off_prev[1];
|
|
347
|
+
ret.offsets[ilns.offsets++] = off_this[0];
|
|
348
|
+
ret.offsets[ilns.offsets++] = off_this[1];
|
|
349
|
+
ret.offsets[ilns.offsets++] = off_this[0];
|
|
350
|
+
ret.offsets[ilns.offsets++] = off_this[1];
|
|
351
|
+
}
|
|
352
|
+
ret.offsets[ilns.offsets++] = off_this[0];
|
|
353
|
+
ret.offsets[ilns.offsets++] = off_this[1];
|
|
328
354
|
}
|
|
329
|
-
|
|
330
|
-
|
|
355
|
+
if ('data' in ret) {
|
|
356
|
+
const data = line.data;
|
|
357
|
+
let data_prev, data_this = data[0];
|
|
358
|
+
ret.data[ilns.data++] = data_this;
|
|
359
|
+
for (let ivt = 1; ivt < data.length; ivt++) {
|
|
360
|
+
data_this = data[ivt];
|
|
361
|
+
data_prev = data[ivt - 1];
|
|
362
|
+
ret.data[ilns.data++] = data_prev;
|
|
363
|
+
ret.data[ilns.data++] = data_prev;
|
|
364
|
+
ret.data[ilns.data++] = data_this;
|
|
365
|
+
ret.data[ilns.data++] = data_this;
|
|
366
|
+
}
|
|
367
|
+
ret.data[ilns.data++] = data_this;
|
|
368
|
+
}
|
|
369
|
+
if ('zoom' in ret) {
|
|
370
|
+
for (let ivt = 0; ivt < verts.length * 4 - 2; ivt++) {
|
|
371
|
+
ret.zoom[ilns.zoom++] = line['zoom'];
|
|
372
|
+
}
|
|
331
373
|
}
|
|
332
|
-
Object.keys(ilns).forEach(k => {
|
|
333
|
-
ilns[k] += (verts.length - 1) * 6 * n_points_per_vert[k];
|
|
334
|
-
});
|
|
335
374
|
});
|
|
336
375
|
return ret;
|
|
337
376
|
}
|
|
@@ -1,17 +1,28 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { LineData, WebGLAnyRenderingContext } from "./AutumnTypes";
|
|
2
|
+
import { ColorMap } from "./Colormap";
|
|
3
|
+
interface PolylineCollectionOpts {
|
|
4
|
+
offset_scale?: number;
|
|
5
|
+
color?: string;
|
|
6
|
+
cmap?: ColorMap;
|
|
7
|
+
line_width?: number;
|
|
8
|
+
}
|
|
3
9
|
declare class PolylineCollection {
|
|
4
10
|
readonly width: number;
|
|
5
|
-
readonly scale: number;
|
|
11
|
+
readonly scale: number | null;
|
|
6
12
|
private readonly program;
|
|
7
|
-
private readonly
|
|
8
|
-
private readonly offset;
|
|
13
|
+
private readonly vertices;
|
|
9
14
|
private readonly extrusion;
|
|
15
|
+
private readonly offset;
|
|
10
16
|
private readonly min_zoom;
|
|
11
|
-
private readonly
|
|
12
|
-
private readonly
|
|
13
|
-
|
|
17
|
+
private readonly line_data;
|
|
18
|
+
private readonly line_texture;
|
|
19
|
+
private readonly color;
|
|
20
|
+
private readonly cmap_min;
|
|
21
|
+
private readonly cmap_max;
|
|
22
|
+
private readonly index_map;
|
|
23
|
+
private readonly cmap_nonlin_texture;
|
|
24
|
+
private constructor();
|
|
25
|
+
static make(gl: WebGLAnyRenderingContext, lines: LineData[], opts?: PolylineCollectionOpts): Promise<PolylineCollection>;
|
|
14
26
|
render(gl: WebGLAnyRenderingContext, matrix: number[] | Float32Array, [map_width, map_height]: [number, number], map_zoom: number, map_bearing: number, map_pitch: number): void;
|
|
15
27
|
}
|
|
16
28
|
export { PolylineCollection };
|
|
17
|
-
export type { PolylineSpec, LineSpec };
|