📄 xoptions.c
字号:
/*
** Astrolog (Version 4.00) File: xoptions.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"
#ifdef GRAPH
/*
******************************************************************************
** Chart Graphics Subroutines.
******************************************************************************
*/
/* Return whether the specified object should be displayed in the current */
/* graphics chart type. For example, don't include the Moon in the solar */
/* system charts, don't include house cusps in astro-graph, and so on. */
int Proper(i)
int i;
{
int j;
if (modex == MODEL || modex == MODEE) /* astro-graph or ephem charts */
j = IsThing(i);
else if (modex == MODEZ || modex == MODEG) /* horizon or zenith charts */
j = IsObject(i);
else if (modex == MODES) /* solar system charts */
j = (i != _MOO && IsObject(i));
else
j = TRUE;
return j && !ignore[i]; /* check restriction status */
}
/* Set up arrays with the sine and cosine values of each degree. This is */
/* used by the wheel chart routines which draw lots of circles. Memory is */
/* allocated for this array if not already done. The allocation and */
/* initialization is only done once, the first time the routine is called. */
bool InitCircle()
{
char string[STRING];
int i;
if (circ != NULL)
return TRUE;
Allocate(circ, sizeof(circlestruct), circlestruct PTR);
if (circ == NULL
#ifdef PC
/* For PC's the array better not cross a segment boundary. */
|| HIWORD(LOWORD(circ) + sizeof(circlestruct)) > 0
#endif
) {
sprintf(string, "Not enough memory for sine table (%d bytes).",
sizeof(circlestruct));
PrintError(string);
return FALSE;
}
for (i = 0; i < DEGR; i++) {
circ->x[i] = COSD((real) i);
circ->y[i] = SIND((real) i);
}
circ->x[DEGR] = circ->x[0]; circ->y[DEGR] = circ->y[0];
return TRUE;
}
/* Adjust an array of zodiac positions so that no two positions are within */
/* a certain orb of each other. This is used by the wheel drawing chart */
/* routines in order to make sure that we don't draw any planet glyphs on */
/* top of each other. We'll later draw the glyphs at the adjusted positions. */
void FillSymbolRing(symbol)
real *symbol;
{
real orb = DEFORB*256.0/(real)charty*(real)SCALE, k1, k2, temp;
int i, j, k = 1, l;
/* Keep adjusting as long as we can still make changes, or until we do 'n' */
/* rounds. (With many objects, there just may not be enough room for all.) */
for (l = 0; k && l < divisions*2; l++) {
k = 0;
for (i = 1; i <= total; i++) if (Proper(i)) {
/* For each object, determine who is closest on either side. */
k1 = LARGE; k2 = -LARGE;
for (j = 1; j <= total; j++)
if (Proper(j) && i != j) {
temp = symbol[j]-symbol[i];
if (dabs(temp) > DEGHALF)
temp -= DEGREES*Sgn(temp);
if (temp < k1 && temp >= 0.0)
k1 = temp;
else if (temp > k2 && temp <= 0.0)
k2 = temp;
}
/* If an object's too close on one side, then we move to the other. */
if (k2 > -orb && k1 > orb) {
k = 1; symbol[i] = Mod(symbol[i]+orb*0.51+k2*0.49);
} else if (k1 < orb && k2 < -orb) {
k = 1; symbol[i] = Mod(symbol[i]-orb*0.51+k1*0.49);
/* If we are bracketed by close objects on both sides, then let's move */
/* to the midpoint, so we are as far away as possible from either one. */
} else if (k2 > -orb && k1 < orb) {
k = 1; symbol[i] = Mod(symbol[i]+(k1+k2)*0.5);
}
}
}
}
/* Adjust an array of longitude positions so that no two are within a */
/* certain orb of each other. This is used by the astro-graph routine to */
/* make sure we don't draw any planet glyphs marking the lines on top of */
/* each other. This is almost identical to the FillSymbolRing() routine */
/* used by the wheel charts; however, there the glyphs are placed in a */
/* continuous ring, while here we have the left and right screen edges. */
/* Also, here we are placing two sets of planets at the same time. */
void FillSymbolLine(symbol)
real *symbol;
{
real orb = DEFORB*1.35*(real)SCALE, max = DEGREES, k1, k2, temp;
int i, j, k = 1, l;
if (modex != MODEE)
max *= (real)SCALE;
else
orb *= DEGREES/(real)chartx;
/* Keep adjusting as long as we can still make changes. */
for (l = 0; k && l < divisions*2; l++) {
k = 0;
for (i = 1; i <= total*2; i++)
if (Proper((i+1)/2) && symbol[i] >= 0.0) {
/* For each object, determine who is closest to the left and right. */
k1 = max-symbol[i]; k2 = -symbol[i];
for (j = 1; j <= total*2; j++) {
if (Proper((j+1)/2) && i != j) {
temp = symbol[j]-symbol[i];
if (temp < k1 && temp >= 0.0)
k1 = temp;
else if (temp > k2 && temp <= 0.0)
k2 = temp;
}
}
/* If an object's too close on one side, then we move to the other. */
if (k2 > -orb && k1 > orb) {
k = 1; symbol[i] = symbol[i]+orb*0.51+k2*0.49;
} else if (k1 < orb && k2 < -orb) {
k = 1; symbol[i] = symbol[i]-orb*0.51+k1*0.49;
} else if (k2 > -orb && k1 < orb) {
k = 1; symbol[i] = symbol[i]+(k1+k2)*0.5;
}
}
}
}
/* Another stream reader, this one is used by the globe drawing routine: */
/* for the next body of land/water, return its name (and color), its */
/* longitude and latitude, and a vector description of its outline. */
int ReadWorldData(nam, loc, lin)
char **nam, **loc, **lin;
{
static char FAR **datapointer = worlddata;
*loc = *datapointer++;
*lin = *datapointer++;
*nam = *datapointer++;
if (*loc[0]) {
if ((exdisplay & DASHXP0) && xfile)
fprintf(stdout, "%s\n", *nam+1);
return TRUE;
}
datapointer = worlddata; /* Reset stream when no data left. */
return FALSE;
}
/* Given longitude and latitude values on a globe, return the window */
/* coordinates corresponding to them. In other words, project the globe */
/* onto the view plane, and return where our coordinates got projected to, */
/* as well as whether our location is hidden on the back side of the globe. */
int GlobeCalc(x1, y1, u, v, cx, cy, rx, ry, deg)
real x1, y1;
int *u, *v, cx, cy, rx, ry, deg;
{
real j, siny1;
/* Compute coordinates for a general globe invoked with -XG switch. */
if (modex == MODEG) {
x1 = Mod(x1+(real)deg); /* Shift by current globe rotation value. */
if (tilt != 0.0) {
x1 = DTOR(x1); y1 = DTOR(DEGQUAD-y1); /* Do another coordinate */
CoorXform(&x1, &y1, tilt / DEGRAD); /* shift if the globe's */
x1 = Mod(RTOD(x1)); y1 = DEGQUAD-RTOD(y1); /* equator is tilted any. */
}
*v = cy + (int) ((real)ry*-COSD(y1)-ROUND);
*u = cx + (int) ((real)rx*-COSD(x1)*SIND(y1)-ROUND);
return x1 > DEGHALF;
}
/* Compute coordinates for a polar globe invoked with -XP switch. */
siny1 = SIND(y1);
j = xbonus ? DEGQUAD+x1+deg : 270.0-x1-deg;
*v = cy + (int) (siny1*(real)ry*SIND(j)-ROUND);
*u = cx + (int) (siny1*(real)rx*COSD(j)-ROUND);
return xbonus ? y1 < DEGQUAD : y1 > DEGQUAD;
}
/* Draw a globe in the window, based on the specified rotational and tilt */
/* values. In addition, we may draw in each planet at its zenith position. */
void DrawGlobe(deg)
int deg;
{
char *nam, *loc, *lin, d;
int X[TOTAL+1], Y[TOTAL+1], M[TOTAL+1], N[TOTAL+1],
cx = chartx/2, cy = charty/2, rx, ry, lon, lat, unit = 12*SCALE,
x, y, m, n, u, v, i, J, k, l, o;
real planet1[TOTAL+1], planet2[TOTAL+1], x1, y1, j;
colpal c;
rx = cx-1; ry = cy-1;
/* Loop through each coastline string, drawing visible parts on the globe. */
while (ReadWorldData(&nam, &loc, &lin)) {
i = nam[0]-'0';
c = (modex == MODEG && xbonus) ? gray :
(i ? rainbowcolor[i] : maincolor[6]);
DrawColor(c);
/* Get starting longitude and latitude of current coastline piece. */
lon = (loc[0] == '+' ? 1 : -1)*
((loc[1]-'0')*100 + (loc[2]-'0')*10 + (loc[3]-'0'));
lat = (loc[4] == '+' ? 1 : -1)*((loc[5]-'0')*10 + (loc[6]-'0'));
x = 180-lon;
y = 90-lat;
GlobeCalc((real) x, (real) y, &m, &n, cx, cy, rx, ry, deg);
/* Go down the coastline piece, drawing each visible segment on globe. */
o = (tilt == 0.0 && modex != MODEP);
k = l = TRUE;
while (d = *lin++) {
if (d == 'L' || d == 'H' || d == 'G')
x--;
else if (d == 'R' || d == 'E' || d == 'F')
x++;
if (d == 'U' || d == 'H' || d == 'E')
y--;
else if (d == 'D' || d == 'G' || d == 'F')
y++;
if (x > 359)
x = 0;
else if (x < 0)
x = 359;
if (o) {
k = x+deg;
if (k > 359)
k -= DEGR;
k = (k <= 180);
}
if (k && !GlobeCalc((real) x, (real) y, &u, &v, cx, cy, rx, ry, deg)) {
if (l)
DrawLine(m, n, u, v);
m = u; n = v;
l = TRUE;
} else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -