@itwin/core-frontend
Version:
iTwin.js frontend components
203 lines • 10.2 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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