UNPKG

@itwin/core-frontend

Version:
282 lines • 11.8 kB
"use strict"; /*--------------------------------------------------------------------------------------------- * Copyright (c) Bentley Systems, Incorporated. All rights reserved. * See LICENSE.md in the project root for license terms and full copyright notice. *--------------------------------------------------------------------------------------------*/ Object.defineProperty(exports, "__esModule", { value: true }); exports.ViewCreator2d = void 0; /** @packageDocumentation * @module Views */ /* API for creating a 2D view from a given modelId and modelType (classFullName). Additional options (such as background color) can be passed during view creation. */ const core_bentley_1 = require("@itwin/core-bentley"); const core_common_1 = require("@itwin/core-common"); const core_geometry_1 = require("@itwin/core-geometry"); const DrawingViewState_1 = require("./DrawingViewState"); const ModelState_1 = require("./ModelState"); const SheetViewState_1 = require("./SheetViewState"); /** * API for creating a [[ViewState2d]] for a 2D model ([[GeometricModel2dState]]). @see [[ViewCreator3d]] to create a view for a 3d model. * Example usage: * ```ts * const viewCreator = new ViewCreator2d(imodel); * const models = await imodel.models.queryProps({ from: "BisCore.GeometricModel2d" }); * if (models.length > 0) * const view = await viewCreator.createViewForModel(models[0].id!); * ``` * @public * @extensions */ class ViewCreator2d { _imodel; // Types of 2D models the API supports static _drawingModelClasses = [ModelState_1.DrawingModelState.classFullName, ModelState_1.SectionDrawingModelState.classFullName]; static _sheetModelClasses = [ModelState_1.SheetModelState.classFullName]; /** * Constructs a ViewCreator2d using an [[IModelConnection]]. * @param _imodel [[IModelConnection]] to query for categories and/or models. */ constructor(_imodel) { this._imodel = _imodel; } /** * Creates and returns view for the 2D model id passed in. * @param modelId Id of the 2D model for the view. * @param [options] Options for creating the view. * @throws [IModelError]($common) If modelType is not supported. */ async createViewForModel(modelId, options) { const baseClassName = await this._getModelBaseClassName(modelId); const viewState = await this._createViewState2d(modelId, baseClassName.classFullName, options); try { await viewState.load(); } catch { } return viewState; } /** * Gets model base class name from id. * @param modelId of target model. * @throws [IModelError]($common) if modelId is invalid. */ async _getModelBaseClassName(modelId) { let baseClassName; const modelProps = await this._imodel.models.getProps(modelId); if (modelProps.length > 0) { const modelType = modelProps[0].classFullName; baseClassName = await this._imodel.findClassFor(modelType, undefined); } else throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadModel, "ViewCreator2d._getModelBaseClassName: modelId is invalid"); if (baseClassName === undefined) throw new core_common_1.IModelError(core_bentley_1.IModelStatus.WrongClass, "ViewCreator2d.getViewForModel: modelType is invalid"); return baseClassName; } /** * Creates view from any 2D model type (Drawing/SectionDrawing/Sheet) * @param modelId of target model. * @param modelType classFullName of target 2D model. * @param options for view creation. * @throws [IModelError]($common) if modelType is not supported. */ async _createViewState2d(modelId, modelType, options) { let viewState; if (this._isDrawingModelClass(modelType)) { const props = await this._createViewStateProps(modelId, options); viewState = DrawingViewState_1.DrawingViewState.createFromProps(props, this._imodel); } else if (this._isSheetModelClass(modelType)) { let props = await this._createViewStateProps(modelId, options); props = await this._addSheetViewProps(modelId, props); viewState = SheetViewState_1.SheetViewState.createFromProps(props, this._imodel); } else throw new core_common_1.IModelError(core_bentley_1.IModelStatus.WrongClass, "ViewCreator2d._createViewState2d: modelType not supported"); return viewState; } /** * Checks to see if given model is of [[DrawingModelState]]. * @param modelType classFullName of model. */ _isDrawingModelClass(modelType) { if (ViewCreator2d._drawingModelClasses.includes(modelType)) { return true; } return false; } /** * Checks to see if given model is of [[SheetModelState]]. * @param modelType classFullName of model. */ _isSheetModelClass(modelType) { if (ViewCreator2d._sheetModelClasses.includes(modelType)) { return true; } return false; } /** * Creates ViewStateProps for the model. ViewStateProps are composed of the 4 sets of Props below. * @param modelId of target model. * @param options for view creation. */ _createViewStateProps = async (modelId, options) => { // Use dictionary model in all props const dictionaryId = core_common_1.IModel.dictionaryId; const categories = await this._getAllCategories(); // Get bg color from options or default to white const bgColor = options?.bgColor ? options.bgColor : core_common_1.ColorDef.white; // model extents const modelProps = await this._imodel.models.queryExtents(modelId); const modelExtents = core_geometry_1.Range3d.fromJSON(modelProps[0]?.extents); let originX = modelExtents.low.x; let originY = modelExtents.low.y; let deltaX = modelExtents.xLength(); let deltaY = modelExtents.yLength(); // if vp aspect given, update model extents to fit view if (options?.vpAspect) { const modelAspect = deltaY / deltaX; if (modelAspect > options.vpAspect) { const xFix = deltaY / options.vpAspect; originX = originX - xFix / 2; deltaX = deltaX + xFix; } else if (modelAspect < options.vpAspect) { const yFix = deltaX * options.vpAspect; originY = originY - yFix / 2; deltaY = deltaY + yFix; } } const modelSelectorProps = { models: [modelId], code: core_common_1.Code.createEmpty(), model: dictionaryId, classFullName: "BisCore:ModelSelector", }; const categorySelectorProps = { categories, code: core_common_1.Code.createEmpty(), model: dictionaryId, classFullName: "BisCore:CategorySelector", }; const viewDefinitionProps = { baseModelId: modelId, categorySelectorId: "", displayStyleId: "", origin: { x: originX, y: originY }, delta: { x: deltaX, y: deltaY }, angle: { radians: 0 }, code: core_common_1.Code.createEmpty(), model: dictionaryId, classFullName: "BisCore:ViewDefinition2d", }; const displayStyleProps = { code: core_common_1.Code.createEmpty(), model: dictionaryId, classFullName: "BisCore:DisplayStyle2d", jsonProperties: { styles: { backgroundColor: bgColor.tbgr, }, }, }; const viewStateProps = { displayStyleProps, categorySelectorProps, modelSelectorProps, viewDefinitionProps, modelExtents, }; // merge seed view props if needed return options?.useSeedView ? this._mergeSeedView(modelId, viewStateProps) : viewStateProps; }; /** * Adds Sheet view props to given view props. * @param modelId of target model. * @param props input ViewStateProps. */ async _addSheetViewProps(modelId, props) { let width = 0; let height = 0; for await (const row of this._imodel.createQueryReader(`SELECT Width, Height FROM bis.Sheet WHERE ECInstanceId = ?`, core_common_1.QueryBinder.from([modelId]), { rowFormat: core_common_1.QueryRowFormat.UseJsPropertyNames })) { width = row.width; height = row.height; break; } const sheetProps = { model: modelId, code: { spec: "", scope: "" }, classFullName: "DrawingSheetModel", height, width, }; props.sheetAttachments = await this._getSheetAttachments(modelId); props.sheetProps = sheetProps; return props; } /** * Merges a seed view in the iModel with the passed view state props. It will be a no-op if there are no 2D views for target model. * @param modelId of target model. * @param props Input view props to be merged */ async _mergeSeedView(modelId, props) { const viewDefinitionId = await this._getViewDefinitionsIdForModel(modelId); // Return incase no viewDefinition found. if (viewDefinitionId === undefined) return props; const seedViewState = (await this._imodel.views.load(viewDefinitionId)); const seedViewStateProps = { categorySelectorProps: seedViewState.categorySelector.toJSON(), viewDefinitionProps: seedViewState.toJSON(), displayStyleProps: seedViewState.displayStyle.toJSON(), }; const mergedDisplayProps = seedViewStateProps.displayStyleProps; if (mergedDisplayProps.jsonProperties !== undefined) { mergedDisplayProps.jsonProperties.styles = { ...mergedDisplayProps.jsonProperties.styles, ...props.displayStyleProps.jsonProperties.styles, }; } return { ...seedViewStateProps, ...props, displayStyleProps: mergedDisplayProps }; } /** * Get all view definitions for a given model. * @param modelId of target model. */ async _getViewDefinitionsIdForModel(modelId) { const query = `SELECT ECInstanceId from Bis.ViewDefinition2D WHERE BaseModel.Id = ${modelId} AND isPrivate = false LIMIT 1`; const viewDefinitionsId = await this._executeQuery(query); return (viewDefinitionsId.length) > 0 ? viewDefinitionsId[0] : undefined; } /** * Get all drawing categories */ async _getAllCategories() { const query = "SELECT ECInstanceId from BisCore.DrawingCategory"; const categories = await this._executeQuery(query); return categories; } /** * Get all sheet attachments * @param modelId of target model. */ async _getSheetAttachments(modelId) { const query = `SELECT ECInstanceId FROM Bis.ViewAttachment WHERE Model.Id = ${modelId}`; const attachments = await this._executeQuery(query); return attachments; } /** * Helper function to execute ECSql queries. * @param query statement to execute. */ _executeQuery = async (query) => { const rows = []; for await (const row of this._imodel.createQueryReader(query, undefined, { rowFormat: core_common_1.QueryRowFormat.UseJsPropertyNames })) rows.push(row.id); return rows; }; } exports.ViewCreator2d = ViewCreator2d; //# sourceMappingURL=ViewCreator2d.js.map