@itwin/core-frontend
Version:
iTwin.js frontend components
118 lines • 6.85 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 { FeatureAppearance, PlanarClipMaskMode, PlanarClipMaskPriority, PlanarClipMaskSettings } from "@itwin/core-common";
import { FeatureSymbology } from "./render/FeatureSymbology";
import { Range3d } from "@itwin/core-geometry";
/** The State of Planar Clip Mask applied to a reality model or background map.
* Handles loading models and their associated tiles for models that are used by masks but may not be otherwise loaded or displayed.
* @beta
*/
export class PlanarClipMaskState {
settings;
_tileTreeRefs;
_allLoaded = false;
_usingViewportOverrides = false;
_overridesModelVisibility = false;
_maskRange = Range3d.createNull();
constructor(settings) {
this.settings = settings;
}
static create(settings) {
return new PlanarClipMaskState(settings);
}
static fromJSON(props) {
return this.create(PlanarClipMaskSettings.fromJSON(props));
}
get usingViewportOverrides() { return this._usingViewportOverrides; }
;
/** @internal */
get overridesModelVisibility() { return this._overridesModelVisibility; }
discloseTileTrees(trees) {
if (this._tileTreeRefs)
this._tileTreeRefs.forEach((treeRef) => treeRef.discloseTileTrees(trees));
}
// Returns the TileTreeReferences for the models that need to be drawn to create the planar clip mask, and extend the maskRange if needed.
getTileTrees(context, classifiedModelId, maskRange) {
if (this.settings.mode === PlanarClipMaskMode.Priority) {
// For priority mode we simply want refs for all viewed models if the priority is higher than the mask priority.
// For this case, we don't need a maskRange so leave it as null.
const viewTrees = new Array();
const thisPriority = this.settings.priority === undefined ? PlanarClipMaskPriority.RealityModel : this.settings.priority;
for (const ref of context.viewport.getTileTreeRefs()) {
const tree = ref.treeOwner.load();
if (tree && tree.modelId !== classifiedModelId && ref.planarClipMaskPriority > thisPriority)
viewTrees.push(ref);
}
return viewTrees;
}
// For all other modes we need to let the tree refs in the view state decide which refs need to be drawn
// since batched tiles cannot turn on/off individual models just by their tile tree refs.
// Keep calling this until loaded so that the range is valid.
if (!this._allLoaded) {
this._tileTreeRefs = new Array();
if (this.settings.modelIds && context.viewport.view.isSpatialView()) {
context.viewport.view.collectMaskRefs(this.settings.modelIds, this._tileTreeRefs, maskRange);
}
this._allLoaded = this._tileTreeRefs.every((treeRef) => treeRef.treeOwner.load() !== undefined);
maskRange.clone(this._maskRange);
}
else // If already loaded, just set the maskRange to the saved maskRange.
this._maskRange.clone(maskRange);
return this._allLoaded ? this._tileTreeRefs : undefined;
}
// Returns any potential FeatureSymbology overrides for drawing the planar clip mask.
getPlanarClipMaskSymbologyOverrides(context, featureSymbologySource) {
this._usingViewportOverrides = this._overridesModelVisibility = false;
// First obtain a list of models that will need to be turned off for drawing the planar clip mask (only used for batched tile trees).
const overrideModels = context.viewport.view.isSpatialView() ? context.viewport.view.getModelsNotInMask(this.settings.modelIds, PlanarClipMaskMode.Priority === this.settings.mode) : undefined;
const noSubCategoryOrElementIds = !this.settings.subCategoryOrElementIds;
if (noSubCategoryOrElementIds && !overrideModels)
return undefined;
const ovrBasedOnContext = PlanarClipMaskMode.Priority === this.settings.mode || PlanarClipMaskMode.Models === this.settings.mode || noSubCategoryOrElementIds;
const viewport = overrideModels && ovrBasedOnContext ? context.viewport : undefined;
const overrides = FeatureSymbology.Overrides.withSource(featureSymbologySource, viewport);
if (overrideModels) {
this._overridesModelVisibility = true;
// overrideModels is used for batched models. For those, we need to create model overrides to turn off models that are
// not wanted in the mask (using transparency) no matter what mask mode is being used.
const appOff = FeatureAppearance.fromTransparency(1.0);
// For Priority or Models mode, we need to start with the current overrides and modify them
if (ovrBasedOnContext) {
this._usingViewportOverrides = true; // Set flag to use listener since context.viewport might change afterwards.
overrides.addInvisibleElementOverridesToNeverDrawn(); // need this for fully trans element overrides to not participate in mask
overrideModels.forEach((modelId) => {
overrides.override({ modelId, appearance: appOff, onConflict: "replace" });
});
return overrides;
}
// Otherwise, we just start with a default overrides and modify it.
overrideModels.forEach((modelId) => {
overrides.override({ modelId, appearance: appOff, onConflict: "replace" });
});
}
// Add overrides to turn things on or off based on the subcategories or elements in the mask settings.
switch (this.settings.mode) {
case PlanarClipMaskMode.IncludeElements: {
overrides.setAlwaysDrawnSet(this.settings.subCategoryOrElementIds, true);
return overrides;
}
case PlanarClipMaskMode.ExcludeElements: {
overrides.ignoreSubCategory = true;
overrides.setNeverDrawnSet(this.settings.subCategoryOrElementIds);
return overrides;
}
case PlanarClipMaskMode.IncludeSubCategories: {
for (const subCategoryId of this.settings.subCategoryOrElementIds)
overrides.setVisibleSubCategory(subCategoryId);
return overrides;
}
}
return undefined;
}
}
//# sourceMappingURL=PlanarClipMaskState.js.map