UNPKG

@itwin/core-frontend

Version:
503 lines • 23.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. *--------------------------------------------------------------------------------------------*/ /** @packageDocumentation * @module Views */ Object.defineProperty(exports, "__esModule", { value: true }); exports.WmtsCapabilities = exports.WmtsCapability = exports.WmtsConstants = void 0; const core_geometry_1 = require("@itwin/core-geometry"); const internal_1 = require("../../../tile/internal"); var OwsConstants; (function (OwsConstants) { OwsConstants["ABSTRACT_XMLTAG"] = "ows:Abstract"; OwsConstants["ACCESSCONSTRAINTS_XMLTAG"] = "ows:AccessConstraints"; OwsConstants["ALLOWEDVALUES_XMLTAG"] = "ows:AllowedValues"; OwsConstants["BOUNDINGBOX_XMLTAG"] = "ows:BoundingBox"; OwsConstants["CONSTRAINT_XMLTAG"] = "ows:Constraint"; OwsConstants["DCP_XMLTAG"] = "ows:DCP"; OwsConstants["FEES_XMLTAG"] = "ows:Fees"; OwsConstants["GET_XMLTAG"] = "ows:Get"; OwsConstants["HTTP_XMLTAG"] = "ows:HTTP"; OwsConstants["IDENTIFIER_XMLTAG"] = "ows:Identifier"; OwsConstants["KEYWORDS_XMLTAG"] = "ows:Keywords"; OwsConstants["KEYWORD_XMLTAG"] = "ows:Keyword"; OwsConstants["LOWERCORNER_XMLTAG"] = "ows:LowerCorner"; OwsConstants["OPERATION_XMLTAG"] = "ows:Operation"; OwsConstants["OPERATIONSMETADATA_XMLTAG"] = "ows:OperationsMetadata"; OwsConstants["POST_XMLTAG"] = "ows:Post"; OwsConstants["SERVICEIDENTIFICATION_XMLTAG"] = "ows:ServiceIdentification"; OwsConstants["SERVICETYPE_XMLTAG"] = "ows:ServiceType"; OwsConstants["SERVICETYPEVERSION_XMLTAG"] = "ows:ServiceTypeVersion"; OwsConstants["SUPPORTEDCRS_XMLTAG"] = "ows:SupportedCRS"; OwsConstants["TITLE_XMLTAG"] = "ows:Title"; OwsConstants["UPPERCORNER_XMLTAG"] = "ows:UpperCorner"; OwsConstants["VALUE_XMLTAG"] = "ows:Value"; OwsConstants["WGS84BOUNDINGBOX_XMLTAG"] = "ows:WGS84BoundingBox"; })(OwsConstants || (OwsConstants = {})); var XmlConstants; (function (XmlConstants) { // Operations names XmlConstants["GETCAPABILITIES"] = "GetCapabilities"; XmlConstants["GETTILE"] = "GetTile"; XmlConstants["GETFEATUREINFO"] = "GetFeatureInfo"; XmlConstants["MATRIXWIDTH_XMLTAG"] = "MatrixWidth"; XmlConstants["MATRIXHEIGHT_XMLTAG"] = "MatrixHeight"; XmlConstants["SCALEDENOMINATOR_XMLTAG"] = "ScaleDenominator"; XmlConstants["TILEHEIGHT_XMLTAG"] = "TileHeight"; XmlConstants["TILEMATRIX_XMLTAG"] = "TileMatrix"; XmlConstants["TILEMATRIXSETLINK_XMLTAG"] = "TileMatrixSetLink"; XmlConstants["RESOURCEURL_XMLTAG"] = "ResourceURL"; XmlConstants["TILEWIDTH_XMLTAG"] = "TileWidth"; XmlConstants["TOPLEFTCORNER_XMLTAG"] = "TopLeftCorner"; XmlConstants["WELLKNOWNSCALESET_XMLTAG"] = "WellKnownScaleSet"; XmlConstants["CONSTRAINT_NAME_FILTER"] = "Encoding"; XmlConstants["STYLE_ISDEFAULT"] = "IsDefault"; XmlConstants["XLINK_HREF"] = "xlink:href"; })(XmlConstants || (XmlConstants = {})); var WmtsConstants; (function (WmtsConstants) { WmtsConstants[WmtsConstants["GOOGLEMAPS_LEVEL0_SCALE_DENOM"] = 559082264.0287178] = "GOOGLEMAPS_LEVEL0_SCALE_DENOM"; WmtsConstants["GOOGLEMAPS_COMPATIBLE_WELLKNOWNNAME"] = "googlemapscompatible"; })(WmtsConstants || (exports.WmtsConstants = WmtsConstants = {})); /** * Utility function to extract an element' text content * @return An element's text content, default to provided defaultTest value if no text is available. * @param url server URL to address the request */ const getElementTextContent = (elem, qualifiedName, defaultText) => { const tmpElem = elem.getElementsByTagName(qualifiedName); if (tmpElem.length > 0) { return tmpElem[0].textContent ?? defaultText; } else return defaultText; }; /** Encapsulation of the capabilities for an WMTS server */ var WmtsCapability; (function (WmtsCapability) { class ServiceIdentification { abstract; accessConstraints; fees; serviceType; serviceTypeVersion; title; keywords; constructor(elem) { this.abstract = getElementTextContent(elem, OwsConstants.ABSTRACT_XMLTAG); this.serviceType = getElementTextContent(elem, OwsConstants.SERVICETYPE_XMLTAG); this.serviceTypeVersion = getElementTextContent(elem, OwsConstants.SERVICETYPEVERSION_XMLTAG); this.title = getElementTextContent(elem, OwsConstants.TITLE_XMLTAG); const keywords = elem.getElementsByTagName(OwsConstants.KEYWORDS_XMLTAG); if (keywords.length > 0) { const keyword = keywords[0].getElementsByTagName(OwsConstants.KEYWORD_XMLTAG); this.keywords = []; for (const keyworkElem of keyword) { const keyWordText = keyworkElem.textContent; if (keyWordText) this.keywords.push(keyWordText); } } this.accessConstraints = getElementTextContent(elem, OwsConstants.ACCESSCONSTRAINTS_XMLTAG); this.fees = getElementTextContent(elem, OwsConstants.FEES_XMLTAG); } } WmtsCapability.ServiceIdentification = ServiceIdentification; class OperationMetadata { _getCapabilities; get getCapabilities() { return this._getCapabilities; } _getFeatureInfo; get getFeatureInfo() { return this._getFeatureInfo; } _getTile; get getTile() { return this._getTile; } readOperation(op) { const nameAttr = op.attributes.getNamedItem("name"); if (!nameAttr) return; if (nameAttr.textContent === XmlConstants.GETCAPABILITIES) { this._getCapabilities = new Operation(op); } else if (nameAttr.textContent === XmlConstants.GETTILE) { this._getTile = new Operation(op); } else if (nameAttr.textContent === XmlConstants.GETFEATUREINFO) { this._getFeatureInfo = new Operation(op); } } constructor(elem) { const operation = elem.getElementsByTagName(OwsConstants.OPERATION_XMLTAG); if (operation.length > 0) { for (const op of operation) { this.readOperation(op); } } } } WmtsCapability.OperationMetadata = OperationMetadata; class HttpDcp { url; constraintName; // For simplicity of use we create a 'static' encoding property instead of having // a generic constraint data model. // We make sure the constraint name is 'encoding' related. encoding; constructor(elem) { const url = elem.getAttribute(XmlConstants.XLINK_HREF); if (url) this.url = url ?? ""; const constraint = elem.getElementsByTagName(OwsConstants.CONSTRAINT_XMLTAG); if (constraint.length > 0) { this.constraintName = constraint[0].getAttribute("name") ?? ""; if (this.constraintName?.endsWith(XmlConstants.CONSTRAINT_NAME_FILTER)) { const allowedValues = constraint[0].getElementsByTagName(OwsConstants.ALLOWEDVALUES_XMLTAG); if (allowedValues.length > 0) { this.encoding = getElementTextContent(allowedValues[0], OwsConstants.VALUE_XMLTAG); } } } } } WmtsCapability.HttpDcp = HttpDcp; class Operation { name; _getDcpHttp; get getDcpHttp() { return this._getDcpHttp; } _postDcpHttp; get postDcpHttp() { return this._postDcpHttp; } constructor(elem) { const name = elem.getAttribute("name"); if (name) this.name = name; const dcp = elem.getElementsByTagName(OwsConstants.DCP_XMLTAG); if (!dcp || dcp.length === 0) return; const dcpHttp = dcp[0].getElementsByTagName(OwsConstants.HTTP_XMLTAG); if (!dcpHttp || dcpHttp.length === 0) return; const get = dcpHttp[0].getElementsByTagName(OwsConstants.GET_XMLTAG); if (get.length > 0) { this._getDcpHttp = []; for (const getItem of get) { this._getDcpHttp?.push(new HttpDcp(getItem)); } } const post = dcpHttp[0].getElementsByTagName(OwsConstants.POST_XMLTAG); if (post.length > 0) { this._postDcpHttp = []; for (const postItem of post) { this._postDcpHttp?.push(new HttpDcp(postItem)); } } } } WmtsCapability.Operation = Operation; class Contents { layers = []; tileMatrixSets = []; constructor(elem) { // Layers const layer = elem.getElementsByTagName("Layer"); if (layer) { for (const layerElem of layer) this.layers.push(new Layer(layerElem)); } // TileMatrixSet const tms = elem.querySelectorAll("Contents > TileMatrixSet"); if (tms) { for (const tmsElem of tms) this.tileMatrixSets.push(new TileMatrixSet(tmsElem)); } } getGoogleMapsCompatibleTileMatrixSet() { const googleMapsTms = []; this.tileMatrixSets.forEach((tms) => { if (tms.wellKnownScaleSet?.toLowerCase().includes(WmtsConstants.GOOGLEMAPS_COMPATIBLE_WELLKNOWNNAME)) googleMapsTms.push(tms); // In case wellKnownScaleSet was not been set properly, infer from scaleDenominator // Note: some servers are quite inaccurate in their scale values, hence I used a delta value of 1. else if (tms.tileMatrix.length > 0 && Math.abs(tms.tileMatrix[0].scaleDenominator - WmtsConstants.GOOGLEMAPS_LEVEL0_SCALE_DENOM) < 1 && (tms.supportedCrs.includes("3857") || tms.supportedCrs.includes("900913"))) googleMapsTms.push(tms); }); return googleMapsTms; } getEpsg4326CompatibleTileMatrixSet() { return this.tileMatrixSets.filter((tms) => tms.supportedCrs.includes("4326")); } } WmtsCapability.Contents = Contents; class Style { isDefault = false; title; identifier; // TODO: LegendURL constructor(elem) { if (!elem) return; const isDefault = elem.getAttribute("isDefault"); if (isDefault) this.isDefault = isDefault.toLowerCase() === "true"; this.title = getElementTextContent(elem, OwsConstants.TITLE_XMLTAG); this.identifier = getElementTextContent(elem, OwsConstants.IDENTIFIER_XMLTAG); } } WmtsCapability.Style = Style; class BoundingBox { crs; range; constructor(elem) { this.crs = elem.getAttribute("crs") ?? undefined; const lowerCorner = getElementTextContent(elem, OwsConstants.LOWERCORNER_XMLTAG); const upperCorner = getElementTextContent(elem, OwsConstants.UPPERCORNER_XMLTAG); if (lowerCorner && upperCorner) { const lowerCornerArray = lowerCorner?.split(" ").map((x) => +x); const upperCornerArray = upperCorner?.split(" ").map((x) => +x); if (lowerCornerArray && lowerCornerArray.length === 2 && upperCornerArray && upperCornerArray.length === 2) this.range = core_geometry_1.Range2d.createXYXY(lowerCornerArray[0], lowerCornerArray[1], upperCornerArray[0], upperCornerArray[1]); } } } WmtsCapability.BoundingBox = BoundingBox; class TileMatrixSetLimits { limits; tileMatrix; constructor(elem) { this.tileMatrix = getElementTextContent(elem, "TileMatrix"); const minTileRow = getElementTextContent(elem, "MinTileRow"); const maxTileRow = getElementTextContent(elem, "MaxTileRow"); const minTileCol = getElementTextContent(elem, "MinTileCol"); const maxTileCol = getElementTextContent(elem, "MaxTileCol"); if (minTileRow !== undefined && maxTileRow !== undefined && minTileCol !== undefined && maxTileCol) this.limits = core_geometry_1.Range2d.createXYXY(Number(minTileCol), Number(minTileRow), Number(maxTileCol), Number(maxTileRow)); } } WmtsCapability.TileMatrixSetLimits = TileMatrixSetLimits; class TileMatrixSetLink { tileMatrixSet; tileMatrixSetLimits = new Array(); constructor(elem) { this.tileMatrixSet = getElementTextContent(elem, "TileMatrixSet", ""); const tileMatrixLimitsRoot = elem.getElementsByTagName("TileMatrixSetLimits"); if (tileMatrixLimitsRoot.length > 0) { const tileMatrixLimits = tileMatrixLimitsRoot[0].getElementsByTagName("TileMatrixSetLimits"); for (const tmsl of tileMatrixLimits) { this.tileMatrixSetLimits.push(new TileMatrixSetLimits(tmsl)); } } } } WmtsCapability.TileMatrixSetLink = TileMatrixSetLink; class ResourceURL { format; resourceType; template; constructor(elem) { this.format = elem.getAttribute("format") ?? ""; this.resourceType = elem.getAttribute("resourceType") ?? ""; this.template = elem.getAttribute("template") ?? ""; } } WmtsCapability.ResourceURL = ResourceURL; class TileMatrixSet { identifier; title; abstract; supportedCrs; wellKnownScaleSet; tileMatrix = []; constructor(elem) { const identifier = getElementTextContent(elem, OwsConstants.IDENTIFIER_XMLTAG); if (identifier) this.identifier = identifier; else throw new Error("No Identifier found."); this.title = getElementTextContent(elem, OwsConstants.TITLE_XMLTAG); this.abstract = getElementTextContent(elem, OwsConstants.ABSTRACT_XMLTAG); const supportedCrs = getElementTextContent(elem, OwsConstants.SUPPORTEDCRS_XMLTAG); if (supportedCrs) this.supportedCrs = supportedCrs; else throw new Error("No supported CRS found."); this.wellKnownScaleSet = getElementTextContent(elem, XmlConstants.WELLKNOWNSCALESET_XMLTAG, ""); // TileMatrix: // TileMatrix is mandatory on TileMatrixSet, if it doesn't exists, something is OFF with the capability. const tileMatrix = elem.getElementsByTagName(XmlConstants.TILEMATRIX_XMLTAG); if (tileMatrix.length === 0) throw new Error("No matrix set link found for WMTS layer"); for (const tm of tileMatrix) { this.tileMatrix.push(new TileMatrix(tm)); } } } WmtsCapability.TileMatrixSet = TileMatrixSet; class TileMatrix { identifier; title; abstract; scaleDenominator; topLeftCorner; tileWidth; tileHeight; matrixWidth; matrixHeight; constructor(elem) { const identifier = getElementTextContent(elem, OwsConstants.IDENTIFIER_XMLTAG, ""); if (identifier) this.identifier = identifier; else throw new Error("No Identifier found."); this.title = getElementTextContent(elem, OwsConstants.TITLE_XMLTAG); this.abstract = getElementTextContent(elem, OwsConstants.ABSTRACT_XMLTAG); // Scale denominator const scaleDenom = getElementTextContent(elem, XmlConstants.SCALEDENOMINATOR_XMLTAG, ""); if (!scaleDenom) throw new Error("No scale denominator found on TileMatrix."); this.scaleDenominator = +scaleDenom; // Top left corner const topLeftCorner = getElementTextContent(elem, XmlConstants.TOPLEFTCORNER_XMLTAG, "")?.split(" ").map((x) => +x); if (topLeftCorner?.length !== 2) throw new Error("No TopLeftCorner found on TileMatrix."); this.topLeftCorner = core_geometry_1.Point2d.create(topLeftCorner[0], topLeftCorner[1]); // Tile Width const tileWidth = getElementTextContent(elem, XmlConstants.TILEWIDTH_XMLTAG); if (!tileWidth) throw new Error("No tile width found on TileMatrix."); this.tileWidth = +tileWidth; // Tile Height const tileHeight = getElementTextContent(elem, XmlConstants.TILEHEIGHT_XMLTAG); if (!tileHeight) throw new Error("No tile height found on TileMatrix."); this.tileHeight = +tileHeight; // Matrix Width const matrixWidth = getElementTextContent(elem, XmlConstants.MATRIXWIDTH_XMLTAG); if (!matrixWidth) throw new Error("No tile width found on TileMatrix."); this.matrixWidth = +matrixWidth; // Matrix Height const matrixHeight = getElementTextContent(elem, XmlConstants.MATRIXHEIGHT_XMLTAG); if (!matrixHeight) throw new Error("No tile height found on TileMatrix."); this.matrixHeight = +matrixHeight; } } WmtsCapability.TileMatrix = TileMatrix; class Layer { identifier; title; abstract; format; wsg84BoundingBox; boundingBox; styles = []; tileMatrixSetLinks = []; resourceUrls = []; constructor(elem) { const identifier = getElementTextContent(elem, OwsConstants.IDENTIFIER_XMLTAG, ""); if (identifier) this.identifier = identifier; else throw new Error("No Identifier found."); this.title = getElementTextContent(elem, OwsConstants.TITLE_XMLTAG); this.format = getElementTextContent(elem, "Format"); // BoundingBox const boundingBox = elem.getElementsByTagName(OwsConstants.BOUNDINGBOX_XMLTAG); if (boundingBox.length > 0) this.boundingBox = new BoundingBox(boundingBox[0]); let lowerCornerArray, upperCornerArray; const bbox = elem.getElementsByTagName(OwsConstants.WGS84BOUNDINGBOX_XMLTAG); if (bbox.length > 0) { lowerCornerArray = getElementTextContent(bbox[0], OwsConstants.LOWERCORNER_XMLTAG)?.split(" ").map((x) => +x); upperCornerArray = getElementTextContent(bbox[0], OwsConstants.UPPERCORNER_XMLTAG)?.split(" ").map((x) => +x); } if (lowerCornerArray?.length === 2 && upperCornerArray?.length === 2) this.wsg84BoundingBox = internal_1.MapCartoRectangle.fromDegrees(lowerCornerArray[0], lowerCornerArray[1], upperCornerArray[0], upperCornerArray[1]); // If we could not initialized WSG84 bounding box, attempt to initialized it from Bounding Box if (!this.wsg84BoundingBox && (this.boundingBox?.crs?.includes("EPSG:4326") || this.boundingBox?.crs?.includes("CRS:84"))) { const range = this.boundingBox.range; if (range) this.wsg84BoundingBox = internal_1.MapCartoRectangle.fromDegrees(range.low.x, range.low.y, range.high.x, range.high.y); else this.wsg84BoundingBox = internal_1.MapCartoRectangle.createMaximum(); } // Style const style = elem.getElementsByTagName("Style"); if (style.length > 0) { for (const styleElem of style) this.styles.push(new Style(styleElem)); } // TileMatrixSetLink // TileMatrixSetLink is mandatory on Layer, if it doesn't exists, something is OFF with the capability. const tileMatrixSetLink = elem.getElementsByTagName(XmlConstants.TILEMATRIXSETLINK_XMLTAG); if (tileMatrixSetLink.length === 0) throw new Error("No matrix set link found for WMTS layer"); for (const tmsl of tileMatrixSetLink) this.tileMatrixSetLinks.push(new TileMatrixSetLink(tmsl)); // ResourceURL are optional. It can be repeated for different resource types. const resourceUrls = elem.getElementsByTagName(XmlConstants.RESOURCEURL_XMLTAG); for (const url of resourceUrls) this.resourceUrls.push(new ResourceURL(url)); } } WmtsCapability.Layer = Layer; })(WmtsCapability || (exports.WmtsCapability = WmtsCapability = {})); class WmtsCapabilities { static _capabilitiesCache = new Map(); version; serviceIdentification; contents; operationsMetadata; constructor(xmlDoc) { const capabilities = xmlDoc.getElementsByTagName("Capabilities"); if (capabilities.length !== 0) { const capability = capabilities[0]; this.version = capability.getAttribute("version") ?? undefined; // Service Identification const serviceIdentification = capability.getElementsByTagName(OwsConstants.SERVICEIDENTIFICATION_XMLTAG); if (serviceIdentification.length > 0) this.serviceIdentification = new WmtsCapability.ServiceIdentification(serviceIdentification[0]); // Operations metadata const operationsMetadata = capability.getElementsByTagName(OwsConstants.OPERATIONSMETADATA_XMLTAG); if (operationsMetadata.length > 0) this.operationsMetadata = new WmtsCapability.OperationMetadata(operationsMetadata[0]); // Contents const content = capability.getElementsByTagName("Contents"); if (content.length > 0) this.contents = new WmtsCapability.Contents(content[0]); } } static createFromXml(xmlCapabilities) { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(xmlCapabilities, "text/xml"); return new WmtsCapabilities(xmlDoc); } static async create(url, credentials, ignoreCache, queryParams) { if (!ignoreCache) { const cached = WmtsCapabilities._capabilitiesCache.get(url); if (cached !== undefined) return cached; } const tmpUrl = new URL(internal_1.WmsUtilities.getBaseUrl(url)); tmpUrl.searchParams.append("request", "GetCapabilities"); tmpUrl.searchParams.append("service", "WMTS"); if (queryParams) { Object.keys(queryParams).forEach((paramKey) => { if (!tmpUrl.searchParams.has(paramKey)) tmpUrl.searchParams.append(paramKey, queryParams[paramKey]); }); } const xmlCapabilities = await internal_1.WmsUtilities.fetchXml(tmpUrl.toString(), credentials); if (!xmlCapabilities) return undefined; const capabilities = WmtsCapabilities.createFromXml(xmlCapabilities); if (capabilities) WmtsCapabilities._capabilitiesCache.set(url, capabilities); return capabilities; } } exports.WmtsCapabilities = WmtsCapabilities; //# sourceMappingURL=WmtsCapabilities.js.map