"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 Albers, Krovak, OSTN, Cassini, Grinten, Mollweide, Eckert, Homolosine, Carree, Winkel, Tripel, Polyconic
Object.defineProperty(exports, "__esModule", { value: true });
exports.Carto2DDegrees = exports.Projection = exports.AffineTransform = void 0;
const core_geometry_1 = require("@itwin/core-geometry");
/** The equations are:
 *  X1 = a1*X + a2*Y + TranslationX
 *  Y1 = b1*X + b2*Y + translationY
 *  An affine representing no transformation will have: a1 = 1.0, a2 = 0.0, b1 = 0.0, b2 = 1.0.
 *  @public
 */
class AffineTransform {
    constructor(data) {
        if (data) {
            this.translationX = data.translationX;
            this.translationY = data.translationY;
            this.a1 = data.a1;
            this.b1 = data.b1;
            this.a2 = data.a2;
            this.b2 = data.b2;
        }
    }
    /** Creates an Affine Transform from JSON representation.
     * @public */
    static fromJSON(data) {
        return new AffineTransform(data);
    }
    /** Creates a JSON from the Affine Transform definition
     * @public */
    toJSON() {
        return { translationX: this.translationX, a1: this.a1, a2: this.a2, translationY: this.translationY, b1: this.b1, b2: this.b2 };
    }
    /** Compares two Affine Transforms. It applies a minuscule tolerance for number compares
     *  @public */
    equals(other) {
        return (Math.abs(this.translationX - other.translationX) < core_geometry_1.Geometry.smallMetricDistance &&
            Math.abs(this.translationY - other.translationY) < core_geometry_1.Geometry.smallMetricDistance &&
            Math.abs(this.a1 - other.a1) < core_geometry_1.Geometry.smallFraction &&
            Math.abs(this.b1 - other.b1) < core_geometry_1.Geometry.smallFraction &&
            Math.abs(this.a2 - other.a2) < core_geometry_1.Geometry.smallFraction &&
            Math.abs(this.b2 - other.b2) < core_geometry_1.Geometry.smallFraction);
    }
}
exports.AffineTransform = AffineTransform;
/** This class encapsulates the projection of the CRS. The projection relies on a projection method and a set
 *  of projection parameters specific to projection method selected to flatten the surface of the model of the Earth
 *  defines as a geodetic ellipsoid. The flattening and the distortion angular, linear, scale from the process varies between methods.
 *  Refer to appropriate external documentation for details.
 *  @note Various property sets are required for specific projection methods. The current class implementation does not enforce
 *        these rules yet and it is possible to define or not define any property regardless the method used.
 *  @public
 */
