Feature/spice sunrise sunset times by micahnyc · Pull Request #4214 · OpenSpace/OpenSpace · GitHub
Skip to content

Feature/spice sunrise sunset times - #4214

Draft
micahnyc wants to merge 4 commits into
masterfrom
feature/spice-sunrise-sunset-times
Draft

micahnyc wants to merge 4 commits into
masterfrom
feature/spice-sunrise-sunset-times

Conversation

@micahnyc

Copy link
Copy Markdown
Contributor

These are the functions for getting the sunset/rise times. In separate PR I will add elements to the Night Sky panel that will let users see sunrise/set without having to script.

2026-08-18.18-46-12.mp4

@micahnyc
micahnyc marked this pull request as draft August 19, 2026 02:46
@micahnyc

Copy link
Copy Markdown
Contributor Author

@alexanderbock alexanderbock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why we'd need two sets of functions that basicallyt do the same thing. I think the globebrowsing functions could move into the spicemanager_lua and become the only functions we'll need

Comment thread include/openspace/util/spicemanager.h Outdated
Comment on lines +881 to +889
* \\param lat_deg Latitude in degrees
* \\param lon_deg Longitude in degrees
* \\param utc_date UTC date as a string (e.g., "2024-01-01")
* \\param observer The observing body (e.g., "EARTH")
* \\param isSunrise If true, computes sunrise time; if false, computes sunset time
* \\return The ephemeris time (ET seconds past J2000) of the solar event
*
* \\throw SpiceException If no sunrise/sunset found for the given date/location
* (e.g., polar day or night)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* \\param lat_deg Latitude in degrees
* \\param lon_deg Longitude in degrees
* \\param utc_date UTC date as a string (e.g., "2024-01-01")
* \\param observer The observing body (e.g., "EARTH")
* \\param isSunrise If true, computes sunrise time; if false, computes sunset time
* \\return The ephemeris time (ET seconds past J2000) of the solar event
*
* \\throw SpiceException If no sunrise/sunset found for the given date/location
* (e.g., polar day or night)
* \param latitude Latitude in degrees
* \param longitude Longitude in degrees
* \param date UTC date as a string (e.g., "2024-01-01")
* \param observer The observing body (e.g., "EARTH")
* \param isSunrise If true, computes sunrise time; if false, computes sunset time
* \return The ephemeris time (ET seconds past J2000) of the solar event
*
* \throw SpiceException If no sunrise/sunset found for the given date/location
* (e.g., polar day or night)

Comment thread include/openspace/util/spicemanager.h Outdated
Comment on lines +891 to +892
double solarEventTime(double lat_deg, double lon_deg, const std::string& utc_date,
const std::string& observer, bool isSunrise) const;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
double solarEventTime(double lat_deg, double lon_deg, const std::string& utc_date,
const std::string& observer, bool isSunrise) const;
double solarEventTime(double latitude, double longitude, const std::string& date,
const std::string& observer, bool isSunrise) const;

Comment on lines +602 to +606
std::string_view date = global::timeManager->time().ISO8601();
std::string_view dateTrim = date.substr(0, date.find('T'));
std::string dateStr(dateTrim);
std::string globe = global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
return SpiceManager::ref().solarEventTime(lon, lat, dateStr.c_str(), globe, false);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::string_view date = global::timeManager->time().ISO8601();
std::string_view dateTrim = date.substr(0, date.find('T'));
std::string dateStr(dateTrim);
std::string globe = global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
return SpiceManager::ref().solarEventTime(lon, lat, dateStr.c_str(), globe, false);
std::string date = global::timeManager->time().ISO8601();
std::string dateTrim = date.substr(0, date.find('T'));
std::string globe = global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
constexpr bool IsSunrise = true;
return SpiceManager::ref().solarEventTime(lon, lat, dateTrim, globe, IsSunrise);

