UNPKG

@itwin/core-backend

Version:
139 lines 7.37 kB
/*--------------------------------------------------------------------------------------------- * 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 { CompressedId64Set, IModelStatus, OpenMode } from "@itwin/core-bentley"; import { LineSegment3d, Point3d, YawPitchRollAngles } from "@itwin/core-geometry"; import { Code, ColorByName, GeometryStreamBuilder, IModel, SubCategoryAppearance, } from "@itwin/core-common"; import { _nativeDb, ChannelControl, IModelJsFs, PhysicalModel, SpatialCategory, StandaloneDb, VolumeElement, } from "../../core-backend"; import { IModelTestUtils } from "../IModelTestUtils"; describe("Model geometry changes", () => { let imodel; let modelId; let categoryId; let lastChanges; before(async () => { const testFileName = IModelTestUtils.prepareOutputFile("ModelGeometryTracking", "ModelGeometryTracking.bim"); const seedFileName = IModelTestUtils.resolveAssetFile("test.bim"); IModelJsFs.copySync(seedFileName, testFileName); // Upgrade the schema to include the GeometryGuid and LastMod model properties. StandaloneDb.upgradeStandaloneSchemas(testFileName); imodel = StandaloneDb.openFile(testFileName, OpenMode.ReadWrite); imodel.channels.addAllowedChannel(ChannelControl.sharedChannelName); modelId = PhysicalModel.insert(imodel, IModel.rootSubjectId, "TestModel"); categoryId = SpatialCategory.insert(imodel, IModel.dictionaryId, "TestCategory", new SubCategoryAppearance({ color: ColorByName.darkRed })); imodel.saveChanges("set up"); imodel[_nativeDb].deleteAllTxns(); imodel.txns.onGeometryChanged.addListener((props) => lastChanges = props); }); after(async () => { imodel[_nativeDb].setGeometricModelTrackingEnabled(false); imodel.close(); }); function expectChanges(expected) { if (!expected) { expect(lastChanges).to.be.undefined; return; } expect(lastChanges).to.be.not.undefined; expect(Array.isArray(lastChanges)).to.be.true; expect(lastChanges.length).to.equal(1); const actual = lastChanges[0]; expect(actual.id).to.equal(modelId); const expectElements = (ids, exp) => { expect(undefined === ids).to.equal(undefined === exp); if (ids && exp) { const act = CompressedId64Set.decompressArray(ids); expect(act.length).to.equal(exp.length); expect(act.sort()).to.deep.equal(exp.sort()); } }; expectElements(actual.inserted?.ids, expected.inserted); expectElements(actual.updated?.ids, expected.updated); expectElements(actual.deleted, expected.deleted); lastChanges = undefined; } function expectNoChanges() { expect(lastChanges).to.be.undefined; } it("emits events", async () => { expect(imodel[_nativeDb].isGeometricModelTrackingSupported()).to.be.true; expect(imodel[_nativeDb].setGeometricModelTrackingEnabled(true).result).to.be.true; const builder = new GeometryStreamBuilder(); builder.appendGeometry(LineSegment3d.create(Point3d.createZero(), Point3d.create(5, 0, 0))); // Insert a geometric element. const props = { classFullName: VolumeElement.classFullName, model: modelId, category: categoryId, code: Code.createEmpty(), placement: { origin: new Point3d(1, 2, 0), angles: new YawPitchRollAngles(), }, geom: builder.geometryStream, }; const elemId0 = imodel.elements.insertElement(props); imodel.saveChanges("insert elem 0"); expectChanges({ modelId, inserted: [elemId0] }); // Modify the element without touching its geometry. props.userLabel = "new label"; props.id = elemId0; imodel.elements.updateElement(props); imodel.saveChanges("change label"); expectNoChanges(); // Modify the element's geometry. props.placement = { origin: new Point3d(2, 1, 0), angles: new YawPitchRollAngles() }; imodel.elements.updateElement(props); imodel.saveChanges("change placement"); expectChanges({ modelId, updated: [elemId0] }); // Insert another element. props.id = undefined; const elemId1 = imodel.elements.insertElement(props); imodel.saveChanges("insert elem 1"); expectChanges({ modelId, inserted: [elemId1] }); // Delete an element. imodel.elements.deleteElement(elemId0); imodel.saveChanges("delete elem 0"); expectChanges({ modelId, deleted: [elemId0] }); // Stop tracking geometry changes expect(imodel[_nativeDb].setGeometricModelTrackingEnabled(false).result).to.be.false; expect(imodel[_nativeDb].isGeometricModelTrackingSupported()).to.be.true; // Modify element's geometry. props.id = elemId1; props.placement = { origin: new Point3d(2, 10, 0), angles: new YawPitchRollAngles() }; imodel.elements.updateElement(props); imodel.saveChanges("change placement again without tracking"); expectNoChanges(); // Restart tracking and undo everything. expect(imodel[_nativeDb].setGeometricModelTrackingEnabled(true).result).to.be.true; expect(imodel.txns.reverseSingleTxn()).to.equal(IModelStatus.Success); expectChanges({ modelId, updated: [elemId1] }); expect(imodel.txns.reverseSingleTxn()).to.equal(IModelStatus.Success); expectChanges({ modelId, inserted: [elemId0] }); expect(imodel.txns.reverseSingleTxn()).to.equal(IModelStatus.Success); expectChanges({ modelId, deleted: [elemId1] }); expect(imodel.txns.reverseSingleTxn()).to.equal(IModelStatus.Success); expectChanges({ modelId, updated: [elemId0] }); expect(imodel.txns.reverseSingleTxn()).to.equal(IModelStatus.Success); expectNoChanges(); expect(imodel.txns.reverseSingleTxn()).to.equal(IModelStatus.Success); expectChanges({ modelId, deleted: [elemId0] }); // Redo everything. expect(imodel.txns.reinstateTxn()).to.equal(IModelStatus.Success); expectChanges({ modelId, inserted: [elemId0] }); expect(imodel.txns.reinstateTxn()).to.equal(IModelStatus.Success); expectNoChanges(); expect(imodel.txns.reinstateTxn()).to.equal(IModelStatus.Success); expectChanges({ modelId, updated: [elemId0] }); expect(imodel.txns.reinstateTxn()).to.equal(IModelStatus.Success); expectChanges({ modelId, inserted: [elemId1] }); expect(imodel.txns.reinstateTxn()).to.equal(IModelStatus.Success); expectChanges({ modelId, deleted: [elemId0] }); expect(imodel.txns.reinstateTxn()).to.equal(IModelStatus.Success); expectChanges({ modelId, updated: [elemId1] }); expect(imodel[_nativeDb].setGeometricModelTrackingEnabled(false).result).to.be.false; }); }); //# sourceMappingURL=GeometryChangeEvents.test.js.map