UNPKG

@itwin/core-frontend

Version:
203 lines • 10.2 kB
/*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Views */ import { compareStrings, Id64, SortedArray } from "@itwin/core-bentley"; /** Per-model category visibility permits the visibility of categories within a [[Viewport]] displaying a [[SpatialViewState]] to be overridden in * the context of individual [[GeometricModelState]]s. * If a category's visibility is overridden for a given model, then elements belonging to that category within that model will be displayed or hidden regardless of the category's inclusion in the Viewport's [[CategorySelectorState]]. * The override affects geometry on all subcategories belonging to the overridden category. That is, if the category is overridden to be visible, then geometry on all subcategories of the category * will be visible, regardless of any [SubCategoryOverride]($common)s applied by the view's [[DisplayStyleState]]. * @see [[Viewport.perModelCategoryVisibility]] to define the per-model category visibility for a viewport. * @public * @extensions */ export var PerModelCategoryVisibility; (function (PerModelCategoryVisibility) { /** Describes whether and how a category's visibility is overridden. */ let Override; (function (Override) { /** The category's visibility is not overridden; its visibility is wholly controlled by the [[Viewport]]'s [[CategorySelectorState]]. */ Override[Override["None"] = 0] = "None"; /** The category is overridden to be visible. */ Override[Override["Show"] = 1] = "Show"; /** The category is overridden to be invisible. */ Override[Override["Hide"] = 2] = "Hide"; })(Override = PerModelCategoryVisibility.Override || (PerModelCategoryVisibility.Override = {})); function createOverrides(viewport) { return new PerModelCategoryVisibilityOverrides(viewport); } PerModelCategoryVisibility.createOverrides = createOverrides; })(PerModelCategoryVisibility || (PerModelCategoryVisibility = {})); class PerModelCategoryVisibilityOverride { modelId; categoryId; visible; constructor(modelId, categoryId, visible) { this.modelId = modelId; this.categoryId = categoryId; this.visible = visible; } reset(modelId, categoryId, visible) { this.modelId = modelId; this.categoryId = categoryId; this.visible = visible; } } function compareCategoryOverrides(lhs, rhs) { const cmp = compareStrings(lhs.modelId, rhs.modelId); return 0 === cmp ? compareStrings(lhs.categoryId, rhs.categoryId) : cmp; } /** The Viewport-specific implementation of PerModelCategoryVisibility.Overrides. */ class PerModelCategoryVisibilityOverrides extends SortedArray { _scratch = new PerModelCategoryVisibilityOverride("0", "0", false); _vp; constructor(vp) { super(compareCategoryOverrides); this._vp = vp; } getOverride(modelId, categoryId) { this._scratch.reset(modelId, categoryId, false); const ovr = this.findEqual(this._scratch); if (undefined !== ovr) return ovr.visible ? PerModelCategoryVisibility.Override.Show : PerModelCategoryVisibility.Override.Hide; else return PerModelCategoryVisibility.Override.None; } /** * set the overrides for multiple perModelCategoryVisibility props, loading categoryIds from the iModel if necessary. * @see [[PerModelCategoryVisibility]] * @param perModelCategoryVisibility array of model category visibility overrides @see [[PerModelCategoryVisibility.Props]] * @param iModel Optional param iModel. If no iModel is provided, then the iModel associated with the viewport (used to construct this class) is used. * This optional iModel param is useful for apps which may show multiple iModels at once. Passing in an iModel ensures that the subcategories cache for the provided iModel * is populated as opposed to the iModel associated with the viewport which may or may not be an empty iModel. * @returns a promise that resolves once the overrides have been applied. */ async setOverrides(perModelCategoryVisibility, iModel) { let anyChanged = false; const catIdsToLoad = []; const iModelToUse = iModel ? iModel : this._vp.iModel; for (const override of perModelCategoryVisibility) { const modelId = override.modelId; // The caller may pass a single categoryId as a string, if we don't convert this to an array we will iterate // over each individual character of that string, which is not the desired behavior. const categoryIds = typeof override.categoryIds === "string" ? [override.categoryIds] : override.categoryIds; const visOverride = override.visOverride; for (const categoryId of categoryIds) { if (this.findAndUpdateOverrideInArray(modelId, categoryId, visOverride)) { anyChanged = true; if (PerModelCategoryVisibility.Override.None !== visOverride) { catIdsToLoad.push(categoryId); } } } } if (anyChanged) { this._vp.setViewedCategoriesPerModelChanged(); if (catIdsToLoad.length !== 0) { this._vp.subcategories.push(iModelToUse.subcategories, catIdsToLoad, () => this._vp.setViewedCategoriesPerModelChanged()); } } return; } /** Find and update the override in the array of overrides. If override not found, adds it to the array. * If the array was changed, returns true. */ findAndUpdateOverrideInArray(modelId, categoryId, override) { const ovr = this._scratch; ovr.reset(modelId, categoryId, false); let changed = false; const index = this.indexOf(ovr); if (-1 === index) { if (PerModelCategoryVisibility.Override.None !== override) { this.insert(new PerModelCategoryVisibilityOverride(modelId, categoryId, PerModelCategoryVisibility.Override.Show === override)); changed = true; } } else { if (PerModelCategoryVisibility.Override.None === override) { this._array.splice(index, 1); changed = true; } else if (this._array[index].visible !== (PerModelCategoryVisibility.Override.Show === override)) { this._array[index].visible = (PerModelCategoryVisibility.Override.Show === override); changed = true; } } return changed; } setOverride(modelIds, categoryIds, override) { let changed = false; for (const modelId of Id64.iterable(modelIds)) { for (const categoryId of Id64.iterable(categoryIds)) { if (this.findAndUpdateOverrideInArray(modelId, categoryId, override)) changed = true; } } if (changed) { this._vp.setViewedCategoriesPerModelChanged(); if (PerModelCategoryVisibility.Override.None !== override) { // Ensure subcategories loaded. this._vp.subcategories.push(this._vp.iModel.subcategories, categoryIds, () => this._vp.setViewedCategoriesPerModelChanged()); } } } clearOverrides(modelIds) { if (undefined === modelIds) { if (0 < this.length) { this.clear(); this._vp.setViewedCategoriesPerModelChanged(); } return; } for (let i = 0; i < this.length;) { const ovr = this._array[i]; let removed = false; for (const modelId of Id64.iterable(modelIds)) { if (modelId === ovr.modelId) { this._array.splice(i, 1); this._vp.setViewedCategoriesPerModelChanged(); removed = true; break; } } if (!removed) ++i; } } addOverrides(fs, ovrs) { const cache = this._vp.iModel.subcategories; for (const ovr of this._array) { const subcats = cache.getSubCategories(ovr.categoryId); if (undefined === subcats) continue; // It's pointless to override for models which aren't displayed...except if we do this, and then someone enables that model, // we would need to regenerate our symbology overrides in response. Preferably people wouldn't bother overriding models that // they don't want us to draw... /* if (!this._vp.view.viewsModel(ovr.modelId)) continue; */ // ###TODO: Avoid recomputing upper and lower portions of modelId if modelId repeated. // (Array is sorted first by modelId). // Also avoid computing if no effective overrides. const modelLo = Id64.getLowerUint32(ovr.modelId); const modelHi = Id64.getUpperUint32(ovr.modelId); for (const subcat of subcats) { const subcatLo = Id64.getLowerUint32(subcat); const subcatHi = Id64.getUpperUint32(subcat); const vis = fs.isSubCategoryVisible(subcatLo, subcatHi); if (vis !== ovr.visible) { // Only care if visibility differs from that defined for entire view let entry = ovrs.get(modelLo, modelHi); if (undefined === entry) { entry = new Id64.Uint32Set(); ovrs.set(modelLo, modelHi, entry); } entry.add(subcatLo, subcatHi); } } } } } //# sourceMappingURL=PerModelCategoryVisibility.js.map