import { Cartesian3, Cesium3DTileset, Color, HeadingPitchRange, Multiple3DTileContent, MetadataClass, GroupMetadata, RequestScheduler, Resource, when, } from "../../Source/Cesium.js"; import Cesium3DTilesTester from "../Cesium3DTilesTester.js"; import createScene from "../createScene.js"; import generateJsonBuffer from "../generateJsonBuffer.js"; describe( "Scene/Multiple3DTileContent", function () { var scene; // This scene is the same as Composite/Composite, just rephrased // using 3DTILES_multiple_contents var centerLongitude = -1.31968; var centerLatitude = 0.698874; var multipleContentsUrl = "./Data/Cesium3DTiles/MultipleContents/MultipleContents/tileset.json"; var tilesetResource = new Resource({ url: "http://example.com" }); var extensionJson = { content: [ { uri: "pointcloud.pnts", }, { uri: "batched.b3dm", }, { uri: "gltfModel.glb", }, ], }; function makeGltfBuffer() { var gltf = { asset: { version: "1.0", }, }; return generateJsonBuffer(gltf).buffer; } var originalRequestsPerServer; function setZoom(distance) { var center = Cartesian3.fromRadians(centerLongitude, centerLatitude); scene.camera.lookAt(center, new HeadingPitchRange(0.0, -1.57, distance)); } function viewAllTiles() { setZoom(26.0); } function viewNothing() { setZoom(200.0); } beforeAll(function () { scene = createScene(); // One item in each data set is always located in the center, so point the camera there originalRequestsPerServer = RequestScheduler.maximumRequestsPerServer; }); afterAll(function () { scene.destroyForSpecs(); }); beforeEach(function () { RequestScheduler.maximumRequestsPerServer = originalRequestsPerServer; viewAllTiles(); }); afterEach(function () { scene.primitives.removeAll(); }); function expectRenderMultipleContents(tileset) { expect(scene).toPickAndCall(function (result) { // Pick a building var pickedBuilding = result; expect(pickedBuilding).toBeDefined(); // Change the color of the picked building to yellow pickedBuilding.color = Color.clone(Color.YELLOW, pickedBuilding.color); // Expect the pixel color to be some shade of yellow Cesium3DTilesTester.expectRender(scene, tileset, function (rgba) { expect(rgba[0]).toBeGreaterThan(0); expect(rgba[1]).toBeGreaterThan(0); expect(rgba[2]).toEqual(0); expect(rgba[3]).toEqual(255); }); // Both a building and instance are located at the center, hide the building and pick the instance pickedBuilding.show = false; var pickedInstance; expect(scene).toPickAndCall(function (result) { pickedInstance = result; expect(pickedInstance).toBeDefined(); expect(pickedInstance).not.toEqual(pickedBuilding); }); // Change the color of the picked instance to green pickedInstance.color = Color.clone(Color.GREEN, pickedInstance.color); // Expect the pixel color to be some shade of green Cesium3DTilesTester.expectRender(scene, tileset, function (rgba) { expect(rgba[0]).toEqual(0); expect(rgba[1]).toBeGreaterThan(0); expect(rgba[2]).toEqual(0); expect(rgba[3]).toEqual(255); }); // Hide the instance, and expect the render to be blank pickedInstance.show = false; Cesium3DTilesTester.expectRenderBlank(scene, tileset); }); } it("innerContentUrls returns the urls from the extension", function () { var tileset = {}; var tile = {}; var content = new Multiple3DTileContent( tileset, tile, tilesetResource, extensionJson ); expect(content.innerContentUrls).toEqual([ "pointcloud.pnts", "batched.b3dm", "gltfModel.glb", ]); }); it("contentsFetchedPromise is undefined until requestInnerContents is successful", function () { var mockTileset = { statistics: { numberOfPendingRequests: 0, }, }; var tile = {}; var content = new Multiple3DTileContent( mockTileset, tile, tilesetResource, extensionJson ); expect(content.contentsFetchedPromise).not.toBeDefined(); spyOn(Resource.prototype, "fetchArrayBuffer").and.callFake(function () { return when.resolve(makeGltfBuffer()); }); content.requestInnerContents(); expect(content.contentsFetchedPromise).toBeDefined(); }); it("contentsFetchedPromise is undefined if no requests are scheduled", function () { var mockTileset = { statistics: { numberOfPendingRequests: 0, }, }; var tile = {}; var content = new Multiple3DTileContent( mockTileset, tile, tilesetResource, extensionJson ); expect(content.contentsFetchedPromise).not.toBeDefined(); RequestScheduler.maximumRequestsPerServer = 2; content.requestInnerContents(); expect(content.contentsFetchedPromise).not.toBeDefined(); }); it("requestInnerContents returns 0 if successful", function () { var mockTileset = { statistics: { numberOfPendingRequests: 0, }, }; var tile = {}; var content = new Multiple3DTileContent( mockTileset, tile, tilesetResource, extensionJson ); var fetchArray = spyOn( Resource.prototype, "fetchArrayBuffer" ).and.callFake(function () { return when.resolve(makeGltfBuffer()); }); expect(content.requestInnerContents()).toBe(0); expect(fetchArray.calls.count()).toBe(3); }); it("requestInnerContents schedules no requests if there are not enough open slots", function () { var mockTileset = { statistics: { numberOfPendingRequests: 0, }, }; var tile = {}; var content = new Multiple3DTileContent( mockTileset, tile, tilesetResource, extensionJson ); var fetchArray = spyOn(Resource.prototype, "fetchArrayBuffer"); RequestScheduler.maximumRequestsPerServer = 2; expect(content.requestInnerContents()).toBe(3); expect(fetchArray).not.toHaveBeenCalled(); }); it("resolves readyPromise", function () { return Cesium3DTilesTester.resolvesReadyPromise( scene, multipleContentsUrl ); }); it("renders multiple contents", function () { return Cesium3DTilesTester.loadTileset(scene, multipleContentsUrl).then( expectRenderMultipleContents ); }); it("renders valid tiles after tile failure", function () { var originalLoadJson = Cesium3DTileset.loadJson; spyOn(Cesium3DTileset, "loadJson").and.callFake(function (tilesetUrl) { return originalLoadJson(tilesetUrl).then(function (tilesetJson) { var content = tilesetJson.root.extensions["3DTILES_multiple_contents"].content; var badTile = { uri: "nonexistent.b3dm", }; content.splice(1, 0, badTile); return tilesetJson; }); }); return Cesium3DTilesTester.loadTileset(scene, multipleContentsUrl).then( expectRenderMultipleContents ); }); it("cancelRequests cancels in-flight requests", function () { viewNothing(); return Cesium3DTilesTester.loadTileset(scene, multipleContentsUrl).then( function (tileset) { viewAllTiles(); scene.renderForSpecs(); var multipleContents = tileset.root.content; multipleContents.cancelRequests(); return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset).then( function () { // the content should be canceled once in total expect(multipleContents._cancelCount).toBe(1); } ); } ); }); it("destroys", function () { return Cesium3DTilesTester.tileDestroys(scene, multipleContentsUrl); }); describe("3DTILES_metadata", function () { var withGroupMetadataUrl = "./Data/Cesium3DTiles/MultipleContents/GroupMetadata/tileset.json"; var metadataClass = new MetadataClass({ id: "test", class: { properties: { name: { componentType: "STRING", }, height: { componentType: "FLOAT32", }, }, }, }); var groupMetadata = new GroupMetadata({ id: "testGroup", group: { properties: { name: "Test Group", height: 35.6, }, }, class: metadataClass, }); it("groupMetadata returns undefined", function () { return Cesium3DTilesTester.loadTileset(scene, multipleContentsUrl).then( function (tileset) { var content = tileset.root.content; expect(content.groupMetadata).not.toBeDefined(); } ); }); it("assigning groupMetadata throws", function () { return Cesium3DTilesTester.loadTileset(scene, multipleContentsUrl).then( function (tileset) { expect(function () { var content = tileset.root.content; content.groupMetadata = groupMetadata; }).toThrowDeveloperError(); } ); }); it("initializes groupMetadata for inner contents", function () { return Cesium3DTilesTester.loadTileset( scene, withGroupMetadataUrl ).then(function (tileset) { var multipleContents = tileset.root.content; var innerContents = multipleContents.innerContents; var buildingsContent = innerContents[0]; var groupMetadata = buildingsContent.groupMetadata; expect(groupMetadata).toBeDefined(); expect(groupMetadata.getProperty("color")).toEqual( new Cartesian3(255, 127, 0) ); expect(groupMetadata.getProperty("priority")).toBe(10); expect(groupMetadata.getProperty("isInstanced")).toBe(false); var cubesContent = innerContents[1]; groupMetadata = cubesContent.groupMetadata; expect(groupMetadata).toBeDefined(); expect(groupMetadata.getProperty("color")).toEqual( new Cartesian3(0, 255, 127) ); expect(groupMetadata.getProperty("priority")).toBe(5); expect(groupMetadata.getProperty("isInstanced")).toBe(true); }); }); }); }, "WebGL" );