如何将2个bim中的图形模型显示在一个视图中 我们通过TiledGraphicsProvider接口可以实现将2个bim中的图形模型显示在同一个视图中。
示例如下所示:
现有V1.bim,其预览如下所示:
有V2.bim,其预览如下所示:
我们首先在APP中加载并预览V1.bim,然后通过TiledGraphicsProvider接口,导入V2.bim中的Tile内容,即可得到如下所示预览内容:
核心代码如下所示:
async function addFeatureSymbology() { const vp = IModelApp.viewManager.selectedView; if (vp) { await addProvider(vp); } } async function removeFeatureSymbology() { const vp = IModelApp.viewManager.selectedView; if (vp) { await removeProvider(vp); } } /** 对TileTree的引用源自与用户打开的对象不同的IModelConnection */ class ExternalTreeRef extends TileTreeReference { private readonly _ref: TileTreeReference; private readonly _ovrs: FeatureSymbology.Overrides; public constructor(ref: TileTreeReference, ovrs: FeatureSymbology.Overrides) { super(); this._ref = ref; this._ovrs = ovrs; } public get castsShadows() { return this._ref.castsShadows; } public get treeOwner() { return this._ref.treeOwner; } public addToScene(context: SceneContext): void { const tree = this.treeOwner.load(); if (undefined === tree) return; // ###TODO transform const args = this.createDrawArgs(context); if (undefined === args) return; tree.draw(args); args.graphics.symbologyOverrides = this._ovrs; const branch = context.createBranch(args.graphics, args.location); context.outputGraphic(branch); } } class Provider implements TiledGraphicsProvider { private readonly _refs: TileTreeReference[] = []; public readonly iModel: IModelConnection; private constructor( vp: Viewport, iModel: IModelConnection, ovrs: FeatureSymbology.Overrides ) { this.iModel = iModel; for (const kvp of iModel.models.loaded) { const spatial = kvp[1].asSpatialModel; if (undefined !== spatial) { const ref = spatial.createTileTreeReference(vp.view); this._refs.push(new ExternalTreeRef(ref, ovrs)); } } } public static async create( vp: Viewport, iModel: IModelConnection ): Promise<Provider> { const query = { from: SpatialModelState.classFullName, wantPrivate: false }; const props = await iModel.models.queryProps(query); const modelIds = []; for (const prop of props) if (undefined !== prop.id) modelIds.push(prop.id); await iModel.models.load(modelIds); // Enable all categories (and subcategories thereof) const ecsql = "SELECT DISTINCT Category.Id as CategoryId from BisCore.GeometricElement3d WHERE Category.Id IN (SELECT ECInstanceId from BisCore.SpatialCategory)"; const catIds: string[] = []; for await (const catId of iModel.query(ecsql)) catIds.push(catId.categoryId); const subcatsRequest = iModel.subcategories.load(catIds); if (undefined !== subcatsRequest) await subcatsRequest.promise; // Ignore the symbology overrides defined on the viewport - instead, set up our own to draw our iModel's categories. const ovrs = new FeatureSymbology.Overrides(); for (const catId of catIds) { const subcats = iModel.subcategories.getSubCategories(catId); if (undefined !== subcats) for (const subcat of subcats) ovrs.setVisibleSubCategory(subcat); } return new Provider(vp, iModel, ovrs); } public forEachTileTreeRef( _vp: Viewport, func: (ref: TileTreeReference) => void ): void { for (const ref of this._refs) func(ref); } } const providersByViewport = new Map<Viewport, Provider>(); /** A simple proof-of-concept for drawing tiles from a different IModelConnection into a Viewport. */ export async function addProvider(vp: Viewport): Promise<void> { const existing = providersByViewport.get(vp); if (undefined !== existing) { vp.dropTiledGraphicsProvider(existing); providersByViewport.delete(vp); await existing.iModel.close(); return; } const filename = Config.App.getString("imjs_offline_imodel_Next"); if (undefined === filename) return; let iModel; try { iModel = await SnapshotConnection.openFile(filename); const provider = await Provider.create(vp, iModel); providersByViewport.set(vp, provider); vp.addTiledGraphicsProvider(provider); } catch (err) { alert(err.toString()); } } export async function removeProvider(vp: Viewport): Promise<void> { const existing = providersByViewport.get(vp); if (undefined !== existing) { vp.dropTiledGraphicsProvider(existing); providersByViewport.delete(vp); await existing.iModel.close(); } else { alert("Provider不存在."); } }