1 2(********************************************************************) 3(* *) 4(* planets.sd7 Display information about the planets *) 5(* Copyright (C) 2006, 2007 Thomas Mertes *) 6(* *) 7(* This program is free software; you can redistribute it and/or *) 8(* modify it under the terms of the GNU General Public License as *) 9(* published by the Free Software Foundation; either version 2 of *) 10(* the License, or (at your option) any later version. *) 11(* *) 12(* This program is distributed in the hope that it will be useful, *) 13(* but WITHOUT ANY WARRANTY; without even the implied warranty of *) 14(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *) 15(* GNU General Public License for more details. *) 16(* *) 17(* You should have received a copy of the GNU General Public *) 18(* License along with this program; if not, write to the *) 19(* Free Software Foundation, Inc., 51 Franklin Street, *) 20(* Fifth Floor, Boston, MA 02110-1301, USA. *) 21(* *) 22(********************************************************************) 23 24 25$ include "seed7_05.s7i"; 26 include "time.s7i"; 27 include "duration.s7i"; 28 include "float.s7i"; 29 include "keybd.s7i"; 30 include "echo.s7i"; 31 include "line.s7i"; 32 include "draw.s7i"; 33 include "graph_file.s7i"; 34 include "window.s7i"; 35 include "stars.s7i"; 36 include "math.s7i"; 37 38var text: scr is STD_NULL; 39 40const float: julianDayOfEpoch is 2451545.0; # 2000-01-01 12:00:00 41const integer: numberOfPlanets is 9; 42const integer: centerX is 440; 43const integer: centerY is 345; 44const integer: panoramaHorizont is 700; 45const integer: panoramaXMin is 62; 46const float: sizePanorama is 900.0; 47const integer: windowWidth is 1024; 48const integer: windowHeight is 768; 49const float: screenAspect is 1.0; 50const integer: scaleForInnerPlanets is 210; 51const integer: scaleForOuterPlanets is 9; 52const float: radianToDegrees is 57.295779513082320876798154814114; 53const float: degreesToRadian is 0.017453292519943295769236907684883; 54 55var boolean: displayDegreesInDecimal is FALSE; 56var boolean: displayHourAngleInDegrees is FALSE; 57var boolean: displayRAinDegrees is FALSE; 58 59 60const type: orbitType is new struct 61 var string: name is ""; 62 var float: orbitalPeriod is 0.0; # days 63 var float: meanLongitudeAtEpoch is 0.0; # deg 64 var float: longitudeOfPerihelion is 0.0; # deg 65 var float: longitudeOfPerihelionPerCentury is 0.0; # deg/century 66 var float: eccentricity is 0.0; # rad 67 var float: eccentricityPerCentury is 0.0; # rad/century 68 var float: axis is 0.0; # AU 69 var float: axisPerCentury is 0.0; # AU/century 70 var float: inclination is 0.0; 71 var float: longitudeOfTheAscendingNode is 0.0; 72 var float: argumentOfThePerihelion is 0.0; 73 var float: size is 0.0; 74 var float: brightness is 0.0; 75 end struct; 76 77var array orbitType: orbitDescr is numberOfPlanets times orbitType.value; 78 79var time: aTime is time.value; 80var integer: currTimeChange is 4; 81 82const type: heliocentricPlanetType is new struct 83 var float: axis is 0.0; 84 var float: eccentricity is 0.0; 85 var float: meanLongitude is 0.0; 86 var float: longitudeOfPerihelion is 0.0; 87 var float: meanAnomaly is 0.0; 88 var float: heliocentricLongitude is 0.0; 89 var float: trueAnomaly is 0.0; 90 var float: radiusVector is 0.0; 91 var float: heliocentricEclipticLatitude is 0.0; 92 var float: projectedHeliocentricLongitude is 0.0; 93 var float: projectedRadius is 0.0; 94 end struct; 95 96const type: eclipticalCoordinateType is new struct 97 var float: geocentricEclipticLongitude is 0.0; 98 var float: geocentricLatitude is 0.0; 99 end struct; 100 101const type: equatorialCoordinateType is new struct 102 var float: rightAscension is 0.0; 103 var float: declination is 0.0; 104 end struct; 105 106const type: horizontalCoordinateType is new struct 107 var float: azimuth is 0.0; 108 var float: altitude is 0.0; 109 end struct; 110 111const type: earthCoordinateType is new struct 112 var float: longitude is -16.42; 113 var float: latitude is 48.25; 114 end struct; 115 116const type: geocentricPlanetType is new struct 117 var eclipticalCoordinateType: eclipticalCoordinate is eclipticalCoordinateType.value; 118 var equatorialCoordinateType: equatorialCoordinate is equatorialCoordinateType.value; 119 var float: hourAngle is 0.0; 120 var horizontalCoordinateType: horizontalCoordinate is horizontalCoordinateType.value; 121 end struct; 122 123var earthCoordinateType: posAtEarth is earthCoordinateType.value; 124var float: localSiderealTime is 0.0; 125 126 127(* Trigonometric functions for degrees *) 128 129 130const func float: toDegrees (in float: x) is 131 return x * radianToDegrees; 132 133 134const func float: toRadians (in float: x) is 135 return x * degreesToRadian; 136 137 138const func float: sinD (in float: x) is 139 return sin(x * degreesToRadian); 140 141 142const func float: cosD (in float: x) is 143 return cos(x * degreesToRadian); 144 145 146const func float: tanD (in float: x) is 147 return tan(x * degreesToRadian); 148 149 150const func float: asinD (in float: x) is 151 return asin(x) * radianToDegrees; 152 153 154const func float: acosD (in float: x) is 155 return acos(x) * radianToDegrees; 156 157 158const func float: atanD (in float: x) is 159 return atan(x) * radianToDegrees; 160 161 162const func float: atan2D (in float: y, in float: x) is 163 return atan2(y, x) * radianToDegrees; 164 165 166const func float: frac (in float: x) is 167 return x - flt(trunc(x)); 168 169 170(* Astronomy functions *) 171 172 173const func float: julianDay (in time: aTime) is 174 return flt(julianDayNumber(aTime)) + 175 ((flt(aTime.second) / 60.0 + flt(aTime.minute)) / 60.0 + flt(aTime.hour - 12)) / 24.0; 176 177 178const func integer: minutes (in float: time) is 179 return abs(trunc(60.0 * (frac(time)))); 180 181 182const func integer: seconds (in float: time) is 183 return abs(trunc(60.0 * (frac(60.0 * frac(time))))); 184 185 186const func string: angleAsDegrees (in float: angle) is func 187 result 188 var string: degreesMinutesSeconds is ""; 189 begin 190 if displayDegreesInDecimal then 191 degreesMinutesSeconds &:= angle digits 4 lpad 9; 192 degreesMinutesSeconds &:= "° "; 193 else 194 if angle < 0.0 then 195 degreesMinutesSeconds := "-"; 196 else 197 degreesMinutesSeconds := " "; 198 end if; 199 degreesMinutesSeconds &:= abs(trunc(angle)) lpad 3; 200 degreesMinutesSeconds &:= "° "; 201 degreesMinutesSeconds &:= minutes(angle) lpad 2; 202 degreesMinutesSeconds &:= "' "; 203 degreesMinutesSeconds &:= seconds(angle) lpad 2; 204 degreesMinutesSeconds &:= "\""; 205 end if; 206 end func; 207 208 209const func string: angleAsHours (in float: angle) is func 210 result 211 var string: hoursMinutesSeconds is ""; 212 begin 213 if displayDegreesInDecimal then 214 hoursMinutesSeconds &:= angle / 15.0 digits 4 lpad 8; 215 hoursMinutesSeconds &:= "h"; 216 else 217 if angle < 0.0 then 218 hoursMinutesSeconds := "-"; 219 else 220 hoursMinutesSeconds := " "; 221 end if; 222 hoursMinutesSeconds &:= abs(trunc(angle / 15.0)) lpad 3; 223 hoursMinutesSeconds &:= "h "; 224 hoursMinutesSeconds &:= minutes(angle / 15.0) lpad 2; 225 hoursMinutesSeconds &:= "m "; 226 hoursMinutesSeconds &:= seconds(angle / 15.0) lpad 2; 227 hoursMinutesSeconds &:= "s"; 228 end if; 229 end func; 230 231 232const func float: anomaly (in float: m, in float: eccentricity) is func 233 result 234 var float: anomaly is 0.0; 235 local 236 var float: d is 0.0; 237 var float: e is 0.0; 238 begin 239 e := m; 240 d := -eccentricity * sin(m); 241 while abs(d) > 0.000001 do 242 e := e - d / (1.0 - eccentricity * cos(e)); 243 d := e - eccentricity * sin(e) - m; 244 end while; 245 anomaly := 2.0 * atan(sqrt((1.0 + eccentricity) / (1.0 - eccentricity)) * tan(e / 2.0)) 246 end func; (* anomaly *) 247 248 249const func float: anomaly2 (in float: m, in float: eccentricity) is func 250 result 251 var float: anomaly is 0.0; 252 local 253 var float: e is 0.0; 254 var float: deltaM is 0.0; 255 var float: deltaE is 0.0; 256 begin 257 e := m - eccentricity * sin(m); 258 repeat 259 deltaM := m - e - eccentricity * sin(e); 260 deltaE := deltaM / (1.0 - eccentricity * cos(e)); 261 e +:= deltaE; 262 until abs(deltaE) < 0.000001; 263 anomaly := e; 264 end func; (* anomaly2 *) 265 266 267const func float: eclipticalCoordinatesToRightAscension (in float: l, in float: b) is func 268 result 269 var float: rightAscension is 0.0; 270 local 271 var float: x is 0.0; 272 var float: y is 0.0; 273 begin 274 x := cosD(l); 275 y := sinD(l) * 0.91746406 - tanD(b) * 0.397818676; 276 rightAscension := atan2D(y, x) / 15.0; 277 end func; (* eclipticalCoordinatesToRightAscension *) 278 279 280const func float: eclipticalCoordinatesToDeclination (in float: l, in float: b) is 281 return asinD(sinD(b) * 0.91746406 + cosD(b) * sinD(l) * 0.397818676); 282 283 284const proc: degreesToRange (inout float: degrees) is func 285 begin 286 while degrees > 360.0 do 287 degrees -:= 360.0; 288 end while; 289 while degrees < 0.0 do 290 degrees +:= 360.0; 291 end while; 292 end func; 293 294 295const proc: hoursToRange (inout float: hours) is func 296 begin 297 while hours >= 24.0 do 298 hours -:= 24.0; 299 end while; 300 while hours < 0.0 do 301 hours +:= 24.0; 302 end while; 303 end func; 304 305 306const func float: localSiderealToCivilTime (in float: localSiderealTime, 307 in float: longitude, in time: aTime) is func 308 result 309 var float: localCivilTime is 0.0 310 local 311 var float: t is 0.0; 312 var float: b is 0.0; 313 var float: greenwichSiderealTime is 0.0; 314 var float: greenwichMeanTime is 0.0; 315 begin 316 greenwichSiderealTime := localSiderealTime + longitude / 15.0; 317 if greenwichSiderealTime > 24.0 then 318 greenwichSiderealTime -:= 24.0; 319 end if; 320 if greenwichSiderealTime < 0.0 then 321 greenwichSiderealTime +:= 24.0; 322 end if; 323 t := (julianDay(truncToYear(aTime) - 1 . DAYS) - 2415020.0) / 36525.0; 324 b := 24.0 - 6.6460656 - (2400.051262 * t) - (0.00002581 * t * t) + 325 flt(24 * (aTime.year - 1900)); 326 t := greenwichSiderealTime - flt(dayOfYear(aTime)) * 0.0657098 + b; 327 hoursToRange(t); 328 greenwichMeanTime := t * 0.99727; 329 localCivilTime := greenwichMeanTime + flt(aTime.timeZone) / 60.0; 330 end func; 331 332 333const proc: showLocalTime (inout text: win) is func 334 local 335 var string: timeStri is ""; 336 const integer: column is 1; 337 begin 338 timeStri := aTime lpad 19; 339 setPos(win, 1, column); 340 writeln(win, timeStri); 341 color(win, light_cyan); 342 case currTimeChange of 343 when {1}: 344 setPos(win, 1, column); 345 write(win, timeStri[.. 4]); 346 when {2}: 347 setPos(win, 1, column + 5); 348 write(win, timeStri[6 .. 7]); 349 when {3}: 350 setPos(win, 1, column + 8); 351 write(win, timeStri[9 .. 10]); 352 when {4}: 353 setPos(win, 1, column + 11); 354 write(win, timeStri[12 .. 13]); 355 when {5}: 356 setPos(win, 1, column + 14); 357 write(win, timeStri[15 .. 16]); 358 when {6}: 359 setPos(win, 1, column + 17); 360 write(win, timeStri[18 .. 19]); 361 when {7}: 362 setPos(win, 1, column + 20); 363 write(win, timeStri[21 .. 26]); 364 end case; 365 color(win, white); 366 writeln(win); 367 end func; 368 369 370const func float: calculateGreenwichMeanSiderealTime (in time: gmTime) is func 371 result 372 var float: greenwichMeanSiderealTime is 0.0; 373 local 374 var float: d is 0.0; 375 var float: d0 is 0.0; 376 var float: h is 0.0; 377 var integer: t is 0; 378 begin 379 d := julianDay(gmTime) - julianDayOfEpoch; 380 d0 := flt(julianDayNumber(gmTime)) + 0.5 - julianDayOfEpoch; 381 h := (flt(gmTime.second) / 60.0 + flt(gmTime.minute)) / 60.0 + flt(gmTime.hour); 382 t := round(d) div 36525; 383 greenwichMeanSiderealTime := 6.697374558 + 0.06570982441908 * d0 + 384 1.00273790935 * h + 0.000026 * flt(t * t); 385 hoursToRange(greenwichMeanSiderealTime); 386 end func; 387 388 389const proc: showTime is func 390 local 391 var text: win is STD_NULL; 392 var integer: julianDayNumber is 0; 393 var float: greenwichMeanSiderealTime is 0.0; 394 var time: gmTime is time.value; 395 begin 396 win := openWindow(scr, 2, 58, 8, 32); 397 showLocalTime(win); 398 julianDayNumber := julianDayNumber(aTime); 399 writeln(win, "julianDayNum =" <& julianDayNumber lpad 10); 400 writeln(win, "Longitude = " <& angleAsDegrees(posAtEarth.longitude)); 401 writeln(win, "Latitude = " <& angleAsDegrees(posAtEarth.latitude)); 402 write(win, "localCivilTime = "); 403 writeln(win, strTime(aTime)); 404 gmTime := toUTC(aTime); 405 write(win, "greenwichMeanTime = "); 406 writeln(win, strTime(gmTime)); 407 greenwichMeanSiderealTime := calculateGreenwichMeanSiderealTime(gmTime); 408 write(win, "greenwichSiderealTime = "); 409 write(win, trunc(greenwichMeanSiderealTime) lpad0 2); 410 write(win, ":"); 411 write(win, minutes(greenwichMeanSiderealTime) lpad0 2); 412 write(win, ":"); 413 writeln(win, seconds(greenwichMeanSiderealTime) lpad0 2); 414 localSiderealTime := greenwichMeanSiderealTime - posAtEarth.longitude / 15.0; 415 hoursToRange(localSiderealTime); 416 write(win, "localSiderealTime = "); 417 write(win, trunc(localSiderealTime) lpad0 2); 418 write(win, ":"); 419 write(win, minutes(localSiderealTime) lpad0 2); 420 write(win, ":"); 421 write(win, seconds(localSiderealTime) lpad0 2); 422 end func; (* showTime *) 423 424 425const func heliocentricPlanetType: locatePositionOfPlanetInItsOrbitalPlane ( 426 in orbitType: planetDescr) is func 427 result 428 var heliocentricPlanetType: planet is heliocentricPlanetType.value; 429 begin 430 planet.axis := planetDescr.axis + 431 planetDescr.axisPerCentury * (julianDay(aTime) - julianDayOfEpoch) / 36525.0; 432 planet.eccentricity := planetDescr.eccentricity + 433 planetDescr.eccentricityPerCentury * (julianDay(aTime) - julianDayOfEpoch) / 36525.0; 434 planet.meanLongitude := planetDescr.meanLongitudeAtEpoch + 435 360.0 / (planetDescr.orbitalPeriod / orbitDescr[3].orbitalPeriod * 365.2425) * 436 (julianDay(aTime) - julianDayOfEpoch); 437 degreesToRange(planet.meanLongitude); 438 planet.longitudeOfPerihelion := planetDescr.longitudeOfPerihelion + 439 planetDescr.longitudeOfPerihelionPerCentury * (julianDay(aTime) - julianDayOfEpoch) / 36525.0; 440 planet.meanAnomaly := planet.meanLongitude - planet.longitudeOfPerihelion; 441 planet.trueAnomaly := toDegrees(anomaly(toRadians(planet.meanAnomaly), planet.eccentricity)); 442 planet.heliocentricLongitude := planet.trueAnomaly + planet.longitudeOfPerihelion; 443 degreesToRange(planet.heliocentricLongitude); 444 planet.radiusVector := planetDescr.axis * (1.0 - planet.eccentricity * planet.eccentricity) / 445 (1.0 + planet.eccentricity * cosD(planet.trueAnomaly)); 446 planet.heliocentricEclipticLatitude := asinD(sinD(planet.heliocentricLongitude - 447 planetDescr.longitudeOfTheAscendingNode) * sinD(planetDescr.inclination)); 448 end func; 449 450 451const proc: plotPlanet (in integer: planetNumber, in integer: scale) is func 452 local 453 const func float: computeRadiusVector (in heliocentricPlanetType: planet, in integer: angle) is 454 return planet.axis * 455 (1.0 - planet.eccentricity * planet.eccentricity) / 456 (1.0 + planet.eccentricity * cosD(flt(angle) - planet.longitudeOfPerihelion)); 457 458 var heliocentricPlanetType: planet is heliocentricPlanetType.value; 459 var integer: oldX is 0; 460 var integer: oldY is 0; 461 var integer: newX is 0; 462 var integer: newY is 0; 463 var integer: angle is 0; 464 begin 465 planet := locatePositionOfPlanetInItsOrbitalPlane(orbitDescr[planetNumber]); 466 newY := round(flt(scale) * planet.radiusVector * sinD(planet.heliocentricLongitude)) + 467 centerY; 468 newX := round(flt(scale) * planet.radiusVector * cosD(planet.heliocentricLongitude) * 469 screenAspect) + centerX; 470 fcircle(newX, windowHeight - newY, 3, light_cyan); 471 setPosXY(scr, newX + 4, windowHeight - newY); 472 write(scr, orbitDescr[planetNumber].name); 473 474 newX := centerX + round(computeRadiusVector(planet, 0) * flt(scale) * screenAspect); 475 newY := windowHeight - centerY; 476 for angle range 1 to 60 do 477 oldX := newX; 478 oldY := newY; 479 newX := round(computeRadiusVector(planet, angle * 6) * flt(scale) * screenAspect 480 * cosD(flt(angle * 6))) + centerX; 481 newY := windowHeight - 482 (round(computeRadiusVector(planet, angle * 6) * flt(scale) * sinD(flt(angle * 6))) 483 + centerY); 484 lineTo(oldX, oldY, newX, newY, light_cyan); 485 end for; 486 end func; (* plotPlanet *) 487 488 489const proc: showMenu is func 490 local 491 var integer: num is 0; 492 begin 493 clear(black); 494 showTime; 495 setPos(scr, 2, 1); 496 writeln(scr, " P L A N E T S Display information about the planets"); 497 setPos(scr, 4, 1); 498 writeln(scr, " Copyright (C) 2006, 2007 Thomas Mertes"); 499 setPos(scr, 6, 1); 500 writeln(scr, " This program is free software under the"); 501 writeln(scr, " terms of the GNU General Public License"); 502 setPos(scr, 9, 1); 503 writeln(scr, " Planets is written in the Seed7 programming language"); 504 writeln(scr, " Homepage: http://seed7.sourceforge.net"); 505 writeln(scr); 506 writeln(scr); 507 writeln(scr, " Possible commands are:"); 508 writeln(scr); 509 writeln(scr, " M Menu"); 510 writeln(scr, " I Plot Inner Planets"); 511 writeln(scr, " O Plot Outer Planets"); 512 writeln(scr, " D Change Date/Time"); 513 writeln(scr, " L Change Long/Lat"); 514 writeln(scr, " S Set_up"); 515 writeln(scr, " Q Quit"); 516 for num range 1 to numberOfPlanets do 517 setPos(scr, 14 + num, 25); 518 writeln(scr, " " <& num <& " " <& orbitDescr[num].name); 519 end for; 520 setPos(scr, 15, 42); 521 writeln(scr, "Horizontal cursor keys:"); 522 setPos(scr, 16, 42); 523 writeln(scr, " Select time step"); 524 setPos(scr, 18, 42); 525 writeln(scr, "Vertical cursor keys:"); 526 setPos(scr, 19, 42); 527 write(scr, " Add or subtract a time step"); 528 setPos(scr, 25, 1); 529 writeln(scr, " Enter command:"); 530 end func; (* showMenu *) 531 532 533const proc: setup is func 534 local 535 var char: ch is ' '; 536 begin 537 clear(curr_win); 538 setPos(scr, 1, 1); 539 writeln(scr, "Display Degrees in Decimal Degrees (Y/N)? "); 540 ch := getc(KEYBOARD); 541 if upper(ch) = 'Y' then 542 displayDegreesInDecimal := TRUE; 543 elsif upper(ch) = 'N' then 544 displayDegreesInDecimal := FALSE; 545 end if; 546 writeln(scr, "Display Hour Angle in Degrees (Y/N)? "); 547 ch := getc(KEYBOARD); 548 if upper(ch) = 'Y' then 549 displayHourAngleInDegrees := TRUE; 550 elsif upper(ch) = 'N' then 551 displayHourAngleInDegrees := FALSE; 552 end if; 553 writeln(scr, "Display RA in Degrees (Y/N)? "); 554 ch := getc(KEYBOARD); 555 if upper(ch) = 'Y' then 556 displayRAinDegrees := TRUE; 557 elsif upper(ch) = 'N' then 558 displayRAinDegrees := FALSE; 559 end if; 560 end func; (* setup *) 561 562 563const proc: plotInnerPlanets is func 564 local 565 var text: win is STD_NULL; 566 var integer: julianDayNumber is 0; 567 var integer: planetNumber is 0; 568 begin 569 clear(curr_win); 570 win := openWindow(scr, 2, 135, 7, 32); 571 showLocalTime(win); 572 julianDayNumber := julianDayNumber(aTime); 573 writeln(win, "julianDayNum =" <& julianDayNumber lpad 10); 574 writeln(win); 575 writeln(win, "Horizontal cursor keys:"); 576 writeln(win, " Select time step"); 577 writeln(win, "Vertical cursor keys:"); 578 write(win, " Add or subtract a time step"); 579 fcircle(centerX, windowHeight - centerY, 3, light_cyan); 580 setPosXY(scr, centerX + 4, windowHeight - centerY); 581 write(scr, "Sun"); 582 for planetNumber range 1 to 4 do 583 plotPlanet(planetNumber, scaleForInnerPlanets); 584 end for; 585 end func; (* plotInnerPlanets *) 586 587 588const proc: plotOuterPlanets is func 589 local 590 var text: win is STD_NULL; 591 var integer: julianDayNumber is 0; 592 var integer: planetNumber is 0; 593 begin 594 clear(curr_win); 595 win := openWindow(scr, 2, 135, 7, 32); 596 showLocalTime(win); 597 julianDayNumber := julianDayNumber(aTime); 598 writeln(win, "julianDayNum =" <& julianDayNumber lpad 10); 599 writeln(win); 600 writeln(win, "Horizontal cursor keys:"); 601 writeln(win, " Select time step"); 602 writeln(win, "Vertical cursor keys:"); 603 write(win, " Add or subtract a time step"); 604 point(centerX, windowHeight - centerY, light_cyan); 605 plotPlanet(3, scaleForOuterPlanets); 606 for planetNumber range 5 to 9 do 607 plotPlanet(planetNumber, scaleForOuterPlanets); 608 end for; 609 end func; (* plotOuterPlanets *) 610 611 612const proc: changeDateTime is func 613 local 614 var text: win is STD_NULL; 615 begin 616 clear(curr_win); 617 showTime; 618 setPos(scr, 1, 1); 619 case currTimeChange of 620 when {1}: 621 write(scr, "Enter year: "); 622 read(aTime.year); 623 when {2}: 624 write(scr, "Enter month: "); 625 read(aTime.month); 626 when {3}: 627 write(scr, "Enter day: "); 628 read(aTime.day); 629 when {4}: 630 write(scr, "Enter hour: "); 631 read(aTime.hour); 632 when {5}: 633 write(scr, "Enter minute: "); 634 read(aTime.minute); 635 when {6}: 636 write(scr, "Enter second: "); 637 read(aTime.second); 638 end case; 639 showMenu; 640 end func; 641 642 643const proc: changeLongLat is func 644 begin 645 clear(curr_win); 646 showTime; 647 setPos(scr, 1, 1); 648 writeln("Enter Longitude"); 649 readln(posAtEarth.longitude); 650 writeln("Enter Latitude"); 651 readln(posAtEarth.latitude); 652 showMenu; 653 end func; 654 655 656const func float: computeProjectedHeliocentricLongitude (in heliocentricPlanetType: planet, 657 in orbitType: orbitDescr) is func 658 result 659 var float: projectedHeliocentricLongitude is 0.0; 660 local 661 var float: y is 0.0; 662 var float: x is 0.0; 663 var float: z is 0.0; 664 begin 665 y := sinD(planet.heliocentricLongitude - orbitDescr.longitudeOfTheAscendingNode) * 666 cosD(orbitDescr.inclination); 667 x := cosD(planet.heliocentricLongitude - orbitDescr.longitudeOfTheAscendingNode); 668 z := atan2D(y, x); 669 projectedHeliocentricLongitude := z + orbitDescr.longitudeOfTheAscendingNode; 670 end func; 671 672 673const proc: ProjectPlanetOntoEclipticalPlane (inout heliocentricPlanetType: planet, 674 in orbitType: orbitDescr) is func 675 begin 676 planet.projectedHeliocentricLongitude := computeProjectedHeliocentricLongitude(planet, orbitDescr); 677 degreesToRange(planet.projectedHeliocentricLongitude); 678 planet.projectedRadius := planet.radiusVector * cosD(planet.heliocentricEclipticLatitude); 679 end func; 680 681 682const func eclipticalCoordinateType: calculateEclipticalCoordinates (in heliocentricPlanetType: planet, 683 in heliocentricPlanetType: earth) is func 684 result 685 var eclipticalCoordinateType: eclipticalCoordinate is eclipticalCoordinateType.value; 686 begin 687 if planet.radiusVector < earth.radiusVector then 688 eclipticalCoordinate.geocentricEclipticLongitude := earth.heliocentricLongitude + 180.0 + 689 atanD(planet.projectedRadius * sinD(earth.heliocentricLongitude - 690 planet.projectedHeliocentricLongitude) / (earth.radiusVector - 691 planet.projectedRadius * cosD(earth.heliocentricLongitude - 692 planet.projectedHeliocentricLongitude))); 693 else 694 eclipticalCoordinate.geocentricEclipticLongitude := planet.projectedHeliocentricLongitude + 695 atanD(earth.radiusVector * sinD(planet.projectedHeliocentricLongitude - 696 earth.heliocentricLongitude) / (planet.projectedRadius - 697 earth.radiusVector * cosD(planet.projectedHeliocentricLongitude - 698 earth.heliocentricLongitude))); 699 end if; 700 degreesToRange(eclipticalCoordinate.geocentricEclipticLongitude); 701 eclipticalCoordinate.geocentricLatitude := atanD(planet.projectedRadius * 702 tanD(planet.heliocentricEclipticLatitude) * 703 sinD(eclipticalCoordinate.geocentricEclipticLongitude - 704 planet.projectedHeliocentricLongitude) / (earth.radiusVector * 705 sinD(planet.projectedHeliocentricLongitude - earth.heliocentricLongitude))); 706 end func; 707 708 709const func equatorialCoordinateType: calculateEquatorialCoordinates ( 710 in eclipticalCoordinateType: eclipticalCoordinate) is func 711 result 712 var equatorialCoordinateType: equatorialCoordinate is equatorialCoordinateType.value; 713 begin 714 equatorialCoordinate.rightAscension := eclipticalCoordinatesToRightAscension( 715 eclipticalCoordinate.geocentricEclipticLongitude, 716 eclipticalCoordinate.geocentricLatitude); 717 equatorialCoordinate.declination := eclipticalCoordinatesToDeclination( 718 eclipticalCoordinate.geocentricEclipticLongitude, 719 eclipticalCoordinate.geocentricLatitude); 720 end func; 721 722 723const func float: calculateHourAngle (in equatorialCoordinateType: equatorialCoordinate, 724 in float: localSiderealTime) is func 725 result 726 var float: hourAngle is 0.0; 727 begin 728 hourAngle := localSiderealTime - equatorialCoordinate.rightAscension; 729 if hourAngle < 0.0 then 730 hourAngle +:= 24.0; 731 end if; 732 end func; 733 734 735const func horizontalCoordinateType: calculateHorizontalCoordinates ( 736 in equatorialCoordinateType: equatorialCoordinate, 737 in earthCoordinateType: posAtEarth, in float: hourAngle) is func 738 result 739 var horizontalCoordinateType: horizontalCoordinate is horizontalCoordinateType.value; 740 begin 741 horizontalCoordinate.altitude := asinD(sinD(equatorialCoordinate.declination) * sinD(posAtEarth.latitude) + 742 cosD(equatorialCoordinate.declination) * cosD(posAtEarth.latitude) * 743 cosD(hourAngle * 15.0)); 744 horizontalCoordinate.azimuth := acosD((sinD(equatorialCoordinate.declination) - 745 sinD(posAtEarth.latitude) * sinD(horizontalCoordinate.altitude)) / 746 (cosD(posAtEarth.latitude) * cosD(horizontalCoordinate.altitude))); 747 if sinD(hourAngle * 15.0) > 0.0 then 748 horizontalCoordinate.azimuth := 360.0 - horizontalCoordinate.azimuth; 749 end if; 750 end func; 751 752 753const func geocentricPlanetType: genGeocentricPos (in heliocentricPlanetType: planet, 754 in heliocentricPlanetType: earth, in float: localSiderealTime, 755 in earthCoordinateType: posAtEarth) is func 756 result 757 var geocentricPlanetType: geocentricPos is geocentricPlanetType.value; 758 begin 759 geocentricPos.eclipticalCoordinate := calculateEclipticalCoordinates(planet, earth); 760 geocentricPos.equatorialCoordinate := calculateEquatorialCoordinates(geocentricPos.eclipticalCoordinate); 761 geocentricPos.hourAngle := calculateHourAngle(geocentricPos.equatorialCoordinate, localSiderealTime); 762 geocentricPos.horizontalCoordinate := calculateHorizontalCoordinates(geocentricPos.equatorialCoordinate, 763 posAtEarth, geocentricPos.hourAngle); 764 end func; 765 766 767const func integer: panoramaXPos (in float: azimuth) is 768 return panoramaXMin + round(azimuth / 360.0 * sizePanorama); 769 770 771const func integer: panoramaYPos (in float: altitude) is 772 return panoramaHorizont - round(altitude / 360.0 * sizePanorama); 773 774 775const proc: drawAllPlanets (in heliocentricPlanetType: earth) is func 776 local 777 var integer: planetNumber is 0; 778 var heliocentricPlanetType: planet is heliocentricPlanetType.value; 779 var geocentricPlanetType: geocentricPos is geocentricPlanetType.value; 780 begin 781 for planetNumber range 1 to 9 do 782 if planetNumber <> 3 then 783 planet := locatePositionOfPlanetInItsOrbitalPlane(orbitDescr[planetNumber]); 784 ProjectPlanetOntoEclipticalPlane(planet, orbitDescr[planetNumber]); 785 geocentricPos := genGeocentricPos(planet, earth, localSiderealTime, posAtEarth); 786 if geocentricPos.horizontalCoordinate.altitude >= 0.0 then 787 fcircle(panoramaXPos(geocentricPos.horizontalCoordinate.azimuth), 788 panoramaYPos(geocentricPos.horizontalCoordinate.altitude), 2, light_cyan); 789 end if; 790 end if; 791 end for; 792 end func; 793 794 795const proc: drawSun (in heliocentricPlanetType: earth) is func 796 local 797 var heliocentricPlanetType: sun is heliocentricPlanetType.value; 798 var geocentricPlanetType: geocentricPos is geocentricPlanetType.value; 799 begin 800 geocentricPos := genGeocentricPos(sun, earth, localSiderealTime, posAtEarth); 801 if geocentricPos.horizontalCoordinate.altitude >= 0.0 then 802 fcircle(panoramaXPos(geocentricPos.horizontalCoordinate.azimuth), 803 panoramaYPos(geocentricPos.horizontalCoordinate.altitude), 4, yellow); 804 end if; 805 end func; 806 807 808const proc: drawHorizont is func 809 local 810 var integer: azimuth is 0; 811 var integer: length is 0; 812 const array string: name is [] ("North", "East", "South", "West", "North"); 813 var integer: pos is 1; 814 begin 815 lineTo(0, panoramaHorizont, 1023, panoramaHorizont, white); 816 for azimuth range 0 to 360 do 817 if azimuth rem 90 = 0 then 818 length := 12; 819 setPosXY(scr, panoramaXPos(flt(azimuth)) - 12, panoramaHorizont + 25); 820 writeln(scr, name[pos]); 821 incr(pos); 822 elsif azimuth rem 45 = 0 then 823 length := 10; 824 elsif azimuth rem 10 = 0 then 825 length := 8; 826 elsif azimuth rem 5 = 0 then 827 length := 6; 828 elsif azimuth rem 5 = 0 then 829 length := 4; 830 else 831 length := 2; 832 end if; 833 line(panoramaXPos(flt(azimuth)), panoramaHorizont, 0, length, white); 834 end for; 835 end func; 836 837 838const proc: writePoint (in integer: x, in integer: y, in float: vis) is func 839 begin 840 if vis >= 5.0 then 841 point(x, y, dark_gray); 842 elsif vis >= 4.5 then 843 point(x, y, Gray); 844 elsif vis >= 4.0 then 845 point(x, y, light_gray); 846 elsif vis >= 3.5 then 847 point(x, y, white); 848 elsif vis >= 3.0 then 849 point(x, y, white); 850 point(succ(x), y, dark_gray); 851 point(pred(x), y, dark_gray); 852 point(x, succ(y), dark_gray); 853 point(x, pred(y), dark_gray); 854 elsif vis >= 2.5 then 855 point(x, y, white); 856 point(succ(x), y, Gray); 857 point(pred(x), y, Gray); 858 point(x, succ(y), Gray); 859 point(x, pred(y), Gray); 860 elsif vis >= 2.0 then 861 point(x, y, white); 862 point(succ(x), y, light_gray); 863 point(pred(x), y, light_gray); 864 point(x, succ(y), light_gray); 865 point(x, pred(y), light_gray); 866 elsif vis >= 1.5 then 867 line(pred(x), y, 2, 0, white); 868 point(x, succ(y), white); 869 point(x, pred(y), white); 870 elsif vis >= 1.0 then 871 line(pred(x), y, 2, 0, white); 872 point(x, succ(y), white); 873 point(x, pred(y), white); 874 point(succ(x), succ(y), dark_gray); 875 point(succ(x), pred(y), dark_gray); 876 point(pred(x), succ(y), dark_gray); 877 point(pred(x), pred(y), dark_gray); 878 elsif vis >= 0.5 then 879 line(pred(x), y, 2, 0, white); 880 point(x, succ(y), white); 881 point(x, pred(y), white); 882 point(succ(x), succ(y), Gray); 883 point(succ(x), pred(y), Gray); 884 point(pred(x), succ(y), Gray); 885 point(pred(x), pred(y), Gray); 886 elsif vis >= 0.0 then 887 line(pred(x), y, 2, 0, white); 888 point(x, succ(y), white); 889 point(x, pred(y), white); 890 point(succ(x), succ(y), light_gray); 891 point(succ(x), pred(y), light_gray); 892 point(pred(x), succ(y), light_gray); 893 point(pred(x), pred(y), light_gray); 894 elsif vis >= -0.5 then 895 rect (pred(x), pred(y), 3, 3, white); 896 else 897 fcircle(x, y, 2, white); 898 end if; 899 end func; 900 901 902const proc: drawStars is func 903 local 904 var integer: index is 0; 905 var equatorialCoordinateType: equatorialCoordinate is equatorialCoordinateType.value; 906 var float: hourAngle is 0.0; 907 var horizontalCoordinateType: horizontalCoordinate is horizontalCoordinateType.value; 908 var integer: xPos is 0; 909 var integer: yPos is 0; 910 begin 911 for index range length(stars) downto 1 do 912 equatorialCoordinate.rightAscension := stars[index].rightAscension; 913 equatorialCoordinate.declination := stars[index].declination; 914 hourAngle := calculateHourAngle(equatorialCoordinate, localSiderealTime); 915 horizontalCoordinate := calculateHorizontalCoordinates(equatorialCoordinate, 916 posAtEarth, hourAngle); 917 if horizontalCoordinate.altitude >= 0.0 then 918 xPos := panoramaXPos(horizontalCoordinate.azimuth); 919 yPos := panoramaYPos(horizontalCoordinate.altitude); 920 writePoint(xPos, yPos, stars[index].magnitude); 921 if xPos + round(sizePanorama) < windowWidth then 922 writePoint(xPos + round(sizePanorama), yPos, stars[index].magnitude); 923 end if; 924 if xPos - round(sizePanorama) >= 0 then 925 writePoint(xPos - round(sizePanorama), yPos, stars[index].magnitude); 926 end if; 927 end if; 928 end for; 929 end func; 930 931 932const proc: locatePlanet (in integer: planetNumber) is func 933 local 934 var text: win is STD_NULL; 935 var heliocentricPlanetType: planet is heliocentricPlanetType.value; 936 var heliocentricPlanetType: earth is heliocentricPlanetType.value; 937 var geocentricPlanetType: geocentricPos is geocentricPlanetType.value; 938 var float: azimuthOfRise is 0.0; 939 var float: azimuthOfSet is 0.0; 940 var float: localSiderealTime_Rise is 0.0; 941 var float: localSiderealTime_Set is 0.0; 942 var float: localCivilTime_Rise is 0.0; 943 var float: localCivilTime_Set is 0.0; 944 var float: phase is 0.0; 945 var float: distanceFromEarth is 0.0; 946 var float: diameter is 0.0; 947 var float: magnitude is 0.0; 948 begin 949 clear(curr_win, black); 950 showTime; 951 planet := locatePositionOfPlanetInItsOrbitalPlane(orbitDescr[planetNumber]); 952 953 win := openWindow(scr, 2, 3, 7, 51); 954 setPos(win, 1, 1); 955 write (win, " "); 956 writeln(win, orbitDescr[planetNumber].name); 957 writeln(win, "mean longitude = " <& angleAsDegrees(planet.meanLongitude)); 958 writeln(win, "mean anomaly = " <& angleAsDegrees(planet.meanAnomaly)); 959 writeln(win, "true anomaly = " <& angleAsDegrees(planet.trueAnomaly)); 960 writeln(win, "heliocentric long = " <& angleAsDegrees(planet.heliocentricLongitude)); 961 writeln(win, "radius vector = " <& planet.radiusVector digits 3 lpad 8 <& " AU"); 962 write (win, "helio ecliptic lat. = " <& angleAsDegrees(planet.heliocentricEclipticLatitude)); 963 964 if planetNumber <> 3 then 965 966 earth := locatePositionOfPlanetInItsOrbitalPlane(orbitDescr[3]); 967 win := openWindow(scr, 2, 40, 7, 14); 968 setPos(win, 1, 1); 969 writeln(win, " Earth"); 970 writeln(win, angleAsDegrees(earth.meanLongitude)); 971 writeln(win, angleAsDegrees(earth.meanAnomaly)); 972 writeln(win, angleAsDegrees(earth.trueAnomaly)); 973 writeln(win, angleAsDegrees(earth.heliocentricLongitude)); 974 writeln(win, earth.radiusVector digits 3 lpad 8 <& " AU"); 975 write (win, angleAsDegrees(0.0)); 976 977 978 (* Project Position of Planet onto plane of ecliptic *) 979 ProjectPlanetOntoEclipticalPlane(planet, orbitDescr[planetNumber]); 980 981 win := openWindow(scr, 11, 12, 2, 68); 982 setPos(win, 1, 1); 983 write(win, "Projected Longitude = "); 984 write(win, angleAsDegrees(planet.projectedHeliocentricLongitude)); 985 writeln(win); 986 write(win, "Projected Radius = "); 987 write(win, planet.projectedRadius digits 3 lpad 8); 988 write(win, " AU"); 989 990 991 (* Calculate Ecliptical Coordinates *) 992 geocentricPos.eclipticalCoordinate := calculateEclipticalCoordinates(planet, earth); 993 994 win := openWindow(scr, 19, 3, 5, 22); 995 setPos(win, 1, 1); 996 writeln(win, " ECLIPTIC"); 997 writeln(win); 998 writeln(win, " Long = " <& angleAsDegrees( 999 geocentricPos.eclipticalCoordinate.geocentricEclipticLongitude)); 1000 write(win, " Lat = " <& angleAsDegrees( 1001 geocentricPos.eclipticalCoordinate.geocentricLatitude)); 1002 1003 1004 (* Calculate Equatorial Coordinates *) 1005 geocentricPos.equatorialCoordinate := calculateEquatorialCoordinates( 1006 geocentricPos.eclipticalCoordinate); 1007 1008 win := openWindow(scr, 19, 29, 5, 23); 1009 setPos(win, 1, 1); 1010 writeln(win, " EQUATORIAL"); 1011 writeln(win); 1012 write(win, " RA = "); 1013 if displayRAinDegrees then 1014 writeln(win, angleAsDegrees(geocentricPos.equatorialCoordinate.rightAscension * 15.0)); 1015 else 1016 writeln(win, angleAsHours(geocentricPos.equatorialCoordinate.rightAscension * 15.0)); 1017 end if; 1018 writeln(win, " DEC = " <& angleAsDegrees(geocentricPos.equatorialCoordinate.declination)); 1019 1020 1021 geocentricPos.hourAngle := calculateHourAngle(geocentricPos.equatorialCoordinate, localSiderealTime); 1022 write(win, " HA = "); 1023 if displayHourAngleInDegrees then 1024 write(win, angleAsDegrees(geocentricPos.hourAngle * 15.0)); 1025 else 1026 write(win, angleAsHours(geocentricPos.hourAngle * 15.0)); 1027 end if; 1028 1029 1030 (* Calculate Horizontal Coordinates *) 1031 geocentricPos.horizontalCoordinate := calculateHorizontalCoordinates( 1032 geocentricPos.equatorialCoordinate, 1033 posAtEarth, geocentricPos.hourAngle); 1034 1035 win := openWindow(scr, 19, 56, 5, 23); 1036 setPos(win, 1, 1); 1037 writeln(win, " HORIZONTAL"); 1038 writeln(win); 1039 writeln(win, " Alt = " <& angleAsDegrees(geocentricPos.horizontalCoordinate.altitude)); 1040 write(win, " Azim = " <& angleAsDegrees(geocentricPos.horizontalCoordinate.azimuth)); 1041 1042 1043 (* Calculate Time and Position of Rise and Set *) 1044 1045 win := openWindow(scr, 15, 4, 2, 50); 1046 setPos(win, 1, 1); 1047 azimuthOfRise := sinD(geocentricPos.equatorialCoordinate.declination) / cosD(posAtEarth.latitude); 1048 if azimuthOfRise < -1.0 or azimuthOfRise > 1.0 then 1049 if geocentricPos.horizontalCoordinate.altitude < 0.0 then 1050 writeln(win, "never rises above horizon"); 1051 else 1052 writeln(win, "never sets below horizon"); 1053 end if; 1054 else 1055 azimuthOfRise := acosD(azimuthOfRise); 1056 azimuthOfSet := 360.0 - azimuthOfRise; 1057 localSiderealTime_Rise := 24.0 + geocentricPos.equatorialCoordinate.rightAscension - 1058 (acosD(-tanD(posAtEarth.latitude) * 1059 tanD(geocentricPos.equatorialCoordinate.declination))) / 15.0; 1060 if localSiderealTime_Rise > 24.0 then 1061 localSiderealTime_Rise := localSiderealTime_Rise - 24.0; 1062 end if; 1063 localSiderealTime_Set := geocentricPos.equatorialCoordinate.rightAscension + 1064 (acosD(-tanD(posAtEarth.latitude) * 1065 tanD(geocentricPos.equatorialCoordinate.declination))) / 15.0; 1066 if localSiderealTime_Set > 24.0 then 1067 localSiderealTime_Set := localSiderealTime_Set - 24.0; 1068 end if; 1069 1070 localCivilTime_Set := localSiderealToCivilTime(localSiderealTime_Set, 1071 posAtEarth.longitude, aTime); 1072 if localCivilTime_Set < 0.0 then 1073 localCivilTime_Set := localCivilTime_Set + 24.0; 1074 end if; 1075 1076 localCivilTime_Rise := localSiderealToCivilTime(localSiderealTime_Rise, 1077 posAtEarth.longitude, aTime); 1078 if localCivilTime_Rise < 0.0 then 1079 localCivilTime_Rise := localCivilTime_Rise + 24.0; 1080 end if; 1081 1082 write(win, "Rises at "); 1083 write(win, trunc(localCivilTime_Rise) lpad 2 <& ":" <& 1084 minutes(localCivilTime_Rise) lpad 2 <& " local time"); 1085 write(win, " Azimuth "); 1086 write(win, angleAsDegrees(azimuthOfRise)); 1087 writeln(win); 1088 write(win, "Sets at "); 1089 write(win, trunc(localCivilTime_Set) lpad 2 <& ":" <& 1090 minutes(localCivilTime_Set) lpad 2 <& " local time"); 1091 write(win, " Azimuth "); 1092 write(win, angleAsDegrees(azimuthOfSet)); 1093 1094 line(panoramaXPos(azimuthOfRise), panoramaHorizont - 4, 0, 4, light_red); 1095 line(panoramaXPos(azimuthOfSet), panoramaHorizont - 4, 0, 4, light_red); 1096 end if; 1097 1098 1099 (* Calculate Phase, Distance, Diameter, Magnitude *) 1100 1101 win := openWindow(scr, 12, 57, 5, 23); 1102 setPos(win, 1, 1); 1103 1104 phase := (1.0 + cosD(geocentricPos.eclipticalCoordinate.geocentricEclipticLongitude - 1105 planet.heliocentricLongitude)) / 2.0; 1106 write(win, "Phase = "); 1107 write(win, 100.0 * phase digits 2 lpad 6); 1108 writeln(win, "%"); 1109 distanceFromEarth := sqrt(earth.radiusVector * earth.radiusVector 1110 + planet.radiusVector * planet.radiusVector 1111 - 2.0 * earth.radiusVector * planet.radiusVector * 1112 cosD(planet.heliocentricLongitude - 1113 earth.heliocentricLongitude)); 1114 write(win, "Distance = "); 1115 write(win, distanceFromEarth digits 2 lpad 6); 1116 writeln(win, " AU"); 1117 1118 diameter := orbitDescr[planetNumber].size / distanceFromEarth; 1119 write(win, "Diameter = "); 1120 write(win, diameter digits 2 lpad 6); 1121 writeln(win, "\""); 1122 1123 write(win, "magnitude = "); 1124 if distanceFromEarth * planet.radiusVector / 1125 orbitDescr[planetNumber].brightness * sqrt(phase) <> 0.0 then 1126 magnitude := 2.17147 * log(distanceFromEarth * planet.radiusVector / 1127 orbitDescr[planetNumber].brightness * sqrt(phase)) - 26.7; 1128 write(win, magnitude digits 2 lpad 6); 1129 else 1130 write(win, "*****" lpad 6); 1131 end if; 1132 1133 drawHorizont; 1134 drawStars; 1135 if geocentricPos.horizontalCoordinate.altitude >= 0.0 then 1136 fcircle(panoramaXPos(geocentricPos.horizontalCoordinate.azimuth), 1137 panoramaYPos(geocentricPos.horizontalCoordinate.altitude), 2, light_cyan); 1138 end if; 1139 drawSun(earth); 1140 else 1141 drawHorizont; 1142 drawStars; 1143 drawAllPlanets(planet); 1144 drawSun(planet); 1145 end if; 1146 end func; (* locatePlanet *) 1147 1148 1149const proc: showName is func 1150 local 1151 var integer: mouseXPos is 0; 1152 var integer: mouseYPos is 0; 1153 var integer: index is 0; 1154 var equatorialCoordinateType: equatorialCoordinate is equatorialCoordinateType.value; 1155 var float: hourAngle is 0.0; 1156 var horizontalCoordinateType: horizontalCoordinate is horizontalCoordinateType.value; 1157 var heliocentricPlanetType: sun is heliocentricPlanetType.value; 1158 var heliocentricPlanetType: earth is heliocentricPlanetType.value; 1159 var heliocentricPlanetType: planet is heliocentricPlanetType.value; 1160 var geocentricPlanetType: geocentricPos is geocentricPlanetType.value; 1161 var integer: xPos is 0; 1162 var integer: yPos is 0; 1163 var integer: delta is 0; 1164 var integer: minDelta is 0; 1165 var integer: selectedStar is 0; 1166 var integer: selectedPlanet is 0; 1167 var string: name is ""; 1168 begin 1169 mouseXPos := getxpos(KEYBOARD); 1170 mouseYPos := getypos(KEYBOARD); 1171 for index range 1 to length(stars) do 1172 equatorialCoordinate.rightAscension := stars[index].rightAscension; 1173 equatorialCoordinate.declination := stars[index].declination; 1174 hourAngle := calculateHourAngle(equatorialCoordinate, localSiderealTime); 1175 horizontalCoordinate := calculateHorizontalCoordinates(equatorialCoordinate, 1176 posAtEarth, hourAngle); 1177 if horizontalCoordinate.altitude >= 0.0 then 1178 xPos := panoramaXPos(horizontalCoordinate.azimuth); 1179 yPos := panoramaYPos(horizontalCoordinate.altitude); 1180 delta := (mouseXPos - xPos) ** 2 + (mouseYPos - yPos) ** 2; 1181 if selectedStar = 0 or delta < minDelta then 1182 selectedStar := index; 1183 minDelta := delta; 1184 end if; 1185 if xPos + round(sizePanorama) < windowWidth then 1186 delta := (mouseXPos - xPos - round(sizePanorama)) ** 2 + (mouseYPos - yPos) ** 2; 1187 if selectedStar = 0 or delta < minDelta then 1188 selectedStar := index; 1189 minDelta := delta; 1190 end if; 1191 end if; 1192 if xPos - round(sizePanorama) >= 0 then 1193 delta := (mouseXPos - xPos + round(sizePanorama)) ** 2 + (mouseYPos - yPos) ** 2; 1194 if selectedStar = 0 or delta < minDelta then 1195 selectedStar := index; 1196 minDelta := delta; 1197 end if; 1198 end if; 1199 end if; 1200 end for; 1201 earth := locatePositionOfPlanetInItsOrbitalPlane(orbitDescr[3]); 1202 for index range 1 to 9 do 1203 if index <> 3 then 1204 planet := locatePositionOfPlanetInItsOrbitalPlane(orbitDescr[index]); 1205 ProjectPlanetOntoEclipticalPlane(planet, orbitDescr[index]); 1206 geocentricPos := genGeocentricPos(planet, earth, localSiderealTime, posAtEarth); 1207 if geocentricPos.horizontalCoordinate.altitude >= 0.0 then 1208 xPos := panoramaXPos(geocentricPos.horizontalCoordinate.azimuth); 1209 yPos := panoramaYPos(geocentricPos.horizontalCoordinate.altitude); 1210 delta := (mouseXPos - xPos) ** 2 + (mouseYPos - yPos) ** 2; 1211 if delta <= minDelta then 1212 selectedStar := 0; 1213 selectedPlanet := index; 1214 minDelta := delta; 1215 end if; 1216 end if; 1217 end if; 1218 end for; 1219 geocentricPos := genGeocentricPos(sun, earth, localSiderealTime, posAtEarth); 1220 if geocentricPos.horizontalCoordinate.altitude >= 0.0 then 1221 xPos := panoramaXPos(geocentricPos.horizontalCoordinate.azimuth); 1222 yPos := panoramaYPos(geocentricPos.horizontalCoordinate.altitude); 1223 delta := (mouseXPos - xPos) ** 2 + (mouseYPos - yPos) ** 2; 1224 if delta <= minDelta then 1225 selectedStar := 0; 1226 selectedPlanet := 0; 1227 minDelta := delta; 1228 end if; 1229 end if; 1230 if selectedStar <> 0 then 1231 equatorialCoordinate.rightAscension := stars[selectedStar].rightAscension; 1232 equatorialCoordinate.declination := stars[selectedStar].declination; 1233 hourAngle := calculateHourAngle(equatorialCoordinate, localSiderealTime); 1234 horizontalCoordinate := calculateHorizontalCoordinates(equatorialCoordinate, 1235 posAtEarth, hourAngle); 1236 xPos := panoramaXPos(horizontalCoordinate.azimuth); 1237 yPos := panoramaYPos(horizontalCoordinate.altitude); 1238 name := stars[selectedStar].name; 1239 elsif selectedPlanet <> 0 then 1240 planet := locatePositionOfPlanetInItsOrbitalPlane(orbitDescr[selectedPlanet]); 1241 ProjectPlanetOntoEclipticalPlane(planet, orbitDescr[selectedPlanet]); 1242 geocentricPos := genGeocentricPos(planet, earth, localSiderealTime, posAtEarth); 1243 xPos := panoramaXPos(geocentricPos.horizontalCoordinate.azimuth); 1244 yPos := panoramaYPos(geocentricPos.horizontalCoordinate.altitude); 1245 name := orbitDescr[selectedPlanet].name; 1246 else 1247 geocentricPos := genGeocentricPos(sun, earth, localSiderealTime, posAtEarth); 1248 xPos := panoramaXPos(geocentricPos.horizontalCoordinate.azimuth); 1249 yPos := panoramaYPos(geocentricPos.horizontalCoordinate.altitude); 1250 name := "Sun"; 1251 end if; 1252 if minDelta <= 900 then 1253 setPosXY(scr, xPos + 4, yPos); 1254 write(name); 1255 if xPos + round(sizePanorama) < windowWidth then 1256 setPosXY(scr, xPos + round(sizePanorama) + 4, yPos); 1257 write(name); 1258 end if; 1259 if xPos - round(sizePanorama) >= 0 then 1260 setPosXY(scr, xPos - round(sizePanorama) + 4, yPos); 1261 write(name); 1262 end if; 1263 end if; 1264 end func; 1265 1266 1267const proc: initOrbitDescr is func 1268 begin 1269 orbitDescr[1].name :="Mercury"; 1270 orbitDescr[1].orbitalPeriod := 87.96934; # 0.2408469 years 1271 orbitDescr[1].meanLongitudeAtEpoch := 252.25032350; 1272 orbitDescr[1].longitudeOfPerihelion := 77.45779628; 1273 orbitDescr[1].longitudeOfPerihelionPerCentury := 0.16047689; 1274 orbitDescr[1].eccentricity := 0.20563593; 1275 orbitDescr[1].eccentricityPerCentury := 0.00001906; 1276 orbitDescr[1].axis := 0.38709927; 1277 orbitDescr[1].axisPerCentury := 0.00000037; 1278 orbitDescr[1].inclination := 7.00497902; 1279 orbitDescr[1].longitudeOfTheAscendingNode := 48.33167; 1280 orbitDescr[1].argumentOfThePerihelion := 29.12478; 1281 orbitDescr[1].size := 6.74; 1282 orbitDescr[1].brightness := 0.000001918; 1283 1284 orbitDescr[2].name :="Venus"; 1285 orbitDescr[2].orbitalPeriod := 224.70069; # 0.6151970 years 1286 orbitDescr[2].meanLongitudeAtEpoch := 181.97909950; 1287 orbitDescr[2].longitudeOfPerihelion := 131.60246718; 1288 orbitDescr[2].longitudeOfPerihelionPerCentury := 0.00268329; 1289 orbitDescr[2].eccentricity := 0.00677672; 1290 orbitDescr[2].eccentricityPerCentury := -0.00004107; 1291 orbitDescr[2].axis := 0.72333566; 1292 orbitDescr[2].axisPerCentury := 0.00000390; 1293 orbitDescr[2].inclination := 3.39467605; 1294 orbitDescr[2].longitudeOfTheAscendingNode := 76.68069; 1295 orbitDescr[2].argumentOfThePerihelion := 54.85229; 1296 orbitDescr[2].size := 16.92; 1297 orbitDescr[2].brightness := 0.00001721; 1298 1299 orbitDescr[3].name :="Earth"; 1300 orbitDescr[3].orbitalPeriod := 365.256366; # 1.0000175 years 1301 orbitDescr[3].meanLongitudeAtEpoch := 100.46457166; 1302 orbitDescr[3].longitudeOfPerihelion := 102.93768193; 1303 orbitDescr[3].longitudeOfPerihelionPerCentury := 0.32327364; 1304 orbitDescr[3].eccentricity := 0.01671123; 1305 orbitDescr[3].eccentricityPerCentury := -0.00004392; 1306 orbitDescr[3].axis := 1.00000261; 1307 orbitDescr[3].axisPerCentury := 0.00000562; 1308 orbitDescr[3].inclination := 0.00001531; 1309 orbitDescr[3].longitudeOfTheAscendingNode := 348.73936; 1310 orbitDescr[3].argumentOfThePerihelion := 114.20783; 1311 orbitDescr[3].size := 17.0; 1312 orbitDescr[3].brightness := 0.0; 1313 1314 orbitDescr[4].name :="Mars"; 1315 orbitDescr[4].orbitalPeriod := 686.9600; # 1.8808 years 1316 orbitDescr[4].meanLongitudeAtEpoch := 355.44656795; 1317 orbitDescr[4].longitudeOfPerihelion := 336.05637041; 1318 orbitDescr[4].longitudeOfPerihelionPerCentury := 0.44441088; 1319 orbitDescr[4].eccentricity := 0.09339410; 1320 orbitDescr[4].eccentricityPerCentury := 0.00007882; 1321 orbitDescr[4].axis := 1.52371034; 1322 orbitDescr[4].axisPerCentury := 0.00001847; 1323 orbitDescr[4].inclination := 1.84969142; 1324 orbitDescr[4].longitudeOfTheAscendingNode := 49.57854; 1325 orbitDescr[4].argumentOfThePerihelion := 286.46230; 1326 orbitDescr[4].size := 9.36; 1327 orbitDescr[4].brightness := 0.00000454; 1328 1329 orbitDescr[5].name :="Jupiter"; 1330 orbitDescr[5].orbitalPeriod := 4333.2867; # 11.86 years 1331 orbitDescr[5].meanLongitudeAtEpoch := 34.39644051; 1332 orbitDescr[5].longitudeOfPerihelion := 14.72847983; 1333 orbitDescr[5].longitudeOfPerihelionPerCentury := 0.21252668; 1334 orbitDescr[5].eccentricity := 0.04838624; 1335 orbitDescr[5].eccentricityPerCentury := -0.00013253; 1336 orbitDescr[5].axis := 5.20288700; 1337 orbitDescr[5].axisPerCentury := -0.00011607; 1338 orbitDescr[5].inclination := 1.30439695; 1339 orbitDescr[5].longitudeOfTheAscendingNode := 100.55615; 1340 orbitDescr[5].argumentOfThePerihelion := 274.19770; 1341 orbitDescr[5].size := 196.74; 1342 orbitDescr[5].brightness := 0.0001994; 1343 1344 orbitDescr[6].name :="Saturn"; 1345 orbitDescr[6].orbitalPeriod := 10756.1995; # 29.45 years 1346 orbitDescr[6].meanLongitudeAtEpoch := 49.95424423; 1347 orbitDescr[6].longitudeOfPerihelion := 92.59887831; 1348 orbitDescr[6].longitudeOfPerihelionPerCentury := -0.41897216; 1349 orbitDescr[6].eccentricity := 0.05386179; 1350 orbitDescr[6].eccentricityPerCentury := -0.00050991; 1351 orbitDescr[6].axis := 9.53667594; 1352 orbitDescr[6].axisPerCentury := -0.00125060; 1353 orbitDescr[6].inclination := 2.48599187; 1354 orbitDescr[6].longitudeOfTheAscendingNode := 113.71504; 1355 orbitDescr[6].argumentOfThePerihelion := 338.71690; 1356 orbitDescr[6].size := 165.60; 1357 orbitDescr[6].brightness := 0.0001740; 1358 1359 orbitDescr[7].name :="Uranus"; 1360 orbitDescr[7].orbitalPeriod := 30707.4896; # 84.07 years 1361 orbitDescr[7].meanLongitudeAtEpoch := 313.23810451; 1362 orbitDescr[7].longitudeOfPerihelion := 170.95427630; 1363 orbitDescr[7].longitudeOfPerihelionPerCentury := 0.40805281; 1364 orbitDescr[7].eccentricity := 0.04725744; 1365 orbitDescr[7].eccentricityPerCentury := -0.00004397; 1366 orbitDescr[7].axis := 19.18916464; 1367 orbitDescr[7].axisPerCentury := -0.00196176; 1368 orbitDescr[7].inclination := 0.77263783; 1369 orbitDescr[7].longitudeOfTheAscendingNode := 74.22988; 1370 orbitDescr[7].argumentOfThePerihelion := 96.73436; 1371 orbitDescr[7].size := 65.80; 1372 orbitDescr[7].brightness := 0.00007768; 1373 1374 orbitDescr[8].name :="Neptune"; 1375 orbitDescr[8].orbitalPeriod := 60223.3528; # 164.88 years 1376 orbitDescr[8].meanLongitudeAtEpoch := 304.87997031; 1377 orbitDescr[8].longitudeOfPerihelion := 44.96476227; 1378 orbitDescr[8].longitudeOfPerihelionPerCentury := -0.32241464; 1379 orbitDescr[8].eccentricity := 0.00859048; 1380 orbitDescr[8].eccentricityPerCentury := 0.00005105; 1381 orbitDescr[8].axis := 30.06992276; 1382 orbitDescr[8].axisPerCentury := 0.00026291; 1383 orbitDescr[8].inclination := 1.77004347; 1384 orbitDescr[8].longitudeOfTheAscendingNode := 131.72169; 1385 orbitDescr[8].argumentOfThePerihelion := 273.24966; 1386 orbitDescr[8].size := 62.20; 1387 orbitDescr[8].brightness := 0.00007597; 1388 1389 orbitDescr[9].name :="Pluto"; 1390 orbitDescr[9].orbitalPeriod := 90613.3055; # 248.09 years 1391 orbitDescr[9].meanLongitudeAtEpoch := 238.92903833; 1392 orbitDescr[9].longitudeOfPerihelion := 224.06891629; 1393 orbitDescr[9].longitudeOfPerihelionPerCentury := -0.04062942; 1394 orbitDescr[9].eccentricity := 0.24882730; 1395 orbitDescr[9].eccentricityPerCentury := 0.00005170; 1396 orbitDescr[9].axis := 39.48211675; 1397 orbitDescr[9].axisPerCentury := -0.00031596; 1398 orbitDescr[9].inclination := 17.14001206; 1399 orbitDescr[9].longitudeOfTheAscendingNode := 110.30347; 1400 orbitDescr[9].argumentOfThePerihelion := 113.76329; 1401 orbitDescr[9].size := 8.2; 1402 orbitDescr[9].brightness := 0.000004073; 1403 end func; (* initOrbitDescr *) 1404 1405 1406const proc: main is func 1407 local 1408 var char: ch is ' '; 1409 var char: command is 'M'; 1410 var char: old_command is 'M'; 1411 begin 1412 screen(windowWidth, windowHeight); 1413 selectInput(curr_win, KEY_CLOSE, TRUE); 1414 clear(curr_win, black); 1415 KEYBOARD := GRAPH_KEYBOARD; 1416 scr := open(curr_win); 1417 IN := openEcho(KEYBOARD, scr); 1418 IN := openLine(IN); 1419 OUT := scr; 1420 aTime := truncToSecond(time(NOW)); 1421 initOrbitDescr; 1422 1423 showMenu; 1424 repeat 1425 ch := getc(KEYBOARD); 1426 if ch = KEY_RIGHT then 1427 if currTimeChange < 7 then 1428 incr(currTimeChange); 1429 end if; 1430 elsif ch = KEY_LEFT then 1431 if currTimeChange > 1 then 1432 decr(currTimeChange); 1433 end if; 1434 elsif ch = KEY_UP then 1435 case currTimeChange of 1436 when {1}: aTime -:= 1 . YEARS; 1437 when {2}: aTime -:= 1 . MONTHS; 1438 when {3}: aTime -:= 1 . DAYS; 1439 when {4}: aTime -:= 1 . HOURS; 1440 when {5}: aTime -:= 1 . MINUTES; 1441 when {6}: aTime -:= 1 . SECONDS; 1442 when {7}: if aTime.timeZone > -720 then 1443 aTime.timeZone -:= 60; 1444 end if; 1445 end case; 1446 elsif ch = KEY_DOWN then 1447 case currTimeChange of 1448 when {1}: aTime +:= 1 . YEARS; 1449 when {2}: aTime +:= 1 . MONTHS; 1450 when {3}: aTime +:= 1 . DAYS; 1451 when {4}: aTime +:= 1 . HOURS; 1452 when {5}: aTime +:= 1 . MINUTES; 1453 when {6}: aTime +:= 1 . SECONDS; 1454 when {7}: if aTime.timeZone < 840 then 1455 aTime.timeZone +:= 60; 1456 end if; 1457 end case; 1458 else 1459 old_command := command; 1460 command := ch; 1461 end if; 1462 case command of 1463 when {'M', 'm'}: showMenu; 1464 when {'I', 'i'}: plotInnerPlanets; 1465 when {'O', 'o'}: plotOuterPlanets; 1466 when {'D', 'd'}: changeDateTime; 1467 command := 'M'; 1468 when {'L', 'l'}: changeLongLat; 1469 command := 'M'; 1470 when {'S', 's'}: setup; 1471 when {'1', '2', '3', '4', '5', '6', '7', '8', '9'}: 1472 locatePlanet(ord(command) - ord('0')); 1473 when {KEY_MOUSE1}: 1474 if old_command in {'1', '2', '3', '4', '5', '6', '7', '8', '9'} then 1475 showName; 1476 end if; 1477 command := old_command; 1478 otherwise: 1479 command := old_command; 1480 end case; 1481 setPos(scr, 58, 1); 1482 write(scr, "(M)enu (I)nner (O)uter (D)ate (L)ong (Q)uit (1-9) Planet"); 1483 until ch = 'Q' or ch = 'q' or ch = KEY_CLOSE; 1484 end func; 1485