Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

318 lines
7.5 KiB

  1. #include <windows.h>
  2. #include <GL/glu.h>
  3. #ifdef X11
  4. #include <GL/glx.h>
  5. #endif
  6. #ifdef WIN32
  7. #include "stonehen.h"
  8. #endif
  9. #include "TimeDate.h"
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #ifdef X11
  13. #include <sys/time.h>
  14. #else
  15. #include <time.h>
  16. #endif
  17. inline float sign(float a) {return a > 0.0 ? 1. : (a < 0.0 ? -1. : 0.);}
  18. inline float degrees(float a) {return a * 180.0 / M_PI;}
  19. inline float radians(float a) {return a * M_PI / 180.0;}
  20. inline float arcsin(float a) {return atan2(a, sqrt(1.-a*a));}
  21. /* Thirty days hath September... */
  22. const int mday[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
  23. TimeDate::TimeDate(int hour, int minute, int second, long usecond)
  24. {
  25. read_time();
  26. t.tm_hour = hour;
  27. t.tm_min = minute;
  28. t.tm_sec = second;
  29. usec = usecond;
  30. }
  31. TimeDate TimeDate::operator=(TimeDate a)
  32. {
  33. usec = a.usec;
  34. t = a.t;
  35. return *this;
  36. }
  37. TimeDate TimeDate::operator+(TimeDate a)
  38. {
  39. TimeDate td;
  40. td = *this + a.t;
  41. td.usec = usec + a.usec;
  42. return td;
  43. }
  44. TimeDate TimeDate::operator+(struct tm t2)
  45. {
  46. TimeDate td;
  47. td.usec = 0;
  48. td.t.tm_sec = t.tm_sec + t2.tm_sec;
  49. td.t.tm_min = t.tm_min + t2.tm_min;
  50. td.t.tm_hour = t.tm_hour + t2.tm_hour;
  51. td.t.tm_mday = t.tm_mday + t2.tm_mday;
  52. td.t.tm_mon = t.tm_mon + t2.tm_mon;
  53. td.t.tm_year = t.tm_year + t2.tm_year;
  54. td.t.tm_wday = t.tm_wday + t2.tm_wday;
  55. td.t.tm_yday = t.tm_yday + t2.tm_yday;
  56. return td;
  57. }
  58. TimeDate TimeDate::operator+=(TimeDate a)
  59. {
  60. /* This is slower than it needs to be */
  61. *this = *this + a.t;
  62. return *this;
  63. }
  64. TimeDate TimeDate::operator-(TimeDate a)
  65. {
  66. TimeDate td;
  67. td.usec = usec - a.usec;
  68. td.t.tm_sec = t.tm_sec - a.t.tm_sec;
  69. td.t.tm_min = t.tm_min - a.t.tm_min;
  70. td.t.tm_hour = t.tm_hour - a.t.tm_hour;
  71. td.t.tm_mday = t.tm_mday - a.t.tm_mday;
  72. td.t.tm_mon = t.tm_mon - a.t.tm_mon;
  73. td.t.tm_year = t.tm_year - a.t.tm_year;
  74. td.t.tm_wday = t.tm_wday - a.t.tm_wday;
  75. td.t.tm_yday = t.tm_yday - a.t.tm_yday;
  76. return td;
  77. }
  78. TimeDate TimeDate::operator*(float f)
  79. {
  80. TimeDate td;
  81. td.usec = (long)((float)usec * f);
  82. td.t.tm_sec = (int)((float)t.tm_sec * f);
  83. td.t.tm_min = (int)((float)t.tm_min * f);
  84. td.t.tm_hour = (int)((float)t.tm_hour * f);
  85. td.t.tm_mday = (int)((float)t.tm_mday * f);
  86. td.t.tm_mon = (int)((float)t.tm_mon * f);
  87. td.t.tm_year = (int)((float)t.tm_year * f);
  88. td.t.tm_wday = (int)((float)t.tm_wday * f);
  89. td.t.tm_yday = (int)((float)t.tm_yday * f);
  90. return td;
  91. }
  92. TimeDate TimeDate::read_time()
  93. {
  94. #ifdef X11
  95. struct timeval tv;
  96. #else
  97. LPSYSTEMTIME lpst;
  98. #endif
  99. time_t cal_time;
  100. struct tm *tmp;
  101. cal_time = time(NULL);
  102. tmp = localtime(&cal_time);
  103. #ifdef X11
  104. gettimeofday(&tv);
  105. usec = tv.tv_usec;
  106. #else
  107. lpst = (LPSYSTEMTIME) malloc(sizeof(SYSTEMTIME));
  108. GetSystemTime(lpst);
  109. usec = 1000 * lpst->wMilliseconds;
  110. #endif
  111. t = *tmp;
  112. return *this;
  113. }
  114. void TimeDate::print()
  115. {
  116. puts(asctime(&t));
  117. }
  118. /* The sun_direction routine comes from an awk program by Stuart Levy
  119. * (slevy@geom.umn.edu) */
  120. /* Day number of March 21st, roughly the vernal equinox */
  121. const float equinox = mday[0] + mday[1] + 21;
  122. /*
  123. * Date E.T. [degrees]
  124. * Jan 1 0.82
  125. * Jan 31 3.35
  126. * Mar 1 3.08
  127. * Mar 31 1.02
  128. * Apr 30 -0.71
  129. * May 30 -0.62
  130. * Jun 29 0.87
  131. * Jul 29 1.60
  132. * Aug 28 0.28
  133. * Sep 27 -2.28
  134. * Oct 27 -4.03
  135. * Nov 26 -3.15
  136. * Dec 26 0.19
  137. */
  138. const float et[] = {
  139. .82, 3.35, 3.08, 1.02, -.71, -.62, .87,
  140. 1.60, .28, -2.28, -4.03, -3.15, .19, 2.02};
  141. const float DEG = 180. / M_PI;
  142. Point TimeDate::sun_direction(float lon, float lat)
  143. {
  144. float yearday, eti, etoffset, ET, HA, LON, decl, altitude, azimuth;
  145. int etindex;
  146. Point dir;
  147. long tmp_usec;
  148. int m;
  149. tmp_usec = usec;
  150. usec = 0;
  151. *this = correct_smaller();
  152. /*
  153. * hour angle of the sun (time since local noon):
  154. * HA = (time - noon) * 15 degrees/hour
  155. * + (observer''s east longitude - long. of time zone''s
  156. * central meridian
  157. * POSITIVE east, NEGATIVE west)
  158. * - (15 degrees if time above was daylight savings time, else 0)
  159. * - "equation of time" (depends on date, correcting the
  160. * hour angle for
  161. * the earth''s elliptical orbit and the slope of the ecliptic)
  162. */
  163. yearday = (float)t.tm_mday +
  164. ((float)t.tm_hour + (float)t.tm_min / 60.0) / 24.0;
  165. for (m = 0; m < t.tm_mon; m++) yearday += mday[m];
  166. /*
  167. * Index into equation-of-time table, tabulated at 30-day intervals
  168. * We''ve added an extra entry at the end of the et table, corresponding
  169. * to January 25th of the following year, to make interpolation work
  170. * throughout the year.
  171. * Use simple linear interpolation.
  172. */
  173. eti = (yearday - 1.) / 30.;
  174. #ifdef X11
  175. etoffset = eti - trunc(eti);
  176. etindex = (int)trunc(eti) + 1;
  177. #else
  178. etoffset = eti - (int)eti;
  179. etindex = (int)eti + 1;
  180. #endif
  181. ET = et[etindex - 1] + etoffset*(et[etindex+1 - 1] - et[etindex - 1]);
  182. /* The 90. puts us in the Central time zone */
  183. HA = ((float)t.tm_hour + (float)t.tm_min/60. - 12.)*15. +
  184. lon + 90. - ET;
  185. /*
  186. * Sun''s declination:
  187. * sun''s longitude = (date - March 21) * 360 degrees / 365.25 days
  188. * [This ignores the earth''s elliptical orbit...]
  189. */
  190. LON = (yearday - equinox) * 360. / 365.25;
  191. decl = DEG * arcsin( sin(LON/DEG) * sin(23.4/DEG) );
  192. /*
  193. * Then a spherical triangle calculation to convert the Sun''s
  194. * hour angle and declination, and the observer''s latitude,
  195. * to give the Sun''s altitude and azimuth (angle east from north).
  196. */
  197. altitude = DEG * arcsin( sin(decl/DEG)*sin(lat/DEG)
  198. + cos(decl/DEG)*cos(lat/DEG)*cos(HA/DEG) );
  199. azimuth = DEG * atan2( -cos(decl/DEG)*sin(HA/DEG),
  200. sin(decl/DEG)*cos(lat/DEG)
  201. - cos(decl/DEG)*cos(HA/DEG)*sin(lat/DEG) );
  202. /*
  203. printf("On %d/%d at %d:%02d, lat %g, lon %g\n",
  204. t.tm_mon + 1, t.tm_mday + 1, t.tm_hour, t.tm_min, lat, lon);
  205. printf("HA %.1f ET %.1f Sun lon %.1f decl %.1f alt %.1f az %.1f\n",
  206. HA,ET,LON,decl,altitude,azimuth);
  207. */
  208. dir.pt[2] = sin(radians(altitude));
  209. dir.pt[0] = cos(radians(azimuth));
  210. dir.pt[1] = sin(radians(azimuth));
  211. dir.pt[3] = 0;
  212. dir.unitize();
  213. // dir.print();
  214. usec = tmp_usec;
  215. return dir;
  216. }
  217. TimeDate TimeDate::correct_bigger()
  218. {
  219. TimeDate td;
  220. int days;
  221. td.t = t;
  222. td.usec = usec;
  223. td.t.tm_sec += (int)(td.usec / 1000000);
  224. td.usec %= 1000000;
  225. td.t.tm_min += td.t.tm_sec / 60;
  226. td.t.tm_sec %= 60;
  227. td.t.tm_hour += td.t.tm_min / 60;
  228. td.t.tm_min %= 60;
  229. if (td.t.tm_hour > 23) {
  230. days = td.t.tm_hour / 24;
  231. td.t.tm_hour %= 24;
  232. td.t.tm_mday += days;
  233. td.t.tm_wday = (td.t.tm_wday + days) % 7;
  234. td.t.tm_yday = (td.t.tm_yday + days) % 365;
  235. while (td.t.tm_mday > mday[td.t.tm_mon]) {
  236. td.t.tm_mday -= mday[td.t.tm_mon++];
  237. if (td.t.tm_mon >= 12) {
  238. td.t.tm_year += td.t.tm_mon / 12;
  239. td.t.tm_mon %= 12;
  240. }
  241. }
  242. }
  243. return td;
  244. }
  245. TimeDate TimeDate::correct_smaller()
  246. {
  247. TimeDate td;
  248. td.t = t;
  249. td.usec = usec;
  250. while (td.usec < 0) {
  251. td.t.tm_sec--;
  252. td.usec += 1000000;
  253. }
  254. while (td.t.tm_sec < 0) {
  255. td.t.tm_min--;
  256. td.t.tm_sec += 60;
  257. }
  258. while (td.t.tm_min < 0) {
  259. td.t.tm_hour--;
  260. td.t.tm_min += 60;
  261. }
  262. while (td.t.tm_hour < 0) {
  263. td.t.tm_mday--;
  264. if (td.t.tm_wday) td.t.tm_wday--;
  265. else td.t.tm_wday = 6;
  266. td.t.tm_yday--;
  267. td.t.tm_hour += 24;
  268. }
  269. if (td.t.tm_mon < 0 || td.t.tm_year < 0 || td.t.tm_yday < 0) {
  270. fprintf(stderr, "Warning: day < 0 in TimeDate.c++.\n");
  271. td.t.tm_mon = td.t.tm_year = td.t.tm_yday = 0;
  272. }
  273. return td.correct_bigger();
  274. }