📄 darkcal.cpp
字号:
/*----------------------------------------------------------------------------
* DarkCal - calculates the darkest hours for a given month and year.
*
* Created by Mark Huss <mark@mhuss.com>
*
* This is a generic console program and has been built and run on both
* win32 and "unix-like" systems.
*
* Developed and built using the mingw32 gcc compiler 2.95.2
*
* THIS SOFTWARE IS NOT COPYRIGHTED
*
* This source code is offered for use in the public domain. You may
* use, modify or distribute it freely.
*
* This code is distributed in the hope that it will be useful but
* WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
* DISCLAMED. This includes but is not limited to warranties of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* Astro library based on Bill Gray's open-source code at projectpluto.com
*
* created August 2000
*/
//---------------------------------------------------------------------------
#include "AstroOps.h"
#include "PlanetData.h"
#include "DateOps.h"
#include "RiseSet.h"
#include "ConfigFile.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//----------------------------------------------------------------------------
#define TP_START a
#define TP_END b
#define TP_RISE a
#define TP_SET b
#define DEBUG 1
#undef PROGRESS_BAR
static const char* CFG_EXT = ".cfg";
static const int DAYS=33; // 31 max plus one on either side
static const char* monthNames[] = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
};
enum DST { DST_NONE, DST_START, DST_END };
// Struct to hold date & location
struct CalData {
CalData() : month(1), year(2000) {}
int month;
int year;
ObsInfo loc;
};
// file globals
static bool g_tabDelimited = false; // true means produce tab-delimited output
static bool g_ignoreDst = false; // true means ignore DST
static bool g_html = false; // true means produce HTML output
static FILE* g_fp = stdout; // file to use for tab-d or HTML
//----------------------------------------------------------------------------
// print heading
//
void printHeading(CalData& cd) {
const char* pUtc = ( cd.loc.timeZone() < 0 ) ? "UTC" : "UTC+";
char title[256];
sprintf( title,
"%s, %d at latitude %5.2f, longitude %5.2f, tz %s%d",
monthNames[ cd.month-1 ], cd.year, cd.loc.degLatitude(),
cd.loc.degLongitude(), pUtc, cd.loc.timeZone() );
if ( g_tabDelimited ) {
fprintf( g_fp, "\n%s\n\n", title );
fputs( "Day\tDarkest Hours\tEvent\tMoon Rises\tMoon Sets\t"
"Sunset\tAstronomical Twilight Ends\tNext Day\t"
"Astronomical Twilight Starts\tSunrise\n", g_fp );
}
else if (g_html)
fprintf( g_fp, "<HTML>\n"
"<HEAD>\n"
" <TITLE>Darkest Hours</TITLE>\n"
"</HEAD>\n<BODY>\n"
"<STYLE type=\"text/css\">\n<!--\n"
" TH, TD { font-size:12px }\n"
" .bar { background:silver }\n"
"-->\n</STYLE>\n"
"<H2>Darkest Hours</H2>\n"
"<TABLE CELLSPACING=0 BORDER=0 WIDTH=\"100%%\">\n"
"<TR CLASS=\"bar\"><TH COLSPAN=10 ALIGN=\"center\">%s</TH></TR>\n"
"<TR>\n"
" <TH>Day</TH>\n <TH>Darkest<BR>Hours</TH>\n <TH>Event</TH>\n"
" <TH>Moon<BR>Rises</TH>\n <TH>Moon<BR>Sets</TH>\n"
" <TH>Sunset</TH>\n <TH>AstTwi<BR>Ends</TH>\n <TH>Next<BR>Day</TH>\n"
" <TH>AstTwi<BR>Starts</TH>\n <TH>Sunrise</TH>\n"
"</TR>\n", title );
else {
printf( "\n%s\n\n"
"Day Darkest Moon Moon Sunset AstTwi Next AstTwi Sunrise\n"
" Hours Events Rises Sets Ends Day Starts\n"
"-- ------------- -------- ----- ----- ----- ----- -- ----- -----\n",
title );
}
}
//----------------------------------------------------------------------------
static char* nextColumn( char* p, int sp, bool empty=false )
{
if (g_tabDelimited)
*p++ = '\t';
else if (g_html) {
if (empty)
strcpy(p," </TD>\n <TD>");
else
strcpy(p,"</TD>\n <TD>");
p += strlen(p);
}
else {
while (sp--)
*p++ = ' ';
}
return p;
}
//----------------------------------------------------------------------------
// print a (double) time as hh:mm
//
// a time < 0 is printed as '--:--'
//
static char* printTime( char* p, double t, bool ws=true )
{
if( t < 0.)
sprintf( p, "--:--" );
else {
// round up to nearest minute
long minutes = long(t * 24. * 60. + .5);
sprintf( p, "%02d:%02d", int(minutes / 60), int(minutes % 60) );
}
return ws ? nextColumn( p+5, 2) : p+5;
}
//----------------------------------------------------------------------------
// print a pair of (double) times as hh:mm
//
static char* printTimes( char* p, TimePair& tp ) {
p = printTime( p, tp.a, false );
*p++ = ' ';
*p++ = '-';
*p++ = ' ';
return printTime( p, tp.b );
}
//----------------------------------------------------------------------------
// print the day, substituting 'Su' on Sundays
//
// d = 1..31
//
static char* printDay( char* p, long jd, int d, bool eom ) {
if( (jd+d) % 7 == 6) /* Sunday */
strcpy( p, "Su" );
else {
int nextDay = eom ? 1 : d+1;
sprintf( p, "%2d", nextDay );
}
return nextColumn(p+2,2);
}
//----------------------------------------------------------------------------
// figure out darkest hours & print to buffer
//
char* printDarkness( char* p, int i, const TimePair* const astTwi, const TimePair* const moonRSOrg )
{
TimePair dark = { astTwi[i].TP_END, astTwi[i+1].TP_START };
// first time in, create a local copy that we can munge
static TimePair moonRS[DAYS];
if ( 0 == i )
memcpy( moonRS, moonRSOrg, sizeof(TimePair)*DAYS);
// define day + time vars to deal with 'yesterday' and 'tomorrow'
double darkStart = astTwi[i].TP_END + i;
double darkEnd = astTwi[i+1].TP_START + (i+1);
double moonRise;
if ( moonRS[i].TP_RISE < 0. || moonRS[i].TP_SET > moonRS[i].TP_RISE) {
moonRise = moonRS[i+1].TP_RISE + (i+1);
moonRS[i].TP_RISE = moonRS[i+1].TP_RISE;
}
else
moonRise = moonRS[i].TP_RISE + i;
double moonSet;
if ( moonRS[i].TP_SET < 0. || moonRS[i].TP_RISE > moonRS[i].TP_SET ) {
moonSet = moonRS[i+1].TP_SET + (i+1);
moonRS[i].TP_SET = moonRS[i+1].TP_SET;
}
else
moonSet = moonRS[i].TP_SET + i;
// check moon rise & set
if (moonSet > darkStart && moonSet < darkEnd) {
darkStart = moonSet;
dark.TP_START = moonRS[i].TP_SET;
}
if (moonRise > darkStart && moonRise < darkEnd ) {
darkEnd = moonRise;
dark.TP_END = moonRS[i].TP_RISE;
}
bool noDarkness = (moonRise < darkStart && moonSet > darkEnd );
// print out darkness range or 'none'
if ( noDarkness ) {
strcpy(p, " -- none -- " );
p = nextColumn(p+12, 3);
}
else
p = printTimes( p, dark );
return p;
}
//----------------------------------------------------------------------------
// helper fn for printEvents
inline char* append(char* pTo, const char* pFrom, int len)
{
memcpy( pTo, pFrom, len );
return pTo + len;
}
//----------------------------------------------------------------------------
// check for lunar and solar quarters & print if found
//
char* printEvents( char*p, int i, double* jd, ObsInfo& oi, DST dstDay )
{
char* pStart = p;
static PlanetData pd;
double lunarLon[2], solarLon[2];
// get ecliptic longitude for earth & moon
//
for( int j=0; j<2; j++ ) {
pd.calc( EARTH, jd[i] + double(j), oi );
solarLon[j] = pd.eclipticLon();
pd.calc( LUNA, jd[i] + double(j), oi );
lunarLon[j] = pd.eclipticLon();
}
// We don't bother finding the exact instant of the following events.
// The code just checks for a quadrant change and reports the event.
// check for lunar quarters
//
int quad1 = RiseSet::quadrant( lunarLon[1] - solarLon[1] );
int quad0 = RiseSet::quadrant( lunarLon[0] - solarLon[0] );
if( quad1 != quad0 ) {
static const char* strings[4] = { "1Q ", "FM ", "3Q ", "NM " };
p = append( p, strings[quad0], 3);
}
// check for solar quarters
//
quad1 = RiseSet::quadrant( solarLon[1] );
quad0 = RiseSet::quadrant( solarLon[0] );
if( quad1 != quad0 ) {
static const char* strings[4] =
{ "SumSol ", "Aut Eq ", "WinSol ", "Ver Eq " };
p = append( p, strings[quad0], 7 );
}
// handle DST indicator
if ( DST_START == dstDay )
p = append( p, "DSTime", 6 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -