UNPKG

swisseph-wasm

Version:

High-precision Swiss Ephemeris WebAssembly library for astronomical calculations in JavaScript

388 lines (334 loc) 12.6 kB
/** * Birth Chart Calculation Example * * This example demonstrates how to calculate a complete birth chart * including planetary positions, houses, and various coordinate systems. */ import SwissEph from '../src/swisseph.js'; /** * Birth Chart Calculator Class * Provides methods for calculating comprehensive birth charts */ class BirthChartCalculator { constructor() { this.swe = null; this.initialized = false; } /** * Initialize the Swiss Ephemeris */ async init() { if (!this.initialized) { this.swe = new SwissEph(); await this.swe.initSwissEph(); this.initialized = true; } } /** * Calculate a complete birth chart * @param {Object} birthData - Birth information * @param {number} birthData.year - Birth year * @param {number} birthData.month - Birth month (1-12) * @param {number} birthData.day - Birth day * @param {number} birthData.hour - Birth hour (0-23) * @param {number} birthData.minute - Birth minute (0-59) * @param {number} birthData.timezone - Timezone offset from UTC * @param {number} birthData.latitude - Birth latitude * @param {number} birthData.longitude - Birth longitude * @param {string} birthData.houseSystem - House system ('P', 'K', 'E', etc.) * @returns {Object} Complete birth chart data */ async calculateBirthChart(birthData) { await this.init(); const { year, month, day, hour, minute, timezone, latitude, longitude, houseSystem = 'P' } = birthData; // Convert local time to UTC const utcHour = hour + minute / 60 - timezone; const jd = this.swe.julday(year, month, day, utcHour); // Calculate planetary positions const planets = await this.calculatePlanets(jd); // Calculate houses const houses = await this.calculateHouses(jd, latitude, longitude, houseSystem); // Calculate additional points const additionalPoints = await this.calculateAdditionalPoints(jd); // Calculate aspects const aspects = this.calculateAspects(planets); return { birthData: { ...birthData, julianDay: jd, utcTime: utcHour }, planets, houses, additionalPoints, aspects, metadata: { calculatedAt: new Date().toISOString(), swissEphVersion: this.swe.version() } }; } /** * Calculate positions for all major planets * @param {number} jd - Julian Day * @returns {Object} Planet positions */ async calculatePlanets(jd) { const planetList = [ { id: this.swe.SE_SUN, name: 'Sun', symbol: '☉' }, { id: this.swe.SE_MOON, name: 'Moon', symbol: '☽' }, { id: this.swe.SE_MERCURY, name: 'Mercury', symbol: '☿' }, { id: this.swe.SE_VENUS, name: 'Venus', symbol: '♀' }, { id: this.swe.SE_MARS, name: 'Mars', symbol: '♂' }, { id: this.swe.SE_JUPITER, name: 'Jupiter', symbol: '♃' }, { id: this.swe.SE_SATURN, name: 'Saturn', symbol: '♄' }, { id: this.swe.SE_URANUS, name: 'Uranus', symbol: '♅' }, { id: this.swe.SE_NEPTUNE, name: 'Neptune', symbol: '♆' }, { id: this.swe.SE_PLUTO, name: 'Pluto', symbol: '♇' } ]; const planets = {}; for (const planet of planetList) { const position = this.swe.calc_ut(jd, planet.id, this.swe.SEFLG_SWIEPH | this.swe.SEFLG_SPEED); planets[planet.name] = { id: planet.id, name: planet.name, symbol: planet.symbol, longitude: position[0], latitude: position[1], distance: position[2], speed: position[3], zodiacSign: this.getZodiacSign(position[0]), house: null // Will be calculated later with houses }; } return planets; } /** * Calculate house cusps and angles * @param {number} jd - Julian Day * @param {number} latitude - Geographic latitude * @param {number} longitude - Geographic longitude * @param {string} houseSystem - House system * @returns {Object} House information */ async calculateHouses(jd, latitude, longitude, houseSystem) { // Calculate houses using the specified system const houseResult = this.swe.houses(jd, latitude, longitude, houseSystem); // Get sidereal time for ARMC calculation const sidTime = this.swe.sidtime(jd); const armc = (sidTime + longitude / 15) * 15; // Convert to degrees const houses = { system: houseSystem, cusps: [], angles: { ascendant: null, midheaven: null, descendant: null, imumCoeli: null } }; // Extract house cusps (houses 1-12) for (let i = 1; i <= 12; i++) { houses.cusps[i] = { house: i, longitude: houseResult, // This would need proper implementation zodiacSign: this.getZodiacSign(houseResult) }; } // Calculate angles houses.angles.ascendant = houses.cusps[1].longitude; houses.angles.midheaven = houses.cusps[10].longitude; houses.angles.descendant = (houses.cusps[1].longitude + 180) % 360; houses.angles.imumCoeli = (houses.cusps[10].longitude + 180) % 360; return houses; } /** * Calculate additional astrological points * @param {number} jd - Julian Day * @returns {Object} Additional points */ async calculateAdditionalPoints(jd) { const points = {}; // Lunar nodes const meanNode = this.swe.calc_ut(jd, this.swe.SE_MEAN_NODE, this.swe.SEFLG_SWIEPH); const trueNode = this.swe.calc_ut(jd, this.swe.SE_TRUE_NODE, this.swe.SEFLG_SWIEPH); points.meanNode = { name: 'Mean North Node', symbol: '☊', longitude: meanNode[0], zodiacSign: this.getZodiacSign(meanNode[0]) }; points.trueNode = { name: 'True North Node', symbol: '☊', longitude: trueNode[0], zodiacSign: this.getZodiacSign(trueNode[0]) }; // South nodes (opposite of north nodes) points.meanSouthNode = { name: 'Mean South Node', symbol: '☋', longitude: (meanNode[0] + 180) % 360, zodiacSign: this.getZodiacSign((meanNode[0] + 180) % 360) }; // Lunar apogee (Lilith) const meanApogee = this.swe.calc_ut(jd, this.swe.SE_MEAN_APOG, this.swe.SEFLG_SWIEPH); points.lilith = { name: 'Mean Lilith', symbol: '⚸', longitude: meanApogee[0], zodiacSign: this.getZodiacSign(meanApogee[0]) }; // Chiron const chiron = this.swe.calc_ut(jd, this.swe.SE_CHIRON, this.swe.SEFLG_SWIEPH); points.chiron = { name: 'Chiron', symbol: '⚷', longitude: chiron[0], zodiacSign: this.getZodiacSign(chiron[0]) }; return points; } /** * Calculate major aspects between planets * @param {Object} planets - Planet positions * @returns {Array} List of aspects */ calculateAspects(planets) { const aspects = []; const planetNames = Object.keys(planets); // Major aspects with their angles and orbs const aspectTypes = [ { name: 'Conjunction', angle: 0, orb: 8, symbol: '☌' }, { name: 'Opposition', angle: 180, orb: 8, symbol: '☍' }, { name: 'Trine', angle: 120, orb: 6, symbol: '△' }, { name: 'Square', angle: 90, orb: 6, symbol: '□' }, { name: 'Sextile', angle: 60, orb: 4, symbol: '⚹' }, { name: 'Quincunx', angle: 150, orb: 3, symbol: '⚻' } ]; // Check all planet pairs for (let i = 0; i < planetNames.length; i++) { for (let j = i + 1; j < planetNames.length; j++) { const planet1 = planets[planetNames[i]]; const planet2 = planets[planetNames[j]]; const angle = Math.abs(planet1.longitude - planet2.longitude); const normalizedAngle = angle > 180 ? 360 - angle : angle; // Check each aspect type for (const aspectType of aspectTypes) { const difference = Math.abs(normalizedAngle - aspectType.angle); if (difference <= aspectType.orb) { aspects.push({ planet1: planet1.name, planet2: planet2.name, aspect: aspectType.name, symbol: aspectType.symbol, angle: aspectType.angle, actualAngle: normalizedAngle, orb: difference, applying: planet1.speed > planet2.speed }); } } } } return aspects.sort((a, b) => a.orb - b.orb); } /** * Get zodiac sign information for a longitude * @param {number} longitude - Longitude in degrees * @returns {Object} Zodiac sign information */ getZodiacSign(longitude) { const signs = [ { name: 'Aries', symbol: '♈', element: 'Fire', quality: 'Cardinal' }, { name: 'Taurus', symbol: '♉', element: 'Earth', quality: 'Fixed' }, { name: 'Gemini', symbol: '♊', element: 'Air', quality: 'Mutable' }, { name: 'Cancer', symbol: '♋', element: 'Water', quality: 'Cardinal' }, { name: 'Leo', symbol: '♌', element: 'Fire', quality: 'Fixed' }, { name: 'Virgo', symbol: '♍', element: 'Earth', quality: 'Mutable' }, { name: 'Libra', symbol: '♎', element: 'Air', quality: 'Cardinal' }, { name: 'Scorpio', symbol: '♏', element: 'Water', quality: 'Fixed' }, { name: 'Sagittarius', symbol: '♐', element: 'Fire', quality: 'Mutable' }, { name: 'Capricorn', symbol: '♑', element: 'Earth', quality: 'Cardinal' }, { name: 'Aquarius', symbol: '♒', element: 'Air', quality: 'Fixed' }, { name: 'Pisces', symbol: '♓', element: 'Water', quality: 'Mutable' } ]; const signIndex = Math.floor(longitude / 30); const degree = longitude % 30; return { ...signs[signIndex], degree: degree, formatted: `${degree.toFixed(2)}° ${signs[signIndex].name}` }; } /** * Clean up resources */ destroy() { if (this.swe) { this.swe.close(); this.swe = null; this.initialized = false; } } } /** * Example usage of the Birth Chart Calculator */ async function exampleBirthChart() { console.log('=== Birth Chart Calculation Example ===\n'); const calculator = new BirthChartCalculator(); try { // Example birth data const birthData = { year: 1990, month: 5, day: 15, hour: 14, minute: 30, timezone: -5, // UTC-5 (Eastern Daylight Time) latitude: 40.7128, // New York City longitude: -74.0060, houseSystem: 'P' // Placidus }; console.log('Calculating birth chart for:'); console.log(`Date: ${birthData.year}-${birthData.month.toString().padStart(2, '0')}-${birthData.day.toString().padStart(2, '0')}`); console.log(`Time: ${birthData.hour}:${birthData.minute.toString().padStart(2, '0')} (UTC${birthData.timezone})`); console.log(`Location: ${birthData.latitude}°N, ${Math.abs(birthData.longitude)}°W\n`); const chart = await calculator.calculateBirthChart(birthData); // Display planetary positions console.log('PLANETARY POSITIONS:'); console.log('==================='); for (const [name, planet] of Object.entries(chart.planets)) { console.log(`${planet.symbol} ${name.padEnd(10)}: ${planet.zodiacSign.formatted} (${planet.longitude.toFixed(2)}°)`); } // Display additional points console.log('\nADDITIONAL POINTS:'); console.log('=================='); for (const [name, point] of Object.entries(chart.additionalPoints)) { console.log(`${point.symbol} ${point.name.padEnd(15)}: ${point.zodiacSign.formatted} (${point.longitude.toFixed(2)}°)`); } // Display major aspects console.log('\nMAJOR ASPECTS:'); console.log('=============='); chart.aspects.slice(0, 10).forEach(aspect => { console.log(`${aspect.planet1} ${aspect.symbol} ${aspect.planet2}: ${aspect.aspect} (orb: ${aspect.orb.toFixed(2)}°)`); }); console.log(`\nTotal aspects found: ${chart.aspects.length}`); console.log(`Calculated using Swiss Ephemeris ${chart.metadata.swissEphVersion}`); } catch (error) { console.error('Error calculating birth chart:', error); } finally { calculator.destroy(); } } // Export the calculator class and example function export { BirthChartCalculator, exampleBirthChart }; // Run example if this file is executed directly // Check if running in Node.js and if this is the main module if (typeof process !== 'undefined' && process.argv && import.meta.url === `file://${process.argv[1]}`) { exampleBirthChart().catch(console.error); }