Comment on lines +611 to +615
std::string_view date = global::timeManager->time().ISO8601();
std::string_view dateTrim = date.substr(0, date.find('T'));
std::string dateStr(dateTrim);
std::string globe = global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
return SpiceManager::ref().solarEventTime(lon, lat, dateStr.c_str(), globe, true);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::string_view date = global::timeManager->time().ISO8601();
std::string_view dateTrim = date.substr(0, date.find('T'));
std::string dateStr(dateTrim);
std::string globe = global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
return SpiceManager::ref().solarEventTime(lon, lat, dateStr.c_str(), globe, true);
std::string date = global::timeManager->time().ISO8601();
std::string dateTrim = date.substr(0, date.find('T'));
std::string globe = global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
constexpr bool IsSunrise = false;
return SpiceManager::ref().solarEventTime(lon, lat, dateTrim, globe, IsSunrise);

return res;
}

[[codegen::luawrap]] double sunriseTimeForSimulation() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The functions would become more useful if they'd have an optional parameter that is the date, and only if the parameter is not specified we'd use the current simulation time. Ofc the ForSimulation would be removed from the function name

Comment thread src/util/spicemanager.cpp Outdated

if (!found) {
std::string eventType = isSunrise ? "sunrise" : "sunset";
throwSpiceError("No " + eventType + " found for the given date/location");

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
throwSpiceError("No " + eventType + " found for the given date/location");
throwSpiceError(std::format(
"No {} found for the given date/location",
eventType
));

Comment thread src/util/spicemanager.cpp Outdated
}

