UNPKG

@itwin/frontend-devtools

Version:

Debug menu and supporting UI widgets

371 lines • 16.4 kB
/*--------------------------------------------------------------------------------------------- * 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