Skip to content

Commit

Permalink
Merge pull request #136 from CesiumGS/update-alignment
Browse files Browse the repository at this point in the history
Add function to update alignment
  • Loading branch information
lilleyse authored Jun 26, 2024
2 parents 05c3ab1 + 364a448 commit ccbfbdc
Show file tree
Hide file tree
Showing 14 changed files with 149 additions and 1 deletion.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,13 +265,23 @@ This example optimizes the b3dm and compresses the meshes using Draco, with a hi

#### optimizeI3dm

Optimize a i3dm using [gltf-pipeline](https://github.com/CesiumGS/gltf-pipeline/blob/main/README.md).
Optimize an i3dm using [gltf-pipeline](https://github.com/CesiumGS/gltf-pipeline/blob/main/README.md).
```
npx 3d-tiles-tools optimizeI3dm -i ./specs/data/instancedWithBatchTableBinary.i3dm -o ./output/optimized.i3dm
```
See [optimizeB3dm](#optimizeb3dm) for further examples.


#### updateAlignment

Update a B3DM, I3DM, PNTS or CMPT file to ensure 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.

```
npx 3d-tiles-tools updateAlignment -i ./specs/data/updateAlignment/testComposite.cmpt -o ./output/testCompositeFixed.cmpt
```


#### analyze

Expand Down
11 changes: 11 additions & 0 deletions specs/data/updateAlignment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@

Individual tile content files (one of each type) for testing the `updateAlignment`
command. These have been taken from the state at
https://github.com/CesiumGS/cesium/blob/83306253e36bbc3fb53801fdae8dee62f1a47be5
which was before the alignment of the spec data was fixed via
https://github.com/CesiumGS/cesium/commit/4b3b4186b4afa2307d7d1666569826d864b984ca

The `testComposite.cmpt` was created specifically for this test,
from `batchedColors.b3dm` and `pointCloudRGB.pnts`.


Binary file added specs/data/updateAlignment/batchedColors.b3dm
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added specs/data/updateAlignment/instancedScale.i3dm
Binary file not shown.
Binary file added specs/data/updateAlignment/pointCloudRGB.pnts
Binary file not shown.
Binary file added specs/data/updateAlignment/testComposite.cmpt
Binary file not shown.
59 changes: 59 additions & 0 deletions specs/tools/contentProcessing/UpdateAlignmentSpec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import fs from "fs";

import { Paths } from "../../../src/base";

import { ContentOps } from "../../../src/tools";

import { SpecHelpers } from "../../SpecHelpers";

const SPECS_DATA_BASE_DIRECTORY = SpecHelpers.getSpecsDataBaseDirectory();

const sourceDir = SPECS_DATA_BASE_DIRECTORY + "/updateAlignment";
const targetDir = SPECS_DATA_BASE_DIRECTORY + "/updateAlignment/output";
const goldenDir = SPECS_DATA_BASE_DIRECTORY + "/updateAlignment/golden";

function updateAlignmentForSpec(fileName: string) {
const sourceFileName = sourceDir + "/" + fileName;
const targetFileName = targetDir + "/" + fileName;
const goldenFileName = goldenDir + "/" + fileName;

const sourceData = fs.readFileSync(sourceFileName);

const targetData = ContentOps.updateAlignment(sourceData);
Paths.ensureDirectoryExists(targetDir);
fs.writeFileSync(targetFileName, targetData);

const goldenData = fs.readFileSync(goldenFileName);
const passed = targetData.equals(goldenData);
return passed;
}

describe("ContentOps", function () {
afterEach(function () {
SpecHelpers.forceDeleteDirectory(targetDir);
});

it("updateAlignment updates the alignment of a B3DM file", async function () {
const fileName = "batchedColors.b3dm";
const passed = updateAlignmentForSpec(fileName);
expect(passed).toBe(true);
});

it("updateAlignment updates the alignment of an I3DM file", async function () {
const fileName = "instancedScale.i3dm";
const passed = updateAlignmentForSpec(fileName);
expect(passed).toBe(true);
});

it("updateAlignment updates the alignment of a PNTS file", async function () {
const fileName = "pointCloudRGB.pnts";
const passed = updateAlignmentForSpec(fileName);
expect(passed).toBe(true);
});

it("updateAlignment updates the alignment of a CMPT file", async function () {
const fileName = "testComposite.cmpt";
const passed = updateAlignmentForSpec(fileName);
expect(passed).toBe(true);
});
});
14 changes: 14 additions & 0 deletions src/cli/ToolsMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
12 changes: 12 additions & 0 deletions src/cli/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -490,6 +500,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);
Expand Down
42 changes: 42 additions & 0 deletions src/tools/contentProcessing/ContentOps.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { TileFormats } from "../../tilesets";
import { CompositeTileData } from "../../tilesets";

import { GltfUtilities } from "./GltfUtilities";

Expand Down Expand Up @@ -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;
}
}

0 comments on commit ccbfbdc

Please sign in to comment.