@itwin/frontend-devtools
Version:
Debug menu and supporting UI widgets
371 lines • 16.4 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
import { PlanarClipMaskMode, PlanarClipMaskPriority, PlanarClipMaskSettings } from "@itwin/core-common";
import { EventHandled, IModelApp, LocateFilterStatus, LocateResponse, PrimitiveTool, Tool, } from "@itwin/core-frontend";
import { parseBoolean } from "./parseBoolean";
/** Set Map Masking by selected models.
* @beta
*/
export class SetMapHigherPriorityMasking extends Tool {
static toolId = "SetMapHigherPriorityMask";
static get minArgs() { return 0; }
static get maxArgs() { return 2; }
async run(transparency, invert) {
const vp = IModelApp.viewManager.selectedView;
if (undefined === vp)
return false;
vp.changeBackgroundMapProps({ planarClipMask: { mode: PlanarClipMaskMode.Priority, priority: PlanarClipMaskPriority.BackgroundMap, transparency, invert } });
vp.invalidateRenderPlan();
return true;
}
async parseAndRun(...args) {
const transparency = parseFloat(args[0]);
let invert;
if (args.length > 1)
invert = parseBoolean(args[1]);
return this.run((transparency !== undefined && transparency < 1.0) ? transparency : 0, invert === true);
}
}
/** Unmask Mask.
* @beta
*/
export class UnmaskMapTool extends Tool {
static toolId = "UnmaskMap";
static get minArgs() { return 0; }
static get maxArgs() { return 0; }
async run() {
const vp = IModelApp.viewManager.selectedView;
if (undefined === vp)
return false;
vp.changeBackgroundMapProps({ planarClipMask: { mode: PlanarClipMaskMode.None, transparency: 0, invert: false } });
vp.invalidateRenderPlan();
return true;
}
}
/** Base class for the reality model planar masking tools.
* @beta
*/
export class PlanarMaskBaseTool extends PrimitiveTool {
_acceptedModelIds = new Set();
_acceptedSubCategoryIds = new Set();
_acceptedElementIds = new Set();
_transparency = 0;
_useSelection = false;
_invert = false;
_targetMaskModel;
requireWriteableTarget() { return false; }
async onPostInstall() {
await super.onPostInstall();
this.setupAndPromptForNextAction();
}
async onUnsuspend() { this.showPrompt(); }
setupAndPromptForNextAction() {
this._useSelection = (undefined !== this.targetView && this.iModel.selectionSet.isActive);
this.initLocateElements(!this._useSelection || (this.targetModelRequired() && !this._targetMaskModel));
IModelApp.locateManager.options.allowDecorations = true; // So we can select "contextual" reality models.
this.showPrompt();
}
targetModelRequired() { return true; }
elementRequired() { return true; }
allowSelection() { return true; }
clearIds() {
this._acceptedElementIds.clear();
this._acceptedModelIds.clear();
}
async exitTool() {
await super.exitTool();
this._transparency = 0;
}
async onRestartTool() {
this.clearIds();
this._acceptedSubCategoryIds.clear();
const tool = this.createToolInstance();
if (!await tool.run())
await this.exitTool();
}
async parseAndRun(...args) {
const transparency = parseFloat(args[0]);
this._transparency = (transparency !== undefined && transparency < 1.0) ? transparency : 0;
if (args.length > 1)
this._invert = parseBoolean(args[1]) === true;
return this.run();
}
async onCleanup() {
if (0 !== this._acceptedElementIds.size)
this.iModel.hilited.remove({ elements: this._acceptedElementIds });
this.clearIds();
}
async filterHit(hit, _out) {
if (!hit.modelId)
return LocateFilterStatus.Reject;
if (undefined === this._targetMaskModel && this.targetModelRequired()) {
if (undefined !== hit.viewport.displayStyle.contextRealityModelStates.find((x) => x.modelId === hit.modelId))
return LocateFilterStatus.Accept;
const model = this.iModel.models.getLoaded(hit.modelId)?.asSpatialModel;
return model?.isRealityModel ? LocateFilterStatus.Accept : LocateFilterStatus.Reject;
}
else
return (hit.isElementHit && !hit.isModelHit && !this._acceptedElementIds.has(hit.sourceId)) ? LocateFilterStatus.Accept : LocateFilterStatus.Reject;
}
async onDataButtonDown(ev) {
const hit = await IModelApp.locateManager.doLocate(new LocateResponse(), true, ev.point, ev.viewport, ev.inputSource);
const vp = IModelApp.viewManager.selectedView;
if (undefined === vp)
return EventHandled.No;
if (undefined !== hit && undefined === this._targetMaskModel && this.targetModelRequired()) {
if (hit.modelId) {
this._targetMaskModel = hit.viewport.displayStyle.contextRealityModelStates.find((x) => x.modelId === hit.modelId) ?? hit.modelId;
if (!this.elementRequired()) {
this.applyMask(vp);
await this.onRestartTool();
}
}
}
else if (this._useSelection && this.iModel.selectionSet.isActive) {
const elements = await this.iModel.elements.getProps(this.iModel.selectionSet.elements);
for (const element of elements) {
if (element.id && element.model) {
this._acceptedElementIds.add(element.id);
this._acceptedModelIds.add(element.model);
}
}
this.applyMask(vp);
await this.exitTool();
return EventHandled.No;
}
else if (undefined !== hit && hit.isElementHit) {
const sourceId = hit.sourceId;
if (!this._acceptedElementIds.has(sourceId)) {
this._acceptedElementIds.add(sourceId);
this._acceptedModelIds.add(hit.modelId);
if (hit.subCategoryId)
this._acceptedSubCategoryIds.add(hit.subCategoryId);
this.applyMask(vp);
}
}
this.setupAndPromptForNextAction();
return EventHandled.No;
}
createSubCategoryMask() {
return PlanarClipMaskSettings.create({
subCategoryIds: this._acceptedSubCategoryIds,
modelIds: this._acceptedModelIds,
transparency: this._transparency,
invert: this._invert,
});
}
createElementMask(option) {
return PlanarClipMaskSettings.create({
elementIds: this._acceptedElementIds,
exclude: "exclude" === option,
modelIds: this._acceptedModelIds,
transparency: this._transparency,
invert: this._invert,
});
}
createModelMask() {
return PlanarClipMaskSettings.create({ modelIds: this._acceptedModelIds, transparency: this._transparency, invert: this._invert });
}
setRealityModelMask(vp, mask) {
if (typeof this._targetMaskModel === "string")
vp.displayStyle.settings.planarClipMasks.set(this._targetMaskModel, mask);
else if (undefined !== this._targetMaskModel)
this._targetMaskModel.planarClipMaskSettings = mask;
}
}
/** Tool to mask background map by elements
* @beta
*/
export class MaskBackgroundMapByElementTool extends PlanarMaskBaseTool {
static toolId = "MaskBackgroundMapByElement";
static get minArgs() { return 0; }
static get maxArgs() { return 2; }
targetModelRequired() { return false; }
showPrompt() {
IModelApp.notifications.outputPromptByKey(`FrontendDevTools:tools.MaskBackgroundMapByElement.Prompts.${this._useSelection ? "AcceptSelection" : "IdentifyMaskElement"}`);
}
createToolInstance() { return new MaskBackgroundMapByElementTool(); }
applyMask(vp) {
vp.changeBackgroundMapProps({ planarClipMask: this.createElementMask("include").toJSON() });
}
}
/** Tool to mask background map by excluded elements
* @beta
*/
export class MaskBackgroundMapByExcludedElementTool extends PlanarMaskBaseTool {
static toolId = "MaskBackgroundMapByExcludedElement";
static get minArgs() { return 0; }
static get maxArgs() { return 2; }
targetModelRequired() { return false; }
showPrompt() {
IModelApp.notifications.outputPromptByKey(`FrontendDevTools:tools.MaskBackgroundMapByExcludedElement.Prompts.${this._useSelection ? "AcceptSelection" : "IdentifyMaskElement"}`);
}
createToolInstance() { return new MaskBackgroundMapByExcludedElementTool(); }
applyMask(vp) {
vp.changeBackgroundMapProps({ planarClipMask: this.createElementMask("exclude").toJSON() });
}
}
/** Tool to mask background map by SubCategories
* @beta
*/
export class MaskBackgroundMapBySubCategoryTool extends PlanarMaskBaseTool {
static toolId = "MaskBackgroundMapBySubCategory";
static get minArgs() { return 0; }
static get maxArgs() { return 2; }
targetModelRequired() { return false; }
allowSelection() { return false; } // Need picking to get subcategory.
showPrompt() {
IModelApp.notifications.outputPromptByKey("FrontendDevTools:tools.MaskBackgroundMapBySubCategory.Prompts.IdentifyMaskSubCategory");
}
createToolInstance() { return new MaskBackgroundMapBySubCategoryTool(); }
applyMask(vp) {
vp.changeBackgroundMapProps({ planarClipMask: this.createSubCategoryMask().toJSON() });
}
}
/** Tool to mask background map by geometric models
* @beta
*/
export class MaskBackgroundMapByModelTool extends PlanarMaskBaseTool {
static toolId = "MaskBackgroundMapByModel";
static get minArgs() { return 0; }
static get maxArgs() { return 2; }
targetModelRequired() { return false; }
showPrompt() {
IModelApp.notifications.outputPromptByKey(`FrontendDevTools:tools.MaskBackgroundMapByModel.Prompts.${this._useSelection ? "AcceptSelection" : "IdentifyMaskModel"}`);
}
createToolInstance() { return new MaskBackgroundMapByModelTool(); }
applyMask(vp) {
vp.changeBackgroundMapProps({ planarClipMask: this.createModelMask().toJSON() });
}
}
/** Tool to mask reality model by elements
* @beta
*/
export class MaskRealityModelByElementTool extends PlanarMaskBaseTool {
static toolId = "MaskRealityModelByElement";
static get minArgs() { return 0; }
static get maxArgs() { return 2; }
targetModelRequired() { return true; }
showPrompt() {
const key = `FrontendDevTools:tools.MaskRealityModelByElement.Prompts.${this._targetMaskModel === undefined ? "IdentifyRealityModel" : (this._useSelection ? "AcceptSelection" : "IdentifyMaskElement")}`;
IModelApp.notifications.outputPromptByKey(key);
}
createToolInstance() { return new MaskRealityModelByElementTool(); }
applyMask(vp) {
this.setRealityModelMask(vp, this.createElementMask("include"));
}
}
/** Tool to mask reality model by excluded elements
* @beta
*/
export class MaskRealityModelByExcludedElementTool extends PlanarMaskBaseTool {
static toolId = "MaskRealityModelByExcludedElement";
static get minArgs() { return 0; }
static get maxArgs() { return 2; }
targetModelRequired() { return true; }
showPrompt() {
const key = `FrontendDevTools:tools.MaskRealityModelByExcludedElement.Prompts.${this._targetMaskModel === undefined ? "IdentifyRealityModel" : (this._useSelection ? "AcceptSelection" : "IdentifyMaskElement")}`;
IModelApp.notifications.outputPromptByKey(key);
}
createToolInstance() { return new MaskRealityModelByExcludedElementTool(); }
applyMask(vp) {
this.setRealityModelMask(vp, this.createElementMask("exclude"));
}
}
/** Tool to mask reality model by geometric models
* @beta
*/
export class MaskRealityModelByModelTool extends PlanarMaskBaseTool {
static toolId = "MaskRealityModelByModel";
static get minArgs() { return 0; }
static get maxArgs() { return 2; }
targetModelRequired() { return true; }
showPrompt() {
const key = `FrontendDevTools:tools.MaskRealityModelByModel.Prompts.${this._targetMaskModel === undefined ? "IdentifyRealityModel" : (this._useSelection ? "AcceptSelection" : "IdentifyMaskModel")}`;
IModelApp.notifications.outputPromptByKey(key);
}
createToolInstance() { return new MaskRealityModelByModelTool(); }
applyMask(vp) {
this.setRealityModelMask(vp, this.createModelMask());
}
}
/** Tool to mask reality model by SubCategories
* @beta
*/
export class MaskRealityModelBySubCategoryTool extends PlanarMaskBaseTool {
static toolId = "MaskRealityModelBySubCategory";
static get minArgs() { return 0; }
static get maxArgs() { return 2; }
targetModelRequired() { return true; }
allowSelection() { return false; } // Need picking to get subcategory.
showPrompt() {
const key = `FrontendDevTools:tools.MaskRealityModelByModel.Prompts.${this._targetMaskModel === undefined ? "IdentifyRealityModel" : "IdentifyMaskSubCategory"}`;
IModelApp.notifications.outputPromptByKey(key);
}
createToolInstance() { return new MaskRealityModelBySubCategoryTool(); }
applyMask(vp) {
this.setRealityModelMask(vp, this.createSubCategoryMask());
}
}
/** Tool to mask reality model by higher priority models.
* @beta
*/
export class SetHigherPriorityRealityModelMasking extends PlanarMaskBaseTool {
static toolId = "SetHigherPriorityRealityModelMasking";
static get minArgs() { return 0; }
static get maxArgs() { return 3; }
targetModelRequired() { return true; }
elementRequired() { return false; }
_priority = 0;
showPrompt() {
IModelApp.notifications.outputPromptByKey("FrontendDevTools:tools.SetHigherPriorityRealityModelMasking.Prompts.IdentifyRealityModel");
}
createToolInstance() { return new SetHigherPriorityRealityModelMasking(); }
applyMask(vp) {
const basePriority = this._targetMaskModel === vp.displayStyle.getOSMBuildingRealityModel() ? PlanarClipMaskPriority.GlobalRealityModel : PlanarClipMaskPriority.RealityModel;
this.setRealityModelMask(vp, PlanarClipMaskSettings.create({ priority: basePriority + this._priority, transparency: this._transparency, invert: this._invert }));
}
async parseAndRun(...args) {
await super.parseAndRun(...args);
const priority = parseInt(args[0], 10);
this._priority = (priority === undefined || isNaN(priority)) ? 0 : priority;
if (args.length > 1) {
const value = parseInt(args[1], 10);
if (!isNaN(value) && value >= 0 && value <= 1)
this._transparency = value;
}
if (args.length > 2)
this._invert = parseBoolean(args[2]) === true;
return this.run();
}
}
/** Remove masks from reality model.
* @beta
*/
export class UnmaskRealityModelTool extends PlanarMaskBaseTool {
static toolId = "UnmaskRealityModel";
targetModelRequired() { return true; }
showPrompt() {
IModelApp.notifications.outputPromptByKey("FrontendDevTools:tools.UnmaskRealityModel.Prompts.IdentifyRealityModel");
}
createToolInstance() { return new UnmaskRealityModelTool(); }
applyMask(vp) {
const settings = PlanarClipMaskSettings.create({ subCategoryIds: this._acceptedSubCategoryIds, modelIds: this._acceptedModelIds });
this.setRealityModelMask(vp, settings);
}
async onDataButtonDown(ev) {
const hit = await IModelApp.locateManager.doLocate(new LocateResponse(), true, ev.point, ev.viewport, ev.inputSource);
if (hit?.modelId) {
const model = hit.viewport.displayStyle.contextRealityModelStates.find((x) => x.modelId === hit.modelId);
if (model)
model.planarClipMaskSettings = undefined;
else
hit.viewport.displayStyle.settings.planarClipMasks.delete(hit.modelId);
await this.onRestartTool();
}
return EventHandled.No;
}
}
//# sourceMappingURL=PlanarMaskTools.js.map