diff --git a/src/cli/ToolsMain.ts b/src/cli/ToolsMain.ts index bc51c3c..57050f9 100644 --- a/src/cli/ToolsMain.ts +++ b/src/cli/ToolsMain.ts @@ -282,6 +282,20 @@ export class ToolsMain { logger.debug(`Executing optimizeI3dm DONE`); } + static updateAlignment(input: string, output: string, force: boolean) { + logger.debug(`Executing updateAlignment`); + logger.debug(` input: ${input}`); + logger.debug(` output: ${output}`); + logger.debug(` force: ${force}`); + + ToolsMain.ensureCanWrite(output, force); + const inputBuffer = fs.readFileSync(input); + const outputBuffer = ContentOps.updateAlignment(inputBuffer); + fs.writeFileSync(output, outputBuffer); + + logger.debug(`Executing updateAlignment DONE`); + } + static analyze( inputFileName: string, outputDirectoryName: string, diff --git a/src/cli/main.ts b/src/cli/main.ts index a5137ac..a745314 100644 --- a/src/cli/main.ts +++ b/src/cli/main.ts @@ -225,6 +225,16 @@ function parseToolArgs(a: string[]) { }, } ) + .command( + "updateAlignment", + "Update the alignment of the batch- and feature table and the tile data" + + "as a whole, to meet the alignment requirements of the specification. " + + "This can be applied to B3DM, I3DM, PNTS, or CMPT tile data.", + { + i: inputStringDefinition, + o: outputStringDefinition, + } + ) .command("gzip", "Gzips the input tileset directory.", { i: inputStringDefinition, o: outputStringDefinition, @@ -488,6 +498,8 @@ async function runCommand(command: string, toolArgs: any, optionArgs: any) { await ToolsMain.optimizeB3dm(input, output, force, parsedOptionArgs); } else if (command === "optimizeI3dm") { await ToolsMain.optimizeI3dm(input, output, force, parsedOptionArgs); + } else if (command === "updateAlignment") { + await ToolsMain.updateAlignment(input, output, force); } else if (command === "gzip") { const tilesOnly = toolArgs.tilesOnly === true; await ToolsMain.gzip(input, output, force, tilesOnly); diff --git a/src/tools/contentProcessing/ContentOps.ts b/src/tools/contentProcessing/ContentOps.ts index 89805ab..913b996 100644 --- a/src/tools/contentProcessing/ContentOps.ts +++ b/src/tools/contentProcessing/ContentOps.ts @@ -1,4 +1,5 @@ import { TileFormats } from "../../tilesets"; +import { CompositeTileData } from "../../tilesets"; import { GltfUtilities } from "./GltfUtilities"; @@ -149,4 +150,45 @@ export class ContentOps { const outputBuffer = TileFormats.createTileDataBuffer(outputTileData); return outputBuffer; } + + /** + * Update the alignment of the given tile data buffer. + * + * This can be applied to B3DM, I3DM, PNTS, or CMPT tile data. It will + * read the tile data from the input, and generate a new tile data + * buffer with the same contents, but ensuring that the alignment + * requirements for the batch- and feature tables and the tile data + * as a whole are met. For CMPT tile data, the data of inner tiles + * will be updated recursively. + * + * @param inputBuffer - The input buffer + * @returns The resulting buffer + */ + static updateAlignment(inputBuffer: Buffer): Buffer { + const isComposite = TileFormats.isComposite(inputBuffer); + if (isComposite) { + const inputCompositeTileData = + TileFormats.readCompositeTileData(inputBuffer); + const header = inputCompositeTileData.header; + const inputInnerTileBuffers = inputCompositeTileData.innerTileBuffers; + const outputInnerTileBuffers: Buffer[] = []; + for (let i = 0; i < inputInnerTileBuffers.length; i++) { + const inputInnerTileBuffer = inputInnerTileBuffers[i]; + const outputInnerTileBuffer = + ContentOps.updateAlignment(inputInnerTileBuffer); + outputInnerTileBuffers.push(outputInnerTileBuffer); + } + const outputCompositeTileData: CompositeTileData = { + header: header, + innerTileBuffers: outputInnerTileBuffers, + }; + const outputBuffer = TileFormats.createCompositeTileDataBuffer( + outputCompositeTileData + ); + return outputBuffer; + } + const tileData = TileFormats.readTileData(inputBuffer); + const outputBuffer = TileFormats.createTileDataBuffer(tileData); + return outputBuffer; + } }