From 37e8a09b609364e19e1ea25da68b9b57d7c0b4ae Mon Sep 17 00:00:00 2001 From: Marcos Corona Date: Mon, 14 Dec 2020 01:34:43 -0300 Subject: [PATCH] feature(horoscope): add aspects to response (#7) * Refactor aspect test * Add orbs when calculating aspects * Disable rules of arrow-line-body * Add direction of aspect (bidirecional/unidirectional) * Add aspects to /horoscope response (using huber orbs) --- .eslintrc.js | 3 +- src/api/index.js | 3 +- src/astrologer/aspects.js | 130 ++++++++++++++++++ src/astrologer/astros.js | 20 +++ src/astrologer/index.js | 8 +- src/astrologer/utils.js | 12 ++ ...culate-aspects-between-two-planets.test.js | 62 +++++++++ .../units/calculate-aspects-with-orbs.test.js | 101 ++++++++++++++ 8 files changed, 335 insertions(+), 4 deletions(-) create mode 100644 src/astrologer/aspects.js create mode 100644 test/units/calculate-aspects-between-two-planets.test.js create mode 100644 test/units/calculate-aspects-with-orbs.test.js diff --git a/.eslintrc.js b/.eslintrc.js index 2f012b3..45a1787 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,7 +11,8 @@ module.exports = { camelcase: 0, "no-bitwise": ["error", { allow: ["|"] }], "max-len": 0, - quotes: [2, "double", "avoid-escape"] + quotes: [2, "double", "avoid-escape"], + "arrow-body-style": 0 }, settings: { "import/resolver": { diff --git a/src/api/index.js b/src/api/index.js index 51e9163..6afa41b 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -10,7 +10,7 @@ router.get("/horoscope", async (req, res) => { const { latitude, longitude } = req.query; const planets = astrologer.planets(date); - + const aspects = astrologer.aspects(planets); const houses = astrologer.houses(date, { latitude: parseFloat(latitude), longitude: parseFloat(longitude), @@ -22,6 +22,7 @@ router.get("/horoscope", async (req, res) => { ...planets, }, ...houses, + aspects }, }); }); diff --git a/src/astrologer/aspects.js b/src/astrologer/aspects.js new file mode 100644 index 0000000..3958236 --- /dev/null +++ b/src/astrologer/aspects.js @@ -0,0 +1,130 @@ +const { normalizeDegrees } = require("./utils"); + +const ASPECTS = { + 0: "conjunction", + 30: "semisextile", + 60: "sextile", + 90: "quadrature", + 120: "trigone", + 150: "quincunx", + 180: "opposition", +}; + +// HUBER ORBS... but mars and jupiter modified... +const DEFAULT_ORBS = { + luminary: { + 0: 10, + 30: 3, + 60: 5, + 90: 6, + 120: 8, + 150: 5, + 180: 10 + }, + personal: { + 0: 7, + 30: 2, + 60: 4, + 90: 5, + 120: 6, + 150: 2, + 180: 7 + }, + social: { + 0: 6, + 30: 1.5, + 60: 3, + 90: 4, + 120: 5, + 150: 3, + 180: 6 + }, + transpersonal: { + 0: 5, + 30: 1, + 60: 2, + 90: 3, + 120: 4, + 150: 2, + 180: 5 + }, + other: { + 0: 5, + 30: 1, + 60: 2, + 90: 3, + 120: 4, + 150: 2, + 180: 5 + } +}; + +const calculateAspect = (first, second, orbs) => { + return Object.keys({ ...ASPECTS }).filter( + (a) => { + const totalOrbsForAspect = orbs[a]; + const from = parseFloat(a) - (totalOrbsForAspect / 2); + const to = parseFloat(a) + (totalOrbsForAspect / 2); + + const firstLongitude = normalizeDegrees(first.position.longitude); + const secondLongitude = normalizeDegrees(second.position.longitude); + + const diff = Math.abs(firstLongitude - secondLongitude); + return diff >= from && diff <= to; + } + ); +}; + +const aspect = (first, second, orbs) => { + if (orbs === undefined) { + orbs = { ...DEFAULT_ORBS }; + } + + const aspectsFirst = calculateAspect(first, second, orbs[first.type]); + const aspectsSecond = calculateAspect(first, second, orbs[second.type]); + + if (aspectsFirst.length === 0 && aspectsSecond.length === 0) { + return undefined; + } + + const direction = aspectsFirst.length === 1 && aspectsSecond.length === 1 ? "bidirectional" : "unidirectional"; + + return { + name: ASPECTS[aspectsFirst[0]], + direction, + first: { + name: first.name, + exist: aspectsFirst.length === 1 + }, + second: { + name: second.name, + exist: aspectsSecond.length === 1 + }, + }; +}; + +const aspects = (planets) => { + return Object.keys(planets).reduce((acc, planetKey) => { + if (acc[planetKey]) { + return acc; + } + + acc[planetKey] = []; + + Object.values(planets).filter((p) => p.name !== planetKey).forEach((p) => { + if (!acc[p.name]) { + const aspectsFounds = aspect(planets[planetKey], p); + if (aspectsFounds) { + acc[planetKey].push(aspectsFounds); + } + } + }); + + return acc; + }, {}); +}; + +module.exports = { + aspect, + aspects +}; diff --git a/src/astrologer/astros.js b/src/astrologer/astros.js index e40eba9..fae7519 100644 --- a/src/astrologer/astros.js +++ b/src/astrologer/astros.js @@ -23,6 +23,25 @@ const PLANETS = { juno: swisseph.SE_JUNO, }; +const planetsByType = { + sun: "luminary", + moon: "luminary", + mercury: "personal", + venus: "personal", + mars: "personal", + jupiter: "social", + saturn: "social", + uranus: "transpersonal", + neptune: "transpersonal", + pluto: "transpersonal", + chiron: "other", + lilith: "other", + ceres: "other", + vesta: "other", + pallas: "other", + juno: "other", +}; + const FLAG = swisseph.SEFLG_SPEED | swisseph.SEFLG_SWIEPH; const getPositionOfAstro = (astro, julianDayUT) => swisseph.swe_calc_ut(julianDayUT, PLANETS[astro], FLAG); @@ -44,4 +63,5 @@ const position = (astrologyObject, moment) => { module.exports = { PLANETS, position, + planetsByType }; diff --git a/src/astrologer/index.js b/src/astrologer/index.js index 3b7e1d8..d354d6e 100644 --- a/src/astrologer/index.js +++ b/src/astrologer/index.js @@ -1,5 +1,6 @@ -const { PLANETS, position } = require("./astros"); +const { PLANETS, position, planetsByType } = require("./astros"); const { houses } = require("./houses"); +const { aspect, aspects } = require("./aspects"); const planets = (date) => { const astros = Object.keys(PLANETS) @@ -9,6 +10,7 @@ const planets = (date) => { accumulator[name] = { name, ...planetPosition, + type: planetsByType[name] }; return accumulator; }, @@ -21,5 +23,7 @@ module.exports = { houses, position, PLANETS, - planets + planets, + aspect, + aspects, }; diff --git a/src/astrologer/utils.js b/src/astrologer/utils.js index e30cc5f..5315880 100644 --- a/src/astrologer/utils.js +++ b/src/astrologer/utils.js @@ -27,8 +27,20 @@ const degreesToDms = (value) => { const zodiacSign = (degrees) => (Math.floor(degrees / 30) % 12) + 1; +const normalizeDegrees = (degress) => { + if (degress < -180) { + return degress + 360; + } + if (degress > 180) { + return degress - 360; + } + + return degress; +}; + module.exports = { utcToJulianUt, degreesToDms, zodiacSign, + normalizeDegrees }; diff --git a/test/units/calculate-aspects-between-two-planets.test.js b/test/units/calculate-aspects-between-two-planets.test.js new file mode 100644 index 0000000..34c47c0 --- /dev/null +++ b/test/units/calculate-aspects-between-two-planets.test.js @@ -0,0 +1,62 @@ +const astrologer = require("./../../src/astrologer"); + +describe("Calculate aspects between two planets", () => { + const planetOne = { + name: "sun", + type: "luminary", + position: { + longitude: 10, + }, + }; + + const planetTwo = { + name: "pluto", + type: "transpersonal", + position: { + longitude: 30, + }, + }; + + it("2 planets may have no aspects", async () => { + planetOne.position.longitude = 10; + planetTwo.position.longitude = 30; + const aspect = astrologer.aspect(planetOne, planetTwo); + expect(aspect).toBe(undefined); + }); + + it("If two planets longitude difference is equal to 30 then exist conjunction", async () => { + planetOne.position.longitude = 30; + planetTwo.position.longitude = 30; + const aspect = astrologer.aspect(planetOne, planetTwo); + expect(aspect.name).toBe("conjunction"); + }); + + it("If two planets longitude difference is equal to 60 then exist sextile", async () => { + planetOne.position.longitude = 30; + planetTwo.position.longitude = 90; + + const aspect = astrologer.aspect(planetOne, planetTwo); + expect(aspect.name).toBe("sextile"); + }); + + it("If two planets longitude difference is equal to 90 then exist quadrature", async () => { + planetOne.position.longitude = 0; + planetTwo.position.longitude = 90; + const aspect = astrologer.aspect(planetOne, planetTwo); + expect(aspect.name).toBe("quadrature"); + }); + + it("If two planets longitude difference is equal to 120 then exist trigone", async () => { + planetOne.position.longitude = 355; + planetTwo.position.longitude = 115; + const aspect = astrologer.aspect(planetOne, planetTwo); + expect(aspect.name).toBe("trigone"); + }); + + it("If two planets longitude difference is equal to 180 then exist opposition", async () => { + planetOne.position.longitude = -270; + planetTwo.position.longitude = -90; + const aspect = astrologer.aspect(planetOne, planetTwo); + expect(aspect.name).toBe("opposition"); + }); +}); diff --git a/test/units/calculate-aspects-with-orbs.test.js b/test/units/calculate-aspects-with-orbs.test.js new file mode 100644 index 0000000..a2db3a6 --- /dev/null +++ b/test/units/calculate-aspects-with-orbs.test.js @@ -0,0 +1,101 @@ +const astrologer = require("../../src/astrologer"); + +describe("Calculate aspects between two planets applying orbs...", () => { + const first = { + position: { + longitude: 30 + } + }; + + const second = { + position: { + longitude: 34 + } + }; + + const orbs = { + luminary: { + 0: 10, + 30: 3, + 60: 5, + 90: 6, + 120: 8, + 150: 5, + 180: 10 + }, + personal: { + 0: 7, + 30: 2, + 60: 4, + 90: 5, + 120: 6, + 150: 2, + 180: 7 + }, + social: { + 0: 6, + 30: 1.5, + 60: 3, + 90: 4, + 120: 5, + 150: 3, + 180: 6 + }, + transpersonal: { + 0: 5, + 30: 1, + 60: 2, + 90: 3, + 120: 4, + 150: 2, + 180: 5 + }, + others: { + 0: 5, + 30: 1, + 60: 2, + 90: 3, + 120: 4, + 150: 2, + 180: 5 + } + }; + + it("using orb you can get a conjunction", () => { + first.type = "luminary"; + second.type = "luminary"; + + const aspect = astrologer.aspect( + first, + second, + orbs + ); + + expect(aspect.name).toBe("conjunction"); + }); + + it("using defaults orbs", () => { + first.type = "luminary"; + second.type = "luminary"; + + const aspect = astrologer.aspect( + first, + second + ); + + expect(aspect.name).toBe("conjunction"); + }); + + it("When by orbs, the second planet haven't aspect... then aspect is one direction...", () => { + first.type = "luminary"; + second.type = "transpersonal"; + + first.position.longitude = 30; + second.position.longitude = 34; + + const aspect = astrologer.aspect(first, second, orbs); + + expect(aspect.direction).toBe("unidirectional"); + expect(aspect.second.exist).toBe(false); + }); +});