calculations.js•19 kB
/**
 * Human Design Calculations
 * Модуль для расчета карты Human Design
 */
// Импорт для расчета позиций планет
import Swisseph from 'swisseph';
// Примечание: Для работы с CommonJS модулем swisseph может потребоваться динамический импорт
// или использование require в CommonJS контексте
// 64 ворот (gates) в Human Design
const GATES = {
  // Создание/Творчество/Формы
  1: { name: 'The Creative', house: 1, line: 6 },
  // Питание/Взаимодействие
  2: { name: 'The Receptive', house: 1, line: 6 },
  // Образование/Начало
  3: { name: 'Ordering', house: 1, line: 6 },
  // Формирование/Решение
  4: { name: 'Formulization', house: 1, line: 6 },
  // Время/Ожидание
  5: { name: 'Needing', house: 1, line: 6 },
  // Конфликт/Приспособление
  6: { name: 'Friction', house: 1, line: 6 },
  // Армейское управление/Роль
  7: { name: 'The Role of Self', house: 1, line: 6 },
  // Сдерживание/Вклад
  8: { name: 'Holding Together', house: 1, line: 6 },
  // Сосредоточение/Детали
  9: { name: 'The Focus', house: 1, line: 6 },
  // Поведение/Кризис
  10: { name: 'The Treading', house: 1, line: 6 },
  // Идеи/Мир
  11: { name: 'Ideas', house: 1, line: 6 },
  // Привязанность/Устойчивость
  12: { name: 'Caution', house: 1, line: 6 },
  // Слушатель/Сообщества
  13: { name: 'The Listener', house: 1, line: 6 },
  // Могущество/Навыки
  14: { name: 'Power Skills', house: 1, line: 6 },
  // Смирение/Экстремизм
  15: { name: 'Modesty', house: 1, line: 6 },
  // Энтузиазм/Навыки
  16: { name: 'Skills', house: 1, line: 6 },
  // Мнение/Следование
  17: { name: 'Following', house: 1, line: 6 },
  // Корректировка/Работа
  18: { name: 'Work', house: 1, line: 6 },
  // Желание/Сближение
  19: { name: 'Approach', house: 1, line: 6 },
  // Присутствие/Сейчас
  20: { name: 'Now', house: 1, line: 6 },
  // Контроль/Редактор
  21: { name: 'The Editor', house: 1, line: 6 },
  // Грация/Открытость
  22: { name: 'Openness', house: 1, line: 6 },
  // Ассимиляция/Разделение
  23: { name: 'Splitting Apart', house: 1, line: 6 },
  // Возвращение/Рационализация
  24: { name: 'Rationalizing', house: 1, line: 6 },
  // Невинность/Дух
  25: { name: 'Spirit of the Self', house: 1, line: 6 },
  // Эгоистический/Передача транса
  26: { name: 'The Transmitter', house: 1, line: 6 },
  // Заботливость/Кормление
  27: { name: 'Caring', house: 1, line: 6 },
  // Игрок/Преодоление
  28: { name: 'The Game Player', house: 1, line: 6 },
  // Сказать да/Обязательства
  29: { name: 'Saying Yes', house: 1, line: 6 },
  // Чувства/Распознавание
  30: { name: 'Recognition of Feelings', house: 1, line: 6 },
  // Притягательная сила/Лидерство
  31: { name: 'Influence', house: 1, line: 6 },
  // Продолжительность/Редкость
  32: { name: 'The Duration', house: 1, line: 6 },
  // Скрытность/Отступление
  33: { name: 'Retreat', house: 1, line: 6 },
  // Могущество/Большой вклад
  34: { name: 'Great Power', house: 1, line: 6 },
  // Изменение/Прогресс
  35: { name: 'Progress', house: 1, line: 6 },
  // Несоответствие/Кризис
  36: { name: 'Crisis', house: 1, line: 6 },
  // Семья/Равенство
  37: { name: 'Friendship', house: 1, line: 6 },
  // Воин/Сражение
  38: { name: 'The Fighter', house: 1, line: 6 },
  // Возбудитель/Противодействие
  39: { name: 'Provocation', house: 1, line: 6 },
  // Необходимость/Работа
  40: { name: 'Deliverance', house: 1, line: 6 },
  // Желание/Сжатие
  41: { name: 'Contraction', house: 1, line: 6 },
  // Рост/Увеличение
  42: { name: 'Growth', house: 1, line: 6 },
  // Прозрение/Различение
  43: { name: 'Insight', house: 1, line: 6 },
  // Встреча/Подход
  44: { name: 'Coming to Meet', house: 1, line: 6 },
  // Собрание/Король
  45: { name: 'The Gatherer', house: 1, line: 6 },
  // Восхождение на холм/Определение
  46: { name: 'Determination', house: 1, line: 6 },
  // Понимание/Реализация
  47: { name: 'Realization', house: 1, line: 6 },
  // Источник/Колодец
  48: { name: 'The Well', house: 1, line: 6 },
  // Революция/Принципы
  49: { name: 'Revolution', house: 1, line: 6 },
  // Огонь/Ценности
  50: { name: 'Values', house: 1, line: 6 },
  // Возбуждение/Инициатива
  51: { name: 'The Arousing', house: 1, line: 6 },
  // Остановка/Накопление
  52: { name: 'Keeping Still', house: 1, line: 6 },
  // Развитие/Порядок
  53: { name: 'Development', house: 1, line: 6 },
  // Верность/Невестка
  54: { name: 'The Marrying Maiden', house: 1, line: 6 },
  // Избыток/Изобилие
  55: { name: 'Abundance', house: 1, line: 6 },
  // Странник/Путешествие
  56: { name: 'The Wanderer', house: 1, line: 6 },
  // Нежный/Проникновение
  57: { name: 'The Gentle', house: 1, line: 6 },
  // Источник удовольствия/Радость
  58: { name: 'The Joyous', house: 1, line: 6 },
  // Разделение/Сближение
  59: { name: 'Dispersion', house: 1, line: 6 },
  // Ограничение/Распределение
  60: { name: 'Limitation', house: 1, line: 6 },
  // Внутренняя правда/Центральность
  61: { name: 'Inner Truth', house: 1, line: 6 },
  // Малая экспансия/Детали
  62: { name: 'Detail', house: 1, line: 6 },
  // После завершения/Завершение
  63: { name: 'After Completion', house: 1, line: 6 },
  // До завершения/Не до конца
  64: { name: 'Before Completion', house: 1, line: 6 },
};
// 36 каналов в Human Design
const CHANNELS = {
  '1-8': { name: 'Channel of Inspiration', centers: [1, 8] },
  '2-14': { name: 'Channel of The Beat', centers: [2, 14] },
  '3-60': { name: 'Channel of Mutation', centers: [3, 60] },
  '4-63': { name: 'Channel of Logic', centers: [4, 63] },
  '5-15': { name: 'Channel of Rhythm', centers: [5, 15] },
  '6-59': { name: 'Channel of Mating', centers: [6, 59] },
  '7-31': { name: 'Channel of The Alpha', centers: [7, 31] },
  '9-52': { name: 'Channel of Determination', centers: [9, 52] },
  '10-20': { name: 'Channel of Awakening', centers: [10, 20] },
  '10-34': { name: 'Channel of Exploration', centers: [10, 34] },
  '10-57': { name: 'Channel of Perfected Form', centers: [10, 57] },
  '11-56': { name: 'Channel of Curiosity', centers: [11, 56] },
  '12-22': { name: 'Channel of Openness', centers: [12, 22] },
  '13-33': { name: 'Channel of The Prodigal', centers: [13, 33] },
  '16-48': { name: 'Channel of The Wavelength', centers: [16, 48] },
  '17-62': { name: 'Channel of Acceptance', centers: [17, 62] },
  '18-58': { name: 'Channel of Judgement', centers: [18, 58] },
  '19-49': { name: 'Channel of Synthesis', centers: [19, 49] },
  '20-34': { name: 'Channel of Charisma', centers: [20, 34] },
  '20-57': { name: 'Channel of The Brain Wave', centers: [20, 57] },
  '21-45': { name: 'Channel of Money', centers: [21, 45] },
  '23-43': { name: 'Channel of Structuring', centers: [23, 43] },
  '24-61': { name: 'Channel of Awareness', centers: [24, 61] },
  '25-51': { name: 'Channel of Initiation', centers: [25, 51] },
  '26-44': { name: 'Channel of Surrender', centers: [26, 44] },
  '27-50': { name: 'Channel of Preservation', centers: [27, 50] },
  '28-38': { name: 'Channel of Struggle', centers: [28, 38] },
  '29-46': { name: 'Channel of Discovery', centers: [29, 46] },
  '30-41': { name: 'Channel of Recognition', centers: [30, 41] },
  '32-54': { name: 'Channel of Transformation', centers: [32, 54] },
  '34-57': { name: 'Channel of Power', centers: [34, 57] },
  '35-36': { name: 'Channel of Transitoriness', centers: [35, 36] },
  '37-40': { name: 'Channel of Community', centers: [37, 40] },
  '39-55': { name: 'Channel of Emoting', centers: [39, 55] },
  '42-53': { name: 'Channel of Maturation', centers: [42, 53] },
  '47-64': { name: 'Channel of Abstraction', centers: [47, 64] },
};
// 9 центров Human Design
const CENTERS = {
  1: { name: 'Root Center', type: 'pressure', color: '#FF6B6B' },
  2: { name: 'Sacral Center', type: 'motor', color: '#FF9F43' },
  3: { name: 'Solar Plexus Center', type: 'motor', color: '#FFD93D' },
  4: { name: 'Heart Center', type: 'motor', color: '#6BCF7F' },
  5: { name: 'Throat Center', type: 'output', color: '#4ECDC4' },
  6: { name: 'Ajna Center', type: 'awareness', color: '#45B7D1' },
  7: { name: 'Head Center', type: 'pressure', color: '#96CEB4' },
  8: { name: 'Spleen Center', type: 'awareness', color: '#FFEAA7' },
  9: { name: 'G Center', type: 'identity', color: '#DDA0DD' },
};
/**
 * Рассчитывает позицию планеты в Human Design
 * @param {number} jd - Юлианская дата
 * @param {string} planetName - Название планеты
 * @returns {Object} Позиция планеты с воротами и линией
 */
