Astrology Engine

Choose a simple house convention

Twelve equal pieces can divide a circle, but we still have to decide where the first piece begins. A house convention makes that choice for a chart. We will construct the Equal cusp list, then see why choosing Whole Sign produces a different kind of output in this engine.

Before this lesson

Read “Find the horizon and meridian angles.” Keep the Ascendant and midheaven as distinct longitudes. All examples here use invented angles and teach chart conventions, rather than claims about their interpretation.

Read the preceding lesson.

What you will learn

Calculate any Equal cusp, keep house numbering separate from array indexing, and recognize the absence of a Whole Sign cusp list.

Dotted-underlined terms open a definition beside the text. Select one to read more, then close it to continue.

Each step has its own check. Pass every step to complete the lesson. Your answers and checked steps are saved in this browser, so you can continue after leaving or reloading.

1. Begin twelve equal intervals at the Ascendant

Imagine marking a circular dial every 30°. Twelve marks return you to the first because 12 × 30° = 360°. In the Equal convention implemented here, the first mark is the Ascendant. A house cusp is a boundary longitude; the twelve boundaries describe twelve equal intervals around the ecliptic. This division is an astrological convention applied after the astronomical directions have been calculated.

Use an invented Ascendant of 350°. The first three boundaries are 350°, 380° and 410° before wrapping. Subtracting a full turn from the last two gives 350°, 20° and 50°. The circle has not reversed direction at zero: the second boundary is still 30° beyond the first.

cusp h = wrap(Asc + (h − 1) × 30°), for house h = 1, …, 12

Here Asc is a longitude in degrees and wrap removes complete turns. House numbers begin at one, whereas the array index n in equal_cusps begins at zero. For house 10, n = 9, so the offset is 270°, not 300°. The complete list for Asc = 350° is [350, 20, 50, 80, 110, 140, 170, 200, 230, 260, 290, 320] degrees.

The supplied midheaven does not enter this formula. If our invented MC is 80°, the tenth Equal cusp is still 260°. house_set retains both the separate MC and the cusp array; it does not move a boundary to force MC onto house 10. The next lesson will introduce a convention that anchors the tenth cusp at MC.

Where the convention fits

Swiss Ephemeris documents several Equal variants. This engine uses the variant beginning at the Ascendant. The reference establishes that convention, but does not establish an original inventor for this repository’s helper; no inventor is assumed.

Once Equal is selected, house_set returns Some containing twelve values. Latitude and time have already helped produce the Ascendant, but equal_cusps needs only that longitude. Changing the house choice therefore changes the subdivision without resampling the planetary positions.

See the teaching TypeScript
const wrap = (x: number): number => { const r = x % 360; return r < 0 ? r + 360 : r; };
const equalCusps = (ascendant: number): number[] =>
  Array.from({ length: 12 }, (_, n) => wrap(ascendant + n * 30));

Finite, correctly labeled inputs are assumed. This demonstrates the arithmetic; it does not fetch data or replace the engine.

Connect this step to the source

src/astro/houses.rs

equal_cusps; house_set

Paths refer to the astrology-engine repository. Examples use invented inputs; a successful exercise is not an astronomical-accuracy test.

Sources for this section

Apply this step

Answer every part, then check. You can retry as often as you like.

Enter the longitude in degrees. Accepted tolerance: ±0 degrees. Omit units and commas.

Enter the longitude in degrees. Accepted tolerance: ±0 degrees. Omit units and commas.

Enter the longitude in degrees. Accepted tolerance: ±0 degrees. Omit units and commas.

4. Asc = 350° and MC = 80°. Must the tenth Equal cusp be changed to 80°?

2. Keep a convention separate from its representation

Equal houses follow the exact Ascendant degree. Whole Sign convention instead associates the first house with the entire zodiac sign containing that direction. A sign here is one of twelve 30° zodiac sectors; it is not a constellation with an irregular sky boundary. This conceptual distinction helps us read the interface, but does not tell us that the runtime constructs sector boundaries.

In fact, house_set’s WholeSign branch returns cusps: None. Take the same invented Asc = 350° and MC = 80°. The HouseSet retains those angles and the WholeSign selection, but contains no twelve-number array. None means an absent optional value, rather than an empty list, twelve zeros or a failed Equal calculation.

WholeSign → HouseSet { system: WholeSign, ascendant: 350°, midheaven: 80°, cusps: None }

The public calculate_chart result copies the optional cusp field and returns its body records separately. It does not compute a Whole Sign array or assign planets to houses. A caller that wants sign-based house assignments needs an additional convention outside this runtime path. Filling in twelve longitudes here would teach behavior the engine does not implement.

A convention with a longer history

Swiss Ephemeris records Whole Sign use in Hellenistic and Hindu astrology. That is context for the name, not evidence that this Rust branch implements a historical house-assignment algorithm. The None representation is a local interface choice.

Connect this step to the source

src/astro/houses.rs

house_set

Paths refer to the astrology-engine repository. Examples use invented inputs; a successful exercise is not an astronomical-accuracy test.

Sources for this section

Apply this step

Answer every part, then check. You can retry as often as you like.

1. For WholeSign with Asc = 350°, what does house_set return in cusps?
2. Does selecting WholeSign remove the four angle records from calculate_chart’s bodies list?
3. Can this output alone be described as the runtime assigning each planet to a Whole Sign house?

Your lesson checks

0 of 2 steps passed.

Use the feedback beside each check to retry any unfinished step.