From 75dc131c674e9f6b0f9be6de86475d9221b6c8ef Mon Sep 17 00:00:00 2001 From: Tawera Manaena Date: Fri, 10 Jan 2025 12:44:00 +1300 Subject: [PATCH] feat: append slug and tile matrix metadata to generated Stac Item files --- .../mappers/map-epsg-to-slug.ts | 27 +++++++++++++++++++ .../stac/create-base-stac-item.ts | 4 ++- .../stac/create-stac-collection.ts | 9 +++++-- .../stac/create-stac-item-groups.ts | 15 ++++++----- .../topo-stac-creation.ts | 23 +++++++++++++--- 5 files changed, 65 insertions(+), 13 deletions(-) create mode 100644 src/commands/basemaps-topo-import/mappers/map-epsg-to-slug.ts diff --git a/src/commands/basemaps-topo-import/mappers/map-epsg-to-slug.ts b/src/commands/basemaps-topo-import/mappers/map-epsg-to-slug.ts new file mode 100644 index 00000000..f0e7dd68 --- /dev/null +++ b/src/commands/basemaps-topo-import/mappers/map-epsg-to-slug.ts @@ -0,0 +1,27 @@ +import { EpsgCode } from '@basemaps/geo'; + +import { logger } from '../../../log.js'; + +const slugs: { [key in EpsgCode]?: string } = { + [EpsgCode.Nztm2000]: 'new-zealand-mainland', + [EpsgCode.Citm2000]: 'chatham-islands', +}; + +/** + * Attempts to map the given EpsgCode enum to a slug. + * + * @param epsg: The EpsgCode enum to map to a slug + * + * @returns if succeeded, a slug string. Otherwise, null. + */ +export function mapEpsgToSlug(epsg: EpsgCode): string | null { + const slug = slugs[epsg]; + + if (slug == null) { + logger.info({ found: false }, 'mapEpsgToSlug()'); + return null; + } + + logger.info({ found: true }, 'mapEpsgToSlug()'); + return slug; +} diff --git a/src/commands/basemaps-topo-import/stac/create-base-stac-item.ts b/src/commands/basemaps-topo-import/stac/create-base-stac-item.ts index 318aa25b..bb8827f0 100644 --- a/src/commands/basemaps-topo-import/stac/create-base-stac-item.ts +++ b/src/commands/basemaps-topo-import/stac/create-base-stac-item.ts @@ -1,3 +1,4 @@ +import { TileMatrixSet } from '@basemaps/geo'; import { GeoJSONPolygon } from 'stac-ts/src/types/geojson.js'; import { CliId, CliInfo } from '../../../cli.info.js'; @@ -18,7 +19,7 @@ const DEFAULT_TRIM_PIXEL_RIGHT = 1.7; * * @returns a StacItem object */ -export function createBaseStacItem(fileName: string, tiffItem: TiffItem): MapSheetStacItem { +export function createBaseStacItem(fileName: string, tiffItem: TiffItem, tileMatrix: TileMatrixSet): MapSheetStacItem { logger.info({ fileName }, 'createBaseStacItem()'); const item: MapSheetStacItem = { @@ -48,6 +49,7 @@ export function createBaseStacItem(fileName: string, tiffItem: TiffItem): MapShe 'source.height': tiffItem.size.height, 'linz_basemaps:options': { tileId: fileName, + tileMatrix: tileMatrix.identifier, preset: 'webp', blockSize: 512, bigTIFF: 'no', diff --git a/src/commands/basemaps-topo-import/stac/create-stac-collection.ts b/src/commands/basemaps-topo-import/stac/create-stac-collection.ts index b8e1b74a..c2d6c857 100644 --- a/src/commands/basemaps-topo-import/stac/create-stac-collection.ts +++ b/src/commands/basemaps-topo-import/stac/create-stac-collection.ts @@ -7,7 +7,12 @@ import { MapSheetStacItem } from '../types/map-sheet-stac-item.js'; const cliDate = new Date().toISOString(); -export function createStacCollection(title: string, imageryBounds: Bounds, items: MapSheetStacItem[]): StacCollection { +export function createStacCollection( + title: string, + linzSlug: string, + imageryBounds: Bounds, + items: MapSheetStacItem[], +): StacCollection { logger.info({ items: items.length }, 'CreateStacCollection()'); const collection: StacCollection = { type: 'Collection', @@ -37,7 +42,7 @@ export function createStacCollection(title: string, imageryBounds: Bounds, items 'linz:geospatial_category': 'topographic-maps', 'linz:region': 'new-zealand', 'linz:security_classification': 'unclassified', - 'linz:slug': 'topo50', + 'linz:slug': linzSlug, extent: { spatial: { bbox: [imageryBounds.toBbox()] }, // Default the temporal time today if no times were found as it is required for STAC diff --git a/src/commands/basemaps-topo-import/stac/create-stac-item-groups.ts b/src/commands/basemaps-topo-import/stac/create-stac-item-groups.ts index a67bd9d0..1ec8bf17 100644 --- a/src/commands/basemaps-topo-import/stac/create-stac-item-groups.ts +++ b/src/commands/basemaps-topo-import/stac/create-stac-item-groups.ts @@ -1,21 +1,24 @@ +import { TileMatrixSet } from '@basemaps/geo'; + import { MapSheetStacItem } from '../types/map-sheet-stac-item.js'; import { TiffItem } from '../types/tiff-item.js'; import { createBaseStacItem } from './create-base-stac-item.js'; /** * This function needs to create two groups: - * - StacItem objects that will live in the "topo[50/250]" directory - * - StacItem objects that will live in the "topo[50/250]-latest" directory + * - StacItem objects that will live in the "topo[50|250]" directory + * - StacItem objects that will live in the "topo[50|250]_latest" directory * - * All versions need a StacItem object that lives in the topo[50/250] directory - * The latest version needs a second StacItem object that lives in the topo[50/250]-latest dir + * All versions need a StacItem object that will live in the topo[50/250] directory + * The latest version needs a second StacItem object that will live in the topo[50|250]_latest directory */ export async function createStacItems( allTargetURL: URL, + tileMatrix: TileMatrixSet, all: TiffItem[], latest: TiffItem, ): Promise<{ all: MapSheetStacItem[]; latest: MapSheetStacItem }> { - const allStacItems = all.map((item) => createBaseStacItem(`${item.mapCode}_${item.version}`, item)); + const allStacItems = all.map((item) => createBaseStacItem(`${item.mapCode}_${item.version}`, item, tileMatrix)); const latestURL = new URL(`${latest.mapCode}_${latest.version}.json`, allTargetURL); @@ -28,7 +31,7 @@ export async function createStacItems( }); }); - const latestStacItem = createBaseStacItem(latest.mapCode, latest); + const latestStacItem = createBaseStacItem(latest.mapCode, latest, tileMatrix); // add link to the latest item referencing its copy that will live in the topo[50/250] directory latestStacItem.links.push({ diff --git a/src/commands/basemaps-topo-import/topo-stac-creation.ts b/src/commands/basemaps-topo-import/topo-stac-creation.ts index b273dd3a..b11580f6 100644 --- a/src/commands/basemaps-topo-import/topo-stac-creation.ts +++ b/src/commands/basemaps-topo-import/topo-stac-creation.ts @@ -1,5 +1,5 @@ import { loadTiffsFromPaths } from '@basemaps/config-loader/build//json/tiff.config.js'; -import { Bounds } from '@basemaps/geo'; +import { Bounds, Epsg, Nztm2000Tms, TileMatrixSets } from '@basemaps/geo'; import { fsa } from '@basemaps/shared'; import { boolean, command, flag, option, string } from 'cmd-ts'; import pLimit from 'p-limit'; @@ -9,6 +9,7 @@ import { logger } from '../../log.js'; import { isArgo } from '../../utils/argo.js'; import { config, forceOutput, registerCli, tryParseUrl, UrlFolder, verbose } from '../common.js'; import { groupTiffsByDirectory } from './mappers/group-tiffs-by-directory.js'; +import { mapEpsgToSlug } from './mappers/map-epsg-to-slug.js'; import { createStacCollection } from './stac/create-stac-collection.js'; import { createStacItems } from './stac/create-stac-item-groups.js'; import { writeStacFiles } from './stac/write-stac-files.js'; @@ -149,6 +150,14 @@ async function loadTiffsToCreateStacs( const latestBounds: Bounds[] = []; const latestStacItems: MapSheetStacItem[] = []; + // parse epsg + const epsgCode = Epsg.parse(epsg); + if (epsgCode == null) throw new Error(`Failed to parse epsg '${epsg}'`); + + // convert epsg to tile matrix + const tileMatrix = TileMatrixSets.tryGet(epsgCode) ?? Nztm2000Tms; // TODO: support other tile matrices + if (tileMatrix == null) throw new Error(`Failed to convert epsg code '${epsgCode.code}' to a tile matrix`); + // create stac items logger.info({ epsg }, 'CreateStacItems:Start'); for (const [mapCode, items] of itemsByMapCode.entries()) { @@ -156,7 +165,7 @@ async function loadTiffsToCreateStacs( const latest = itemsByDir.latest.get(epsg).get(mapCode); // create stac items - const stacItems = await createStacItems(allTargetURL, items, latest); + const stacItems = await createStacItems(allTargetURL, tileMatrix, items, latest); allBounds.push(...items.map((item) => item.bounds)); allStacItems.push(...stacItems.all); @@ -165,9 +174,15 @@ async function loadTiffsToCreateStacs( latestStacItems.push(stacItems.latest); } + // convert epsg to slug + const epsgSlug = mapEpsgToSlug(epsgCode.code); + if (epsgSlug == null) throw new Error(`Failed to map epsg code '${epsgCode.code}' to a slug`); + + const linzSlug = `${scale}-${epsgSlug}`; + // create collections - const collection = createStacCollection(title, Bounds.union(allBounds), allStacItems); - const latestCollection = createStacCollection(title, Bounds.union(latestBounds), latestStacItems); + const collection = createStacCollection(title, linzSlug, Bounds.union(allBounds), allStacItems); + const latestCollection = createStacCollection(title, linzSlug, Bounds.union(latestBounds), latestStacItems); logger.info({ epsg }, 'CreateStacItems:End'); if (force || isArgo()) {