function calculatePlanetPosition(jd, planetName) {
  try {
    const planetIndex = getPlanetIndex(planetName);
    const position = Swisseph.calc_ut(jd, planetIndex);
    const longitude = position.longitude;
    
    // Human Design использует тропический зодиак (не сидерический)
    const sign = Math.floor(longitude / 30) + 1;
    const degree = longitude % 30;
    
    // Каждый знак делится на 6 ворот (по 5.33 градуса каждое)
    // В Human Design всего 64 ворот (не 72!)
    const gateInSign = Math.floor(degree / 5.625) + 1; // 360/64 = 5.625
    const gate = (sign - 1) * 2 + gateInSign;
    
    // Линия определяется по остатку от деления градуса внутри ворот
    const degreeInGate = degree % 5.625;
    const line = Math.floor(degreeInGate / 0.9375) + 1; // 5.625/6 = 0.9375
    
    return {
      name: planetName,
      longitude: longitude,
      sign: sign,
      gate: gate,
      line: line,
      gateName: GATES[gate]?.name || 'Unknown',
    };
  } catch (error) {
    console.error(`Error calculating ${planetName}:`, error);
    return null;
  }
}
/**
 * Получить индекс планеты для Swiss Ephemeris
 */
function getPlanetIndex(planetName) {
  const planetMap = {
    'Sun': 0,
    'Moon': 1,
    'Mercury': 3,
    'Venus': 4,
    'Mars': 2,
    'Jupiter': 5,
    'Saturn': 6,
    'Rahu': 11, // North Node
    'Ketu': 12, // South Node
  };
  return planetMap[planetName] || 0;
}
/**
 * Основная функция расчета Human Design карты
 */
