mirror of
https://github.com/cosinekitty/astronomy.git
synced 2026-05-18 22:01:42 -04:00
Added Kotlin demo: positions.
I also reworked how the Java and Kotlin demos process errors in the command line arguments. Using exceptions that are caught by main() rather than directly exiting the process where the errors are detected.
This commit is contained in:
@@ -23,10 +23,17 @@ public class Main {
|
||||
" current date and time.",
|
||||
"",
|
||||
" seasons year",
|
||||
" Given an integer year number, display the solstices and equinoxes for that year.",
|
||||
" Given an integer year number, displays the solstices and equinoxes for that year.",
|
||||
" The year must be in the range 0000..9999.",
|
||||
""
|
||||
);
|
||||
|
||||
private static class DemoException extends Exception {
|
||||
public DemoException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
int rc = 1;
|
||||
if (args.length == 0) {
|
||||
@@ -51,7 +58,10 @@ public class Main {
|
||||
System.out.printf("ERROR: Unknown command '%s'.%n", verb);
|
||||
}
|
||||
} catch (DateTimeParseException e) {
|
||||
System.out.println("FATAL: Invalid date/time syntax.");
|
||||
System.out.println("ERROR: Invalid date/time format on command line.");
|
||||
rc = 1;
|
||||
} catch (DemoException e) {
|
||||
System.out.printf("ERROR: %s%n", e.getMessage());
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
@@ -67,44 +77,38 @@ public class Main {
|
||||
return Time.fromMillisecondsSince1970(millis);
|
||||
}
|
||||
|
||||
private static double parseNumber(String name, String text, double minValue, double maxValue) {
|
||||
double value = Double.NaN;
|
||||
private static double parseNumber(String name, String text, double minValue, double maxValue) throws DemoException {
|
||||
try {
|
||||
value = Double.parseDouble(text);
|
||||
if (value < minValue || value > maxValue) {
|
||||
System.out.printf("ERROR: Value is out of range for %s.%n", name);
|
||||
System.exit(1);
|
||||
double value = Double.parseDouble(text);
|
||||
if (!Double.isFinite(value) || value < minValue || value > maxValue) {
|
||||
throw new DemoException(String.format("Value is out of range for %s.", name));
|
||||
}
|
||||
return value;
|
||||
} catch (NumberFormatException e) {
|
||||
System.out.printf("ERROR: Invalid numeric format '%s' for %s.%n", text, name);
|
||||
System.exit(1);
|
||||
throw new DemoException(String.format("Invalid numeric format '%s' for %s.%n", text, name));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private static int parseYear(String text) {
|
||||
int year = -1;
|
||||
private static int parseYear(String text) throws DemoException {
|
||||
try {
|
||||
year = Integer.parseInt(text);
|
||||
int year = Integer.parseInt(text);
|
||||
if (year < 0 || year > 9999) {
|
||||
System.out.println("ERROR: Year must be in the range 0000..9999.");
|
||||
System.exit(1);
|
||||
throw new DemoException("Year must be in the range 0000..9999.");
|
||||
}
|
||||
return year;
|
||||
} catch (NumberFormatException e) {
|
||||
System.out.printf("ERROR: Invalid numeric format '%s' for year.%n", text);
|
||||
System.exit(1);
|
||||
throw new DemoException(String.format("Invalid numeric format '%s' for year.", text));
|
||||
}
|
||||
return year;
|
||||
}
|
||||
|
||||
private static Observer parseObserver(String[] args, int index) {
|
||||
private static Observer parseObserver(String[] args, int index) throws DemoException {
|
||||
double latitude = parseNumber("latitude", args[index], -90.0, +90.0);
|
||||
double longitude = parseNumber("longitude", args[index+1], -180.0, +180.0);
|
||||
return new Observer(latitude, longitude, 0.0);
|
||||
}
|
||||
|
||||
private static interface DemoRunner {
|
||||
public int run(String[] args);
|
||||
public int run(String[] args) throws DemoException;
|
||||
}
|
||||
|
||||
private static class Demo {
|
||||
@@ -122,8 +126,21 @@ public class Main {
|
||||
}
|
||||
|
||||
private static Demo[] demoList = new Demo[] {
|
||||
new Demo("moonphase", 1, 2, args -> MoonPhase.run(parseTime(args, 1))),
|
||||
new Demo("positions", 3, 4, args -> Positions.run(parseObserver(args, 1), parseTime(args, 3))),
|
||||
new Demo("seasons", 2, 2, args -> Seasons.run(parseYear(args[1])))
|
||||
new Demo("moonphase", 1, 2, args ->
|
||||
MoonPhase.run(
|
||||
parseTime(args, 1)
|
||||
)
|
||||
),
|
||||
new Demo("positions", 3, 4, args ->
|
||||
Positions.run(
|
||||
parseObserver(args, 1),
|
||||
parseTime(args, 3)
|
||||
)
|
||||
),
|
||||
new Demo("seasons", 2, 2, args ->
|
||||
Seasons.run(
|
||||
parseYear(args[1])
|
||||
)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
13
demo/kotlin/correct/positions.txt
Normal file
13
demo/kotlin/correct/positions.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
UTC date = 2018-11-30T17:55:07.234Z
|
||||
|
||||
BODY RA DEC AZ ALT
|
||||
Sun 16.43 -21.68 180.91 22.72
|
||||
Moon 11.30 7.81 266.73 14.07
|
||||
Mercury 15.92 -18.41 189.05 25.50
|
||||
Venus 13.81 -9.79 224.05 23.85
|
||||
Mars 22.74 -9.25 93.82 -8.52
|
||||
Jupiter 16.19 -20.43 184.62 23.84
|
||||
Saturn 18.54 -22.70 150.51 16.25
|
||||
Uranus 1.80 10.57 43.72 -22.60
|
||||
Neptune 23.01 -7.41 89.63 -10.05
|
||||
Pluto 19.40 -22.09 139.25 11.68
|
||||
@@ -18,7 +18,7 @@ mkdir -p test
|
||||
./gradlew jar || Fail "Error building Kotlin demo application."
|
||||
|
||||
TestDemo moonphase 2019-06-15T09:15:32.987Z
|
||||
#TestDemo positions +45.6 -90.7 2018-11-30T17:55:07.234Z
|
||||
TestDemo positions +45.6 -90.7 2018-11-30T17:55:07.234Z
|
||||
TestDemo seasons 2019
|
||||
|
||||
echo "Kotlin demos: PASS"
|
||||
|
||||
@@ -13,6 +13,7 @@ call gradlew.bat jar || exit /b 1
|
||||
REM ----------------------------------------------------------------------------------
|
||||
|
||||
call :TestDemo moonphase 2019-06-15T09:15:32.987Z || exit /b 1
|
||||
call :TestDemo positions +45.6 -90.7 2018-11-30T17:55:07.234Z || exit /b 1
|
||||
call :TestDemo seasons 2019 || exit /b 1
|
||||
|
||||
echo.
|
||||
|
||||
@@ -11,8 +11,16 @@ Command line arguments:
|
||||
time if none is given on the command line.
|
||||
Also finds the dates and times of the subsequent 10 quarter phases.
|
||||
|
||||
positions latitude longitude [yyyy-mm-ddThh:mm:ssZ]
|
||||
Displays the equatorial and horizontal coordinates of
|
||||
the Sun, Moon, and planets, as seen from a given
|
||||
geographic location. Uses the date and time specified on
|
||||
the command line, if present. Otherwise, uses the computer's
|
||||
current date and time.
|
||||
|
||||
seasons year
|
||||
Given an integer year number, display the solstices and equinoxes for that year.
|
||||
Given an integer year number, displays the solstices and equinoxes for that year.
|
||||
The year must be in the range 0000..9999.
|
||||
|
||||
"""
|
||||
|
||||
@@ -32,6 +40,8 @@ fun main(args: Array<String>) {
|
||||
System.exit(runDemo(args))
|
||||
}
|
||||
|
||||
class DemoException(message:String): Exception(message)
|
||||
|
||||
internal fun runDemo(args: Array<String>): Int {
|
||||
if (args.size > 0) {
|
||||
val verb = args[0];
|
||||
@@ -43,9 +53,12 @@ internal fun runDemo(args: Array<String>): Int {
|
||||
}
|
||||
try {
|
||||
return demo.func(args)
|
||||
} catch (e: DateTimeParseException) {
|
||||
} catch (_: DateTimeParseException) {
|
||||
println("ERROR: Invalid date/time format on command line.")
|
||||
return 1
|
||||
} catch (e: DemoException) {
|
||||
println("ERROR: ${e.message}")
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +76,51 @@ internal fun parseTime(args: Array<String>, index: Int): Time {
|
||||
return Time.fromMillisecondsSince1970(millis)
|
||||
}
|
||||
|
||||
internal fun parseNumber(name: String, text: String, minValue: Double, maxValue: Double): Double {
|
||||
try {
|
||||
val value = text.toDouble()
|
||||
if (!value.isFinite() || value < minValue || value > maxValue) {
|
||||
throw DemoException("Value for $name is out of range.")
|
||||
}
|
||||
return value
|
||||
} catch (_: NumberFormatException) {
|
||||
throw DemoException("Invalid numeric format '$text' for $name.")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun parseYear(text: String): Int {
|
||||
try {
|
||||
val year = text.toInt()
|
||||
if (year < 0 || year > 9999) {
|
||||
throw DemoException("Year must be in the range 0000..9999.")
|
||||
}
|
||||
return year
|
||||
} catch (_: NumberFormatException) {
|
||||
throw DemoException("Invalid numeric format '$text' for year.")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun parseObserver(args: Array<String>, index: Int): Observer {
|
||||
val latitude = parseNumber("latitude", args[index], -90.0, +90.0)
|
||||
val longitude = parseNumber("longitude", args[index+1], -180.0, +180.0)
|
||||
return Observer(latitude, longitude, 0.0)
|
||||
}
|
||||
|
||||
internal val demoList = arrayOf(
|
||||
Demo("moonphase", 1, 2) { args -> `Moon Phase demo`(parseTime(args, 1)) },
|
||||
Demo("seasons", 2, 2) { args -> `Seasons demo`(args[1].toInt()) }
|
||||
Demo("moonphase", 1, 2) { args ->
|
||||
`Moon Phase demo`(
|
||||
parseTime(args, 1)
|
||||
)
|
||||
},
|
||||
Demo("positions", 3, 4) { args ->
|
||||
`Celestial body positions demo`(
|
||||
parseObserver(args, 1),
|
||||
parseTime(args, 3)
|
||||
)
|
||||
},
|
||||
Demo("seasons", 2, 2) { args ->
|
||||
`Seasons demo`(
|
||||
parseYear(args[1])
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
28
demo/kotlin/src/main/kotlin/Positions.kt
Normal file
28
demo/kotlin/src/main/kotlin/Positions.kt
Normal file
@@ -0,0 +1,28 @@
|
||||
import io.github.cosinekitty.astronomy.*
|
||||
|
||||
private val bodyList = arrayOf(
|
||||
Body.Sun, Body.Moon, Body.Mercury, Body.Venus, Body.Mars,
|
||||
Body.Jupiter, Body.Saturn, Body.Uranus, Body.Neptune, Body.Pluto
|
||||
)
|
||||
|
||||
/**
|
||||
* Print a table of solar system body positions in equatorial and horizontal coordinates.
|
||||
*
|
||||
* @param observer
|
||||
* The geographic location for which to calculate apparent celestial body positions.
|
||||
*
|
||||
* @param time
|
||||
* The date and time for which to calculate positions.
|
||||
*/
|
||||
internal fun `Celestial body positions demo`(observer: Observer, time: Time): Int {
|
||||
println("UTC date = $time")
|
||||
println()
|
||||
println("BODY RA DEC AZ ALT")
|
||||
for (body in bodyList) {
|
||||
val equ_2000: Equatorial = equator(body, time, observer, EquatorEpoch.J2000, Aberration.Corrected)
|
||||
val equ_ofdate: Equatorial = equator(body, time, observer, EquatorEpoch.OfDate, Aberration.Corrected)
|
||||
val hor: Topocentric = horizon(time, observer, equ_ofdate.ra, equ_ofdate.dec, Refraction.Normal)
|
||||
println("%-8s %8.2f %8.2f %8.2f %8.2f".format(body, equ_2000.ra, equ_2000.dec, hor.azimuth, hor.altitude))
|
||||
}
|
||||
return 0
|
||||
}
|
||||
Reference in New Issue
Block a user