@itwin/core-backend
Version:
iTwin.js backend components
196 lines • 10.2 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { expect } from "chai";
import { assert, ByteStream, utf8ToString } from "@itwin/core-bentley";
import { CurrentImdlVersion, ElementGeometry, FeatureTableHeader, GeometryStreamIterator, GltfHeader, ImdlHeader, } from "@itwin/core-common";
import { _nativeDb, GeometricElement3d } from "../../core-backend";
import { IModelTestUtils } from "../IModelTestUtils";
import { LineSegment3d } from "@itwin/core-geometry";
describe("ElementGraphics", () => {
let imodel;
before(() => {
imodel = IModelTestUtils.createSnapshotFromSeed(IModelTestUtils.prepareOutputFile("ElementGraphics", "mirukuru.ibim"), IModelTestUtils.resolveAssetFile("mirukuru.ibim"));
});
after(() => {
if (imodel && imodel.isOpen)
imodel.close();
});
it("obtains graphics for elements", async () => {
const elementId = "0x29";
const element = imodel.elements.tryGetElement(elementId);
expect(element).not.to.be.undefined;
expect(element).instanceof(GeometricElement3d);
const request = {
id: "test",
elementId,
toleranceLog10: -2,
formatVersion: CurrentImdlVersion.Major,
};
const result = await imodel[_nativeDb].generateElementGraphics(request);
expect(result.status).to.equal(0 /* ElementGraphicsStatus.Success */);
assert(result.status === 0 /* ElementGraphicsStatus.Success */);
const content = result.content;
expect(content).not.to.be.undefined;
expect(content instanceof Uint8Array).to.be.true;
expect(content.length).least(40);
});
it("obtains graphics for dynamics from json format geometry stream", async () => {
const elementId = "0x29";
const element = imodel.elements.tryGetElement({ id: elementId, wantGeometry: true });
expect(element).not.to.be.undefined;
expect(element).instanceof(GeometricElement3d);
expect(element?.geom).not.to.be.undefined;
expect(element?.placement).not.to.be.undefined;
const request = {
id: "test",
elementId,
toleranceLog10: -2,
formatVersion: CurrentImdlVersion.Major,
type: "3d",
placement: element.placement,
categoryId: element.category,
geometry: { format: "json", data: element.geom },
};
const result = await imodel[_nativeDb].generateElementGraphics(request);
expect(result.status).to.equal(0 /* ElementGraphicsStatus.Success */);
assert(result.status === 0 /* ElementGraphicsStatus.Success */);
const content = result.content;
expect(content).not.to.be.undefined;
expect(content instanceof Uint8Array).to.be.true;
expect(content.length).least(40);
});
it("obtains graphics for dynamics from flatbuffers format geometry stream", async () => {
const elementId = "0x29";
const element = imodel.elements.tryGetElement({ id: elementId, wantGeometry: true });
expect(element).not.to.be.undefined;
expect(element).instanceof(GeometricElement3d);
expect(element?.geom).not.to.be.undefined;
expect(element?.placement).not.to.be.undefined;
const entries = [];
const it = new GeometryStreamIterator(element.geom, element.category);
for (const entry of it) {
if ("geometryQuery" !== entry.primitive.type)
continue;
if (!ElementGeometry.appendGeometryParams(entry.geomParams, entries))
continue;
const geomEntry = ElementGeometry.fromGeometryQuery(entry.primitive.geometry);
expect(geomEntry).not.to.be.undefined;
entries.push(geomEntry);
}
const request = {
id: "test",
elementId,
toleranceLog10: -2,
formatVersion: CurrentImdlVersion.Major,
type: "3d",
placement: element.placement,
categoryId: element.category,
geometry: { format: "flatbuffer", data: entries },
};
const result = await imodel[_nativeDb].generateElementGraphics(request);
expect(result.status).to.equal(0 /* ElementGraphicsStatus.Success */);
assert(result.status === 0 /* ElementGraphicsStatus.Success */);
const content = result.content;
expect(content).not.to.be.undefined;
expect(content instanceof Uint8Array).to.be.true;
expect(content.length).least(40);
});
it("supports an unlimited number of flatbuffer geometry stream entries", async () => {
async function getElementGraphics(numCopies) {
const elementId = "0x29";
const element = imodel.elements.tryGetElement({ id: elementId, wantGeometry: true });
expect(element).not.to.be.undefined;
expect(element).instanceof(GeometricElement3d);
expect(element?.geom).not.to.be.undefined;
expect(element?.placement).not.to.be.undefined;
const entries = [];
const it = new GeometryStreamIterator(element.geom, element.category);
for (const entry of it) {
if ("geometryQuery" !== entry.primitive.type)
continue;
for (let i = 0; i < numCopies; i++) {
const segment = LineSegment3d.createXYXY(i, i, i + 1, i);
const geomEntry = ElementGeometry.fromGeometryQuery(segment);
expect(geomEntry).not.to.be.undefined;
entries.push(geomEntry);
}
break;
}
const request = {
id: "test",
elementId,
toleranceLog10: -2,
formatVersion: CurrentImdlVersion.Major,
type: "3d",
placement: element.placement,
categoryId: element.category,
geometry: { format: "flatbuffer", data: entries },
};
const result = await imodel[_nativeDb].generateElementGraphics(request);
expect(result.status).to.equal(0 /* ElementGraphicsStatus.Success */);
assert(result.status === 0 /* ElementGraphicsStatus.Success */);
const content = result.content;
expect(content).not.to.be.undefined;
expect(content instanceof Uint8Array).to.be.true;
expect(content.length).least(40);
return content;
}
let prevGraphics = [];
let prevRangeDiagonalMagnitude = 0;
for (const numCopies of [1, 2, 3, 10, 100, 1000, 2000, 2047, 2048, 2049, 2050, 2500, 2501, 2600, 3000, 10000]) {
const tileBytes = await getElementGraphics(numCopies);
const newGraphics = Array.from(tileBytes);
expect(newGraphics).not.to.deep.equal(prevGraphics);
// Extract metadata from the tile graphics.
const stream = ByteStream.fromUint8Array(tileBytes);
const header = new ImdlHeader(stream);
const featureTableStartPos = stream.curPos;
const featureTableHeader = FeatureTableHeader.readFrom(stream);
expect(featureTableHeader).not.to.be.undefined;
stream.curPos = featureTableStartPos + featureTableHeader.length;
const gltfHeader = new GltfHeader(stream);
expect(gltfHeader.isValid).to.be.true;
stream.curPos = gltfHeader.scenePosition;
const sceneStrData = stream.nextBytes(gltfHeader.sceneStrLength);
const sceneStr = utf8ToString(sceneStrData);
expect(sceneStr).not.to.be.undefined;
const json = JSON.parse(sceneStr);
// The tile should have two unique vertices per line segment in the input geometry stream.
expect(json.meshes.Mesh_Root.primitives[0].vertices.count).to.equal(numCopies * 2);
expect(header.contentRange.diagonal().magnitude()).greaterThan(prevRangeDiagonalMagnitude);
prevRangeDiagonalMagnitude = header.contentRange.diagonal().magnitude();
expect(newGraphics.length).greaterThan(prevGraphics.length);
prevGraphics = newGraphics;
}
});
it("produces expected errors", async () => {
const testCases = [
[5 /* ElementGraphicsStatus.ElementNotFound */, { elementId: "0" }],
[5 /* ElementGraphicsStatus.ElementNotFound */, { elementId: "0x12345678" }],
[5 /* ElementGraphicsStatus.ElementNotFound */, { elementId: undefined }],
[3 /* ElementGraphicsStatus.InvalidJson */, { id: undefined }],
[3 /* ElementGraphicsStatus.InvalidJson */, { toleranceLog10: undefined }],
[3 /* ElementGraphicsStatus.InvalidJson */, { toleranceLog10: 12.5 }],
[3 /* ElementGraphicsStatus.InvalidJson */, { toleranceLog10: "tol" }],
[0 /* ElementGraphicsStatus.Success */, { formatVersion: undefined }],
[4 /* ElementGraphicsStatus.UnknownMajorFormatVersion */, { formatVersion: CurrentImdlVersion.Major + 1 }],
[4 /* ElementGraphicsStatus.UnknownMajorFormatVersion */, { formatVersion: "latest" }],
];
for (const testCase of testCases) {
const request = {
id: "test",
elementId: "0x29",
toleranceLog10: -2,
formatVersion: CurrentImdlVersion.Major,
...testCase[1],
};
const result = await imodel[_nativeDb].generateElementGraphics(request);
expect(result.status).to.equal(testCase[0]);
if (result.status === 0 /* ElementGraphicsStatus.Success */)
expect(result.content).not.to.be.undefined;
}
});
});
//# sourceMappingURL=ElementGraphics.test.js.map