/**
* @module utilsHSphere
* @description utilities which is used to calculate randomAngles for hypersphere.
*
* @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 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
Заменить сферу на гиперсферу.
Тогда в положении точки появится новый угол altitude в диапазоне от 0 до π.
Также появится новая координата точки w = vertice[3] в декартовой системе координат.
*/
const sAnglesToCartesian = 'polarToCartesian';
/**
* Вычисляет 4D декартовы координаты (x, y, z, w) точки на гиперсфере.
* @param {object} angles - Объект с углами в радианах.
* @param {float} angles.latitude - Широта (от -π/2 до π/2).
* @param {float} angles.longitude - Долгота (от -π до π).
* @param {float} angles.altitude - Угол в 4-е измерение (от 0 до π).
* @param {float} [r=1] - Радиус гиперсферы.
* @param {object|boolean} [debug] - debug = object Выводит на консоль сообщение об ошибке если координаты вычислились не корректно.
* @returns {array} Массив с декартовыми координатами [x, y, z, w].
*/
export function polarToCartesian(angles, r=1, debug) {
const lat = angles.latitude;
const lon = angles.longitude;
const alt = angles.altitude;
// Вычисляем компоненту, которая проецируется на 3D-подпространство (x, y, z)
const r_xyz = r * Math.sin(alt);
// Координата в четвертом измерении
const w = r * Math.cos(alt);
// Стандартные сферические координаты, но масштабированные r_xyz
const x = r_xyz * Math.cos(lat) * Math.cos(lon);
const y = r_xyz * Math.cos(lat) * Math.sin(lon);
const z = r_xyz * Math.sin(lat);
if(debug && (isNaN(x) || isNaN(y) || isNaN(z) || isNaN(w))) console.error(sAnglesToCartesian + ': Invalid cartesian: x = ' + x + ', y = ' + y + ', z = ' + z + ', w = ' + w);
// return { x, y, z, w };
return Position([x, y, z, w]);
}
/*
// --- Пример ---
const params = {
latitude: Math.PI / 6, // 30 градусов
longitude: Math.PI / 4, // 45 градусов
altitude: Math.PI / 3 // 60 градусов
};
const coords4D = hypersphereToCartesian(100, params);
console.log("4D Coordinates:", coords4D);
*/
/*
Результат будет примерно:
{
x: 61.23,
y: 61.23,
z: 43.30,
w: 50.00
}
*/
/*https://gemini.google.com/app/0d61322aa801d5a5
Задана точка vertice на сфере в декартовой системе координат. Начало координат находится в центре сферы.
Положение точки обозначить как
x = vertice[0]
y = vertice[1]
z = vertice[2]
Вычислить координаты точки в полярной системе координат.
Углы в полярной системе координат обозначить как:
longitude - долгота в диапазоне от -π до π.
latitude - широта в диапазоне от -π/2 на южном полюсе до π/2 на северном полюсе.
Написать код на javascript.
Заменить сферу на гиперсферу.
Тогда в положении точки появится новая координата w = vertice[3].
Также появится новый угол в полярной системе координат altitude в диапазоне от 0 до π.
*/
const sCartesianToAngles = 'cartesianToPolar';
/**
* Преобразует декартовы координаты 4D (x, y, z, w) в гиперсферические.
* @param {object} vertice - объект x, y, z, w декартовых координат.
* @param {object|boolean} [debug] - debug = object Выводит на консоль сообщение об ошибке если углы вычислились не корректно.
* @returns {{altitude: number, latitude: number, longitude: number}} Объект с полярными координатами в радианах.
*/
export function cartesianToPolar(vertice, debug) {
const x = vertice.x;//, xx = x * x;
const y = vertice.y;//, yy = y * y;
const z = vertice.z;//, zz = z * z;
const w = vertice.w;//, ww = w * w;
const xyz = x * x + y * y + z * z;
// 1. Полный радиус гиперсферы
const R = Math.sqrt(xyz + w * w);
if (R < 1e-10) {
console.error(sCartesianToAngles + ': Under constraction');
// return { r: 0, altitude: 0, latitude: 0, longitude: 0 };
return angles([0, 0, 0]);
}
// 2. Вычисление Altitude (относительно оси W)
// Диапазон [0, PI]
const altitude = Math.acos(w / R);
// Вычисляем радиус проекции в 3D пространстве (xyz)
const rXYZ = Math.sqrt(xyz);
// Если rXYZ близок к 0, значит точка лежит на оси W,
// и широта с долготой не определены (принимаем за 0)
if (rXYZ < 1e-10) {
return angles([altitude, 0, 0]);
}
// 3. Вычисление Latitude (аналогично 3D сфере)
// Диапазон [-PI/2, PI/2]
const latitude = Math.asin(z / rXYZ);
// 4. Вычисление Longitude
// Диапазон (-PI, PI]
const longitude = Math.atan2(y, x);
if(debug && (isNaN(altitude) || isNaN(latitude) || isNaN(longitude))) console.error(sCartesianToAngles + ': Invalid angles: altitude = ' + altitude + ', latitude = ' + latitude + ', longitude = ' + longitude);
return angles([altitude, latitude, longitude]);
}
/*
// --- Тест ---
const vertice = [1, 1, 1, 1]; // Точка "в углу" 4D куба
const result = cartesianToHyperspherical(vertice);
console.log("Результаты (в радианах):", result);
console.log(`Altitude: ${(result.altitude * 180 / Math.PI).toFixed(2)}°`);
console.log(`Latitude: ${(result.latitude * 180 / Math.PI).toFixed(2)}°`);
console.log(`Longitude: ${(result.longitude * 180 / Math.PI).toFixed(2)}°`);
*/
/**
* Adds a longitude, latitude and altitude property to the vertice angles array for the hypersphere.
* @param {array} vertice array of the vertice angles. Array length is 3. array[0] is altitude. array[1] is latitude. array[2] is longitude.
* @returns {array} Array with longitude and latitude property.
*/
export const angles = (vertice, altitude) => {
if (vertice.longitude != undefined) return vertice;
while (vertice.length < 3) vertice.unshift((vertice.length === 2) && (altitude != undefined) ? altitude : 0);
Object.defineProperty(vertice, 'altitude', {
get: () => { return vertice[0]; },
set: (altitude) => {
if (vertice[0] === altitude) return true;
vertice[0] = altitude;
return true;
},
});
Object.defineProperty(vertice, 'latitude', {
get: () => { return vertice[1]; },
set: (latitude) => {
if (vertice[1] === latitude) return true;
vertice[1] = latitude;
return true;
},
});
Object.defineProperty(vertice, 'longitude', {
get: () => { return vertice[2]; },
set: (longitude) => {
if (vertice[2] === longitude) return true;
vertice[2] = longitude;
return true;
},
});
return vertice;
}