📄 general.c
字号:
/*
** Astrolog (Version 4.00) File: general.c
**
** IMPORTANT NOTICE: the graphics database and chart display routines
** used in this program are Copyright (C) 1991-1993 by Walter D. Pullen
** (cruiser1@stein.u.washington.edu). Permission is granted to freely
** use and distribute these routines provided one doesn't sell,
** restrict, or profit from them in any way. Modification is allowed
** provided these notices remain with any altered or edited versions of
** the program.
**
** The main planetary calculation routines used in this program have
** been Copyrighted and the core of this program is basically a
** conversion to C of the routines created by James Neely as listed in
** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
** available from Matrix Software. The copyright gives us permission to
** use the routines for personal use but not to sell them or profit from
** them in any way.
**
** The PostScript code within the core graphics routines are programmed
** and Copyright (C) 1992-1993 by Brian D. Willoughby
** (brianw@sounds.wa.com). Conditions are identical to those above.
**
** The extended accurate ephemeris databases and formulas are from the
** calculation routines in the program "Placalc" and are programmed and
** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
** (alois@azur.ch). The use of that source code is subject to
** regulations made by Astrodienst Zurich, and the code is not in the
** public domain. This copyright notice must not be changed or removed
** by any user of this program.
**
** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
** X Window graphics initially programmed 10/23-29/1991.
** PostScript graphics initially programmed 11/29-30/1992.
** Last code change made 12/31/1993.
*/
#include "astrolog.h"
/*
******************************************************************************
** General Functions.
******************************************************************************
*/
/* Swap two real floating point values. */
void SwapReal(d1, d2)
real *d1, *d2;
{
real temp;
temp = *d1; *d1 = *d2; *d2 = temp;
}
/* Return the length of a string. */
int StringLen(line)
char *line;
{
int i;
for (i = 0; *line++; i++)
;
return i;
}
/* Return whether one string is greater than another. */
int StringCmp(s1, s2)
char *s1, *s2;
{
while (*s1 && *s1 == *s2)
s1++, s2++;
return *s1 - *s2;
}
/* Determine the sign of a number: -1 if value negative, +1 if value */
/* positive, and 0 if it's zero. */
real Sgn(d)
real d;
{
return d == 0.0 ? 0.0 : SGN2(d);
}
/* Given an x and y coordinate, return the angle formed by a line from the */
/* origin to this coordinate. This is just converting from rectangular to */
/* polar coordinates; however, we don't determine the radius here. */
real Angle(x, y)
real x, y;
{
real a;
if (x != 0.0)
a = ATAN(y/x);
else
a = Sgn(y)*PI/2.0;
if (a < 0.0)
a += PI;
if (y < 0.0)
a += PI;
return a;
}
/* Modulus function for floating point values. The modulus value itself */
/* has been specified earlier: it is usually either 360.0 or PI/2.0. */
real Mod(d)
real d;
{
if (d > modulus) /* In most cases, our value is only slightly */
d -= modulus; /* out of range, so we can test for it and */
else if (d < modulus) /* avoid the more complicated arithmetic. */
d += modulus;
if (d >= 0 && d < modulus)
return d;
return (d - floor(d/modulus)*modulus);
}
/*
******************************************************************************
** General Astrology Functions.
******************************************************************************
*/
/* A similar modulus function: convert an integer to value from 1..12. */
int Mod12(i)
int i;
{
while (i > SIGNS)
i -= SIGNS;
while (i < 1)
i += SIGNS;
return i;
}
/* Convert an inputed fractional degrees/minutes value to a true decimal */
/* degree quantity. For example, the user enters the decimal value "10.30" */
/* to mean 10 degrees and 30 minutes; this will return 10.5, i.e. 10 */
/* degrees and 30 minutes expressed as a floating point degree value. */
real DecToDeg(d)
real d;
{
return Sgn(d)*(floor(dabs(d))+FRACT(dabs(d))*100.0/60.0);
}
/* This is the inverse of the above function. Given a true decimal value */
/* for a zodiac degree, adjust it so the degrees are in the integer part */
/* and the minute expressed as hundredths, e.g. 10.5 degrees -> 10.30 */
real DegToDec(d)
real d;
{
return Sgn(d)*(floor(dabs(d))+FRACT(dabs(d))*60.0/100.0);
}
/* Return the shortest distance between two degrees in the zodiac. This is */
/* normally their difference, but we have to check if near the Aries point. */
real MinDistance(deg1, deg2)
real deg1, deg2;
{
real i;
i = dabs(deg1-deg2);
return i < DEGHALF ? i : DEGREES - i;
}
/* This is just like the above routine, except the min distance value */
/* returned will either be positive or negative based on whether the */
/* second value is ahead or behind the first one in a circular zodiac. */
real MinDifference(deg1, deg2)
real deg1, deg2;
{
real i;
i = deg2 - deg1;
if (dabs(i) < DEGHALF)
return i;
return Sgn(i)*(dabs(i) - DEGREES);
}
/* Return the degree of the midpoint between two zodiac positions, making */
/* sure we return the true midpoint closest to the positions in question. */
real Midpoint(deg1, deg2)
real deg1, deg2;
{
real mid;
mid = (deg1+deg2)/2.0;
return MinDistance(deg1, mid) < DEGQUAD ? mid : Mod(mid+DEGHALF);
}
/* Given a planet and sign, determine whether: The planet rules the sign, */
/* the planet has its fall in the sign, the planet exalts in the sign, or */
/* is debilitated in the sign; and return an appropriate character. */
char Dignify(body, sign)
int body, sign;
{
if (body > U_HI)
return ' ';
if (ruler1[body] == sign || ruler2[body] == sign)
return 'R';
if (ruler1[body] == Mod12(sign+6) || ruler2[body] == Mod12(sign+6))
return 'F';
if (exalt[body] == sign)
return 'e';
if (exalt[body] == Mod12(sign+6))
return 'd';
return '-';
}
/* Determine the number of days in a particular month. The year is needed, */
/* too, because we have to check for leap years in the case of February. */
int DayInMonth(month, year)
int month, year;
{
return (month == 9 || month == 4 || month == 6 || month == 11 ? 30 :
(month != 2 ? 31 : 28 +
(year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))));
}
/* Given an aspect and two objects making that aspect with each other, */
/* return the maximum orb allowed for such an aspect. Normally this only */
/* depends on the aspect itself, but some objects require narrow orbs, */
/* and some allow wider orbs, so check for these cases. */
real Orb(body1, body2, aspect)
int body1, body2, aspect;
{
real orb, i;
orb = aspectorb[aspect];
i = body1 > BASE ? 2.0 : planetorb[body1];
orb = MIN(orb, i);
i = body2 > BASE ? 2.0 : planetorb[body2];
orb = MIN(orb, i);
if (body1 <= BASE)
orb += planetadd[body1];
if (body2 <= BASE)
orb += planetadd[body2];
return orb;
}
/*
******************************************************************************
** File IO Routines.
******************************************************************************
*/
/* Exit the program, and do any cleanup necessary. Note that if we had */
/* a non-fatal error, and we are in the -Q loop mode, then we won't */
/* actually terminate the program, but drop back to the command line loop. */
void Terminate(value)
int value;
{
if (value == _FORCE) {
AnsiColor(WHITE);
fprintf(stdout, "\n%s terminated.\n", appname);
}
if (value == _ERROR && (operation & DASHQ) > 0)
return;
if (ansi)
fprintf(S, "%c[0m", ESCAPE); /* Get out of any Ansi color mode. */
exit(abs(value));
}
/* Print a warning message given a string. This is called in non-fatal */
/* cases where we return to normal execution after printing the string. */
void PrintWarning(string)
char *string;
{
AnsiColor(RED);
fprintf(stderr, "%s\n", string);
AnsiColor(DEFAULT);
}
/* Print an error message. This is called in more serious cases which halt */
/* running of the current chart sequence, which can terminate the program */
/* but isn't a fatal error in that we can still fall back to the -Q loop. */
void PrintError(string)
char *string;
{
AnsiColor(RED);
fprintf(stderr, "%s: %s\n", appname, string);
Terminate(_ERROR);
AnsiColor(DEFAULT);
}
/* Simplification for a commonly printed error message. */
void TooFew(option)
char *option;
{
char string[STRING];
sprintf(string, "Too few options to switch -%s", option);
PrintError(string);
}
/* Another simplification for a commonly printed error message. */
void BadVal(option, value)
char *option;
int value;
{
char string[STRING];
sprintf(string, "Value %d passed to switch -%s out of range.\n",
value, option);
PrintError(string);
}
/* A simple procedure used throughout Astrolog: Print a particular */
/* character on the screen 'n' times. */
void PrintTab(chr, count)
char chr;
int count;
{
int i;
for (i = 0; i < count; i++)
printc(chr);
}
/* Set an Ansi text color. */
void AnsiColor(col)
int col;
{
/* Special case: If we are passed the value REVERSE, and ansi is not */
/* only on but set to a value > 1, then we'll enter reverse video mode. */
if (!ansi || (col == REVERSE && ansi < 2))
return;
fprintf(S, "%c[", ESCAPE);
if (col == DEFAULT)
printc('0');
else if (col == REVERSE) {
printc('7');
} else
fprintf(S, "%c;%d", col > 7 ? '1' : '0', 30 + (col & 7));
printc('m');
}
/* Print a zodiac position on the screen. This is basically just auto- */
/* matically prints the string returned from CharZodiac() below, except */
/* we round here to the nearest minute or second and take care of color. */
void PrintZodiac(deg)
real deg;
{
if (!(operation & DASHs0))
deg = Mod(deg + (seconds < 0 ? 1.0/60.0/60.0/2.0 : 1.0/60.0/2.0));
else
deg = Mod(deg + (seconds < 0 ? 1.0/4.0/60.0/2.0 : 1.0/4.0/2.0));
AnsiColor(elemansi[(int) (deg / 30.0) & 3]);
fprintf(S, "%s", CharZodiac(deg));
AnsiColor(DEFAULT);
}
/* Given a zodiac position, return a string containing it as it's */
/* formatted for display to the user. */
char *CharZodiac(deg)
real deg;
{
static char zod[11];
int sign, d, m;
real s;
if (!(operation & DASHs0)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -