@itwin/core-frontend
Version:
iTwin.js frontend components
192 lines • 8.84 kB
JavaScript
/*---------------------------------------------------------------------------------------------
* 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.ViewCreator3d = void 0;
/** @packageDocumentation
* @module Views
*/
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 SpatialViewState_1 = require("./SpatialViewState");
/**
* API for creating a 3D default [[ViewState3d]] for an iModel. @see [[ViewCreator2d]] to create a view for a 2d model.
* Example usage:
* ```ts
* const viewCreator = new ViewCreator3d(imodel);
* const defaultView = await viewCreator.createDefaultView({skyboxOn: true});
* ```
* @public
* @extensions
*/
class ViewCreator3d {
_imodel;
/**
* Constructs a ViewCreator3d using an [[IModelConnection]].
* @param _imodel [[IModelConnection]] to query for categories and/or models.
*/
constructor(_imodel) {
this._imodel = _imodel;
}
/**
* Creates a default [[ViewState3d]] based on the model ids passed in. If no model ids are passed in, all 3D models in the iModel are used.
* @param [options] Options for creating the view.
* @param [modelIds] Ids of models to display in the view.
* @throws [IModelError]($common) If no 3d models are found in the iModel.
*/
async createDefaultView(options, modelIds) {
const rpcOptions = modelIds ? { modelIds: core_bentley_1.CompressedId64Set.sortAndCompress(modelIds) } : {};
const rpc = core_common_1.IModelReadRpcInterface.getClientForRouting(this._imodel.routingContext.token);
const serializedProps = await rpc.getCustomViewState3dData(this._imodel.getRpcProps(), rpcOptions);
const baseExtents = core_geometry_1.Range3d.fromJSON(serializedProps.modelExtents);
const props = await this._createViewStateProps(core_bentley_1.CompressedId64Set.decompressArray(serializedProps.modelIds), core_bentley_1.CompressedId64Set.decompressArray(serializedProps.categoryIds), baseExtents, options);
const viewState = SpatialViewState_1.SpatialViewState.createFromProps(props, this._imodel);
try {
await viewState.iModel.subcategories.loadAllUsedSpatialSubCategories();
await viewState.load();
}
catch {
}
if (options?.standardViewId)
viewState.setStandardRotation(options.standardViewId);
if (options?.allSubCategoriesVisible)
viewState.displayStyle.enableAllLoadedSubCategories(viewState.categorySelector.categories);
const range = viewState.computeFitRange({ baseExtents });
viewState.lookAtVolume(range, options?.vpAspect);
return viewState;
}
/**
* Generates a view state props object for creating a view. Merges display styles with a seed view if the options.useSeedView is true
* @param models Models to put in view props
* @param options view creation options like camera On and skybox On
*/
async _createViewStateProps(models, categories, modelExtents, options) {
// Use dictionary model in all props
const dictionaryId = core_common_1.IModel.dictionaryId;
if (modelExtents.isNull)
modelExtents.setFrom(this._imodel.projectExtents);
let originX = modelExtents.low.x;
let originY = modelExtents.low.y;
const originZ = modelExtents.low.z;
let deltaX = modelExtents.xLength();
let deltaY = modelExtents.yLength();
const deltaZ = modelExtents.zLength();
// 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 categorySelectorProps = {
categories,
code: core_common_1.Code.createEmpty(),
model: dictionaryId,
classFullName: "BisCore:CategorySelector",
};
const modelSelectorProps = {
models,
code: core_common_1.Code.createEmpty(),
model: dictionaryId,
classFullName: "BisCore:ModelSelector",
};
const cameraData = new core_common_1.Camera();
const cameraOn = options?.cameraOn !== false;
const viewDefinitionProps = {
categorySelectorId: "",
displayStyleId: "",
code: core_common_1.Code.createEmpty(),
model: dictionaryId,
origin: { x: originX, y: originY, z: originZ },
extents: { x: deltaX, y: deltaY, z: deltaZ },
classFullName: "BisCore:SpatialViewDefinition",
cameraOn,
camera: {
lens: cameraData.lens.toJSON(),
focusDist: cameraData.focusDist,
eye: cameraData.eye.toJSON(),
},
};
const displayStyleProps = {
code: core_common_1.Code.createEmpty(),
model: dictionaryId,
classFullName: "BisCore:DisplayStyle3d",
jsonProperties: {
styles: {
viewflags: {
renderMode: core_common_1.RenderMode.SmoothShade,
noSourceLights: false,
noCameraLights: false,
noSolarLight: false,
noConstruct: true,
noTransp: false,
visEdges: false,
backgroundMap: this._imodel.isGeoLocated,
},
environment: options !== undefined &&
options.skyboxOn !== undefined &&
options.skyboxOn
? core_common_1.Environment.defaults.withDisplay({ sky: true }).toJSON()
: undefined,
},
},
};
const viewStateProps = {
displayStyleProps,
categorySelectorProps,
modelSelectorProps,
viewDefinitionProps,
};
// merge seed view props if needed
return options?.useSeedView ? this._mergeSeedView(viewStateProps) : viewStateProps;
}
/**
* Merges a seed view in the iModel with the passed view state props. It will be a no-op if there are no default 3D views in the iModel
* @param viewStateProps Input view props to be merged
*/
async _mergeSeedView(viewStateProps) {
const viewId = await this._getDefaultViewId();
// Handle iModels without any default view id
if (viewId === undefined)
return viewStateProps;
const seedViewState = await this._imodel.views.load(viewId);
const seedViewStateProps = {
categorySelectorProps: seedViewState.categorySelector.toJSON(),
modelSelectorProps: seedViewState.modelSelector.toJSON(),
viewDefinitionProps: seedViewState.toJSON(),
displayStyleProps: seedViewState.displayStyle.toJSON(),
};
const mergedDisplayProps = seedViewStateProps.displayStyleProps;
if (mergedDisplayProps.jsonProperties !== undefined) {
mergedDisplayProps.jsonProperties.styles = {
...mergedDisplayProps.jsonProperties.styles,
...viewStateProps.displayStyleProps.jsonProperties.styles,
};
}
return { ...seedViewStateProps, ...viewStateProps, displayStyleProps: mergedDisplayProps };
}
/**
* Get the Id of the default view.
*/
async _getDefaultViewId() {
// eslint-disable-next-line @typescript-eslint/no-deprecated
const viewId = await this._imodel.views.queryDefaultViewId();
if (viewId !== core_bentley_1.Id64.invalid)
return viewId;
// Return the first spatial view
const viewList = await this._imodel.views.getViewList({ wantPrivate: false, limit: 1, from: SpatialViewState_1.SpatialViewState.classFullName });
return viewList.length === 0 ? undefined : viewList[0].id;
}
}
exports.ViewCreator3d = ViewCreator3d;
//# sourceMappingURL=ViewCreator3d.js.map
;