export async function calculateHumanDesign({
  birthDate,
  birthTime,
  birthLocation,
  latitude,
  longitude,
}) {
  try {
    // Парсинг даты и времени
    const [year, month, day] = birthDate.split('-').map(Number);
    const [hour, minute] = birthTime.split(':').map(Number);
    
    // Конвертация в Юлианскую дату
    const jd = Swisseph.julday(year, month, day, hour + minute / 60, 1); // Gregorian calendar
    
    // Расчет позиций всех планет
    const planets = [
      'Sun',
      'Moon',
      'Mercury',
      'Venus',
      'Mars',
      'Jupiter',
      'Saturn',
      'Rahu',
      'Ketu',
    ];
    
    const planetPositions = planets.map(planet => 
      calculatePlanetPosition(jd, planet)
    ).filter(p => p !== null);
    
    // Определение ворот (активных)
    const gates = planetPositions.map(p => ({
      number: p.gate,
      name: p.gateName,
      line: p.line,
      planet: p.name,
    }));
    
    // Определение типа
    const type = determineType(gates);
    
    // Определение профиля
    const profile = determineProfile(planetPositions);
    
    // Определение авторитета
    const authority = determineAuthority(planetPositions);
    
    // Определение стратегии
    const strategy = determineStrategy(type);
    
    // Определение определенных центров
    const definedCenters = getDefinedCenters(gates);
    
    return {
      birthDate,
      birthTime,
      birthLocation,
      type,
      strategy,
      authority,
      profile,
      gates,
      definedCenters,
      planetPositions: planetPositions.map(p => ({
        planet: p.name,
        sign: p.sign,
        gate: p.gate,
        line: p.line,
      })),
      incarnationCross: determineIncarnationCross(planetPositions),
    };
  } catch (error) {
    console.error('Error calculating Human Design:', error);
    throw new Error(`Failed to calculate Human Design: ${error.message}`);
  }
}
/**
 * Определение типа Human Design
 */
