UNPKG

@itwin/core-common

Version:

iTwin.js components common to frontend and backend

501 lines • 23.2 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 Geometry */ // cspell:ignore JSONXYZ, ETRF, OSGB, DHDN, NADCON, GEOCN Object.defineProperty(exports, "__esModule", { value: true }); exports.GeodeticDatum = exports.GeodeticTransformPath = exports.GeodeticTransform = exports.GridFileTransform = exports.GridFileDefinition = exports.PositionalVectorTransform = exports.GeocentricTransform = exports.XyzRotation = void 0; const core_geometry_1 = require("@itwin/core-geometry"); const GeodeticEllipsoid_1 = require("./GeodeticEllipsoid"); /** Hold 3 components data of a Positional Vector rotation definition in arc seconds * @public */ class XyzRotation { /** X rotation component in arc second */ x; /** Y rotation component in arc second*/ y; /** Z rotation component in arc second*/ z; constructor(data) { if (data) { this.x = data.x; this.y = data.y; this.z = data.z; } } /** Creates a Rotations object from JSON representation. * @public */ static fromJSON(data) { return new XyzRotation(data); } /** Creates a JSON from the Rotations definition * @public */ toJSON() { return { x: this.x, y: this.y, z: this.z }; } /** Compares two geodetic rotations. It applies a minuscule angular tolerance * @public */ equals(other) { return (Math.abs(this.x - other.x) < core_geometry_1.Geometry.smallAngleSeconds && Math.abs(this.y - other.y) < core_geometry_1.Geometry.smallAngleSeconds && Math.abs(this.z - other.z) < core_geometry_1.Geometry.smallAngleSeconds); } } exports.XyzRotation = XyzRotation; /** This class represents a geocentric (three parameters) geodetic transformation. * @public */ class GeocentricTransform { /** The frame translation components in meters */ delta; constructor(data) { this.delta = data ? core_geometry_1.Vector3d.fromJSON(data.delta) : new core_geometry_1.Vector3d(); } /** Creates a Geocentric Transform from JSON representation. * @public */ static fromJSON(data) { return new GeocentricTransform(data); } /** Creates a JSON from the Geodetic GeocentricTransform definition * @public */ toJSON() { return { delta: { x: this.delta.x, y: this.delta.y, z: this.delta.z } }; } /** Compares two geodetic transforms. It applies a minuscule tolerance. * @public */ equals(other) { return (Math.abs(this.delta.x - other.delta.x) < core_geometry_1.Geometry.smallMetricDistance && Math.abs(this.delta.y - other.delta.y) < core_geometry_1.Geometry.smallMetricDistance && Math.abs(this.delta.z - other.delta.z) < core_geometry_1.Geometry.smallMetricDistance); } } exports.GeocentricTransform = GeocentricTransform; /** This class represents a positional vector (seven parameters) geodetic transformation corresponding to * EPSG operation 9606. Beware that the convention relative to rotation direction is different * from the Coordinate Frame operation (epsg 9607). * @public */ class PositionalVectorTransform { /** The frame translation components in meters */ delta; /** The frame rotation components in arc seconds. The rotation sign convention is the one associated with * the operation EPSG:9606 following recommendation of ISO 19111 specifications */ rotation; /** Scale in parts per million. The scale effectively applied will be 1 plus scale divided by 1 000 000. */ scalePPM; constructor(data) { if (data) { this.delta = data.delta ? core_geometry_1.Vector3d.fromJSON(data.delta) : new core_geometry_1.Vector3d(); this.rotation = data.rotation ? XyzRotation.fromJSON(data.rotation) : new XyzRotation(); this.scalePPM = data.scalePPM; } } /** Creates a Positional Vector Transform from JSON representation. * @public */ static fromJSON(data) { return new PositionalVectorTransform(data); } /** Creates a JSON from the Positional Vector Transform definition * @public */ toJSON() { return { delta: { x: this.delta.x, y: this.delta.y, z: this.delta.z }, rotation: this.rotation.toJSON(), scalePPM: this.scalePPM, }; } /** Compares two Positional Vector Transforms. It applies a minuscule tolerance to number compares. * @public */ equals(other) { if (Math.abs(this.delta.x - other.delta.x) > core_geometry_1.Geometry.smallMetricDistance || Math.abs(this.delta.y - other.delta.y) > core_geometry_1.Geometry.smallMetricDistance || Math.abs(this.delta.z - other.delta.z) > core_geometry_1.Geometry.smallMetricDistance || Math.abs(this.scalePPM - other.scalePPM) > core_geometry_1.Geometry.smallFraction) return false; return this.rotation.equals(other.rotation); } } exports.PositionalVectorTransform = PositionalVectorTransform; /** Grid file definition containing name of the file, the format and the direction it should be applied * @public */ class GridFileDefinition { /** Name of the grid shift file. This name is relative to the expected dictionary root document. * Typical grid shift file name will contain first the country name it applies to then possibly some sub path. * Example of existing grid files: * Germany/BETA2007.gsb or Brazil/SAD69_003.GSB but sometimes longer paths USA/NADCON/conus.l*s * Note that the file name can contain wildcards when the format requires more than one file. For example * the NADCON format makes use of a different file for latitude and longitude shifts thus the .l*s extension in the * file name above. * Forward slash is always used to separate the path components. */ fileName; /** The grid file format */ format; /** The grid file application direction */ direction; constructor(data) { this.fileName = data ? data.fileName : ""; this.format = data ? data.format : "NTv2"; this.direction = data ? data.direction : "Direct"; } /** Creates a Grid File Definition from JSON representation. * @public */ static fromJSON(data) { return new GridFileDefinition(data); } /** Creates a JSON from the Grid File Definition * @public */ toJSON() { return { fileName: this.fileName, format: this.format, direction: this.direction }; } /** Compares two grid file definition. It is a strict compare operation not an equivalence test. * @public */ equals(other) { return (this.fileName === other.fileName && this.direction === other.direction && this.format === other.format); } } exports.GridFileDefinition = GridFileDefinition; /** This class represents a grid files based geodetic transformation. * @public */ class GridFileTransform { /** The list of grid files. The order of file is meaningful, the first encountered that covers the extent of coordinate * transformation will be used. */ files; /** The positional vector fallback transformation used for extents not covered by the grid files */ fallback; constructor(data) { this.files = []; if (data) { this.fallback = data.fallback ? PositionalVectorTransform.fromJSON(data.fallback) : undefined; if (Array.isArray(data.files)) { this.files = []; for (const item of data.files) this.files.push(GridFileDefinition.fromJSON(item)); } } } /** Creates a Grid File Transform from JSON representation. * @public */ static fromJSON(data) { return new GridFileTransform(data); } /** Creates a JSON from the Grid File Transform definition * @public */ toJSON() { const data = { files: [] }; data.fallback = this.fallback ? this.fallback.toJSON() : undefined; if (Array.isArray(this.files)) { for (const item of this.files) data.files.push(item.toJSON()); } return data; } /** Compares two Grid File Transforms. It is a strict compare operation not an equivalence test. * @public */ equals(other) { if (this.files.length !== other.files.length) return false; for (let idx = 0; idx < this.files.length; ++idx) if (!this.files[idx].equals(other.files[idx])) return false; if ((this.fallback === undefined) !== (other.fallback === undefined)) return false; if (this.fallback && !this.fallback.equals(other.fallback)) return false; return true; } } exports.GridFileTransform = GridFileTransform; /** This class represents a geodetic transformation that enables transforming longitude/latitude coordinates * from one datum to another. * @public */ class GeodeticTransform { /** The method used by the geodetic transform */ method; /** The identifier of the source geodetic datum as stored in the dictionary or the service database. * This identifier is optional and informational only. */ sourceEllipsoid; /** The complete definition of the target geodetic ellipsoid referred to by ellipsoidId. * The target ellipsoid identifier enables obtaining the shape of the Earth mathematical model * for the purpose of performing the transformation.*/ targetEllipsoid; /** The id of the source datum. */ sourceDatumId; /** The id of the target datum. This id is useful to seach within a geodetic transform path for * a shortcut to another included datum. */ targetDatumId; /** When method is Geocentric this property contains the geocentric parameters */ geocentric; /** When method is PositionalVector this property contains the positional vector parameters */ positionalVector; /** When method is GridFiles this property contains the grid files parameters */ gridFile; constructor(data) { this.method = "None"; if (data) { this.method = data.method; this.sourceEllipsoid = data.sourceEllipsoid ? GeodeticEllipsoid_1.GeodeticEllipsoid.fromJSON(data.sourceEllipsoid) : undefined; this.targetEllipsoid = data.targetEllipsoid ? GeodeticEllipsoid_1.GeodeticEllipsoid.fromJSON(data.targetEllipsoid) : undefined; this.sourceDatumId = data.sourceDatumId; this.targetDatumId = data.targetDatumId; this.geocentric = data.geocentric ? GeocentricTransform.fromJSON(data.geocentric) : undefined; this.positionalVector = data.positionalVector ? PositionalVectorTransform.fromJSON(data.positionalVector) : undefined; this.gridFile = data.gridFile ? GridFileTransform.fromJSON(data.gridFile) : undefined; } } /** Creates a Geodetic Transform from JSON representation. * @public */ static fromJSON(data) { return new GeodeticTransform(data); } /** Creates a JSON from the Geodetic Transform definition * @public */ toJSON() { const data = { method: this.method }; data.sourceEllipsoid = this.sourceEllipsoid ? this.sourceEllipsoid.toJSON() : undefined; data.targetEllipsoid = this.targetEllipsoid ? this.targetEllipsoid.toJSON() : undefined; data.sourceDatumId = this.sourceDatumId; data.targetDatumId = this.targetDatumId; data.geocentric = this.geocentric ? this.geocentric.toJSON() : undefined; data.positionalVector = this.positionalVector ? this.positionalVector.toJSON() : undefined; data.gridFile = this.gridFile ? this.gridFile.toJSON() : undefined; return data; } /** Compares two geodetic Transforms. It is not an equivalence test since * descriptive information is strictly compared. A minuscule tolerance is applied to number compares. * @public */ equals(other) { if (this.method !== other.method) return false; if (this.sourceDatumId !== other.sourceDatumId || this.targetDatumId !== other.targetDatumId) return false; if ((this.sourceEllipsoid === undefined) !== (other.sourceEllipsoid === undefined)) return false; if (this.sourceEllipsoid && !this.sourceEllipsoid.equals(other.sourceEllipsoid)) return false; if ((this.targetEllipsoid === undefined) !== (other.targetEllipsoid === undefined)) return false; if (this.targetEllipsoid && !this.targetEllipsoid.equals(other.targetEllipsoid)) return false; if ((this.geocentric === undefined) !== (other.geocentric === undefined)) return false; if (this.geocentric && !this.geocentric.equals(other.geocentric)) return false; if ((this.positionalVector === undefined) !== (other.positionalVector === undefined)) return false; if (this.positionalVector && !this.positionalVector.equals(other.positionalVector)) return false; if ((this.gridFile === undefined) !== (other.gridFile === undefined)) return false; if (this.gridFile && !this.gridFile.equals(other.gridFile)) return false; return true; } } exports.GeodeticTransform = GeodeticTransform; /** This class represents a geodetic datum transform path. It contains a list of transforms linking * a source to a target geodetic datum. * @public */ class GeodeticTransformPath { /** Source geodetic datum key name */ sourceDatumId; /** Target geodetic datum key name */ targetDatumId; /** The transformation path from source datum to target datum. */ transforms; constructor(_data) { if (_data) { this.sourceDatumId = _data.sourceDatumId; this.targetDatumId = _data.targetDatumId; if (Array.isArray(_data.transforms)) { this.transforms = []; for (const item of _data.transforms) this.transforms.push(GeodeticTransform.fromJSON(item)); } } } /** Creates a Geodetic transform path from JSON representation. * @public */ static fromJSON(data) { return new GeodeticTransformPath(data); } /** Creates a JSON from the Geodetic transform path definition * @public */ toJSON() { const data = {}; data.sourceDatumId = this.sourceDatumId; data.targetDatumId = this.targetDatumId; if (Array.isArray(this.transforms)) { data.transforms = []; for (const item of this.transforms) data.transforms.push(item.toJSON()); } return data; } /** Compares two Geodetic Transform Paths. It is a strict compare operation not an equivalence test. * It takes into account descriptive properties not only mathematical definition properties. * @public */ equals(other) { if (this.sourceDatumId !== other.sourceDatumId || this.targetDatumId !== other.targetDatumId) return false; if ((this.transforms === undefined) !== (other.transforms === undefined)) return false; if (this.transforms && other.transforms) { if (this.transforms.length !== other.transforms.length) return false; for (let idx = 0; idx < this.transforms.length; ++idx) if (!this.transforms[idx].equals(other.transforms[idx])) return false; } return true; } } exports.GeodeticTransformPath = GeodeticTransformPath; /** This class represents a geodetic datum. Geodetic datums are based on an ellipsoid. * In addition to the ellipsoid definition they are the base for longitude/latitude coordinates. * Geodetic datums are the basis for geodetic transformations. Most geodetic datums are defined by specifying * the transformation to the common base WGS84 (or local equivalent). The transforms property can contain the * definition of the transformation path to WGS84. * Sometimes there exists transformation paths direct from one non-WGS84 datum to another non-WGS84. The current model * does not allow specifications of these special paths at the moment. * @public */ class GeodeticDatum { /** GeodeticDatum key name */ id; /** Description */ description; /** If true then indicates the definition is deprecated. It should then be used for backward compatibility only. * If false then the definition is not deprecated. Default is false. */ deprecated; /** A textual description of the source of the geodetic datum definition. */ source; /** The EPSG code of the geodetic datum. If undefined then there is no EPSG code associated. */ epsg; /** The key name to the base Ellipsoid. */ ellipsoidId; /** The full definition of the geodetic ellipsoid associated to the datum. If undefined then the ellipsoidId must * be used to fetch the definition from the dictionary, geographic coordinate system service or the backend */ ellipsoid; /** The transformation to WGS84. If null then there is no known transformation to WGS84. Although * this is rare it occurs in a few cases where the country charges for obtaining and using * the transformation and its parameters, or if the transformation is maintained secret for military reasons. * In this case the recommendation is to considered the geodetic datum to be coincident to WGS84 keeping * in mind imported global data such as Google Map or Bing Map data may be approximately located. * The list of transforms contains normally a single transform but there can be a sequence of transformations * required to transform to WGS84, such as the newer datum definitions for Slovakia or Switzerland. */ transforms; /** The optional list of transformation paths to other datum. These should only be used if the path to * these datum is not included in the transforms property definition of the transformation to WGS84. * It should not be used either if the transformation to the datum can be infered from the concatenation * of their individual paths to WGS84. These should be used to express an alternate shortcut path that is * inherent to the nature of the datum. As an example it is required to represent the transformation * from NAD27 to NAD83/2011 since NAD83/2011 is coincident to WGS84 yet the NAD27 datum to WGS84 path * only includes transformation to NAD83, making the path of transforms to NAD83/2011 not related * to the available paths to WGS84. */ additionalTransformPaths; constructor(_data) { this.deprecated = false; if (_data) { this.id = _data.id; this.description = _data.description; this.deprecated = _data.deprecated ?? false; this.source = _data.source; this.epsg = _data.epsg; this.ellipsoidId = _data.ellipsoidId; this.ellipsoid = _data.ellipsoid ? GeodeticEllipsoid_1.GeodeticEllipsoid.fromJSON(_data.ellipsoid) : undefined; if (Array.isArray(_data.transforms)) { this.transforms = []; for (const item of _data.transforms) this.transforms.push(GeodeticTransform.fromJSON(item)); } if (Array.isArray(_data.additionalTransformPaths)) { this.additionalTransformPaths = []; for (const item of _data.additionalTransformPaths) this.additionalTransformPaths.push(GeodeticTransformPath.fromJSON(item)); } } } /** Creates a Geodetic Datum from JSON representation. * @public */ static fromJSON(data) { return new GeodeticDatum(data); } /** Creates a JSON from the Geodetic Datum definition * @public */ toJSON() { const data = {}; data.id = this.id; data.description = this.description; /* We prefer to use the default undef instead of false value for deprecated value in Json */ data.deprecated = (this.deprecated === false ? undefined : true); data.source = this.source; data.epsg = this.epsg; data.ellipsoidId = this.ellipsoidId; data.ellipsoid = this.ellipsoid ? this.ellipsoid.toJSON() : undefined; if (Array.isArray(this.transforms)) { data.transforms = []; for (const item of this.transforms) data.transforms.push(item.toJSON()); } if (Array.isArray(this.additionalTransformPaths)) { data.additionalTransformPaths = []; for (const item of this.additionalTransformPaths) data.additionalTransformPaths.push(item.toJSON()); } return data; } /** Compares two Geodetic Datums. It is a strict compare operation not an equivalence test. * It takes into account descriptive properties not only mathematical definition properties. * @public */ equals(other) { if (this.id !== other.id || this.description !== other.description || this.deprecated !== other.deprecated || this.source !== other.source || this.epsg !== other.epsg || this.ellipsoidId !== other.ellipsoidId) return false; if ((this.ellipsoid === undefined) !== (other.ellipsoid === undefined)) return false; if (this.ellipsoid && !this.ellipsoid.equals(other.ellipsoid)) return false; if ((this.transforms === undefined) !== (other.transforms === undefined)) return false; if (this.transforms && other.transforms) { if (this.transforms.length !== other.transforms.length) return false; for (let idx = 0; idx < this.transforms.length; ++idx) if (!this.transforms[idx].equals(other.transforms[idx])) return false; } if ((this.additionalTransformPaths === undefined) !== (other.additionalTransformPaths === undefined)) return false; if (this.additionalTransformPaths && other.additionalTransformPaths) { if (this.additionalTransformPaths.length !== other.additionalTransformPaths.length) return false; for (let idx = 0; idx < this.additionalTransformPaths.length; ++idx) if (!this.additionalTransformPaths[idx].equals(other.additionalTransformPaths[idx])) return false; } return true; } } exports.GeodeticDatum = GeodeticDatum; //# sourceMappingURL=GeodeticDatum.js.map