Source: utilsSphere.js

/**
 * @module utilsSphere
 * @description utilities which is used to calculate randomAngles for sphere.
 *
 * @author [Andrej Hristoliubov]{@link https://github.com/anhr}
 *
 * @copyright 2011 Data Arts Team, Google Creative Lab
 *
 * @license under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
*/

//import anglesRange from './anglesRange.js'
import Position from './position.js'

//const range = anglesRange.longitude.range, latitudeMax = anglesRange.latitude.max, latitudeMin = anglesRange.latitude.min, π = Math.PI;

/*https://gemini.google.com/app/fed6dc3ff178ba36
Задана точка на сфере в полярной системе координат. Начало координат находится в центре сферы.
Положение точки обозначить как
angles.longitude - долгота в диапазоне от -π до π.
angles.latitude - широта в диапазоне от -π/2 на южном полюсе до π/2 на северном полюсе.
Радиус сферы обозначить как r.
Долгота и широта может выходить за пределы заданного диапазона.
Вычислить координаты точки в декартовой системе координат.
Написать код на javascript
*/
const sAnglesToCartesian = 'polarToCartesian';
/**
 * Вычисляет декартовы координаты (x, y, z) точки на сфере,
 * заданной в полярной системе координат (r, широта, долгота).
 *
 * Предполагается, что:
 * - Широта (latitude) находится в диапазоне от -π/2 (южный полюс) до π/2 (северный полюс).
 * - Долгота (longitude) находится в диапазоне от -π до π.
 * - Углы заданы в радианах.
 *
 * @param {object} angles - Объект с углами.
 * @param {float} angles.latitude - Широта (от -π/2 до π/2).
 * @param {float} angles.longitude - Долгота (от -π до π).
 * @param {float} [r=1] - Радиус сферы.
 * @returns {array} Массив с декартовыми координатами [x, y, z].
 */
export function polarToCartesian(angles, r = 1) {

	const lat = angles.latitude;
	const lon = angles.longitude;
	if (lon === undefined) console.error(sAnglesToCartesian + ': Invalid longitude = ' + lon);

	// Сначала рассчитываем проекцию радиус-вектора на плоскость XY (r_xy)
	// r_xy = r * cos(latitude)
	const r_xy = r * Math.cos(lat);

	// Вычисляем декартовы координаты:
	// x = r_xy * cos(longitude) = r * cos(lat) * cos(lon)
	const x = r_xy * Math.cos(lon);

	// y = r_xy * sin(longitude) = r * cos(lat) * sin(lon)
	const y = r_xy * Math.sin(lon);

	// z = r * sin(latitude)
	const z = r * Math.sin(lat);

//	return { x, y, z };
	return Position([x, y, z]);

}

/*https://gemini.google.com/app/0d61322aa801d5a5
Задана точка vertice на сфере в декартовой системе координат. Начало координат находится в центре сферы.
Положение точки обозначить как
x = vertice[0]
y = vertice[1]
z = vertice[2]
Вычислить координаты точки в полярной системе координат.
Углы в полярной системе координат обозначить как:
longitude - долгота в диапазоне от -π до π.
latitude - широта в диапазоне от -π/2 на южном полюсе до π/2 на северном полюсе.
Написать код на javascript
*/
const sSartesianToAngles = 'cartesianToPolar';
/**
 * Преобразует декартовы координаты (x, y, z) в географические полярные координаты
 * (r, latitude, longitude).
 *
 * @param {object} vertice - объект x, y, z декартовых координат.
 * @returns {{latitude: float, longitude: float}} Объект с полярными координатами в радианах.
 */
export function cartesianToPolar(vertice) {

	const x = vertice.x;
	const y = vertice.y;
	const z = vertice.z;

	// 1. Вычисление радиуса (r)
	const r = Math.sqrt(x * x + y * y + z * z);

	// Обработка случая, когда точка находится в центре сферы (r = 0)
	if (r === 0) {
		console.error(sSartesianToAngles + ': Under constraction');
//		return { r: 0, latitude: 0, longitude: 0 };
		return angles([0, 0]);
	}

	// 2. Вычисление широты (latitude)
	// Используем Math.asin(z/r). Результат в радианах [-PI/2, PI/2].
	const latitude = Math.asin(z / r);
	if (isNaN(latitude)) console.error(sSartesianToAngles + ': invalid latitude = ' + latitude);

	// 3. Вычисление долготы (longitude)
	// Используем Math.atan2(y, x). Результат в радианах (-PI, PI].
	const longitude = Math.atan2(y, x);

//	return { r, latitude, longitude };
	return angles([latitude, longitude]);

}

/**
 * Adds a longitude and latitude property to the vertice angles array for the sphere hypersphere.
 * @param {array} vertice array of the vertice angles. Array length is 2. array[0] is latitude. array[1] is longitude.
 * @returns {array} Array with longitude and latitude property.
 */
export const angles = (vertice) => {

	if (vertice.longitude != undefined) return vertice;
	while (vertice.length < 2) vertice.push(0);
	Object.defineProperty(vertice, 'latitude', {

		get: () => { return vertice[0]; },
		set: (latitude) => {

			if (vertice[0] === latitude) return true;
			vertice[0] = latitude;
			return true;

		},

	});
	Object.defineProperty(vertice, 'longitude', {

		get: () => { return vertice[1]; },
		set: (longitude) => {

			if (vertice[1] === longitude) return true;
			vertice[1] = longitude;
			return true;

		},

	});
	return vertice;

}