if (!found) {
std::string eventType = isSunrise ? "sunrise" : "sunset";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::string eventType = isSunrise ? "sunrise" : "sunset";
const std::string_view eventType = isSunrise ? "sunrise" : "sunset";

Comment thread src/util/spicemanager.cpp Outdated
while (b - a > tol) {
double mid = 0.5 * (a + b);
double fm = solarElevation(mid);
if (isSunrise ? (fm < 0.0) : (fm >= 0.0)) a = mid; else b = mid;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (isSunrise ? (fm < 0.0) : (fm >= 0.0)) a = mid; else b = mid;
if (isSunrise ? (fm < 0.0) : (fm >= 0.0)) {
a = mid;
}
else {
b = mid;
}

Comment thread src/util/spicemanager_lua.inl Outdated
Comment on lines +473 to +476
/**
* Helper function to compute solar event times (sunrise/sunset).
* Both sunriseTime and sunsetTime delegate to SpiceManager::solarEventTime.
*/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will currently become the documentation for the sunriseTime function

Comment thread src/util/spicemanager_lua.inl Outdated
Comment on lines +478 to +486
[[codegen::luawrap]] double sunriseTime(double lat_deg, double lon_deg,
std::string utc_date, std::string observer) {
return SpiceManager::ref().solarEventTime(lat_deg, lon_deg, utc_date, observer, true);
}

[[codegen::luawrap]] double sunsetTime(double lat_deg, double lon_deg,
std::string utc_date, std::string observer) {
return SpiceManager::ref().solarEventTime(lat_deg, lon_deg, utc_date, observer, false);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These functions should get their own proper documentation

@alexanderbock alexanderbock left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coding style

Comment on lines +878 to +903
/**
* Computes the time of a solar event (sunrise or sunset) for a given location
* and date using bisection search on the solar elevation angle.
*
* \\param latitude The latitude in degrees (range: -90 to 90)
* \\param longitude The longitude in degrees (range: -180 to 180)
* \\param altitude The observer's altitude above the surface in meters
* (default: 0.0 for sea level)
* \\param date UTC date as a string (e.g., "2024-01-01")
* \\param observer The SPICE name of the observing body (e.g., "EARTH")
* \\param isSunrise If \\p true, computes sunrise; if \\p false, computes sunset
* \\return The ephemeris time (ET seconds past J2000) of the requested solar
* event
*
* \\throw SpiceException If no sunrise/sunset is found for the given
* date/location (e.g., polar day or night)
* \\throw SpiceException If required SPICE kernels are not loaded or if the
* observer is not a valid SPICE object
* \\pre \\p latitude must be between -90 and 90
* \\pre \\p longitude must be between -180 and 180
* \\pre \\p date must be a valid UTC date string
* \\pre \\p observer must be a valid SPICE body name
*/
double solarEventTime(double latitude, double longitude, double altitude,
const std::string& date, const std::string& observer,
bool isSunrise) const;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
/**
* Computes the time of a solar event (sunrise or sunset) for a given location
* and date using bisection search on the solar elevation angle.
*
* \\param latitude The latitude in degrees (range: -90 to 90)
* \\param longitude The longitude in degrees (range: -180 to 180)
* \\param altitude The observer's altitude above the surface in meters
* (default: 0.0 for sea level)
* \\param date UTC date as a string (e.g., "2024-01-01")
* \\param observer The SPICE name of the observing body (e.g., "EARTH")
* \\param isSunrise If \\p true, computes sunrise; if \\p false, computes sunset
* \\return The ephemeris time (ET seconds past J2000) of the requested solar
* event
*
* \\throw SpiceException If no sunrise/sunset is found for the given
* date/location (e.g., polar day or night)
* \\throw SpiceException If required SPICE kernels are not loaded or if the
* observer is not a valid SPICE object
* \\pre \\p latitude must be between -90 and 90
* \\pre \\p longitude must be between -180 and 180
* \\pre \\p date must be a valid UTC date string
* \\pre \\p observer must be a valid SPICE body name
*/
double solarEventTime(double latitude, double longitude, double altitude,
const std::string& date, const std::string& observer,
bool isSunrise) const;
/**
* Computes the time of a solar event (sunrise or sunset) for a given location and
* date using bisection search on the solar elevation angle.
*
* \param latitude The latitude in degrees (range: -90 to 90)
* \param longitude The longitude in degrees (range: -180 to 180)
* \param altitude The observer's altitude above the surface in meters (default: 0.0
for sea level)
* \param date UTC date as a string (e.g., "2024-01-01")
* \param observer The SPICE name of the observing body (e.g., "EARTH")
* \param isSunrise If \\p true, computes sunrise; if \\p false, computes sunset
* \return The ephemeris time (ET seconds past J2000) of the requested solar event
*
* \throw SpiceException If no sunrise/sunset is found for the given date/location
* (e.g., polar day or night)
* \throw SpiceException If required SPICE kernels are not loaded or if the observer
* is not a valid SPICE object
* \pre \p latitude must be between -90 and 90
* \pre \p longitude must be between -180 and 180
* \pre \p date must be a valid UTC date string
* \pre \p observer must be a valid SPICE body name
*/
double solarEventTime(double latitude, double longitude, double altitude,
const std::string& date, const std::string& observer, bool isSunrise) const;

Comment on lines +31 to +32
#include <openspace/util/timemanager.h>
#include <openspace/util/spicemanager.h>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#include <openspace/util/timemanager.h>
#include <openspace/util/spicemanager.h>
#include <openspace/util/spicemanager.h>
#include <openspace/util/timemanager.h>

Comment on lines +601 to +602
* Return the ephemeris time (ET seconds past J2000) of sunrise for the current
* camera position

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Return the ephemeris time (ET seconds past J2000) of sunrise for the current
* camera position
* Return the ephemeris time (ET seconds past J2000) of sunrise for the current camera
* position.

Comment on lines +613 to +623
[[codegen::luawrap]] double sunriseTime(bool useCameraAltitude = true,
std::string date = "") {
auto [lat, lon, alt] = geoPositionForCamera();
if (date.empty()) {
date = global::timeManager->time().ISO8601();
}
std::string dateTrim = date.substr(0, date.find('T'));
std::string globe = global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
double eventAlt = useCameraAltitude ? alt : 0.0;
constexpr bool IsSunrise = true;
return SpiceManager::ref().solarEventTime(lat, lon, eventAlt, dateTrim, globe, IsSunrise);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[[codegen::luawrap]] double sunriseTime(bool useCameraAltitude = true,
std::string date = "") {
auto [lat, lon, alt] = geoPositionForCamera();
if (date.empty()) {
date = global::timeManager->time().ISO8601();
}
std::string dateTrim = date.substr(0, date.find('T'));
std::string globe = global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
double eventAlt = useCameraAltitude ? alt : 0.0;
constexpr bool IsSunrise = true;
return SpiceManager::ref().solarEventTime(lat, lon, eventAlt, dateTrim, globe, IsSunrise);
[[codegen::luawrap]] double sunriseTime(bool useCameraAltitude = true,
std::string date = "")
{
auto [lat, lon, alt] = geoPositionForCamera();
if (date.empty()) {
date = global::timeManager->time().ISO8601();
}
std::string dateTrim = date.substr(0, date.find('T'));
std::string globe =
global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
alt = useCameraAltitude ? alt : 0.0;
constexpr bool IsSunrise = true;
return SpiceManager::ref().solarEventTime(lat, lon, alt, dateTrim, globe, IsSunrise);

Comment on lines +639 to +649
[[codegen::luawrap]] double sunsetTime(bool useCameraAltitude = true,
std::string date = "") {
auto [lat, lon, alt] = geoPositionForCamera();
if (date.empty()) {
date = global::timeManager->time().ISO8601();
}
std::string dateTrim = date.substr(0, date.find('T'));
std::string globe = global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
double eventAlt = useCameraAltitude ? alt : 0.0;
constexpr bool IsSunrise = false;
return SpiceManager::ref().solarEventTime(lat, lon, eventAlt, dateTrim, globe, IsSunrise);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
[[codegen::luawrap]] double sunsetTime(bool useCameraAltitude = true,
std::string date = "") {
auto [lat, lon, alt] = geoPositionForCamera();
if (date.empty()) {
date = global::timeManager->time().ISO8601();
}
std::string dateTrim = date.substr(0, date.find('T'));
std::string globe = global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
double eventAlt = useCameraAltitude ? alt : 0.0;
constexpr bool IsSunrise = false;
return SpiceManager::ref().solarEventTime(lat, lon, eventAlt, dateTrim, globe, IsSunrise);
[[codegen::luawrap]] double sunsetTime(bool useCameraAltitude = true,
std::string date = "")
{
auto [lat, lon, alt] = geoPositionForCamera();
if (date.empty()) {
date = global::timeManager->time().ISO8601();
}
std::string dateTrim = date.substr(0, date.find('T'));
std::string globe =
global::navigationHandler->orbitalNavigator().anchorNode()->identifier();
alt = useCameraAltitude ? alt : 0.0;
constexpr bool IsSunrise = false;
return SpiceManager::ref().solarEventTime(lat, lon, alt, dateTrim, globe, IsSunrise);

Comment thread src/util/spicemanager.cpp
Comment on lines +1670 to +1671
georec_c(lon, lat, altitudeKm,
equatorialRadius, flattening, observerPosition);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
georec_c(lon, lat, altitudeKm,
equatorialRadius, flattening, observerPosition);
georec_c(
lon,
lat,
altitudeKm,
equatorialRadius,
flattening,
observerPosition
);

Comment thread src/util/spicemanager.cpp
};

// 3. Bisection search to find the solar event time
const double tolerance = 1.0; // seconds

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const double tolerance = 1.0; // seconds
constexpr double Tolerance = 1.0; // seconds

Comment thread src/util/spicemanager.cpp
}

// Refine the bracket using bisection search
while (bracketsHigh - bracketsLow > tolerance) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
while (bracketsHigh - bracketsLow > tolerance) {
while (bracketsHigh - bracketsLow > Tolerance) {

Comment thread src/util/spicemanager.cpp
(elevationAtMidpoint >= -horizonDipAngle);
if (shouldUpdateLow) {
bracketsLow = midpoint;
} else {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
} else {
}
else {

Comment thread src/util/spicemanager.cpp
return 0.5 * (bracketsLow + bracketsHigh); // ET seconds past J2000
}


Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants