#include "reading.h" #include "i18n.h" #include void reading_generate(const char *tarot_seed, const BirthData *birth, Gender gender, time_t utc_moment, DailyReading *out) { out->utc_moment = utc_moment; out->gender = gender; astro_compute_natal_chart(birth, &out->natal); astro_compute_daily_transits(utc_moment, &out->natal, &out->transits); tarot_draw_celtic_cross(tarot_seed, &out->spread); } /* Everything below uses fprintf, which Pebble's SDK blocks at compile * time (see pebble_warn_unsupported_functions.h) - not compiled at all * for the watch, which only ever calls reading_generate() above. */ #ifndef PBL_SDK_3 /* UI-label keys ("ui.*") are looked up here rather than in i18n.h/.c * because they're specific to these two renderers, not part of the * portable astro/tarot vocabulary. */ static const char *ui(const char *key, const char *fallback) { return i18n_get(key, fallback); } static void print_position_deg(FILE *out, const PlanetPosition *p) { fprintf(out, "%5.1f%s %-11s (%s %d)", p->degree_in_sign, "\xc2\xb0", astro_sign_name(p->sign), ui("ui.house", "House"), p->house); } void reading_print_text(const DailyReading *r, FILE *out) { fprintf(out, "===== %s =====\n", ui("ui.natal_chart", "Natal Chart")); for (int b = 0; b < NUM_BODIES; b++) { fprintf(out, "%-8s ", astro_body_name((Body)b)); print_position_deg(out, &r->natal.bodies[b]); fprintf(out, "\n"); } fprintf(out, "%s %5.1f%s %s\n", ui("ui.ascendant", "Ascendant"), fmod(r->natal.ascendant_longitude, 30.0), "\xc2\xb0", astro_sign_name(r->natal.houses[0])); fprintf(out, "\n"); fprintf(out, "===== %s =====\n", ui("ui.todays_sky", "Today's Sky")); fprintf(out, "%s %s\n", ui("ui.moon_phase", "Moon phase:"), astro_moon_phase_name(r->transits.moon_phase)); for (int b = 0; b < NUM_BODIES; b++) { fprintf(out, "%-8s ", astro_body_name((Body)b)); print_position_deg(out, &r->transits.bodies[b]); fprintf(out, "\n"); } fprintf(out, "\n"); fprintf(out, "===== %s =====\n", ui("ui.todays_aspects", "Today's Aspects to Natal Chart")); if (r->transits.aspect_count == 0) { fprintf(out, "%s\n", ui("ui.no_aspects", "(none within orb)")); } for (int i = 0; i < r->transits.aspect_count; i++) { const Aspect *a = &r->transits.aspects[i]; fprintf(out, "%s %s %s %s %s (%s %.1f%s)\n", ui("ui.transiting", "Transiting"), astro_body_name(a->transiting_planet), astro_aspect_name(a->type), ui("ui.natal", "natal"), astro_body_name(a->natal_planet), ui("ui.orb", "orb"), a->orb, "\xc2\xb0"); } fprintf(out, "\n"); fprintf(out, "===== %s =====\n", ui("ui.celtic_cross", "Celtic Cross")); for (int i = 0; i < TAROT_SPREAD_SIZE; i++) { const TarotDraw *draw = &r->spread.positions[i]; fprintf(out, "%-16s %s%s%s\n", tarot_position_name((CelticCrossPosition)i, r->gender), tarot_card_name(draw->card), draw->reversed ? " " : "", draw->reversed ? ui("ui.reversed", "(Reversed)") : ""); fprintf(out, " %s\n", tarot_position_description((CelticCrossPosition)i, r->gender)); fprintf(out, " %s\n", tarot_card_meaning(draw->card, draw->reversed)); } } static void print_body_row_html(FILE *out, const char *label, const PlanetPosition *p) { fprintf(out, "%s%.1f° %s%s %d\n", label, p->degree_in_sign, astro_sign_name(p->sign), ui("ui.house", "House"), p->house); } void reading_print_html(const DailyReading *r, FILE *out) { fprintf(out, "\n\n" "%s\n" "\n", ui("ui.page_title", "Deck in a Dash - Daily Reading")); fprintf(out, "

%s

\n", ui("ui.daily_reading", "Daily Reading")); fprintf(out, "

%s

\n\n", ui("ui.natal_chart", "Natal Chart")); for (int b = 0; b < NUM_BODIES; b++) { print_body_row_html(out, astro_body_name((Body)b), &r->natal.bodies[b]); } fprintf(out, "\n", ui("ui.ascendant", "Ascendant"), fmod(r->natal.ascendant_longitude, 30.0), astro_sign_name(r->natal.houses[0])); fprintf(out, "
%s%.1f° %s
\n"); fprintf(out, "

%s

\n

%s %s

\n\n", ui("ui.todays_sky", "Today's Sky"), ui("ui.moon_phase", "Moon phase:"), astro_moon_phase_name(r->transits.moon_phase)); for (int b = 0; b < NUM_BODIES; b++) { print_body_row_html(out, astro_body_name((Body)b), &r->transits.bodies[b]); } fprintf(out, "
\n"); fprintf(out, "

%s

\n\n", ui("ui.todays_aspects", "Today's Aspects to Natal Chart")); for (int i = 0; i < r->transits.aspect_count; i++) { const Aspect *a = &r->transits.aspects[i]; fprintf(out, "\n", ui("ui.transiting", "Transiting"), astro_body_name(a->transiting_planet), astro_aspect_name(a->type), ui("ui.natal", "natal"), astro_body_name(a->natal_planet), ui("ui.orb", "orb"), a->orb); } fprintf(out, "
%s %s%s%s %s%s %.1f°
\n"); fprintf(out, "

%s

\n
\n", ui("ui.celtic_cross", "Celtic Cross")); for (int i = 0; i < TAROT_SPREAD_SIZE; i++) { const TarotDraw *draw = &r->spread.positions[i]; fprintf(out, "
\n" "
%s
\n" /* Expects card art at img/ next to the HTML file itself - * `make images` copies res/img/ there alongside the binary in * dist/. */ " \"%s\"\n" "
%s%s%s
\n" "
%s
\n" "
%s
\n" "
\n", tarot_position_name((CelticCrossPosition)i, r->gender), draw->reversed ? "reversed" : "", tarot_card_image_file(draw->card), tarot_card_name(draw->card), tarot_card_name(draw->card), draw->reversed ? " " : "", draw->reversed ? ui("ui.reversed", "(Reversed)") : "", tarot_position_description((CelticCrossPosition)i, r->gender), tarot_card_meaning(draw->card, draw->reversed)); } fprintf(out, "
\n\n"); } static void print_body_position_json(FILE *out, const char *indent, Body body, const PlanetPosition *p) { fprintf(out, "%s{\"body\": \"%s\", \"sign\": \"%s\", \"degree_in_sign\": %.4f, " "\"ecliptic_longitude\": %.4f, \"house\": %d}", indent, astro_body_slug(body), astro_sign_slug(p->sign), p->degree_in_sign, p->ecliptic_longitude, p->house); } void reading_print_json(const DailyReading *r, FILE *out) { fprintf(out, "{\n"); struct tm *utc = gmtime(&r->utc_moment); fprintf(out, " \"date\": \"%04d-%02d-%02d\",\n", utc->tm_year + 1900, utc->tm_mon + 1, utc->tm_mday); fprintf(out, " \"gender\": \"%s\",\n", tarot_gender_slug(r->gender)); fprintf(out, " \"natal\": {\n \"bodies\": [\n"); for (int b = 0; b < NUM_BODIES; b++) { print_body_position_json(out, " ", (Body)b, &r->natal.bodies[b]); fprintf(out, "%s\n", b + 1 < NUM_BODIES ? "," : ""); } fprintf(out, " ],\n \"ascendant_longitude\": %.4f,\n \"houses\": [", r->natal.ascendant_longitude); for (int h = 0; h < 12; h++) { fprintf(out, "\"%s\"%s", astro_sign_slug(r->natal.houses[h]), h + 1 < 12 ? ", " : ""); } fprintf(out, "]\n },\n"); fprintf(out, " \"transits\": {\n \"bodies\": [\n"); for (int b = 0; b < NUM_BODIES; b++) { print_body_position_json(out, " ", (Body)b, &r->transits.bodies[b]); fprintf(out, "%s\n", b + 1 < NUM_BODIES ? "," : ""); } fprintf(out, " ],\n \"moon_phase\": \"%s\",\n \"aspects\": [\n", astro_moon_phase_slug(r->transits.moon_phase)); for (int i = 0; i < r->transits.aspect_count; i++) { const Aspect *a = &r->transits.aspects[i]; fprintf(out, " {\"transiting_planet\": \"%s\", \"natal_planet\": \"%s\", " "\"type\": \"%s\", \"orb\": %.4f}%s\n", astro_body_slug(a->transiting_planet), astro_body_slug(a->natal_planet), astro_aspect_slug(a->type), a->orb, i + 1 < r->transits.aspect_count ? "," : ""); } fprintf(out, " ]\n },\n"); fprintf(out, " \"spread\": {\n \"positions\": [\n"); for (int i = 0; i < TAROT_SPREAD_SIZE; i++) { const TarotDraw *draw = &r->spread.positions[i]; fprintf(out, " {\"position\": \"%s\", \"card\": \"%s\", \"reversed\": %s}%s\n", tarot_position_slug((CelticCrossPosition)i), tarot_card_slug(draw->card), draw->reversed ? "true" : "false", i + 1 < TAROT_SPREAD_SIZE ? "," : ""); } fprintf(out, " ]\n }\n}\n"); } #endif /* !PBL_SDK_3 */