@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
JavaScript
;
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