UNPKG

@itwin/core-backend

Version:
842 lines • 176 kB
var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) { if (value !== null && value !== void 0) { if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected."); var dispose, inner; if (async) { if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined."); dispose = value[Symbol.asyncDispose]; } if (dispose === void 0) { if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined."); dispose = value[Symbol.dispose]; if (async) inner = dispose; } if (typeof dispose !== "function") throw new TypeError("Object not disposable."); if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } }; env.stack.push({ value: value, dispose: dispose, async: async }); } else if (async) { env.stack.push({ async: true }); } return value; }; var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) { return function (env) { function fail(e) { env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e; env.hasError = true; } var r, s = 0; function next() { while (r = env.stack.pop()) { try { if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next); if (r.dispose) { var result = r.dispose.call(r.value); if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); }); } else s |= 1; } catch (e) { fail(e); } } if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve(); if (env.hasError) throw env.error; } return next(); }; })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { var e = new Error(message); return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; }); /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ import { assert, expect } from "chai"; import * as path from "path"; import * as semver from "semver"; import * as sinon from "sinon"; import { DbResult, Guid, Id64, IModelStatus, Logger, OpenMode, ProcessDetector } from "@itwin/core-bentley"; import { BisCodeSpec, BriefcaseIdValue, Code, CodeScopeSpec, CodeSpec, ColorByName, ColorDef, DisplayStyleSettings, EcefLocation, FontMap, FontType, GeoCoordStatus, GeographicCRS, GeometryParams, GeometryStreamBuilder, ImageSourceFormat, IModel, IModelError, RelatedElement, RenderMode, SchemaState, SubCategoryAppearance, TextureMapping, TextureMapUnits, ViewFlags, } from "@itwin/core-common"; import { Geometry, LineString3d, Loop, Matrix4d, Point3d, PolyfaceBuilder, Range3d, StrokeOptions, Transform, YawPitchRollAngles, } from "@itwin/core-geometry"; import { V2CheckpointManager } from "../../CheckpointManager"; import { _nativeDb, BisCoreSchema, Category, ClassRegistry, DefinitionContainer, DefinitionGroup, DefinitionGroupGroupsDefinitions, DefinitionModel, DefinitionPartition, DictionaryModel, DisplayStyle3d, DocumentPartition, DrawingGraphic, Element, ElementDrivesElement, ElementGroupsMembers, ElementOwnsChildElements, GenericGraphicalType2d, GeometricElement2d, GeometricElement3d, GeometricModel, GroupInformationPartition, IModelDb, IModelHost, IModelJsFs, InformationPartitionElement, InformationRecordElement, LinkPartition, Model, PhysicalElement, PhysicalModel, PhysicalObject, PhysicalPartition, RenderMaterialElement, SnapshotDb, SpatialCategory, SqliteValueType, StandaloneDb, SubCategory, Subject, Texture, } from "../../core-backend"; import { BriefcaseDb } from "../../IModelDb"; import { HubMock } from "../../internal/HubMock"; import { KnownTestLocations } from "../KnownTestLocations"; import { IModelTestUtils } from "../IModelTestUtils"; import { DisableNativeAssertions } from "../TestUtils"; import { samplePngTexture } from "../imageData"; import { performance } from "perf_hooks"; import { _hubAccess } from "../../internal/Symbols"; import { CustomAttributeClass, EntityClass, PropertyType, propertyTypeToString, SchemaItemType } from "@itwin/ecschema-metadata"; // spell-checker: disable async function getIModelError(promise) { try { await promise; return undefined; } catch (err) { return err instanceof IModelError ? err : undefined; } } function expectIModelError(expectedErrorNumber, error) { expect(error).not.to.be.undefined; expect(error).instanceof(IModelError); expect(error.errorNumber).to.equal(expectedErrorNumber); } async function generateTestSnapshot(targetFileName, seedAssetName) { const seedFile = IModelTestUtils.resolveAssetFile(seedAssetName); const snapshotFile = IModelTestUtils.prepareOutputFile("IModel", targetFileName); const imodel = IModelTestUtils.createSnapshotFromSeed(snapshotFile, seedFile); const schemaPathname = path.join(KnownTestLocations.assetsDir, "TestBim.ecschema.xml"); await imodel.importSchemas([schemaPathname]); // will throw an exception if import fails imodel.saveChanges(); return imodel; } describe("iModel", () => { //TODO: These imodels are used and modified across multiple tests. This is not a good practice and should be refactored. let imodel1; let imodel2; let imodel3; let imodel4; let imodel5; let originalEnv; before(async () => { originalEnv = { ...process.env }; IModelTestUtils.registerTestBimSchema(); imodel1 = await generateTestSnapshot("test.bim", "test.bim"); imodel2 = IModelTestUtils.createSnapshotFromSeed(IModelTestUtils.prepareOutputFile("IModel", "CompatibilityTestSeed.bim"), IModelTestUtils.resolveAssetFile("CompatibilityTestSeed.bim")); imodel3 = SnapshotDb.openFile(IModelTestUtils.resolveAssetFile("GetSetAutoHandledStructProperties.bim")); imodel4 = IModelTestUtils.createSnapshotFromSeed(IModelTestUtils.prepareOutputFile("IModel", "GetSetAutoHandledArrayProperties.bim"), IModelTestUtils.resolveAssetFile("GetSetAutoHandledArrayProperties.bim")); imodel5 = IModelTestUtils.createSnapshotFromSeed(IModelTestUtils.prepareOutputFile("IModel", "mirukuru.ibim"), IModelTestUtils.resolveAssetFile("mirukuru.ibim")); }); after(() => { process.env = originalEnv; imodel1.close(); imodel2.close(); imodel3.close(); imodel4.close(); imodel5.close(); }); afterEach(() => { sinon.restore(); }); /** Roundtrip the entity through a json string and back to a new entity. */ const roundtripThroughJson = (entity1) => { const string1 = JSON.stringify(entity1); const props1 = JSON.parse(string1); const entity2 = new entity1.constructor(props1, entity1.iModel); // create a new entity from the EntityProps const string2 = JSON.stringify(entity2); assert.equal(string1, string2); return entity2; }; it("should be able to get properties of an iIModel", () => { expect(imodel1.name).equals("TBD"); // That's the name of the root subject! const extents = imodel1.projectExtents; assert(!extents.isNull); // make sure we can construct a new element even if we haven't loaded its metadata (will be loaded in ctor) // eslint-disable-next-line @typescript-eslint/no-deprecated assert.isUndefined(imodel1.classMetaDataRegistry.find("biscore:lightlocation")); const e1 = imodel1.constructEntity({ category: "0x11", classFullName: "BisCore:LightLocation", model: "0x01", code: Code.createEmpty() }); assert.isDefined(e1); // eslint-disable-next-line @typescript-eslint/no-deprecated assert.isDefined(imodel1.classMetaDataRegistry.find("biscore:lightlocation")); // should have been loaded in ctor }); it("should use schema to look up classes by name", () => { const elementClass = ClassRegistry.findRegisteredClass(Element.classFullName); const categoryClass = ClassRegistry.findRegisteredClass(Category.classFullName); assert.isDefined(elementClass); assert.isDefined(categoryClass); assert.equal(elementClass.schema, BisCoreSchema); assert.equal(categoryClass.schema, BisCoreSchema); assert.equal(elementClass.className, "Element"); assert.equal(categoryClass.className, "Category"); }); it("Fonts", () => { const dbFonts = imodel1.fonts; expect(Array.from(dbFonts.queryMappedFamilies({ includeNonEmbedded: true })).length).to.equal(4); expect(dbFonts.findDescriptor(1)).to.deep.equal({ name: "Arial", type: FontType.TrueType }); expect(dbFonts.findId({ name: "Arial" })).to.equal(1); expect(dbFonts.findId({ name: "arial" })).to.equal(1); expect(dbFonts.findDescriptor(2)).to.deep.equal({ name: "Font0", type: FontType.Rsc }); expect(dbFonts.findId({ name: "Font0" })).to.equal(2); expect(dbFonts.findId({ name: "fOnt0" })).to.equal(2); expect(dbFonts.findDescriptor(3)).to.deep.equal({ name: "ShxFont0", type: FontType.Shx }); expect(dbFonts.findId({ name: "ShxFont0" })).to.equal(3); expect(dbFonts.findId({ name: "shxfont0" })).to.equal(3); expect(dbFonts.findDescriptor(4)).to.deep.equal({ name: "Calibri", type: FontType.TrueType }); expect(dbFonts.findId({ name: "Calibri" })).to.equal(4); expect(dbFonts.findId({ name: "cAlIbRi" })).to.equal(4); expect(dbFonts.findId({ name: "notfound" })).to.be.undefined; const fonts1 = imodel1.fontMap; // eslint-disable-line @typescript-eslint/no-deprecated assert.equal(fonts1.fonts.size, 4, "font map size should be 4"); assert.equal(FontType.TrueType, fonts1.getFont(1).type, "get font 1 type is TrueType"); assert.equal("Arial", fonts1.getFont(1).name, "get Font 1 name"); assert.equal(1, fonts1.getFont("Arial").id, "get Font 1, by name"); assert.equal(1, fonts1.getFont("arial").id, "get Font 1, by name case insensitive"); assert.equal(FontType.Rsc, fonts1.getFont(2).type, "get font 2 type is Rsc"); assert.equal("Font0", fonts1.getFont(2).name, "get Font 2 name"); assert.equal(2, fonts1.getFont("Font0").id, "get Font 2, by name"); assert.equal(2, fonts1.getFont("fOnt0").id, "get Font 2, by name case insensitive"); assert.equal(FontType.Shx, fonts1.getFont(3).type, "get font 1 type is Shx"); assert.equal("ShxFont0", fonts1.getFont(3).name, "get Font 3 name"); assert.equal(3, fonts1.getFont("ShxFont0").id, "get Font 3, by name"); assert.equal(3, fonts1.getFont("shxfont0").id, "get Font 3, by name case insensitive"); assert.equal(FontType.TrueType, fonts1.getFont(4).type, "get font 4 type is TrueType"); assert.equal("Calibri", fonts1.getFont(4).name, "get Font 4 name"); assert.equal(4, fonts1.getFont("Calibri").id, "get Font 4, by name"); assert.equal(4, fonts1.getFont("cAlIbRi").id, "get Font 4, by name case insensitive"); assert.isUndefined(fonts1.getFont("notfound"), "attempt lookup of a font that should not be found"); assert.deepEqual(new FontMap(fonts1.toJSON()), fonts1, "toJSON on FontMap"); // eslint-disable-line @typescript-eslint/no-deprecated }); it("should load a known element by Id from an existing iModel", () => { assert.exists(imodel1.elements); const code1 = new Code({ spec: "0x10", scope: "0x11", value: "RF1.dgn" }); const el = imodel1.elements.getElement(code1); assert.exists(el); const el2ById = imodel1.elements.getElement("0x34"); assert.exists(el2ById); const badCode = new Code({ spec: "0x10", scope: "0x11", value: "RF1_does_not_exist.dgn" }); try { imodel1.elements.getElement(badCode); // throws Error assert.fail(); // this line should be skipped } catch (error) { assert.instanceOf(error, Error); assert.instanceOf(error, IModelError); assert.equal(error.errorNumber, IModelStatus.NotFound); } const element1 = imodel1.elements.tryGetElement(code1); const element2 = imodel1.elements.tryGetElement("0x34"); const element3 = imodel1.elements.tryGetElement(badCode); assert.isDefined(element1); assert.isDefined(element2); assert.isUndefined(element3); const elementProps1 = imodel1.elements.tryGetElementProps(code1); const elementProps2 = imodel1.elements.tryGetElementProps("0x34"); const elementProps3 = imodel1.elements.tryGetElementProps(badCode); assert.isDefined(elementProps1); assert.isDefined(elementProps2); assert.isUndefined(elementProps3); const model1 = imodel1.models.tryGetModel(IModel.dictionaryId); const modelProps1 = imodel1.models.tryGetModelProps(IModel.dictionaryId); const subModel1 = imodel1.models.tryGetSubModel(IModel.dictionaryId); assert.isDefined(model1); assert.isDefined(modelProps1); assert.isDefined(subModel1); const badModel1 = imodel1.models.tryGetModel(Id64.fromUint32Pair(999, 999)); const badModelProps1 = imodel1.models.tryGetModelProps(Id64.fromUint32Pair(999, 999)); const badSubModel1 = imodel1.models.tryGetSubModel(IModel.rootSubjectId); const badSubModel2 = imodel1.models.tryGetSubModel(badCode); assert.isUndefined(badModel1); assert.isUndefined(badModelProps1); assert.isUndefined(badSubModel1); assert.isUndefined(badSubModel2); const subCat = imodel1.elements.getElement("0x2e"); assert.isTrue(subCat instanceof SubCategory); if (subCat instanceof SubCategory) { assert.isTrue(subCat.appearance.color.tbgr === 16777215); assert.isTrue(subCat.appearance.weight === 2); assert.equal(Id64.getLocalId(subCat.id), 46); assert.equal(Id64.getBriefcaseId(subCat.id), 0); assert.equal(Id64.getLocalId(subCat.code.spec), 30); assert.equal(Id64.getBriefcaseId(subCat.code.spec), 0); assert.isTrue(subCat.code.scope === "0x2d"); assert.isTrue(subCat.code.value === "A-Z013-G-Legn"); roundtripThroughJson(subCat); } /// Get the parent Category of the subcategory. const cat = imodel1.elements.getElement(subCat.getCategoryId()); assert.isTrue(cat instanceof Category); if (cat instanceof Category) { assert.equal(Id64.getLocalId(cat.id), 45); assert.equal(Id64.getBriefcaseId(cat.id), 0); assert.isTrue(cat.description === "Legends, symbols keys"); assert.equal(Id64.getLocalId(cat.code.spec), 22); assert.equal(Id64.getBriefcaseId(cat.code.spec), 0); assert.isTrue(cat.code.value === "A-Z013-G-Legn"); roundtripThroughJson(cat); } const phys = imodel1.elements.getElement("0x38"); assert.isTrue(phys instanceof GeometricElement3d); const locateMsg = phys.getToolTipMessage(); assert.isDefined(locateMsg); const a2 = imodel2.elements.getElement("0x1d"); assert.exists(a2); expect(a2.federationGuid).equal("18eb4650-b074-414f-b961-d9cfaa6c8746"); const el3 = imodel2.elements.getElement(a2.federationGuid); assert.exists(el3); assert.notEqual(a2, el3); assert.equal(a2.id, el3.id); roundtripThroughJson(el3); const newEl = el3.toJSON(); newEl.federationGuid = undefined; newEl.code = { scope: "bad scope", spec: "0x10", value: "new code" }; expect(() => imodel2.elements.insertElement(newEl)).throws("invalid code scope").to.have.property("metadata"); newEl.code.scope = "0x34322"; // valid id, but element doesn't exist expect(() => imodel2.elements.insertElement(newEl)).throws("invalid code scope").to.have.property("metadata"); newEl.code.scope = el3.federationGuid; const newId = imodel2.elements.insertElement(newEl); // code scope from FederationGuid should get converted to ElementId const a4 = imodel2.elements.getElementProps(newId); expect(a4.code.scope).equal(el3.id); a4.code.scope = "0x13343"; expect(() => imodel2.elements.updateElement(a4)).throws("invalid code scope").to.have.property("metadata"); a4.code.scope = "0x1"; imodel2.elements.updateElement(a4); // should change the code scope to new element let a5 = imodel2.elements.getElementProps(newId); expect(a5.code.scope).equal("0x1"); // only pass minimum, but expect model and classFullName to be added. const newProps = { id: a4.id, code: a4.code, classFullName: undefined, model: undefined }; newProps.code.scope = el3.federationGuid; // should convert FederationGuid to ElementId imodel2.elements.updateElement(newProps); expect(newProps.classFullName).eq(a4.classFullName); expect(newProps.model).eq(a4.model); a5 = imodel2.elements.getElementProps(newId); expect(a5.code.scope).equal(el3.id); }); it("should optionally detect class mismatches", () => { // tryGetElement const subjectUnvalidated = imodel1.elements.tryGetElement(IModel.rootSubjectId); assert.isDefined(subjectUnvalidated); const subjectValidated = imodel1.elements.tryGetElement(IModel.rootSubjectId, Subject); assert.isDefined(subjectValidated); const physicalElementUnvalidated = imodel1.elements.tryGetElement(IModel.rootSubjectId); assert.isDefined(physicalElementUnvalidated); // wrong type, but class to validate was not passed const physicalElementValidated = imodel1.elements.tryGetElement(IModel.rootSubjectId, PhysicalElement); // abstract class assert.isUndefined(physicalElementValidated); // wrong type const physicalObjectUnvalidated = imodel1.elements.tryGetElement(IModel.rootSubjectId); assert.isDefined(physicalObjectUnvalidated); // wrong type, but class to validate was not passed const physicalObjectValidated = imodel1.elements.tryGetElement(IModel.rootSubjectId, PhysicalObject); // concrete class assert.isUndefined(physicalObjectValidated); // wrong type // tryGetModel const dictionaryUnvalidated = imodel1.models.tryGetModel(IModel.dictionaryId); assert.isDefined(dictionaryUnvalidated); const dictionaryValidated = imodel1.models.tryGetModel(IModel.dictionaryId, DictionaryModel); assert.isDefined(dictionaryValidated); const geometricModelUnvalidated = imodel1.models.tryGetModel(IModel.dictionaryId); assert.isDefined(geometricModelUnvalidated); // wrong type, but class to validate was not passed const geometricModelValidated = imodel1.models.tryGetModel(IModel.dictionaryId, GeometricModel); // abstract class assert.isUndefined(geometricModelValidated); // wrong type const physicalModelUnvalidated = imodel1.models.tryGetModel(IModel.dictionaryId); assert.isDefined(physicalModelUnvalidated); // wrong type, but class to validate was not passed const physicalModelValidated = imodel1.models.tryGetModel(IModel.dictionaryId, PhysicalModel); // concrete class assert.isUndefined(physicalModelValidated); // wrong type // tryGetSubModel const dictionarySubUnvalidated = imodel1.models.tryGetSubModel(IModel.dictionaryId); assert.isDefined(dictionarySubUnvalidated); const dictionarySubValidated = imodel1.models.tryGetSubModel(IModel.dictionaryId, DictionaryModel); assert.isDefined(dictionarySubValidated); const geometricSubModelUnvalidated = imodel1.models.tryGetSubModel(IModel.dictionaryId); assert.isDefined(geometricSubModelUnvalidated); // wrong type, but class to validate was not passed const geometricSubModelValidated = imodel1.models.tryGetSubModel(IModel.dictionaryId, GeometricModel); // abstract class assert.isUndefined(geometricSubModelValidated); // wrong type const physicalSubModelUnvalidated = imodel1.models.tryGetSubModel(IModel.dictionaryId); assert.isDefined(physicalSubModelUnvalidated); // wrong type, but class to validate was not passed const physicalSubModelValidated = imodel1.models.tryGetSubModel(IModel.dictionaryId, PhysicalModel); // concrete class assert.isUndefined(physicalSubModelValidated); // wrong type }); it("should create elements", () => { const seedElement = imodel2.elements.getElement("0x1d"); assert.exists(seedElement); assert.isTrue(seedElement.federationGuid === "18eb4650-b074-414f-b961-d9cfaa6c8746"); for (let i = 0; i < 25; i++) { const elementProps = { classFullName: "Generic:PhysicalObject", model: seedElement.model, category: seedElement.category, code: Code.createEmpty(), federationGuid: Guid.createValue(), userLabel: `UserLabel-${i}`, }; const element = imodel2.elements.createElement(elementProps); element.setUserProperties("performanceTest", { s: `String-${i}`, n: i }); const elementId = imodel2.elements.insertElement(element.toJSON()); assert.isTrue(Id64.isValidId64(elementId)); } }); it("should insert a RenderMaterial", () => { const model = imodel2.models.getModel(IModel.dictionaryId); expect(model).not.to.be.undefined; const testMaterialName = "test material name"; const testPaletteName = "test palette name"; const testDescription = "test description"; const color = [0.3, 0.7, 0.8]; const specularColor = [0.1, 1, 0]; const finish = 0.4; const transmit = 0.1; const diffuse = 0.24; const specular = 0.9; const reflect = 0.3; const reflectColor = [1, 0, 0.5]; /* eslint-disable @typescript-eslint/naming-convention */ const textureMapProps = { pattern_angle: 3.0, pattern_u_flip: false, pattern_flip: false, pattern_scale: [1.0, 1.0], pattern_offset: [0.0, 0.0], pattern_scalemode: TextureMapUnits.Inches, pattern_mapping: TextureMapping.Mode.Planar, pattern_weight: 0.5, TextureId: "test_textureid", }; /* eslint-enable @typescript-eslint/naming-convention */ const renderMaterialParams = { paletteName: testPaletteName, description: testDescription, color, specularColor, finish, transmit, diffuse, specular, reflect, reflectColor, patternMap: textureMapProps, }; const renderMaterialId = RenderMaterialElement.insert(imodel2, IModel.dictionaryId, testMaterialName, renderMaterialParams); const renderMaterial = imodel2.elements.getElement(renderMaterialId); assert((renderMaterial instanceof RenderMaterialElement) === true, "did not retrieve an instance of RenderMaterial"); expect(renderMaterial.paletteName).to.equal(testPaletteName); expect(renderMaterial.description).to.equal(testDescription); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasBaseColor).to.equal(true); expect(JSON.stringify(renderMaterial.jsonProperties.materialAssets.renderMaterial.color)).to.equal(JSON.stringify(color)); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasSpecularColor).to.equal(true); expect(JSON.stringify(renderMaterial.jsonProperties.materialAssets.renderMaterial.specular_color)).to.equal(JSON.stringify(specularColor)); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasFinish).to.equal(true); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.finish).to.equal(finish); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasTransmit).to.equal(true); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.transmit).to.equal(transmit); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasDiffuse).to.equal(true); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.diffuse).to.equal(diffuse); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasSpecular).to.equal(true); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.specular).to.equal(specular); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasReflect).to.equal(true); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.reflect).to.equal(reflect); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.HasReflectColor).to.equal(true); expect(JSON.stringify(renderMaterial.jsonProperties.materialAssets.renderMaterial.reflect_color)).to.equal(JSON.stringify(reflectColor)); expect(renderMaterial.jsonProperties.materialAssets.renderMaterial.Map).not.to.be.undefined; const patternMap = renderMaterial.jsonProperties.materialAssets.renderMaterial.Map.Pattern; expect(patternMap).not.to.be.undefined; expect(patternMap.pattern_angle).to.equal(textureMapProps.pattern_angle); expect(patternMap.pattern_u_flip).to.equal(textureMapProps.pattern_u_flip); expect(patternMap.pattern_flip).to.equal(textureMapProps.pattern_flip); expect(JSON.stringify(patternMap.pattern_scale)).to.equal(JSON.stringify(textureMapProps.pattern_scale)); expect(JSON.stringify(patternMap.pattern_offset)).to.equal(JSON.stringify(textureMapProps.pattern_offset)); expect(patternMap.pattern_scalemode).to.equal(textureMapProps.pattern_scalemode); expect(patternMap.pattern_mapping).to.equal(textureMapProps.pattern_mapping); expect(patternMap.pattern_weight).to.equal(textureMapProps.pattern_weight); expect(patternMap.TextureId).to.equal(textureMapProps.TextureId); }); it("attempt to apply material to new element in imodel5", () => { const testTextureName = "fake texture name"; const testTextureFormat = ImageSourceFormat.Png; const testTextureDescription = "empty description"; const texId = Texture.insertTexture(imodel5, IModel.dictionaryId, testTextureName, testTextureFormat, samplePngTexture.base64, testTextureDescription); /* eslint-disable @typescript-eslint/naming-convention */ const matId = RenderMaterialElement.insert(imodel5, IModel.dictionaryId, "test material name", { paletteName: "TestPaletteName", patternMap: { TextureId: texId, pattern_offset: [0, 0], pattern_scale: [1, 1], pattern_scalemode: TextureMapUnits.Relative, }, }); /* eslint-enable @typescript-eslint/naming-convention */ /** Create a simple flat mesh with 4 points (2x2) */ const width = imodel5.projectExtents.xLength() * 0.2; const height = imodel5.projectExtents.yLength() * 0.2; let shape; const doPolyface = true; if (doPolyface) { const options = StrokeOptions.createForFacets(); options.shouldTriangulate = false; const builder = PolyfaceBuilder.create(options); const quad = [ Point3d.create(0.0, 0.0, 0.0), Point3d.create(width, 0.0, 0.0), Point3d.create(width, height, 0.0), Point3d.create(0.0, height, 0.0), ]; builder.addQuadFacet(quad); shape = builder.claimPolyface(); } else { shape = Loop.create(LineString3d.create([ Point3d.create(0, 0, 0), Point3d.create(width, 0, 0), Point3d.create(width, height, 0), Point3d.create(0, height, 0), Point3d.create(0, 0, 0), ])); } const modelId = PhysicalModel.insert(imodel5, IModelDb.rootSubjectId, "test_render_material_model_name"); const categoryId = SpatialCategory.insert(imodel5, IModel.dictionaryId, "GeoJSON Feature", { color: ColorDef.white.toJSON() }); /** generate a geometry stream containing the polyface */ const gsBuilder = new GeometryStreamBuilder(); const params = new GeometryParams(categoryId); params.materialId = matId; gsBuilder.appendGeometryParamsChange(params); gsBuilder.appendGeometry(shape); const geometry = gsBuilder.geometryStream; // geometry[0].material = { materialId: matId }; const props = { classFullName: "Generic:PhysicalObject", placement: { origin: imodel5.projectExtents.center, angles: new YawPitchRollAngles() }, model: modelId, code: Code.createEmpty(), category: categoryId, geom: geometry, }; imodel5.elements.insertElement(props); imodel5.saveChanges(); }); it("should insert a DisplayStyle", () => { const model = imodel2.models.getModel(IModel.dictionaryId); expect(model).not.to.be.undefined; const settings = { backgroundColor: ColorDef.blue.toJSON(), viewflags: ViewFlags.fromJSON({ renderMode: RenderMode.SolidFill, }), }; const props = { classFullName: DisplayStyle3d.classFullName, model: IModel.dictionaryId, code: { spec: BisCodeSpec.displayStyle, scope: IModel.dictionaryId, value: "test style" }, isPrivate: false, jsonProperties: { styles: settings, }, }; const styleId = imodel2.elements.insertElement(props); let style = imodel2.elements.getElement(styleId); expect(style instanceof DisplayStyle3d).to.be.true; expect(style.code.spec).equal(imodel2.codeSpecs.getByName(BisCodeSpec.displayStyle).id); expect(style.settings.viewFlags.renderMode).to.equal(RenderMode.SolidFill); expect(style.settings.backgroundColor.equals(ColorDef.blue)).to.be.true; const newFlags = style.settings.viewFlags.copy({ renderMode: RenderMode.SmoothShade }); style.settings.viewFlags = newFlags; style.settings.backgroundColor = ColorDef.red; style.settings.monochromeColor = ColorDef.green; expect(style.jsonProperties.styles.viewflags.renderMode).to.equal(RenderMode.SmoothShade); imodel2.elements.updateElement(style.toJSON()); style = imodel2.elements.getElement(styleId); expect(style instanceof DisplayStyle3d).to.be.true; expect(style.settings.viewFlags.renderMode).to.equal(RenderMode.SmoothShade); expect(style.settings.backgroundColor.equals(ColorDef.red)).to.be.true; expect(style.settings.monochromeColor.equals(ColorDef.green)).to.be.true; }); it("should create display styles", () => { const defaultViewFlags = new ViewFlags().toJSON(); const defaultMapImagery = new DisplayStyleSettings({}).toJSON().mapImagery; const viewFlags = new ViewFlags({ patterns: false, visibleEdges: true }); const viewflags = { noWhiteOnWhiteReversal: true, shadows: true, noTransp: true }; const mapImagery = { backgroundBase: ColorDef.red.tbgr, backgroundLayers: [{ name: "x", url: "y", transparency: 0.5, formatId: "WMS", visible: true, }], }; const props = { mapImagery, excludedElements: ["0x123", "0xfed"], timePoint: 42, backgroundColor: ColorDef.green.tbgr, }; const testCases = [ [undefined, defaultViewFlags, false], [{ viewFlags }, viewFlags.toJSON(), false], [{ viewflags }, viewflags, false], [{ viewflags, viewFlags }, viewFlags.toJSON(), false], [props, defaultViewFlags, false], [{ ...props, viewflags }, viewflags, false], [{ backgroundColor: ColorDef.blue }, defaultViewFlags, false], [{ backgroundColor: ColorDef.from(1, 2, 3, 4) }, defaultViewFlags, false], [{ backgroundColor: ColorDef.blue.tbgr }, defaultViewFlags, false], [{ backgroundColor: ColorDef.from(1, 2, 3, 4).tbgr }, defaultViewFlags, false], ]; let suffix = 123; for (const test of testCases) { const expected = test[0] ?? {}; const styleId = DisplayStyle3d.insert(imodel2, IModel.dictionaryId, `TestStyle${suffix++}`, expected); const style = imodel2.elements.getElement(styleId).toJSON(); expect(style.jsonProperties.styles).not.to.be.undefined; expect(style.jsonProperties).not.to.be.undefined; expect(style.jsonProperties.styles).not.to.be.undefined; const actual = style.jsonProperties.styles; expect(actual.viewflags).not.to.be.undefined; const expectedVf = ViewFlags.fromJSON(test[1]); const actualVf = ViewFlags.fromJSON(actual.viewflags); expect(actualVf.toJSON()).to.deep.equal(expectedVf.toJSON()); const expectedBGColor = expected.backgroundColor instanceof ColorDef ? expected.backgroundColor.toJSON() : expected.backgroundColor; expect(actual.backgroundColor).to.equal(expectedBGColor); // DisplayStyleSettings constructor always initializes json.mapImagery. expect(actual.mapImagery).to.deep.equal(expected.mapImagery ?? defaultMapImagery); expect(actual.excludedElements).to.deep.equal(expected.excludedElements); expect(actual.timePoint).to.deep.equal(expected.timePoint); } }); it("should have a valid root subject element", () => { const rootSubject = imodel1.elements.getRootSubject(); assert.exists(rootSubject); assert.isTrue(rootSubject instanceof Subject); assert.isAtLeast(rootSubject.code.value.length, 1); assert.isFalse(imodel1.elements.hasSubModel(IModel.rootSubjectId)); try { imodel1.models.getSubModel(rootSubject.id); // throws error assert.fail(); // this line should be skipped } catch (error) { assert.isTrue(error instanceof Error); assert.isTrue(error instanceof IModelError); assert.equal(error.errorNumber, IModelStatus.NotFound); } const childIds = imodel1.elements.queryChildren(rootSubject.id); assert.isAtLeast(childIds.length, 1); for (const childId of childIds) { const childElement = imodel1.elements.getElement(childId); assert.exists(childElement); assert.isTrue(childElement instanceof Element); roundtripThroughJson(childElement); assert.equal(rootSubject.id, childElement.parent.id); const childLocalId = Id64.getLocalId(childId); const childBcId = Id64.getBriefcaseId(childId); if (childElement instanceof InformationPartitionElement) { assert.isTrue(imodel1.elements.hasSubModel(childElement.id)); const childSubModel = imodel1.models.getSubModel(childElement.id); assert.exists(childSubModel, "InformationPartitionElements should have a subModel"); if (childLocalId === 16 && childBcId === 0) { assert.isTrue(childElement instanceof DefinitionPartition, "ChildId 0x00000010 should be a DefinitionPartition"); assert.isTrue(childElement.code.value === "BisCore.DictionaryModel", "Definition Partition should have code value of BisCore.DictionaryModel"); } else if (childLocalId === 14 && childBcId === 0) { assert.isTrue(childElement instanceof LinkPartition); assert.isTrue(childElement.code.value === "BisCore.RealityDataSources"); } else if (childLocalId === 17 && childBcId === 0) { assert.isTrue(childElement instanceof LinkPartition, "ChildId 0x000000011 should be a LinkPartition"); assert.isTrue(childElement.code.value === "Repository Links"); } } else if (childElement instanceof Subject) { assert.isFalse(imodel1.elements.hasSubModel(childElement.id)); if (childLocalId === 19 && childBcId === 0) { assert.isTrue(childElement instanceof Subject); assert.isTrue(childElement.code.value === "DgnV8:mf3, A", "Subject should have code value of DgnV8:mf3, A"); assert.isTrue(childElement.jsonProperties.Subject.Job.DgnV8.V8File === "mf3.dgn", "Subject should have jsonProperty Subject.Job.DgnV.V8File"); assert.isTrue(childElement.jsonProperties.Subject.Job.DgnV8.V8RootModel === "A", "Subject should have jsonProperty Subject.Job.DgnV.V8RootModel"); } } } }); it("should load a known model by Id from an existing iModel", () => { assert.exists(imodel1.models); const model2 = imodel1.models.getModel("0x1c"); assert.exists(model2); const formatter = model2.getJsonProperty("formatter"); assert.exists(formatter, "formatter should exist as json property"); assert.equal(formatter.fmtFlags.angMode, 1, "fmtFlags"); assert.equal(formatter.mastUnit.label, "m", "mastUnit is meters"); roundtripThroughJson(model2); let model = imodel1.models.getModel(IModel.repositoryModelId); assert.exists(model); roundtripThroughJson(model); const code1 = new Code({ spec: "0x1d", scope: "0x1d", value: "A" }); model = imodel1.models.getSubModel(code1); // By this point, we expect the submodel's class to be in the class registry *cache* const geomModel = ClassRegistry.getClass(PhysicalModel.classFullName, imodel1); assert.exists(model); assert.isTrue(model instanceof geomModel); roundtripThroughJson(model); const modelExtents = model.queryExtents(); assert.isBelow(modelExtents.low.x, modelExtents.high.x); assert.isBelow(modelExtents.low.y, modelExtents.high.y); assert.isBelow(modelExtents.low.z, modelExtents.high.z); }); it("should find a tile tree for a geometric model", async () => { // Note: this is an empty model. const tree = await imodel1.tiles.requestTileTreeProps("0x1c"); expect(tree).not.to.be.undefined; expect(tree.id).to.equal("0x1c"); expect(tree.maxTilesToSkip).to.equal(1); expect(tree.rootTile).not.to.be.undefined; // Empty model => identity transform const tf = Transform.fromJSON(tree.location); expect(tf.matrix.isIdentity).to.be.true; expect(tf.origin.x).to.equal(0); expect(tf.origin.y).to.equal(0); expect(tf.origin.z).to.equal(0); expect(tree.rootTile.contentId).to.equal("0/0/0/0/1"); // Empty model => null range const range = Range3d.fromJSON(tree.rootTile.range); expect(range.isNull).to.be.true; expect(tree.rootTile.maximumSize).to.equal(0.0); // empty model => undisplayable root tile => size = 0.0 expect(tree.rootTile.isLeaf).to.be.true; // empty model => empty tile expect(tree.rootTile.contentRange).to.be.undefined; }); it("should throw on invalid tile requests", async () => { const env_1 = { stack: [], error: void 0, hasError: false }; try { const _r = __addDisposableResource(env_1, new DisableNativeAssertions(), false); let error = await getIModelError(imodel1.tiles.requestTileTreeProps("0x12345")); expectIModelError(IModelStatus.InvalidId, error); error = await getIModelError(imodel1.tiles.requestTileTreeProps("NotAValidId")); expectIModelError(IModelStatus.InvalidId, error); error = await getIModelError(imodel1.tiles.requestTileContent("0x1c", "0/0/0/0")); expectIModelError(IModelStatus.InvalidId, error); error = await getIModelError(imodel1.tiles.requestTileContent("0x12345", "0/0/0/0/1")); expectIModelError(IModelStatus.InvalidId, error); error = await getIModelError(imodel1.tiles.requestTileContent("0x1c", "V/W/X/Y/Z")); expectIModelError(IModelStatus.InvalidId, error); error = await getIModelError(imodel1.tiles.requestTileContent("0x1c", "NotAValidId")); expectIModelError(IModelStatus.InvalidId, error); } catch (e_1) { env_1.error = e_1; env_1.hasError = true; } finally { __disposeResources(env_1); } }); // NOTE: this test can be removed when the deprecated executeQuery method is removed it("should produce an array of rows", () => { const rows = IModelTestUtils.executeQuery(imodel1, `SELECT * FROM ${Category.classFullName}`); assert.exists(rows); assert.isArray(rows); assert.isAtLeast(rows.length, 1); assert.exists(rows[0].id); assert.notEqual(rows[0].id.value, ""); }); it("should be some categories", () => { const categorySql = `SELECT ECInstanceId FROM ${Category.classFullName}`; // eslint-disable-next-line @typescript-eslint/no-deprecated imodel1.withPreparedStatement(categorySql, (categoryStatement) => { let numCategories = 0; while (DbResult.BE_SQLITE_ROW === categoryStatement.step()) { numCategories++; const categoryId = categoryStatement.getValue(0).getId(); const category = imodel1.elements.getElement(categoryId); assert.isTrue(category instanceof Category, "Should be instance of Category"); // verify the default subcategory. const defaultSubCategoryId = category.myDefaultSubCategoryId(); const defaultSubCategory = imodel1.elements.getElement(defaultSubCategoryId); assert.isTrue(defaultSubCategory instanceof SubCategory, "defaultSubCategory should be instance of SubCategory"); if (defaultSubCategory instanceof SubCategory) { assert.isTrue(defaultSubCategory.parent.id === categoryId, "defaultSubCategory id should be prescribed value"); assert.isTrue(defaultSubCategory.getSubCategoryName() === category.code.value, "DefaultSubcategory name should match that of Category"); assert.isTrue(defaultSubCategory.isDefaultSubCategory, "isDefaultSubCategory should return true"); } // get the subcategories const subCategorySql = `SELECT ECInstanceId FROM ${SubCategory.classFullName} WHERE Parent.Id=:parentId`; // eslint-disable-next-line @typescript-eslint/no-deprecated imodel1.withPreparedStatement(subCategorySql, (subCategoryStatement) => { let numSubCategories = 0; subCategoryStatement.bindId("parentId", categoryId); while (DbResult.BE_SQLITE_ROW === subCategoryStatement.step()) { numSubCategories++; const subCategoryId = subCategoryStatement.getValue(0).getId(); const subCategory = imodel1.elements.getElement(subCategoryId); assert.isTrue(subCategory instanceof SubCategory); assert.isTrue(subCategory.parent.id === categoryId); } assert.isAtLeast(numSubCategories, 1, "Expected query to find at least one SubCategory"); }); } assert.isAtLeast(numCategories, 1, "Expected query to find some categories"); }); }); it("should be some 2d elements", () => { const sql = `SELECT ECInstanceId FROM ${DrawingGraphic.classFullName}`; // eslint-disable-next-line @typescript-eslint/no-deprecated imodel2.withPreparedStatement(sql, (statement) => { let numDrawingGraphics = 0; let found25 = false; let found26 = false; while (DbResult.BE_SQLITE_ROW === statement.step()) { numDrawingGraphics++; const drawingGraphicId = statement.getValue(0).getId(); const drawingGraphic = imodel2.elements.getElement({ id: drawingGraphicId, wantGeometry: true }); assert.exists(drawingGraphic); assert.isTrue(drawingGraphic.className === "DrawingGraphic", "Should be instance of DrawingGraphic"); assert.isTrue(drawingGraphic instanceof DrawingGraphic, "Is instance of DrawingGraphic"); assert.isTrue(drawingGraphic instanceof GeometricElement2d, "Is instance of GeometricElement2d"); if (Id64.getLocalId(drawingGraphic.id) === 0x25) { found25 = true; assert.isTrue(drawingGraphic.placement.origin.x === 0.0); assert.isTrue(drawingGraphic.placement.origin.y === 0.0); assert.isTrue(drawingGraphic.placement.angle.radians === 0.0); assert.isTrue(drawingGraphic.placement.bbox.low.x === 0.0); assert.isTrue(drawingGraphic.placement.bbox.low.y === 0.0); assert.isTrue(drawingGraphic.placement.bbox.high.x === 1.0); assert.isTrue(drawingGraphic.placement.bbox.high.y === 1.0); assert.isDefined(drawingGraphic.geom); } else if (Id64.getLocalId(drawingGraphic.id) === 0x26) { found26 = true; assert.isTrue(drawingGraphic.placement.origin.x === 1.0); assert.isTrue(drawingGraphic.placement.origin.y === 1.0); assert.isTrue(drawingGraphic.placement.angle.radians === 0.0); assert.isTrue(drawingGraphic.placement.bbox.low.x === 0.0); assert.isTrue(drawingGraphic.placement.bbox.low.y === 0.0); assert.isTrue(drawingGraphic.placement.bbox.high.x === 2.0); assert.isTrue(drawingGraphic.placement.bbox.high.y === 2.0); assert.isDefined(drawingGraphic.geom); } } assert.isAtLeast(numDrawingGraphics, 1, "Expected query to find some DrawingGraphics"); assert.isTrue(found25, "Expected to find a specific element"); assert.isTrue(found26, "Expected to find a specific element"); }); }); it("should be able to query for ViewDefinitionProps", () => { const viewDefinitionProps = imodel2.views.queryViewDefinitionProps(); // query for all ViewDefinitions assert.isAtLeast(viewDefinitionProps.length, 3); assert.isTrue(viewDefinitionProps[0].classFullName.includes("ViewDefinition")); assert.isFalse(viewDefinitionProps[1].isPrivate); const spatialViewDefinitionProps = imodel2.views.queryViewDefinitionProps("BisCore.SpatialViewDefinition"); // limit query to SpatialViewDefinitions assert.isAtLeast(spatialViewDefinitionProps.length, 3); assert.exists(spatialViewDefinitionProps[2].modelSelectorId); }); it("should iterate ViewDefinitions", () => { // imodel2 contains 3 SpatialViewDefinitions and no other views. let numViews = 0; let result = imodel2.views.iterateViews(IModelDb.Views.defaultQueryParams, (_view) => { ++numViews; return true; }); expect(result).to.be.true; expect(numViews).to.equal(3); // Query specifically for spatial views numViews = 0; result = imodel2.views.iterateViews({ from: "BisCore.SpatialViewDefinition" }, (view) => { if (view.isSpatialView()) ++numViews; return view.isSpatialView(); }); expect(result).to.be.true; expect(numViews).to.equal(3); // Query specifically for 2d views numViews = 0; result = imodel2.views.iterateViews({ from: "BisCore.ViewDefinition2d" }, (_view) => { ++numViews; return true; }); expect(result).to.be.true; expect(numViews).to.equal(0); // Terminate iteration on first view numViews = 0; result = imodel2.views.iterateViews(IModelDb.Views.defaultQueryParams, (_view) => { ++numViews; return false; }); expect(result).to.be.f