function determineType(gates) {
  // Это упрощенная версия - в реальности нужно проверять определенные центры
  const definedGates = gates.map(g => g.number);
  
  // Проверка наличия определенных центров через ворота
  const sacralGates = [2, 7, 10, 13, 15, 16, 21, 27, 44, 48, 50, 51, 56, 59, 62];
  const throatGates = [2, 3, 5, 7, 10, 11, 12, 16, 17, 20, 21, 22, 23, 24, 28, 31, 33, 45, 56, 62];
  const solarPlexusGates = [20, 25, 30, 34, 35, 36, 37, 38, 39, 40, 41, 55];
  
  const hasSacral = sacralGates.some(g => definedGates.includes(g));
  const hasThroat = throatGates.some(g => definedGates.includes(g));
  const hasSolarPlexus = solarPlexusGates.some(g => definedGates.includes(g));
  
  if (hasSacral && hasThroat) {
    return {
      name: 'Manifesting Generator',
      description: 'Манифестирующий Генератор',
    };
  }
  
  if (hasSacral) {
    return {
      name: 'Generator',
      description: 'Генератор',
    };
  }
  
  if (!hasThroat) {
    return {
      name: 'Reflector',
      description: 'Рефлектор',
    };
  }
  
  if (hasSolarPlexus) {
    return {
      name: 'Projector',
      description: 'Проектор',
    };
  }
  
  return {
    name: 'Manifestor',
    description: 'Манифестор',
  };
}
/**
 * Определение профиля
 */
