diff --git a/packages/geotiff/src/geotiff.ts b/packages/geotiff/src/geotiff.ts index d84bff3..bf43507 100644 --- a/packages/geotiff/src/geotiff.ts +++ b/packages/geotiff/src/geotiff.ts @@ -5,6 +5,8 @@ import { SourceHttp } from "@chunkd/source-http"; import { SourceMemory } from "@chunkd/source-memory"; import type { Source, TiffImage } from "@cogeotiff/core"; import { Photometric, SubFileType, Tiff, TiffTag } from "@cogeotiff/core"; +// https://github.com/blacha/cogeotiff/issues/1417 +import type { TiffImageTileCount } from "@cogeotiff/core/build/tiff.image.js"; import type { Affine } from "@developmentseed/affine"; import type { ProjJson } from "./crs.js"; import { crsFromGeoKeys } from "./crs.js"; @@ -199,6 +201,11 @@ export class GeoTIFF { return this.image.size.height; } + /** The number of tiles in the x and y directions */ + get tileCount(): TiffImageTileCount { + return this.image.tileCount; + } + /** Tile width in pixels. */ get tileWidth(): number { return this.image.tileSize.width; diff --git a/packages/geotiff/src/overview.ts b/packages/geotiff/src/overview.ts index 10ae96a..c65cbf1 100644 --- a/packages/geotiff/src/overview.ts +++ b/packages/geotiff/src/overview.ts @@ -1,4 +1,5 @@ import type { TiffImage } from "@cogeotiff/core"; +import type { TiffImageTileCount } from "@cogeotiff/core/build/tiff.image.js"; import type { Affine } from "@developmentseed/affine"; import { compose, scale } from "@developmentseed/affine"; import type { ProjJson } from "./crs.js"; @@ -54,6 +55,11 @@ export class Overview { return this.geotiff.nodata; } + /** The number of tiles in the x and y directions */ + get tileCount(): TiffImageTileCount { + return this.image.tileCount; + } + get tileHeight(): number { return this.image.tileSize.height; } @@ -82,6 +88,10 @@ export class Overview { return await fetchTile(this, x, y, options); } + // TiledMixin + + // Transform mixin + /** * Get the (row, col) pixel index containing the geographic coordinate (x, y). * diff --git a/packages/geotiff/src/tile-matrix-set.ts b/packages/geotiff/src/tile-matrix-set.ts index 8c140ee..7d92c97 100644 --- a/packages/geotiff/src/tile-matrix-set.ts +++ b/packages/geotiff/src/tile-matrix-set.ts @@ -49,22 +49,21 @@ function buildTileMatrix( id: string, transform: Affine, mpu: number, - cornerOfOrigin: "bottomLeft" | "topLeft", tileWidth: number, tileHeight: number, - width: number, - height: number, + matrixWidth: number, + matrixHeight: number, ): TileMatrix { return { id, scaleDenominator: (affine.a(transform) * mpu) / SCREEN_PIXEL_SIZE, cellSize: affine.a(transform), - cornerOfOrigin, + cornerOfOrigin: affine.e(transform) > 0 ? "bottomLeft" : "topLeft", pointOfOrigin: [affine.c(transform), affine.f(transform)], tileWidth, tileHeight, - matrixWidth: Math.ceil(width / tileWidth), - matrixHeight: Math.ceil(height / tileHeight), + matrixWidth, + matrixHeight, }; } @@ -88,20 +87,12 @@ export function generateTileMatrixSet( { id = uuidv4() }: { id?: string } = {}, ): TileMatrixSet { const bbox = geotiff.bbox; - const tr = geotiff.transform; // Full-resolution level is appended last. if (!geotiff.isTiled) { throw new Error("GeoTIFF must be tiled to generate a TMS."); } - if (tr[1] !== 0 || tr[3] !== 0) { - // TileMatrixSet assumes orthogonal axes - throw new Error( - "COG TileMatrixSet with rotation/skewed geotransform is not supported", - ); - } - // Perhaps we should allow metersPerUnit to take any string const crsUnit = crs.units as | "m" @@ -119,8 +110,6 @@ export function generateTileMatrixSet( const semiMajorAxis = crs.a || crs.datum?.a; const mpu = metersPerUnit(crsUnit, { semiMajorAxis }); - const cornerOfOrigin: "bottomLeft" | "topLeft" = - affine.e(tr) > 0 ? "bottomLeft" : "topLeft"; const tileMatrices: TileMatrix[] = []; @@ -129,30 +118,38 @@ export function generateTileMatrixSet( for (let idx = 0; idx < overviewsCoarseFirst.length; idx++) { const overview = overviewsCoarseFirst[idx]!; + const { x: matrixWidth, y: matrixHeight } = overview.tileCount; tileMatrices.push( buildTileMatrix( String(idx), overview.transform, mpu, - cornerOfOrigin, overview.tileWidth, overview.tileHeight, - overview.width, - overview.height, + matrixWidth, + matrixHeight, ), ); } + if (geotiff.transform[1] !== 0 || geotiff.transform[3] !== 0) { + // TileMatrixSet assumes orthogonal axes + throw new Error( + "COG TileMatrixSet with rotation/skewed geotransform is not supported", + ); + } + + const { x: matrixWidth, y: matrixHeight } = geotiff.tileCount; + tileMatrices.push( buildTileMatrix( String(geotiff.overviews.length), - tr, + geotiff.transform, mpu, - cornerOfOrigin, geotiff.tileWidth, geotiff.tileHeight, - geotiff.width, - geotiff.height, + matrixWidth, + matrixHeight, ), );