UNPKG

@nrweb/astro-calc

Version:

Comprehensive astrological calculations using Swiss Ephemeris and astronomy-engine for positions, aspects, houses, lots, and scoring metrics

127 lines 5.22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.calculateAspects = calculateAspects; function calculateAspectDegrees(pos1, pos2) { const diff = Math.abs(pos1 - pos2); return Math.min(diff, 360 - diff); } function isWithinRange(diff, target, tolerance) { return Math.abs(diff - target) <= tolerance; } function getAspectType(diff) { if (isWithinRange(diff, 0, 10)) return "conjunction"; if (isWithinRange(diff, 60, 10)) return "sextile"; if (isWithinRange(diff, 90, 10)) return "square"; if (isWithinRange(diff, 120, 10)) return "trine"; if (isWithinRange(diff, 180, 10)) return "opposition"; return null; } function calculateDeviation(diff, target) { return diff - target; } function calculateGrade(deviation) { const absDeviation = Math.abs(deviation); if (absDeviation < 0.001) return "perfect"; if (absDeviation <= 3) return "joining"; return "assembly"; } function calculateDirection(pos1, pos2, target) { // Find which is faster const speed1 = Math.abs(pos1.speed); const speed2 = Math.abs(pos2.speed); const faster = speed1 >= speed2 ? pos1 : pos2; // Calculate current difference const diff = calculateAspectDegrees(pos1.position, pos2.position); const deviation = diff - target; // If the faster planet is ahead, check if it's moving toward or away from the aspect // If deviation > 0, faster planet needs to decrease the difference (move backward relative to slower) // If deviation < 0, faster planet needs to increase the difference (move forward relative to slower) // We'll use the sign of (faster.position - slower.position) and the sign of faster.speed - slower.speed // to determine if the difference is closing (applying) or opening (separating) // Calculate the rate of change of the difference // If the rate of change is reducing the absolute deviation, it's applying const rateOfChange = (faster === pos1 ? pos1.speed : -pos2.speed) - (faster === pos1 ? pos2.speed : -pos1.speed); // If deviation is positive, we want the difference to decrease (rateOfChange < 0) // If deviation is negative, we want the difference to increase (rateOfChange > 0) if ((deviation > 0 && rateOfChange < 0) || (deviation < 0 && rateOfChange > 0)) { return "applying"; } else { return "separating"; } } function calculateAspects(positions) { const aspects = []; for (let i = 0; i < positions.length; i++) { for (let j = i + 1; j < positions.length; j++) { const pos1 = positions[i]; const pos2 = positions[j]; // Skip Sun-Moon aspects as they're handled separately if ((pos1.name === "Sun" && pos2.name === "Moon") || (pos1.name === "Moon" && pos2.name === "Sun")) { continue; } const diff = calculateAspectDegrees(pos1.position, pos2.position); const aspectType = getAspectType(diff); if (aspectType) { const target = { conjunction: 0, sextile: 60, square: 90, trine: 120, opposition: 180, }[aspectType]; const deviation = calculateDeviation(diff, target); const grade = calculateGrade(deviation); // Determine which planet is left (behind) and which is right (ahead) in the zodiac // Handle cases near 0° Aries by calculating shortest distance const pos1Num = pos1.position; const pos2Num = pos2.position; // Calculate the shortest distance between the two positions let distance = Math.abs(pos2Num - pos1Num); if (distance > 180) { distance = 360 - distance; } // Determine which planet is ahead by checking which direction gives us the aspect let leftPlanet; let rightPlanet; // Check if pos1 is ahead of pos2 (clockwise) const pos1Ahead = (pos2Num - pos1Num + 360) % 360; if (pos1Ahead <= 180) { // pos1 is ahead of pos2 leftPlanet = pos2.name; rightPlanet = pos1.name; } else { // pos2 is ahead of pos1 leftPlanet = pos1.name; rightPlanet = pos2.name; } const aspect = { planets: { left: leftPlanet, right: rightPlanet, }, type: aspectType, deviation: deviation, grade: grade, }; if (grade !== "perfect") { aspect.direction = calculateDirection(pos1, pos2, target); } aspects.push(aspect); } } } return aspects; } //# sourceMappingURL=aspects.js.map