function determineProfile(planetPositions) {
  // Профиль определяется линией Солнца и Земли
  const sun = planetPositions.find(p => p.name === 'Sun');
  const earth = planetPositions.find(p => p.name === 'Earth') || planetPositions.find(p => p.name === 'Sun'); // Земля противоположна Солнцу
  
  if (!sun) return null;
  
  const sunLine = sun.line;
  const earthLine = 6 - sunLine; // Earth is opposite to Sun
  
  return {
    number: `${sunLine}/${earthLine}`,
    description: `Профиль ${sunLine}/${earthLine}`,
  };
}
/**
 * Определение авторитета
 */
function determineAuthority(planetPositions) {
  const solarPlexusGates = [20, 25, 30, 34, 35, 36, 37, 38, 39, 40, 41, 55];
  const sacralGates = [2, 7, 10, 13, 15, 16, 21, 27, 44, 48, 50, 51, 56, 59, 62];
  const splenicGates = [18, 26, 44, 45, 48, 57, 58];
  const egoGates = [21, 26, 40, 51];
  const gGates = [1, 2, 7, 10, 13, 15, 25, 46];
  
  const gates = planetPositions.map(p => p.gate);
  
  if (solarPlexusGates.some(g => gates.includes(g))) {
    return {
      name: 'Emotional',
      description: 'Эмоциональная авторитет',
    };
  }
  
  if (sacralGates.some(g => gates.includes(g))) {
    return {
      name: 'Sacral',
      description: 'Сакральная авторитет',
    };
  }
  
  if (splenicGates.some(g => gates.includes(g))) {
    return {
      name: 'Splenic',
      description: 'Селезеночная авторитет',
    };
  }
  
  if (egoGates.some(g => gates.includes(g))) {
    return {
      name: 'Ego Manifested',
      description: 'Проявленный Эго',
    };
  }
  
  if (gGates.some(g => gates.includes(g))) {
    return {
      name: 'G Center',
      description: 'G-Центр авторитет',
    };
  }
  
  return {
    name: 'No Inner Authority',
    description: 'Без внутренней власти',
  };
}
/**
 * Определение стратегии
 */
function determineStrategy(type) {
  const strategies = {
    'Manifestor': 'Информировать',
    'Generator': 'Отвечать',
    'Manifesting Generator': 'Отвечать и информировать',
    'Projector': 'Ждать приглашения',
    'Reflector': 'Ждать полного лунного цикла',
  };
  
  return strategies[type.name] || 'Отвечать';
}
/**
 * Получить определенные центры
 */
function getDefinedCenters(gates) {
  const gateNumbers = gates.map(g => g.number);
  
  // Маппинг ворот к центрам (упрощенно)
  const centerGates = {
    1: [1, 7, 13, 17, 21, 25, 26, 30, 38, 51, 57, 61, 63],
    2: [2, 27, 36, 42, 52],
    3: [37, 38, 39, 40, 41, 55],
    4: [21, 26, 40, 51],
    5: [2, 3, 5, 7, 10, 11, 12, 16, 17, 20, 21, 22, 23, 24, 28, 31, 33, 45, 56, 62],
    6: [9, 24, 43, 47, 61],
    7: [11, 23, 43, 47, 64, 61],
    8: [44, 45, 46, 50],
    9: [1, 2, 7, 10, 13, 15, 25, 46],
  };
  
  const defined = [];
  
  for (const [center, gates] of Object.entries(centerGates)) {
    if (gates.some(g => gateNumbers.includes(g))) {
      defined.push({
        number: parseInt(center),
        name: CENTERS[center]?.name || 'Unknown',
      });
    }
  }
  
  return defined;
}
/**
 * Определение Incarnation Cross
 */
function determineIncarnationCross(planetPositions) {
  const sun = planetPositions.find(p => p.name === 'Sun');
  const earth = planetPositions.find(p => p.name === 'Earth'); // Земля противоположна Солнцу
  
  if (!sun) return null;
  
  // Incarnation Cross определяется солнечной и земной позицией
  return {
    sunGate: sun.gate,
    earthGate: sun.gate, // Упрощенно
    cross: `Cross of ${sun.gate} / ${sun.gate}`,
  };
}