class Projection {
    constructor(_data) {
        if (_data) {
            this.method = _data.method;
            this.falseEasting = _data.falseEasting;
            this.falseNorthing = _data.falseNorthing;
            this.centralMeridian = _data.centralMeridian;
            this.latitudeOfOrigin = _data.latitudeOfOrigin;
            this.longitudeOfOrigin = _data.longitudeOfOrigin;
            this.scaleFactor = _data.scaleFactor;
            this.elevationAboveGeoid = _data.elevationAboveGeoid;
            this.geoidSeparation = _data.geoidSeparation;
            this.affine = _data.affine ? AffineTransform.fromJSON(_data.affine) : undefined;
            this.standardParallel = _data.standardParallel;
            this.standardParallel1 = _data.standardParallel1;
            this.standardParallel2 = _data.standardParallel2;
            this.zoneNumber = _data.zoneNumber;
            this.hemisphere = _data.hemisphere;
            this.centralPointLongitude = _data.centralPointLongitude;
            this.centralPointLatitude = _data.centralPointLatitude;
            this.point1Longitude = _data.point1Longitude;
            this.point1Latitude = _data.point1Latitude;
            this.point2Longitude = _data.point2Longitude;
            this.point2Latitude = _data.point2Latitude;
            this.danishSystem34Region = _data.danishSystem34Region;
            this.azimuth = _data.azimuth;
        }
    }
    /** Creates a Projection from JSON representation.
     * @public */
    static fromJSON(data) {
        return new Projection(data);
    }
    /** Creates a JSON from the Projection definition
     * @public */
    toJSON() {
        const data = { method: this.method };
        data.falseEasting = this.falseEasting;
        data.falseNorthing = this.falseNorthing;
        data.centralMeridian = this.centralMeridian;
        data.latitudeOfOrigin = this.latitudeOfOrigin;
        data.longitudeOfOrigin = this.longitudeOfOrigin;
        data.scaleFactor = this.scaleFactor;
        data.elevationAboveGeoid = this.elevationAboveGeoid;
        data.geoidSeparation = this.geoidSeparation;
        data.affine = this.affine ? this.affine.toJSON() : undefined;
        data.standardParallel = this.standardParallel;
        data.standardParallel1 = this.standardParallel1;
        data.standardParallel2 = this.standardParallel2;
        data.zoneNumber = this.zoneNumber;
        data.hemisphere = this.hemisphere;
        data.centralPointLongitude = this.centralPointLongitude;
        data.centralPointLatitude = this.centralPointLatitude;
        data.point1Longitude = this.point1Longitude;
        data.point1Latitude = this.point1Latitude;
        data.point2Longitude = this.point2Longitude;
        data.point2Latitude = this.point2Latitude;
        data.danishSystem34Region = this.danishSystem34Region;
        data.azimuth = this.azimuth;
        return data;
    }
    /** Compares two projections. It is a strict compare operation as descriptive data is compared
     * but a minuscule tolerance is applied to number compares.
     *  @public */
    equals(other) {
        if (this.method !== other.method ||
            this.zoneNumber !== other.zoneNumber ||
            this.hemisphere !== other.hemisphere ||
            this.danishSystem34Region !== other.danishSystem34Region)
            return false;
        // Note that even though falseEasting, falseNorthing, elevationAboveGeoid and geoidSeparation are expressed
        // in the units of the projection which can be foot or US survey foot, they are still within the same order
        // of size that Geometry.smallMetricDistance can be used effectively.
        if (!core_geometry_1.Geometry.isAlmostEqualOptional(this.falseEasting, other.falseEasting, core_geometry_1.Geometry.smallMetricDistance) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.falseNorthing, other.falseNorthing, core_geometry_1.Geometry.smallMetricDistance) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.centralMeridian, other.centralMeridian, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.latitudeOfOrigin, other.latitudeOfOrigin, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.longitudeOfOrigin, other.longitudeOfOrigin, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.scaleFactor, other.scaleFactor, core_geometry_1.Geometry.smallFraction) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.elevationAboveGeoid, other.elevationAboveGeoid, core_geometry_1.Geometry.smallMetricDistance) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.geoidSeparation, other.geoidSeparation, core_geometry_1.Geometry.smallMetricDistance) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.standardParallel, other.standardParallel, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.standardParallel1, other.standardParallel1, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.standardParallel2, other.standardParallel2, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.centralPointLongitude, other.centralPointLongitude, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.centralPointLatitude, other.centralPointLatitude, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.point1Longitude, other.point1Longitude, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.point1Latitude, other.point1Latitude, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.point2Longitude, other.point2Longitude, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.point2Latitude, other.point2Latitude, core_geometry_1.Geometry.smallAngleDegrees) ||
            !core_geometry_1.Geometry.isAlmostEqualOptional(this.azimuth, other.azimuth, core_geometry_1.Geometry.smallAngleDegrees))
            return false;
        if (this.affine && other.affine) {
            if (!this.affine.equals(other.affine))
                return false;
        }
        else {
            if (this.affine || other.affine)
                return false;
        }
        return true;
    }
}
exports.Projection = Projection;
/** A 2D cartographic point in degrees
 *  @public
 */
class Carto2DDegrees {
    /** Returns or sets the latitude in degrees. When setting the provided number must be between or equal from -90 to 90. */
    get latitude() { return this._latitude; }
    set latitude(newLatitude) {
        if ((newLatitude <= 90.0) && (newLatitude >= -90.0))
            this._latitude = newLatitude;
    }
    constructor(data) {
        this.latitude = 0.0; /* make sure latitude is init even if invalid latitude provided */
        if (data) {
            this.latitude = data.latitude;
            this.longitude = data.longitude;
        }
    }
    /** Creates a Carto2DDegrees object from JSON representation.
     * @public */
    static fromJSON(data) {
        return new Carto2DDegrees(data);
    }
    /** Creates a JSON from the Carto2DDegrees definition
     * @public */
    toJSON() {
        return { latitude: this.latitude, longitude: this.longitude };
    }
    /** Compares two Carto2DDegrees object. It applies a minuscule tolerance to compares.
     *  @public */
    equals(other) {
        return (Math.abs(this.latitude - other.latitude) < core_geometry_1.Geometry.smallAngleDegrees &&
            Math.abs(this.longitude - other.longitude) < core_geometry_1.Geometry.smallAngleDegrees);
    }
}
exports.Carto2DDegrees = Carto2DDegrees;
//# sourceMappingURL=Projection.js.map