Renamed AstroTime to Time.
Renamed AstroVector to Vector.
For some reason this breaks the Java demo build.
I'm pushing the broken build anyway to see if
ebraminio can help me fix it.
I forgot that Mac OS does not have sha256sum
installed by default. This caused the worldmap
demo test to fail, trying to confirm that I got
the output PNG image I expected.
The demo worldmap.cpp now also prints out the
geographic locations where the Sun/Moon appear
to be straight up (at the zenith) for the given time.
This illustrates that Astronomy_VectorObserver can
turn a geocentric vector into a location on the
Earth that is in the same direction from the Earth's
center that a given celestial body lies.
The worldmap.cpp demo was calculating each pixel's
observer location twice. Now it does so only once.
Added verification that the output PNG file is
exactly as expected, using a sha256 checksum.
The new demo worldmap.cpp generates a PNG image of
a Mercator projection of the Earth, showing color-coded
intensity of sunlight (yellow) and moonlight (blue).
This sample program shows how to efficiently calculate
horizontal altitudes of the Sun and Moon across many
different geographic locations, for a given observation time.
Backported fixes to the Seasons functions in
C, C#, Python, and JavaScript. They were failing
to find equinoxes and/or solstices for distant
year values.
Also brought over some other minor code cleanup.
For years before 1582 or years after 3668, the Seasons functions
were unable to find many equinoxes and/or solstices.
The problem was that over time, the Earth's axis precesses
enough that the calendar dates of these events drifts outside
the fixed search ranges I had provided for them.
I expanded the search ranges so all season changes can be found
for a much wider range of years, as verified by unit tests:
C/C++: -2000..9999
C#: 1..9999
JavaScript: -2000..9999
Python: 1..9999
Kotlin: 1..9999
Note: C#, Python, and Kotlin currently do not allow
years values below +1. In fact, I discovered we were not
noticing when an invalid year was passed into the Kotlin code.
I updated that code to throw an exception when the year does
not match what was expected. It is disturbing that the
GregorianCalendar class silently ignores invalid years!
Constricted the search tolerance from 1 second to 0.01
seconds for the seasons search, to ensure more consistent
behavior.
Fixed a bug in the Kotlin search() function's
quadratic interpolation that was causing the convergence
to be slower than it should have been.
Added an InternalError class to explicitly indicate
that an exception occurs due to an internal assertion
failure inside Astronomy Engine. Any InternalError
should be considered a bug in Astronomy Engine, not
a bug in calling code.
Upon reviewing the code for searching moon phases,
I discovered that there was inconsistent behavior
in SearchMoonPhase. It was sometimes returning null,
other times throwing an exception. Because the caller
passes in `limitDays`, it makes sense to simply
return `null` in any case where the search fails.
This is to support callers that intentionally want
to find whether or not a moon phase occurs in a given
small window of time.
Updated internal callers of SearchMoonPhase to throw
an InternalError when they know they should always
find an event.
Internal function FindSeasonChange did not check to
make sure SearchSunLongitude succeeded. There is no
known case where this failure happens, but if it did,
a null AstroTime would have been stored in SeasonsInfo.
It is better to fail early with an explicit InternalError.
Other miscellaneous C# code cleanup.
In the Python code, I found a couple of `raise Error`
that needed to be changed to `raise InternalError`.
While working on the Kotlin implementation, I have
found a few documentation mistakes in the other language
implementations. These have been accumulating in the
`kotlin` branch. I migrated these changes back into
the released code for now, because I don't want to wait
until Kotlin is ready.
Defined consistent __repr__ methods for
Astronomy Engine Python classes.
Each string representation is reversible:
eval(repr(x)) -> x
The main goal is to facilitate interactive
debugging and experimentation for developers
working directly in the Python interpreter.
Fixed documentation mistakes in the following classes:
IlluminationInfo
LunarEclipseInfo
Ported the following types to the Kotlin code:
GlobalSolarEclipseInfo
EclipseEvent
LocalSolarEclipseInfo
TransitInfo
ShadowInfo
IllumInfo
AxisInfo
NodeEventKind
NodeEventInfo
Made some wording fixes in the documentation for the
other languages.
Converting between radians and degrees.
Clamping angles to a desired range of degrees.
Converting between vector, spherical, horizontal.
Refraction and inverse refraction.
Implemented most of the RotationMatrix functions.
Added unit tests for combining rotation matrices, using a
rotation matrix to rotate a vector, and pivoting a rotation
matrix around its axes.
Replaced AstroVector operator '*' with infix function 'dot',
because it removes ambiguity between vector dot products
and vector cross products.
Later I will add a 'cross' infix function too.
Corrected minor typo in documentation for Python, C, C#, JavaScript.
"trasnform" -> "transform"
Restructured the Java code so we pass in command
line arguments to select which demo we want to run.
We will also pass in date/time, latitude/longitude,
or whatever numeric data we need for future demos.
Automated test run of the Java demos from the
unit test suite.
Adopted from https://stackoverflow.com/a/63332420
So one can run the demo with `./gradlew jar && java -jar build/libs/astronomy-demo-0.0.1.jar`
instead `./gradlew run`
The main README.md now includes Kotlin as a supported
language.
Pivoted the table so languages are listed vertically
instead of horizontally, because this fits better on
a screen, especially using the GitHub mobile app.
There is a link to Kotlin demos, but there are no
demos implemented yet.
Likewise, there is a link to Kotlin documentation,
but the generated documentation is not stored in Git yet,
so there is no actual documentation generated from docstrings
in the code yet.
There was already an internal function for calculating
Greenwich Apparent Sidereal Time (GAST). By request,
I have exposed this function for outside users.
Added a minimal unit test to verify the function is
callable and returns the correct result for one case.
This function is already exhaustively tested by unit
tests that verify other functions that already called
this function when it was internal, so minimal testing
is sufficient in this case.
Added the following new functions to all 4 languages:
MassProduct: find the GM product for all Solar System bodies.
LagrangePoint: calculate L1..L5 state vectors for a pair of bodies.
LagrangePointFast: calculate L1..L5 state vectors given
state vectors and GM products of a pair of bodies.
In languages that support it, using hypot(x,y) is a little
easier to read than sqrt(x*x + y*y). Some documentation
(e.g. the man page for the C function) leads me to believe
hypot might also be better behaved than sqrt in some cases.
The JavaScript Math.hypot() is especially nice because it works
for any number of dimensions, so I can use it in 2D and 3D cases.
C only allows 2D usage, as does Python 3.7. Python 3.8 added
support for any number of dimensions, but I don't want to break
compatibility with Python 3.7 just yet. Therefore, in C and Python,
I am only using hypot for 2D cases.
C# does not appear to have any kind of hypot function,
so no changes were made to the C# code.
Thanks to https://github.com/ebraminio for this suggestion.
The phrase "Moon phase" is ambiguous, because sometimes
it means relative ecliptic longitude, other times it means
illuminated fraction. The "moonphase" demos were only
calculating the relative ecliptic longitude, which was
confusing. Now they calculate both.
Changed the documentation for the GeoMoon and GeoMoonState
functions to make it explicit that they calculate coordinates
oriented with respect to the Earth's J2000 equator (EQJ).
This is because I will soon add ecliptic (ECL) counterparts
for the GeoMoon function, to more directly search for ascending
and descending nodes of the Moon.
See this discussion:
https://github.com/cosinekitty/astronomy/issues/150
For the case of calculating a map, where each pixel
on the map represents a different location on the Earth,
it is more efficient to factor out expensive calculation
of sidereal times, assuming the entire map represents
some phenomenon at a single moment in time.
For example, to determine whether the Moon is visible
at different places on the Earth, the following
functions can be calculated across thousands of
different (lat, lon) geographic coordinates around
the world:
ObserverVector
Rotation_EQD_HOR
Before iterating over the map pixels, a program
can call GeoMoon, then convert EQJ coordinates to EQD.
Then by passing the same time value in a loop to
ObserverVector and Rotation_EQD_HOR, the program
can calculate a vector from the observer to the Moon
in EQD coordinates, then convert EQD to HOR.
The z-coordinate of the horizontal coordinates
determines whether the Moon is above or below the
observer's horizon at that point on the Earth.
This calculation pattern performed redundant
sidereal time calculations for each pixel on the map.
I changed the code for all 4 languages to cache
sidereal time so that it only needs to be calculated
once.
In the C version of Astronomy Engine, this resulted
in a speedup factor of about 2.3 in the above use case.
(See the function MapPerformanceTest in generate/ctest.c.)
Reduce the number of redundant Earth nutation calculations
by passing astro_time_t values as pointers in more functions.
Nutation values can then be cached in the time parameter
and passed to other functions that can then avoid calculating
the same nutation again.
Nutation is an expensive calculation, so reducing this overhead
can dramatically speed up certain use cases.
This was only needed in C, because this is the only language
in which times are passed by value. In Python, C#, and JavaScript,
times are objects that are already passed by reference, and
they already benefit from this nutation recyling approach.
The following functions have had their parameters changed.
This is a breaking change, but in every case, the caller
usually just needs to change `time` to `&time`.
Astronomy_Rotation_EQD_EQJ
Astronomy_Rotation_EQD_ECL
Astronomy_Rotation_EQD_HOR
Astronomy_Rotation_EQJ_EQD
Astronomy_Rotation_EQJ_HOR
Astronomy_Rotation_ECL_EQD
Astronomy_Rotation_ECL_HOR
Astronomy_Rotation_HOR_EQD
Astronomy_Rotation_HOR_EQJ
Astronomy_Rotation_HOR_ECL
Astronomy_RotationAxis
Astronomy_VectorObserver
Safari does not work when you try to do this in JavaScript:
const date = new Date('2022-01-08 17:26:59');
Instead, it requires a 'T' between the date and the time:
const date = new Date('2022-01-08T17:26:59');
Fixed this issue in the moonradar.html and positions.html demos.
We still render the date/time as normal, with the space,
but parse it by replacing the space with 'T'.
Thanks to @ebraminio for reporting this!
The code generator was creating slightly different numeric
values for the Pluto state tables and the Jupiter rotation matrix.
I decreased the output precision by one decimal digit.
This should allow the code generator to produce identical
source code on both Linux and macOS.
More work getting MacOS build process to work.
Avoid excessive number of floating point digits of
output in the demo tests, so that insignificant
floating point variations don't cause unit test failures.
I found a mistake in the raytracer's Spheroid class,
thanks to a warning about an unused member variable.
I don't believe it had any effect on the currently
generated images, but it was important to fix it before
I ever do any set operations on Spheroids.
On macOS, there is no 'realpath' command by default.
So I eliminated some more attempts to use 'realpath'
in the demo test scripts.
Renamed the GitHub Actions tests to be consistent:
Astronomy-Engine-Linux
Astronomy-Engine-Macos
The demo tests on Mac OS failed because of very tiny
floating point discrepancies that don't matter.
Changed the output of the "Moon check" so that slight
differences in vector residue no longer fail the unit tests.