@itwin/core-frontend
Version:
iTwin.js frontend components
225 lines • 10.1 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 Tiles
*/
import { request } from "./request/Request";
import { assert, Logger } from "@itwin/core-bentley";
import { RealityDataFormat, RealityDataProvider } from "@itwin/core-common";
import { FrontendLoggerCategory } from "./common/FrontendLoggerCategory";
import { IModelApp } from "./IModelApp";
import { OPCFormatInterpreter, ThreeDTileFormatInterpreter } from "./tile/internal";
/** This class provides access to the reality data provider services.
* It encapsulates access to a reality data weiter it be from local access, http or ProjectWise Context Share.
* The key provided at the creation determines if this is ProjectWise Context Share reference.
* If not then it is considered local (ex: C:\temp\TileRoot.json) or plain http access (http://someserver.com/data/TileRoot.json)
* There is a one to one relationship between a reality data and the instances of present class.
* @internal
*/
export class RealityDataSourceContextShareImpl {
key;
/** The URL that supplies the 3d tiles for displaying the reality model. */
_tilesetUrl;
_isUrlResolved = false;
_rd;
/** For use by all Reality Data. For RD stored on PW Context Share, represents the portion from the root of the Azure Blob Container*/
_baseUrl = "";
/** Construct a new reality data source.
* @param props JSON representation of the reality data source
*/
constructor(props) {
// this implementaiton is specific to ContextShare provider
assert(props.sourceKey.provider === RealityDataProvider.ContextShare);
this.key = props.sourceKey;
this._isUrlResolved = false;
}
/**
* Create an instance of this class from a source key and iTwin context/
*/
static async createFromKey(sourceKey, iTwinId) {
if (sourceKey.provider !== RealityDataProvider.ContextShare)
return undefined;
const rdSource = new RealityDataSourceContextShareImpl({ sourceKey });
let tilesetUrl;
try {
await rdSource.queryRealityData(iTwinId);
tilesetUrl = await rdSource.getServiceUrl(iTwinId);
}
catch { }
return (tilesetUrl !== undefined) ? rdSource : undefined;
}
get isContextShare() {
return (this.key.provider === RealityDataProvider.ContextShare);
}
/**
* Returns Reality Data if available
*/
get realityData() {
return this._rd;
}
get realityDataId() {
const realityDataId = this.key.id;
return realityDataId;
}
/**
* Returns Reality Data type if available
*/
get realityDataType() {
return this._rd?.type;
}
/**
* Query Reality Data from provider
*/
async queryRealityData(iTwinId) {
if (!this._rd) {
const token = await IModelApp.getAccessToken();
if (token && this.realityDataId) {
if (undefined === IModelApp.realityDataAccess)
throw new Error("Missing an implementation of RealityDataAccess on IModelApp, it is required to access reality data. Please provide an implementation to the IModelApp.startup using IModelAppOptions.realityDataAccess.");
this._rd = await IModelApp.realityDataAccess.getRealityData(token, iTwinId, this.realityDataId);
// A reality data that has not root document set should not be considered.
const rootDocument = this._rd.rootDocument ?? "";
this.setBaseUrl(rootDocument);
}
}
}
// This is to set the root url from the provided root document path.
// If the root document is stored on PW Context Share then the root document property of the Reality Data is provided,
// otherwise the full path to root document is given.
// The base URL contains the base URL from which tile relative path are constructed.
// The tile's path root will need to be reinserted for child tiles to return a 200
setBaseUrl(url) {
const urlParts = url.split("/");
urlParts.pop();
if (urlParts.length === 0)
this._baseUrl = "";
else
this._baseUrl = `${urlParts.join("/")}/`;
}
/**
* Gets a tileset's app data json
* @param name name or path of tile
* @returns app data json object
* @internal
*/
async getRealityDataTileJson(accessToken, name, realityData) {
const url = await realityData.getBlobUrl(accessToken, name);
return request(url.toString(), "json");
}
/**
* This method returns the URL to access the actual 3d tiles from the service provider.
* @returns string containing the URL to reality data.
*/
async getServiceUrl(iTwinId) {
// If url was not resolved - resolve it
if (!this._isUrlResolved) {
const rdSourceKey = this.key;
// we need to resolve tilesetURl from realityDataId and iTwinId
if (undefined === IModelApp.realityDataAccess)
throw new Error("Missing an implementation of RealityDataAccess on IModelApp, it is required to access reality data. Please provide an implementation to the IModelApp.startup using IModelAppOptions.realityDataAccess.");
try {
const resolvedITwinId = iTwinId ? iTwinId : rdSourceKey.iTwinId;
this._tilesetUrl = await IModelApp.realityDataAccess.getRealityDataUrl(resolvedITwinId, rdSourceKey.id);
this._isUrlResolved = true;
}
catch {
const errMsg = `Error getting URL from ContextShare using realityDataId=${rdSourceKey.id} and iTwinId=${iTwinId}`;
Logger.logError(FrontendLoggerCategory.RealityData, errMsg);
}
}
return this._tilesetUrl;
}
async getRootDocument(_iTwinId) {
const token = await IModelApp.getAccessToken();
if (token) {
const realityData = this.realityData;
if (!realityData)
throw new Error(`Reality Data not defined`);
if (!realityData.rootDocument)
throw new Error(`Root document not defined for reality data: ${realityData.id}`);
return this.getRealityDataTileJson(token, realityData.rootDocument, realityData);
}
}
/**
* Gets tile content
* @param name name or path of tile
* @returns array buffer of tile content
*/
async getRealityDataTileContent(accessToken, name, realityData) {
const url = await realityData.getBlobUrl(accessToken, name);
return request(url.toString(), "arraybuffer");
}
/**
* Returns the tile content. The path to the tile is relative to the base url of present reality data whatever the type.
*/
async getTileContent(name) {
const token = await IModelApp.getAccessToken();
const tileUrl = this._baseUrl + name;
if (this.realityData) {
return this.getRealityDataTileContent(token, tileUrl, this.realityData);
}
return undefined;
}
/**
* Returns the tile content in json format. The path to the tile is relative to the base url of present reality data whatever the type.
*/
async getTileJson(name) {
const token = await IModelApp.getAccessToken();
const tileUrl = this._baseUrl + name;
if (this.realityData) {
return this.getRealityDataTileJson(token, tileUrl, this.realityData);
}
return undefined;
}
getTileContentType(url) {
return url.endsWith("json") ? "tileset" : "tile";
}
/**
* Gets spatial location and extents of this reality data source
* @returns spatial location and extents
* @internal
*/
async getSpatialLocationAndExtents() {
let spatialLocation;
const fileType = this.realityDataType;
// Mapping Resource are not currenlty supported
if (fileType === "OMR")
return undefined;
if (this.key.format === RealityDataFormat.ThreeDTile) {
const rootDocument = await this.getRootDocument(undefined);
spatialLocation = ThreeDTileFormatInterpreter.getSpatialLocationAndExtents(rootDocument);
}
else if (this.key.format === RealityDataFormat.OPC) {
if (this.realityData === undefined)
return undefined;
const token = await IModelApp.getAccessToken();
const docRootName = this.realityData.rootDocument;
if (!docRootName)
return undefined;
const blobUrl = await this.realityData.getBlobUrl(token, docRootName);
if (!blobUrl)
return undefined;
const blobStringUrl = blobUrl.toString();
const filereader = await OPCFormatInterpreter.getFileReaderFromBlobFileURL(blobStringUrl);
spatialLocation = await OPCFormatInterpreter.getSpatialLocationAndExtents(filereader);
}
return spatialLocation;
}
/**
* Gets information to identify the product and engine that create this reality data
* Will return undefined if cannot be resolved
* @returns information to identify the product and engine that create this reality data
* @alpha
*/
async getPublisherProductInfo() {
let publisherInfo;
if (this.key.format === RealityDataFormat.ThreeDTile) {
const rootDocument = await this.getRootDocument(undefined);
publisherInfo = ThreeDTileFormatInterpreter.getPublisherProductInfo(rootDocument);
}
return publisherInfo;
}
}
//# sourceMappingURL=RealityDataSourceContextShareImpl.js.map