VisiOmatic web client

source

crs/Conical.js

/**
 #	This file part of:	VisiOmatic
 * @file Conic (de-)projections.
 * @requires util/VUtil.js
 * @requires crs/Projection.js

 * @copyright (c) 2014-2023 CNRS/IAP/CFHT/SorbonneU
 * @author Emmanuel Bertin <bertin@cfht.hawaii.edu>
 */
import {latLng, point} from 'leaflet';

import {Projection} from './Projection';


Conical = Projection.extend( /** @lends Conical */ {

	/**
	 * Base class for conic WCS (World Coordinate System) projections.
	 *
	 * @name Conical
	 * @see {@link https://www.atnf.csiro.au/people/mcalabre/WCS/ccs.pdf#page=19}
	 * @extends Projection
	 * @memberof module:crs/Conical.js
	 * @constructs
	 * @param {object} header
	   JSON representation of the image header.
	 * @param {projParam} [options]
	   Projection options: see {@link Projection}.

	 * @returns {Conical} Instance of a conic projection.
	 */
	// Initialize() is inherited from the parent class.

	/**
	 * Convert reduced coordinates to conic (phi,R) coordinates.
	 * @private
	 * @param {leaflet.Point} red
	   Reduced coordinates.
	 * @returns {leaflet.LatLng}
	   (phi,R) conic coordinates in degrees.
	 */
	_redToPhiR: function (red) {
		const	deg = Math.PI / 180.0,
		    projparam = this.projparam,
		    dy = projparam._y0 - red.y,
			rTheta = projparam._sthetaA * Math.sqrt(red.x * red.x + dy * dy);

		return latLng(
			rTheta,
			Math.atan2(red.x / rTheta, dy / rTheta) / projparam._c / deg
		);
	},

	/**
	 * Convert conic (phi,R) coordinates to reduced coordinates.
	 * @private
	 * @param {leaflet.LatLng} phiR
	   (phi,R) conic coordinates in degrees.
	 * @returns {leaflet.Point}
	   Reduced coordinates.
	 */
	_phiRToRed: function (phiR) {
		const	deg = Math.PI / 180.0,
		     p = this.projparam._c * phiR.lng * deg;
		return point(
			phiR.lat * Math.sin(p),
			this.projparam._y0 - phiR.lat * Math.cos(p)
		);
	}
});


export const COE = Conical.extend( /** @lends COE */ {

	/**
	 * Conic Equal-Area projection.
	 *
	 * @name COE
	 * @see {@link https://www.atnf.csiro.au/people/mcalabre/WCS/ccs.pdf#page=20}
	 * @extends Conical
	 * @memberof module:crs/Conical.js
	 * @constructs
	 * @param {object} header
	   JSON representation of the image header.
	 * @param {projParam} [options]
	   Projection options: see {@link Conical}.

	 * @returns {COE} Instance of a COE projection.
	 */
	// Initialize() is inherited from the parent class

	/**
	 * Initialize a COE projection.
	 * @private
	 */
	_projInit: function () {
		const	deg = Math.PI / 180.0,
			projparam = this.projparam;

		projparam._cdinv = this._invertCD(projparam.cd);
		projparam._thetaA = projparam.pv[1][1];
		projparam._eta = projparam.pv[1][2];
		projparam._sthetaA = projparam._thetaA >= 0.0 ? 1.0 : -1.0;
		const	theta1 = projparam._thetaA - projparam._eta,
			theta2 = projparam._thetaA + projparam._eta,
			s1 = Math.sin(theta1 * deg),
			s2 = Math.sin(theta2 * deg);
		projparam._gamma = s1 + s2;
		projparam._s1s2p1 = s1 * s2 + 1.0;
		projparam._c = projparam._gamma / 2.0;
		projparam._y0 = 2.0 / projparam._gamma * Math.sqrt(projparam._s1s2p1 -
		   projparam._gamma * Math.sin(projparam._thetaA * deg)) / deg;
		projparam._natrval = latLng(projparam._thetaA, 0.0);
		projparam._natpole = this._natpole();
		projparam._cpole = this._cpole();
		projparam._infinite = true;
		projparam._pixelFlag = false;
	},

	/**
	 * Convert conic equal-area R coordinate to native theta angle.
	 * @private
	 * @param {number} r
	   R conic equal-area coordinate in degrees.
	 * @returns {number}
	   Native theta angle in degrees.
	 */
	_rToTheta: function (r) {
		const	deg = Math.PI / 180.0,
		    gamma = this.projparam._gamma;
		let	sinarg = this.projparam._s1s2p1 / gamma - gamma *
			r * r * deg * deg / 4.0;
		if (sinarg < -1.0) {
			sinarg = -1.0;
		} else if (sinarg > 1.0) {
			sinarg = 1.0;
		}
		return Math.asin(sinarg) / deg;
	},

	/**
	 * Convert native theta angle to conic equal-area R.
	 * @private
	 * @param {number} theta
	   Native theta angle in degrees.
	 * @returns {number}
	   R conic equal-area coordinate in degrees.
	 */
	_thetaToR: function (theta) {
		const	deg = Math.PI / 180.0,
		    gamma = this.projparam._gamma;
		return 2.0 / gamma * Math.sqrt(this.projparam._s1s2p1 - gamma *
			Math.sin(theta * deg)) / deg;
	}

});