ol 10.2.2-dev.1727715662036 → 10.2.2-dev.1727768316442

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ol",
3
- "version": "10.2.2-dev.1727715662036",
3
+ "version": "10.2.2-dev.1727768316442",
4
4
  "description": "OpenLayers mapping library",
5
5
  "keywords": [
6
6
  "map",
@@ -61,6 +61,10 @@ export type Options = {
61
61
  * transitions in milliseconds. A duration of 0 disables the opacity transition.
62
62
  */
63
63
  transition?: number | undefined;
64
+ /**
65
+ * Render reprojection edges.
66
+ */
67
+ renderEdges?: boolean | undefined;
64
68
  };
65
69
  /**
66
70
  * @typedef {function(number, number, number, number) : import("../DataTile.js").default} TileGetter
@@ -86,6 +90,7 @@ export type Options = {
86
90
  * @property {number} [errorThreshold] Acceptable reprojection error (in px).
87
91
  * @property {number} [transition=250] A duration for tile opacity
88
92
  * transitions in milliseconds. A duration of 0 disables the opacity transition.
93
+ * @property {boolean} [renderEdges] Render reprojection edges.
89
94
  */
90
95
  /**
91
96
  * @classdesc
@@ -98,6 +103,11 @@ declare class ReprojDataTile extends DataTile {
98
103
  * @param {Options} options Tile options.
99
104
  */
100
105
  constructor(options: Options);
106
+ /**
107
+ * @private
108
+ * @type {boolean | Array<number>}
109
+ */
110
+ private renderEdges_;
101
111
  /**
102
112
  * @private
103
113
  * @type {number}
@@ -1 +1 @@
1
- {"version":3,"file":"DataTile.d.ts","sourceRoot":"","sources":["DataTile.js"],"names":[],"mappings":";yBAoBa,CAAS,IAAM,EAAN,MAAM,EAAE,IAAM,EAAN,MAAM,EAAE,IAAM,EAAN,MAAM,EAAE,IAAM,EAAN,MAAM,KAAI,OAAO,gBAAgB,EAAE,OAAO;;;;;UAK1E,QAAQ;;;;YACR,MAAM;;;;;;gBAKN,OAAO,uBAAuB,EAAE,OAAO;;;;oBACvC,OAAO,yBAAyB,EAAE,OAAO;;;;gBACzC,OAAO,uBAAuB,EAAE,OAAO;;;;oBACvC,OAAO,yBAAyB,EAAE,OAAO;;;;eACzC,OAAO,iBAAiB,EAAE,SAAS;;;;;;;;gBAEnC,MAAM;;;;YACN,MAAM;;;;qBACN,UAAU;;;;;;;;;;;;;;;;AApBxB;;GAEG;AAEH;;;;GAIG;AAEH;;;;;;;;;;;;;;;;GAgBG;AAEH;;;;;GAKG;AACH;IACE;;OAEG;IACH,qBAFW,OAAO,EAyNjB;IA/MC;;;OAGG;IACH,oBAAqC;IAErC;;;OAGG;IACH,gBAA6B;IAE7B;;;OAGG;IACH,oBAAuB;IAEvB;;;OAGG;IACH,qBAAwB;IAExB;;;OAGG;IACH,oBAA4B;IAE5B;;;OAGG;IACH,wBAA6C;IAE7C;;;OAGG;IACH,wBAA6C;IAE7C;;;OAGG;IACH,0BAAsE;IAEtE;;;OAGG;IACH,qBAAsB;IAEtB;;;OAGG;IACH,6BAAgC;IAEhC;;;OAGG;IACH,iBAAiB;IAMjB;;;OAGG;IACH,oBAIwB;IAmDxB;;;OAGG;IACH,uBAOC;IAgGH;;OAEG;IACH,mBAoLC;IAqDD;;OAEG;IACH,yBAGC;CACF;qBA3hByD,gBAAgB"}
1
+ {"version":3,"file":"DataTile.d.ts","sourceRoot":"","sources":["DataTile.js"],"names":[],"mappings":";yBAsBa,CAAS,IAAM,EAAN,MAAM,EAAE,IAAM,EAAN,MAAM,EAAE,IAAM,EAAN,MAAM,EAAE,IAAM,EAAN,MAAM,KAAI,OAAO,gBAAgB,EAAE,OAAO;;;;;UAK1E,QAAQ;;;;YACR,MAAM;;;;;;gBAKN,OAAO,uBAAuB,EAAE,OAAO;;;;oBACvC,OAAO,yBAAyB,EAAE,OAAO;;;;gBACzC,OAAO,uBAAuB,EAAE,OAAO;;;;oBACvC,OAAO,yBAAyB,EAAE,OAAO;;;;eACzC,OAAO,iBAAiB,EAAE,SAAS;;;;;;;;gBAEnC,MAAM;;;;YACN,MAAM;;;;qBACN,UAAU;;;;;;;;;;;;;;;;;;;;AApBxB;;GAEG;AAEH;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;;GAKG;AACH;IACE;;OAEG;IACH,qBAFW,OAAO,EAgOjB;IAtNC;;;OAGG;IACH,qBACiE;IAEjE;;;OAGG;IACH,oBAAqC;IAErC;;;OAGG;IACH,gBAA6B;IAE7B;;;OAGG;IACH,oBAAuB;IAEvB;;;OAGG;IACH,qBAAwB;IAExB;;;OAGG;IACH,oBAA4B;IAE5B;;;OAGG;IACH,wBAA6C;IAE7C;;;OAGG;IACH,wBAA6C;IAE7C;;;OAGG;IACH,0BAAsE;IAEtE;;;OAGG;IACH,qBAAsB;IAEtB;;;OAGG;IACH,6BAAgC;IAEhC;;;OAGG;IACH,iBAAiB;IAMjB;;;OAGG;IACH,oBAIwB;IAmDxB;;;OAGG;IACH,uBAOC;IAgGH;;OAEG;IACH,mBAsMC;IAqDD;;OAEG;IACH,yBAGC;CACF;qBAvjByD,gBAAgB"}
@@ -7,13 +7,15 @@ import DataTile, {asArrayLike, asImageLike, toArray} from '../DataTile.js';
7
7
  import EventType from '../events/EventType.js';
8
8
  import TileState from '../TileState.js';
9
9
  import Triangulation from './Triangulation.js';
10
+ import {calculateSourceExtentResolution} from '../reproj.js';
10
11
  import {
11
- calculateSourceExtentResolution,
12
- canvasPool,
12
+ canvasGLPool,
13
+ createCanvasContextWebGL,
14
+ releaseGLCanvas,
13
15
  render as renderReprojected,
14
- } from '../reproj.js';
16
+ } from './glreproj.js';
15
17
  import {clamp} from '../math.js';
16
- import {createCanvasContext2D, releaseCanvas} from '../dom.js';
18
+ import {createCanvasContext2D} from '../dom.js';
17
19
  import {getArea, getIntersection, getWidth, wrapAndSliceX} from '../extent.js';
18
20
  import {listen, unlistenByKey} from '../events.js';
19
21
 
@@ -43,6 +45,7 @@ import {listen, unlistenByKey} from '../events.js';
43
45
  * @property {number} [errorThreshold] Acceptable reprojection error (in px).
44
46
  * @property {number} [transition=250] A duration for tile opacity
45
47
  * transitions in milliseconds. A duration of 0 disables the opacity transition.
48
+ * @property {boolean} [renderEdges] Render reprojection edges.
46
49
  */
47
50
 
48
51
  /**
@@ -63,6 +66,13 @@ class ReprojDataTile extends DataTile {
63
66
  transition: options.transition,
64
67
  });
65
68
 
69
+ /**
70
+ * @private
71
+ * @type {boolean | Array<number>}
72
+ */
73
+ this.renderEdges_ =
74
+ options.renderEdges !== undefined ? options.renderEdges : false;
75
+
66
76
  /**
67
77
  * @private
68
78
  * @type {number}
@@ -334,20 +344,6 @@ class ReprojDataTile extends DataTile {
334
344
  const bandCount = Math.floor(
335
345
  bytesPerRow / bytesPerElement / pixelSize[0],
336
346
  );
337
- const packedLength = pixelCount * bandCount;
338
- let packedData = tileDataR;
339
- if (tileDataR.length !== packedLength) {
340
- packedData = new DataType(packedLength);
341
- let dataIndex = 0;
342
- let rowOffset = 0;
343
- const colCount = pixelSize[0] * bandCount;
344
- for (let rowIndex = 0; rowIndex < pixelSize[1]; ++rowIndex) {
345
- for (let colIndex = 0; colIndex < colCount; ++colIndex) {
346
- packedData[dataIndex++] = tileDataR[rowOffset + colIndex];
347
- }
348
- rowOffset += bytesPerRow / bytesPerElement;
349
- }
350
- }
351
347
  const extent = this.sourceTileGrid_.getTileCoordExtent(tile.tileCoord);
352
348
  extent[0] += source.offset;
353
349
  extent[2] += source.offset;
@@ -359,10 +355,11 @@ class ReprojDataTile extends DataTile {
359
355
  dataSources.push({
360
356
  extent: extent,
361
357
  clipExtent: clipExtent,
362
- data: new Uint8ClampedArray(packedData.buffer),
358
+ data: tileDataR,
363
359
  dataType: DataType,
364
360
  bytesPerPixel: bytesPerPixel,
365
361
  pixelSize: pixelSize,
362
+ bandCount: bandCount,
366
363
  });
367
364
  });
368
365
  this.sourceTiles_.length = 0;
@@ -377,6 +374,8 @@ class ReprojDataTile extends DataTile {
377
374
  const size = this.targetTileGrid_.getTileSize(z);
378
375
  const targetWidth = typeof size === 'number' ? size : size[0];
379
376
  const targetHeight = typeof size === 'number' ? size : size[1];
377
+ const outWidth = targetWidth * this.pixelRatio_;
378
+ const outHeight = targetHeight * this.pixelRatio_;
380
379
  const targetResolution = this.targetTileGrid_.getResolution(z);
381
380
  const sourceResolution = this.sourceTileGrid_.getResolution(this.sourceZ_);
382
381
 
@@ -384,90 +383,122 @@ class ReprojDataTile extends DataTile {
384
383
  this.wrappedTileCoord_,
385
384
  );
386
385
 
387
- let dataR, dataU;
386
+ const bandCount = dataSources[0].bandCount;
387
+ const dataR = new dataSources[0].dataType(bandCount * outWidth * outHeight);
388
388
 
389
- const bytesPerPixel = dataSources[0].bytesPerPixel;
389
+ const gl = createCanvasContextWebGL(outWidth, outHeight, canvasGLPool, {
390
+ premultipliedAlpha: false,
391
+ antialias: false,
392
+ });
390
393
 
391
- const reprojs = Math.ceil(bytesPerPixel / 3);
394
+ let willInterpolate;
395
+ const format = gl.RGBA;
396
+ let textureType;
397
+ if (dataSources[0].dataType == Float32Array) {
398
+ textureType = gl.FLOAT;
399
+ gl.getExtension('WEBGL_color_buffer_float');
400
+ gl.getExtension('OES_texture_float');
401
+ gl.getExtension('EXT_float_blend');
402
+ const extension = gl.getExtension('OES_texture_float_linear');
403
+ const canInterpolate = extension !== null;
404
+ willInterpolate = canInterpolate && this.interpolate;
405
+ } else {
406
+ textureType = gl.UNSIGNED_BYTE;
407
+ willInterpolate = this.interpolate;
408
+ }
409
+
410
+ const BANDS_PR_REPROJ = 4;
411
+ const reprojs = Math.ceil(bandCount / BANDS_PR_REPROJ);
392
412
  for (let reproj = reprojs - 1; reproj >= 0; --reproj) {
393
413
  const sources = [];
394
414
  for (let i = 0, len = dataSources.length; i < len; ++i) {
395
415
  const dataSource = dataSources[i];
396
- const buffer = dataSource.data;
416
+
397
417
  const pixelSize = dataSource.pixelSize;
398
418
  const width = pixelSize[0];
399
419
  const height = pixelSize[1];
400
- const context = createCanvasContext2D(width, height, canvasPool);
401
- const imageData = context.createImageData(width, height);
402
- const data = imageData.data;
403
- let offset = reproj * 3;
404
- for (let j = 0, len = data.length; j < len; j += 4) {
405
- data[j] = buffer[offset];
406
- data[j + 1] = buffer[offset + 1];
407
- data[j + 2] = buffer[offset + 2];
408
- data[j + 3] = 255;
409
- offset += bytesPerPixel;
420
+
421
+ const data = new dataSource.dataType(BANDS_PR_REPROJ * width * height);
422
+ const dataS = dataSource.data;
423
+ let offset = reproj * BANDS_PR_REPROJ;
424
+ for (let j = 0, len = data.length; j < len; j += BANDS_PR_REPROJ) {
425
+ data[j] = dataS[offset];
426
+ data[j + 1] = dataS[offset + 1];
427
+ data[j + 2] = dataS[offset + 2];
428
+ data[j + 3] = dataS[offset + 3];
429
+ offset += bandCount;
410
430
  }
411
- context.putImageData(imageData, 0, 0);
431
+
432
+ const texture = gl.createTexture();
433
+ gl.bindTexture(gl.TEXTURE_2D, texture);
434
+
435
+ if (willInterpolate) {
436
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
437
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
438
+ } else {
439
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
440
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
441
+ }
442
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
443
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
444
+ gl.texImage2D(
445
+ gl.TEXTURE_2D,
446
+ 0,
447
+ format,
448
+ width,
449
+ height,
450
+ 0,
451
+ format,
452
+ textureType,
453
+ data,
454
+ );
455
+
412
456
  sources.push({
413
457
  extent: dataSource.extent,
414
- clipExtent: dataSource.clipExtent,
415
- image: context.canvas,
458
+ texture: texture,
459
+ width: width,
460
+ height: height,
416
461
  });
417
462
  }
418
463
 
419
- const canvas = renderReprojected(
464
+ const {framebuffer, width, height} = renderReprojected(
465
+ gl,
420
466
  targetWidth,
421
467
  targetHeight,
422
468
  this.pixelRatio_,
423
469
  sourceResolution,
424
- this.sourceTileGrid_.getExtent(),
425
470
  targetResolution,
426
471
  targetExtent,
427
472
  this.triangulation_,
428
473
  sources,
429
474
  this.gutter_,
430
- false,
431
- false,
432
- false,
475
+ textureType,
476
+ this.renderEdges_,
477
+ willInterpolate,
433
478
  );
434
479
 
435
- for (let i = 0, len = sources.length; i < len; ++i) {
436
- const canvas = sources[i].image;
437
- const context = canvas.getContext('2d');
438
- releaseCanvas(context);
439
- canvasPool.push(context.canvas);
440
- }
441
-
442
- const context = canvas.getContext('2d');
443
- const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
444
-
445
- releaseCanvas(context);
446
- canvasPool.push(canvas);
447
-
448
- if (!dataR) {
449
- dataU = new Uint8ClampedArray(
450
- bytesPerPixel * imageData.width * imageData.height,
451
- );
452
- dataR = new dataSources[0].dataType(dataU.buffer);
453
- }
454
-
455
- const data = imageData.data;
456
- let offset = reproj * 3;
457
- for (let i = 0, len = data.length; i < len; i += 4) {
458
- if (data[i + 3] === 255) {
459
- dataU[offset] = data[i];
460
- dataU[offset + 1] = data[i + 1];
461
- dataU[offset + 2] = data[i + 2];
462
- } else {
463
- dataU[offset] = 0;
464
- dataU[offset + 1] = 0;
465
- dataU[offset + 2] = 0;
466
- }
467
- offset += bytesPerPixel;
480
+ // The texture is always RGBA.
481
+ const rows = width;
482
+ const cols = height * BANDS_PR_REPROJ;
483
+ const data = new dataSources[0].dataType(rows * cols);
484
+ gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
485
+ gl.readPixels(0, 0, width, height, gl.RGBA, textureType, data);
486
+
487
+ let offset = reproj * BANDS_PR_REPROJ;
488
+ for (let i = 0, len = data.length; i < len; i += BANDS_PR_REPROJ) {
489
+ // The data read by `readPixels` is flipped in the y-axis so flip it again.
490
+ const flipY = (rows - 1 - ((i / cols) | 0)) * cols + (i % cols);
491
+ dataR[offset] = data[flipY];
492
+ dataR[offset + 1] = data[flipY + 1];
493
+ dataR[offset + 2] = data[flipY + 2];
494
+ dataR[offset + 3] = data[flipY + 3];
495
+ offset += bandCount;
468
496
  }
469
497
  }
470
498
 
499
+ releaseGLCanvas(gl);
500
+ canvasGLPool.push(gl.canvas);
501
+
471
502
  if (imageLike) {
472
503
  const context = createCanvasContext2D(targetWidth, targetHeight);
473
504
  const imageData = new ImageData(dataR, targetWidth);
@@ -476,10 +507,7 @@ class ReprojDataTile extends DataTile {
476
507
  } else {
477
508
  this.reprojData_ = dataR;
478
509
  }
479
- this.reprojSize_ = [
480
- Math.round(targetWidth * this.pixelRatio_),
481
- Math.round(targetHeight * this.pixelRatio_),
482
- ];
510
+ this.reprojSize_ = [Math.round(outWidth), Math.round(outHeight)];
483
511
  this.state = TileState.LOADED;
484
512
  this.changed();
485
513
  }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Create an html canvas element and returns its webgl context.
3
+ * @param {number} [width] Canvas width.
4
+ * @param {number} [height] Canvas height.
5
+ * @param {Array<HTMLCanvasElement | OffscreenCanvas>} [canvasPool] Canvas pool to take existing canvas from.
6
+ * @param {WebGLContextAttributes} [settings] CanvasRenderingContext2DSettings
7
+ * @return {WebGLRenderingContext} The context.
8
+ */
9
+ export function createCanvasContextWebGL(width?: number | undefined, height?: number | undefined, canvasPool?: (HTMLCanvasElement | OffscreenCanvas)[] | undefined, settings?: WebGLContextAttributes | undefined): WebGLRenderingContext;
10
+ /**
11
+ * Releases canvas memory to avoid exceeding memory limits in Safari.
12
+ * See https://pqina.nl/blog/total-canvas-memory-use-exceeds-the-maximum-limit/
13
+ * @param {WebGLRenderingContext} gl Context.
14
+ */
15
+ export function releaseGLCanvas(gl: WebGLRenderingContext): void;
16
+ /**
17
+ * @typedef {Object} ImageExtent
18
+ * @property {import("../extent.js").Extent} extent Extent.
19
+ * @property {WebGLTexture} texture Texture.
20
+ * @property {number} width Width of texture.
21
+ * @property {number} height Height of texture.
22
+ */
23
+ /**
24
+ * Renders the source data into new canvas based on the triangulation.
25
+ *
26
+ * @param {WebGLRenderingContext} gl the context to render in.
27
+ * @param {number} width_ Width of the canvas.
28
+ * @param {number} height_ Height of the canvas.
29
+ * @param {number} pixelRatio Pixel ratio.
30
+ * @param {number} sourceResolution Source resolution.
31
+ * @param {number} targetResolution Target resolution.
32
+ * @param {import("../extent.js").Extent} targetExtent Target extent (tile).
33
+ * @param {import("../reproj/Triangulation.js").default} triangulation Calculated triangulation.
34
+ * @param {Array<ImageExtent>} sources Array of sources.
35
+ * @param {number} gutter Gutter of the sources.
36
+ * @param {number} dataType What kind of data is the textures, must be gl.FLOAT or gl.UNSIGNED_BYTE
37
+ * TODO: Allow setting renderEdges value in the data as this is done in "data-space".
38
+ * @param {boolean | Array<number>} [renderEdges] Render reprojection edges.
39
+ * @param {boolean} [interpolate] Use linear interpolation when resampling.
40
+ * @return {{framebuffer: WebGLFramebuffer, width: number, height: number, texture: WebGLTexture}} Canvas with reprojected data.
41
+ */
42
+ export function render(gl: WebGLRenderingContext, width_: number, height_: number, pixelRatio: number, sourceResolution: number, targetResolution: number, targetExtent: import("../extent.js").Extent, triangulation: import("../reproj/Triangulation.js").default, sources: Array<ImageExtent>, gutter: number, dataType: number, renderEdges?: boolean | number[] | undefined, interpolate?: boolean | undefined): {
43
+ framebuffer: WebGLFramebuffer;
44
+ width: number;
45
+ height: number;
46
+ texture: WebGLTexture;
47
+ };
48
+ /**
49
+ * @type {Array<HTMLCanvasElement | OffscreenCanvas>}
50
+ */
51
+ export const canvasGLPool: Array<HTMLCanvasElement | OffscreenCanvas>;
52
+ export type ImageExtent = {
53
+ /**
54
+ * Extent.
55
+ */
56
+ extent: import("../extent.js").Extent;
57
+ /**
58
+ * Texture.
59
+ */
60
+ texture: WebGLTexture;
61
+ /**
62
+ * Width of texture.
63
+ */
64
+ width: number;
65
+ /**
66
+ * Height of texture.
67
+ */
68
+ height: number;
69
+ };
70
+ //# sourceMappingURL=glreproj.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glreproj.d.ts","sourceRoot":"","sources":["glreproj.js"],"names":[],"mappings":"AA4DA;;;;;;;GAOG;AACH,oNAFY,qBAAqB,CAsBhC;AAED;;;;GAIG;AACH,oCAFW,qBAAqB,QAO/B;AAOD;;;;;;GAMG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,2BAhBW,qBAAqB,UACrB,MAAM,WACN,MAAM,cACN,MAAM,oBACN,MAAM,oBACN,MAAM,gBACN,OAAO,cAAc,EAAE,MAAM,iBAC7B,OAAO,4BAA4B,EAAE,OAAO,WAC5C,KAAK,CAAC,WAAW,CAAC,UAClB,MAAM,YACN,MAAM,oFAIL;IAAC,WAAW,EAAE,gBAAgB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAC,CAyThG;AAvVD;;GAEG;AACH,2BAFU,KAAK,CAAC,iBAAiB,GAAG,eAAe,CAAC,CAErB;;;;;YAIjB,OAAO,cAAc,EAAE,MAAM;;;;aAC7B,YAAY;;;;WACZ,MAAM;;;;YACN,MAAM"}