mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-03-13 17:09:05 -05:00
Cleanup of SpiceManager by introducing exceptions
Catch exceptions in RenderableShadowCylinder and LabelParser Catch exceptions in RenderableFov and Hongkangparser
This commit is contained in:
Submodule ext/ghoul updated: b2278ce9d3...970f159ed9
@@ -29,10 +29,12 @@
|
||||
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/designpattern/singleton.h>
|
||||
#include <ghoul/misc/exception.h>
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -50,113 +52,149 @@ public:
|
||||
using TransformMatrix = std::array<double, 36>;
|
||||
using KernelHandle = unsigned int;
|
||||
|
||||
static const KernelHandle InvalidKernel = KernelHandle(-1);
|
||||
|
||||
class SpiceKernelException : public ghoul::RuntimeError {
|
||||
public:
|
||||
explicit SpiceKernelException(const std::string& msg);
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads one or more SPICE kernels into a program. The provided path can either be a
|
||||
* binary, text-kernel, or meta-kernel which gets loaded into the kernel pool. The
|
||||
* loading is done by passing the \p filePath to the <code>furnsh_c</code>
|
||||
* function. http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/furnsh_c.html
|
||||
* Kernels can safely be loaded multiple times and are reference counted
|
||||
* function. Kernels can safely be loaded multiple times and are reference counted.
|
||||
* \param filePath The path to the kernel that should be loaded. This path will be
|
||||
* passed to <code>absPath</code> to convert a relative path to an absolute path
|
||||
* before usage
|
||||
* \return The loaded kernel's unique identifier that can be used to unload the kernel
|
||||
* \throws SpiceKernelException If the loading of the kernel \p filePath failed
|
||||
* \pre \p filePath is a non-empty absolute or relative path pointing to an
|
||||
* existing file that contains a SPICE kernel
|
||||
* \post The kernel is loaded or has its reference counter incremented and the handle
|
||||
* to the kernel is returned if the SPICE kernel is valid, or \a KernelInvalid if the
|
||||
* kernel is invalid
|
||||
* \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/furnsh_c.html
|
||||
*/
|
||||
KernelHandle loadKernel(std::string filePath);
|
||||
|
||||
/**
|
||||
* \return true if SPK kernels have been loaded to cover <code>target</code>
|
||||
* for time <code>et</code>
|
||||
* \param target, the body to be examined
|
||||
* \param et, the time when body is possibly covered
|
||||
*/
|
||||
|
||||
bool hasSpkCoverage(std::string target, double& et) const;
|
||||
|
||||
/**
|
||||
* \return true if CK kernels have been loaded to cover <code>frame</code>
|
||||
* for time <code>et</code>
|
||||
* \param frame, the frame to be examined
|
||||
* \param et, the time when frame is possibly covered
|
||||
*/
|
||||
bool hasCkCoverage(std::string frame, double& et) const;
|
||||
|
||||
/**
|
||||
* Unloads a SPICE kernel identified by the <code>kernelId</code> which was returned
|
||||
* by the loading call to loadKernel. The unloading is done by calling the
|
||||
* Unloads a SPICE kernel identified by the \p kernelId which was returned by the
|
||||
* loading call to #loadKernel. The unloading is done by calling the
|
||||
* <code>unload_c</code> function.
|
||||
* http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/unload_c.html.
|
||||
* \param kernelId The unique identifier that was returned from the call to
|
||||
* loadKernel which loaded the kernel
|
||||
* #loadKernel which loaded the kernel
|
||||
* \pre \p kernelId must be a valid handle and cannot be equal to
|
||||
* <code>KernelHandle(0)</code>
|
||||
* \post The kernel identified by \p kernelId is unloaded
|
||||
* \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/unload_c.html
|
||||
*/
|
||||
void unloadKernel(KernelHandle kernelId);
|
||||
|
||||
/**
|
||||
* Unloads a SPICE kernel identified by the <code>filePath</code> which was used in
|
||||
* the loading call to loadKernel. The unloading is done by calling the
|
||||
* <code>unload_c</code> function.
|
||||
* http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/unload_c.html.
|
||||
* \param filePath The path of the kernel that should be unloaded, it has to refer to
|
||||
* a file that was loaded in using the loadKernel method
|
||||
*/
|
||||
void unloadKernel(const std::string& filePath);
|
||||
|
||||
/**
|
||||
* Determines whether values exist for some <code>item</code> for any body,
|
||||
* identified by it's <code>naifId</code>, in the kernel pool by passing it to the
|
||||
* <code>bodfnd_c</code> function.
|
||||
* http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/bodfnd_c.html
|
||||
* For a description on NAIF IDs, see
|
||||
* http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/naif_ids.html.
|
||||
* Unloads a SPICE kernel identified by the \p filePath which was used in the
|
||||
* loading call to #loadKernel. The unloading is done by calling the
|
||||
* <code>unload_c</code> function.
|
||||
* \param filePath The path of the kernel that should be unloaded. The filePath must
|
||||
* have been previously used to successfully load a kernel, or a SpiceKernelException
|
||||
* is thrown
|
||||
* \pre \p filePath cannot be empty
|
||||
* \post The kernel identified by \p filePath is unloaded or nothing happens if
|
||||
* \p filePath was not used to load a kernel
|
||||
* \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/unload_c.html
|
||||
*/
|
||||
void unloadKernel(std::string filePath);
|
||||
|
||||
/**
|
||||
* Returns whether a given \p target has an Spk kernel covering it at the designated
|
||||
* \p et ephemeris time.
|
||||
* \param target The body to be examined. The target has to name a valid SPICE object
|
||||
* with respect to the kernels that have been loaded
|
||||
* \param et The time for which the coverage should be checked
|
||||
* \return <code>true</code> if SPK kernels have been loaded to cover \p target at the
|
||||
* time \p et, <code>false</code> otherwise.
|
||||
* \pre \p target must be a non-empty string that names a valid SPICE object
|
||||
* \throws SpiceKernelException If \p target is not a valid NAIF target
|
||||
*/
|
||||
bool hasSpkCoverage(const std::string& target, double et) const;
|
||||
|
||||
/**
|
||||
* Returns whether a given \p frame has a CK kernel covering it at the designated
|
||||
* \p et ephemeris time.
|
||||
* \param frame The frame to be examined. The \p frame has to name a valid frame with
|
||||
* respect to the kernels that have been loaded
|
||||
* \param et The time for which the coverage should be checked
|
||||
* \return <code>true</code> if SPK kernels have been loaded to cover \p target at the
|
||||
* time \p et , <code>false</code> otherwise.
|
||||
* \pre \p target must be a non-empty string that names a valid SPICE object
|
||||
* \throws SpiceKernelException If \p frame is not a valid frame
|
||||
*/
|
||||
bool hasCkCoverage(const std::string& frame, double et) const;
|
||||
|
||||
/**
|
||||
* Determines whether values exist for some \p item for any body, identified by its
|
||||
* \p naifId, in the kernel pool by passing it to the <code>bodfnd_c</code> function.
|
||||
* \param naifId NAIF ID code of body
|
||||
* \param item The item to find
|
||||
* \return <code>true</code> if the function succeeded, <code>false</code> otherwise
|
||||
* \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/bodfnd_c.html
|
||||
* \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/naif_ids.html
|
||||
*/
|
||||
bool hasValue(int naifId, const std::string& item) const;
|
||||
|
||||
/**
|
||||
* Determines whether values exist for some <code>item</code> for any
|
||||
* <code>body</code> in the kernel pool by passing it to the <code>bodfnd_c</code>
|
||||
* function.
|
||||
* http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/bodfnd_c.html
|
||||
* Determines whether values exist for some \p item for any \p body in the kernel pool
|
||||
* by passing it to the <code>bodfnd_c</code> function.
|
||||
* \param body The name of the body that should be sampled
|
||||
* \param item The item to find
|
||||
* \param item The item to find in the \p body
|
||||
* \return <code>true</code> if the function succeeded, <code>false</code> otherwise
|
||||
* \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/bodfnd_c.html
|
||||
* \throws SpiceKernelException If \p body is not a valid type
|
||||
* \pre \p body and \item must be non-empty and \p body must name a valid Spice object
|
||||
*/
|
||||
bool hasValue(const std::string& body, const std::string& item) const;
|
||||
|
||||
/**
|
||||
* Returns the NAIF ID for a specific body. For a description on NAIF IDs, see
|
||||
* http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/naif_ids.html. The
|
||||
* <code>id</code> will only be set if the retrieval was successful, otherwise it will
|
||||
* remain unchanged.
|
||||
* Returns the NAIF ID for a specific \p body using the <code>bods2c_c</code>
|
||||
* function.
|
||||
* \param body The body name that should be retrieved
|
||||
* \param id The ID of the <code>body</code> will be stored in this variable. The
|
||||
* \return The ID of the <code>body</code> will be stored in this variable. The
|
||||
* value will only be changed if the retrieval was successful
|
||||
* \return <code>true</code> if the <code>body</code> was found, <code>false</code>
|
||||
* otherwise
|
||||
* \throws SpiceKernelException If \p body is not a valid type
|
||||
* \pre \p body must be not-empty
|
||||
* \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/bods2c_c.html
|
||||
* \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/naif_ids.html
|
||||
*/
|
||||
bool getNaifId(const std::string& body, int& id) const;
|
||||
int naifId(const std::string& body) const;
|
||||
|
||||
/**
|
||||
* Returns the NAIF ID for a specific frame using namfrm_c(), see
|
||||
* http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/namfrm_c.html.
|
||||
* The <code>id</code> will only be set if the retrieval was successful,
|
||||
* otherwise it will remain unchanged.
|
||||
* \param frame The frame name that should be retrieved
|
||||
* \param id The ID of the <code>frame</code> will be stored in this variable. The
|
||||
* value will only be changed if the retrieval was successful
|
||||
* \return <code>true</code> if the <code>frame</code> was found, <code>false</code>
|
||||
* Checks whether the specified \p body has a valid NAIF ID using the currently loaded
|
||||
* Spice kernels.
|
||||
* \param body The body for which the presence of a valid ID should be checked
|
||||
* \return <code>true</code> if the \p body has a NAIF ID, <code>false</code>
|
||||
* otherwise
|
||||
* \pre \p body must be non-empty
|
||||
*/
|
||||
bool getFrameId(const std::string& frame, int& id) const;
|
||||
bool hasNaifId(const std::string& body) const;
|
||||
|
||||
/**
|
||||
* Returns the NAIF ID for a specific frame using <code>namfrm_c</code>.
|
||||
* \param frame The frame name that should be retrieved
|
||||
* \return The NAIF ID of the \p frame
|
||||
* \throws SpiceKernelException If \p frame is not a valid frame
|
||||
* \pre \p frame must be not-empty
|
||||
* \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/namfrm_c.html
|
||||
*/
|
||||
int frameId(const std::string& frame) const;
|
||||
|
||||
/**
|
||||
* Checks whether the specified \p frame has a valid NAIF ID using the currently
|
||||
* loaded Spice kernels.
|
||||
* \param frame The frame for which the presence of a valid ID should be checked
|
||||
* \return <code>true</code> if the \p frame has a NAIF ID, <code>false</code>
|
||||
* otherwise
|
||||
* \pre \p frame must be non-empty
|
||||
*/
|
||||
bool hasFrameId(const std::string& frame) const;
|
||||
|
||||
/**
|
||||
* Retrieves a single <code>value</code> for a certain <code>body</code>. This method
|
||||
* succeeds iff <code>body</code> is the name of a valid body, <code>value</code>
|
||||
@@ -175,7 +213,7 @@ public:
|
||||
* <code>value</code> is a valid item for the <code>body</code> and the retrieved
|
||||
* value is only a single value. <code>false</code> otherwise
|
||||
*/
|
||||
bool getValue(const std::string& body, const std::string& value, double& v) const;
|
||||
void getValue(const std::string& body, const std::string& value, double& v) const;
|
||||
|
||||
/**
|
||||
* Retrieves a <code>value</code> with three components for a certain
|
||||
@@ -195,7 +233,7 @@ public:
|
||||
* <code>value</code> is a valid item for the <code>body</code> and the retrieved
|
||||
* value is only a single value. <code>false</code> otherwise
|
||||
*/
|
||||
bool getValue(const std::string& body, const std::string& value, glm::dvec3& v) const;
|
||||
void getValue(const std::string& body, const std::string& value, glm::dvec3& v) const;
|
||||
|
||||
/**
|
||||
* Retrieves a <code>value</code> with four components for a certain
|
||||
@@ -215,7 +253,7 @@ public:
|
||||
* <code>value</code> is a valid item for the <code>body</code> and the retrieved
|
||||
* value is only a single value. <code>false</code> otherwise
|
||||
*/
|
||||
bool getValue(const std::string& body, const std::string& value, glm::dvec4& v) const;
|
||||
void getValue(const std::string& body, const std::string& value, glm::dvec4& v) const;
|
||||
|
||||
/**
|
||||
* Retrieves a <code>value</code> with an arbitrary number of components for a certain
|
||||
@@ -238,11 +276,23 @@ public:
|
||||
* <code>value</code> is a valid item for the <code>body</code> and the retrieved
|
||||
* value is only a single value. <code>false</code> otherwise
|
||||
*/
|
||||
bool getValue(const std::string& body, const std::string& value,
|
||||
void getValue(const std::string& body, const std::string& value,
|
||||
std::vector<double>& v) const;
|
||||
|
||||
|
||||
bool spacecraftClockToET(const std::string& craftIdCode, double& craftTicks, double& et);
|
||||
/**
|
||||
* Converts the value \p craftTicks of the internal clock for the spacecraft
|
||||
* identified by \p craft into standard ephemeris time and returns the value.
|
||||
* \param craft The NAIF ID of the craft for which the time should be converted
|
||||
* \param craftTicks The internal clock ticks for the specified craft
|
||||
* \return The converted ephemeris time
|
||||
* \throws SpiceKernelException If the name \p craft is not a valid name
|
||||
* available through all loaded kernels, if the craft is not supported by any of the
|
||||
* loaded kernel, or if the provided \p craftTicks is not a valid tick time for the
|
||||
* specific spacecraft
|
||||
* \pre \craftIdCode may not be empty and need to name a valid craft
|
||||
*/
|
||||
double spacecraftClockToET(const std::string& craft, double craftTicks);
|
||||
|
||||
/**
|
||||
* Converts the <code>timeString</code> representing a date to a double precision
|
||||
@@ -656,16 +706,6 @@ public:
|
||||
*/
|
||||
std::string frameFromBody(const std::string body) const;
|
||||
|
||||
/**
|
||||
* This method checks if one of the previous SPICE methods has failed. If it has, the
|
||||
* <code>errorMessage</code> is used to log an error along with the original SPICE
|
||||
* error message.
|
||||
* \param errorMessage The error message that will be logged if the method fails. If
|
||||
* the argument is empty, no error message will be logged
|
||||
* \return <code>true</code> if an error occurred, <code>false</code> otherwise
|
||||
*/
|
||||
static bool checkForError(std::string errorMessage);
|
||||
|
||||
/**
|
||||
* This method uses the SPICE kernels to get the radii of bodies defined as a
|
||||
* triaxial ellipsoid. The benefit of this is to be able to create more accurate
|
||||
@@ -699,8 +739,10 @@ protected:
|
||||
* http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/ckcov_c.html
|
||||
* \param filePath The path to the kernel that should be examined
|
||||
* \return true if the operation was successful
|
||||
* \pre \p path must be nonempty and be an existing file
|
||||
* \post Coverage times are stored only if loading was successful
|
||||
*/
|
||||
bool findCkCoverage(const std::string& path);
|
||||
void findCkCoverage(const std::string& path);
|
||||
|
||||
/**
|
||||
* Function to find and store the intervals covered by a spk file, this is done
|
||||
@@ -709,10 +751,11 @@ protected:
|
||||
* http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkcov_c.html
|
||||
* \param filePath The path to the kernel that should be examined
|
||||
* \return true if the operation was successful
|
||||
* \pre \p path must be nonempty and be an existing file
|
||||
* \post Coverage times are stored only if loading was successful
|
||||
*/
|
||||
bool findSpkCoverage(const std::string& path);
|
||||
void findSpkCoverage(const std::string& path);
|
||||
|
||||
|
||||
/// A list of all loaded kernels
|
||||
std::vector<KernelInformation> _loadedKernels;
|
||||
// Map: id, vector of pairs. Pair: Start time, end time;
|
||||
|
||||
@@ -62,8 +62,14 @@ SpiceEphemeris::SpiceEphemeris(const ghoul::Dictionary& dictionary)
|
||||
if (!success)
|
||||
LERROR("'" << KeyKernels << "' has to be an array-style table");
|
||||
|
||||
SpiceManager::KernelHandle id = SpiceManager::ref().loadKernel(kernel);
|
||||
_kernelsLoadedSuccessfully &= (id != SpiceManager::InvalidKernel);
|
||||
try {
|
||||
SpiceManager::KernelHandle id = SpiceManager::ref().loadKernel(kernel);
|
||||
_kernelsLoadedSuccessfully = true;
|
||||
}
|
||||
catch (const SpiceManager::SpiceKernelException& e) {
|
||||
LERROR("Could not load SPICE kernel: " << e.what());
|
||||
_kernelsLoadedSuccessfully = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,21 +101,24 @@ RenderableFov::RenderableFov(const ghoul::Dictionary& dictionary)
|
||||
void RenderableFov::allocateData() {
|
||||
std::string shape, instrument;
|
||||
// fetch data for specific instrument (shape, boresight, bounds etc)
|
||||
bool found = openspace::SpiceManager::ref().getFieldOfView(_instrumentID, shape, instrument, _boresight, _bounds);
|
||||
if (!found) {
|
||||
LERROR("Could not locate instrument");
|
||||
return;
|
||||
}
|
||||
_stride = 8;
|
||||
try {
|
||||
SpiceManager::ref().getFieldOfView(_instrumentID, shape, instrument, _boresight, _bounds);
|
||||
|
||||
_projectionBounds.resize(_bounds.size());
|
||||
int initBoundPoints = 2 * (_bounds.size() + 1);
|
||||
_fovBounds.resize(initBoundPoints*_stride);
|
||||
_vBoundsSize = static_cast<unsigned int>(_fovBounds.size());
|
||||
// allocate second vbo data
|
||||
_fovPlane.resize(40);
|
||||
_vPlaneSize = 40;
|
||||
_isteps = 10; // Interpolation steps per intersecting segment
|
||||
_stride = 8;
|
||||
|
||||
_projectionBounds.resize(_bounds.size());
|
||||
int initBoundPoints = 2 * (_bounds.size() + 1);
|
||||
_fovBounds.resize(initBoundPoints*_stride);
|
||||
_vBoundsSize = static_cast<unsigned int>(_fovBounds.size());
|
||||
// allocate second vbo data
|
||||
_fovPlane.resize(40);
|
||||
_vPlaneSize = 40;
|
||||
_isteps = 10; // Interpolation steps per intersecting segment
|
||||
|
||||
}
|
||||
catch (const SpiceManager::SpiceKernelException& e) {
|
||||
LERROR(e.what());
|
||||
}
|
||||
}
|
||||
|
||||
RenderableFov::~RenderableFov() {
|
||||
|
||||
@@ -88,7 +88,6 @@ bool RenderableShadowCylinder::isReady() const {
|
||||
bool RenderableShadowCylinder::initialize() {
|
||||
glGenVertexArrays(1, &_vao); // generate array
|
||||
glGenBuffers(1, &_vbo); // generate buffer
|
||||
createCylinder();
|
||||
|
||||
bool completeSuccess = true;
|
||||
_shader = ghoul::opengl::ProgramObject::Build("ShadowProgram",
|
||||
|
||||
@@ -118,7 +118,8 @@ void HongKangParser::writeUTCEventFile(const Image image){
|
||||
bool HongKangParser::create(){
|
||||
//check input for errors.
|
||||
int tmp;
|
||||
bool hasObserver = SpiceManager::ref().getNaifId(_spacecraft, tmp);
|
||||
bool hasObserver = SpiceManager::ref().hasNaifId(_spacecraft);
|
||||
tmp = SpiceManager::ref().naifId(_spacecraft);
|
||||
if (!hasObserver){
|
||||
LERROR("SPICE navigation system has no pooled observer: '" << _spacecraft << "' in kernel" <<
|
||||
"Please check that all necessary kernels are loaded"<<
|
||||
|
||||
@@ -211,7 +211,14 @@ bool LabelParser::create() {
|
||||
read = line.substr(0, line.find_first_of(" "));
|
||||
if (read == "STOP_TIME"){
|
||||
std::string stop = line.substr(line.find("=") + 2);
|
||||
stop.erase(std::remove(stop.begin(), stop.end(), ' '), stop.end());
|
||||
stop.erase(
|
||||
std::remove_if(
|
||||
stop.begin(),
|
||||
stop.end(),
|
||||
[](char c) { return c == ' ' || c == '\r'; }
|
||||
),
|
||||
stop.end()
|
||||
);
|
||||
openspace::SpiceManager::ref().getETfromDate(stop, _stopTime);
|
||||
count++;
|
||||
}
|
||||
|
||||
@@ -487,10 +487,6 @@ bool OpenSpaceEngine::loadSpiceKernels() {
|
||||
}
|
||||
SpiceManager::KernelHandle id =
|
||||
SpiceManager::ref().loadKernel(timeKernel);
|
||||
if (id == SpiceManager::InvalidKernel) {
|
||||
LERROR("Error loading time kernel '" << timeKernel << "'");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load SPICE leap second kernel
|
||||
std::string leapSecondKernel;
|
||||
@@ -501,10 +497,6 @@ bool OpenSpaceEngine::loadSpiceKernels() {
|
||||
return false;
|
||||
}
|
||||
id = SpiceManager::ref().loadKernel(std::move(leapSecondKernel));
|
||||
if (id == SpiceManager::InvalidKernel) {
|
||||
LERROR("Error loading leap second kernel '" << leapSecondKernel << "'");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,16 +27,13 @@
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <ghoul/misc/exception.h>
|
||||
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <format.h>
|
||||
|
||||
#define MAXOBJ 64
|
||||
#define WINSIZ 10000
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "SpiceManager";
|
||||
|
||||
@@ -44,9 +41,30 @@ namespace {
|
||||
// http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/getmsg_c.html
|
||||
// as the maximum message length
|
||||
const unsigned SpiceErrorBufferSize = 1841;
|
||||
|
||||
// This method checks if one of the previous SPICE methods has failed. If it has, an
|
||||
// exception with the SPICE error message is thrown
|
||||
void throwOnSpiceError(std::string errorMessage) {
|
||||
SpiceBoolean failed = failed_c();
|
||||
if (failed) {
|
||||
char buffer[SpiceErrorBufferSize];
|
||||
getmsg_c("LONG", SpiceErrorBufferSize, buffer);
|
||||
reset_c();
|
||||
throw openspace::SpiceManager::SpiceKernelException(
|
||||
errorMessage + ": " + buffer
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using fmt::format;
|
||||
using std::string;
|
||||
|
||||
namespace openspace {
|
||||
|
||||
SpiceManager::SpiceKernelException::SpiceKernelException(const string& msg)
|
||||
: ghoul::RuntimeError(msg, "Spice")
|
||||
{}
|
||||
|
||||
SpiceManager::SpiceManager() {
|
||||
// Set the SPICE library to not exit the program if an error occurs
|
||||
@@ -65,15 +83,11 @@ SpiceManager::~SpiceManager() {
|
||||
}
|
||||
|
||||
|
||||
SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) {
|
||||
// Preconditions:
|
||||
// !filePath.empty()
|
||||
// filePath exists
|
||||
// Directory(filePath) exists
|
||||
SpiceManager::KernelHandle SpiceManager::loadKernel(string filePath) {
|
||||
ghoul_assert(!filePath.empty(), "Empty file path");
|
||||
ghoul_assert(
|
||||
FileSys.fileExists(filePath),
|
||||
fmt::format(
|
||||
format(
|
||||
"File '{}' ('{}') does not exist",
|
||||
filePath,
|
||||
absPath(filePath)
|
||||
@@ -81,14 +95,14 @@ SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) {
|
||||
);
|
||||
ghoul_assert(
|
||||
FileSys.directoryExists(ghoul::filesystem::File(filePath).directoryName()),
|
||||
fmt::format(
|
||||
format(
|
||||
"File '{}' exists, but directory '{}' doesn't",
|
||||
absPath(filePath),
|
||||
ghoul::filesystem::File(filePath).directoryName()
|
||||
)
|
||||
);
|
||||
|
||||
std::string path = absPath(filePath);
|
||||
string path = absPath(filePath);
|
||||
auto it = std::find_if(
|
||||
_loadedKernels.begin(),
|
||||
_loadedKernels.end(),
|
||||
@@ -97,7 +111,7 @@ SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) {
|
||||
if (it != _loadedKernels.end()) {
|
||||
it->refCount++;
|
||||
LDEBUG(
|
||||
fmt::format(
|
||||
format(
|
||||
"Kernel '{}' was already loaded. New reference count: {}",
|
||||
path,
|
||||
it->refCount
|
||||
@@ -110,7 +124,7 @@ SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) {
|
||||
// to the directory they reside in. The directory change is not necessary for regular
|
||||
// kernels
|
||||
ghoul::filesystem::Directory currentDirectory = FileSys.currentDirectory();
|
||||
std::string fileDirectory = ghoul::filesystem::File(path, true).directoryName();
|
||||
string fileDirectory = ghoul::filesystem::File(path, true).directoryName();
|
||||
FileSys.setCurrentDirectory(fileDirectory);
|
||||
|
||||
LINFO("Loading SPICE kernel '" << path << "'");
|
||||
@@ -120,291 +134,196 @@ SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) {
|
||||
// Reset the current directory to the previous one
|
||||
FileSys.setCurrentDirectory(currentDirectory);
|
||||
|
||||
SpiceBoolean failed = failed_c();
|
||||
if (failed) {
|
||||
char* buffer = new char[SpiceErrorBufferSize];
|
||||
getmsg_c("LONG", SpiceErrorBufferSize, buffer);
|
||||
LERROR(fmt::format("Error loading kernel '{}'", path));
|
||||
LERROR(fmt::format("Spice reported: {}", buffer));
|
||||
reset_c();
|
||||
delete[] buffer;
|
||||
return InvalidKernel;
|
||||
}
|
||||
throwOnSpiceError("Kernel loading");
|
||||
|
||||
std::string fileExtension = ghoul::filesystem::File(path, true).fileExtension();
|
||||
bool success = true;
|
||||
string fileExtension = ghoul::filesystem::File(path, true).fileExtension();
|
||||
if (fileExtension == ".bc" || fileExtension == ".BC")
|
||||
success = findCkCoverage(path); // binary ck kernel
|
||||
findCkCoverage(path); // binary ck kernel
|
||||
else if (fileExtension == "bsp" || fileExtension == "BSP")
|
||||
success = findSpkCoverage(path); // binary spk kernel
|
||||
findSpkCoverage(path); // binary spk kernel
|
||||
|
||||
if (!success)
|
||||
return InvalidKernel;
|
||||
else {
|
||||
KernelHandle kernelId = ++_lastAssignedKernel;
|
||||
ghoul_assert(kernelId != 0, fmt::format("Kernel Handle wrapped around to 0"));
|
||||
_loadedKernels.push_back({std::move(path), kernelId, 1});
|
||||
return kernelId;
|
||||
}
|
||||
}
|
||||
|
||||
bool SpiceManager::findCkCoverage(const std::string& path) {
|
||||
SPICEINT_CELL(ids, MAXOBJ);
|
||||
SPICEDOUBLE_CELL(cover, WINSIZ);
|
||||
|
||||
ckobj_c(path.c_str(), &ids);
|
||||
|
||||
for (SpiceInt i = 0; i < card_c(&ids); ++i) {
|
||||
SpiceInt frame = SPICE_CELL_ELEM_I(&ids, i);
|
||||
|
||||
scard_c(0, &cover);
|
||||
ckcov_c(path.c_str(), frame, SPICEFALSE, "SEGMENT", 0.0, "TDB", &cover);
|
||||
|
||||
//Get the number of intervals in the coverage window.
|
||||
SpiceInt numberOfIntervals = wncard_c(&cover);
|
||||
|
||||
for (SpiceInt j = 0; j < numberOfIntervals; ++j) {
|
||||
//Get the endpoints of the jth interval.
|
||||
SpiceDouble b, e;
|
||||
wnfetd_c(&cover, j, &b, &e);
|
||||
|
||||
_ckCoverageTimes[frame].insert(e);
|
||||
_ckCoverageTimes[frame].insert(b);
|
||||
_ckIntervals[frame].emplace_back(b, e);
|
||||
}
|
||||
}
|
||||
|
||||
bool success = checkForError("Error finding Ck Converage");
|
||||
return success;
|
||||
}
|
||||
|
||||
bool SpiceManager::findSpkCoverage(const std::string& path) {
|
||||
SpiceInt obj, numberOfIntervals;
|
||||
SpiceDouble b, e;
|
||||
std::pair <double, double> tempInterval;
|
||||
SPICEINT_CELL(ids, MAXOBJ);
|
||||
SPICEDOUBLE_CELL(cover, WINSIZ);
|
||||
|
||||
spkobj_c(path.c_str(), &ids);
|
||||
for (SpiceInt i = 0; i < card_c(&ids); ++i) {
|
||||
obj = SPICE_CELL_ELEM_I(&ids, i);
|
||||
|
||||
scard_c(0, &cover);
|
||||
spkcov_c(path.c_str(), obj, &cover);
|
||||
//Get the number of intervals in the coverage window.
|
||||
numberOfIntervals = wncard_c(&cover);
|
||||
|
||||
for (SpiceInt j = 0; j < numberOfIntervals; ++j) {
|
||||
//Get the endpoints of the jth interval.
|
||||
wnfetd_c(&cover, j, &b, &e);
|
||||
tempInterval = std::make_pair(b, e);
|
||||
//insert all into coverage time set, the windows could be merged @AA
|
||||
_spkCoverageTimes[obj].insert(e);
|
||||
_spkCoverageTimes[obj].insert(b);
|
||||
_spkIntervals[obj].push_back(tempInterval);
|
||||
}
|
||||
}
|
||||
bool success = checkForError("Error finding Spk Converage");
|
||||
return success;
|
||||
}
|
||||
|
||||
bool SpiceManager::hasSpkCoverage(std::string target, double& et) const {
|
||||
int id;
|
||||
bool idSuccess = getNaifId(target, id);
|
||||
bool hasCoverage = false;
|
||||
|
||||
std::vector< std::pair<double, double> > intervalVector;
|
||||
if (_spkIntervals.find(id) == _spkIntervals.end())
|
||||
return false;
|
||||
else
|
||||
intervalVector = _spkIntervals.find(id)->second;
|
||||
|
||||
for (auto vecElement : intervalVector) {
|
||||
if (vecElement.first < et && vecElement.second > et) {
|
||||
hasCoverage = true;
|
||||
return idSuccess && hasCoverage;
|
||||
}
|
||||
}
|
||||
|
||||
return idSuccess && hasCoverage;
|
||||
}
|
||||
|
||||
bool SpiceManager::hasCkCoverage(std::string frame, double& et) const {
|
||||
int id;
|
||||
bool idSuccess = getFrameId(frame, id);
|
||||
bool hasCoverage = false;
|
||||
|
||||
std::vector< std::pair<double, double> > intervalVector;
|
||||
if (_ckIntervals.find(id) == _ckIntervals.end())
|
||||
return false;
|
||||
else
|
||||
intervalVector = _ckIntervals.find(id)->second;
|
||||
|
||||
for (auto vecElement : intervalVector) {
|
||||
if (vecElement.first < et && vecElement.second > et) {
|
||||
hasCoverage = true;
|
||||
return idSuccess && hasCoverage;
|
||||
}
|
||||
}
|
||||
|
||||
return idSuccess && hasCoverage;
|
||||
KernelHandle kernelId = ++_lastAssignedKernel;
|
||||
ghoul_assert(kernelId != 0, fmt::format("Kernel Handle wrapped around to 0"));
|
||||
_loadedKernels.push_back({std::move(path), kernelId, 1});
|
||||
return kernelId;
|
||||
}
|
||||
|
||||
void SpiceManager::unloadKernel(KernelHandle kernelId) {
|
||||
ghoul_assert(kernelId <= _lastAssignedKernel, "Invalid unassigned kernel");
|
||||
ghoul_assert(kernelId != KernelHandle(0), "Invalid zero handle");
|
||||
|
||||
auto it = std::find_if(_loadedKernels.begin(), _loadedKernels.end(),
|
||||
[&kernelId](const KernelInformation& info) { return info.id == kernelId ; });
|
||||
[&kernelId](const KernelInformation& info) { return info.id == kernelId; });
|
||||
|
||||
if (it != _loadedKernels.end()) {
|
||||
// If there is only one part interested in the kernel, we can unload it
|
||||
// If there was only one part interested in the kernel, we can unload it
|
||||
if (it->refCount == 1) {
|
||||
// No need to check for errors as we do not allow empty path names
|
||||
LINFO("Unloading SPICE kernel '" << it->path << "'");
|
||||
LINFO(format("Unloading SPICE kernel '{}'", it->path));
|
||||
unload_c(it->path.c_str());
|
||||
_loadedKernels.erase(it);
|
||||
}
|
||||
// Otherwise, we hold on to it, but reduce the reference counter by 1
|
||||
else {
|
||||
// Otherwise, we hold on to it, but reduce the reference counter by 1
|
||||
it->refCount--;
|
||||
LDEBUG("Reducing reference counter. New reference count: " << it->refCount);
|
||||
LDEBUG(format("Reducing reference counter to: {}", it->refCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpiceManager::unloadKernel(const std::string& filePath) {
|
||||
if (filePath.empty()) {
|
||||
LERROR("No file path provided");
|
||||
return;
|
||||
}
|
||||
std::string&& path = absPath(filePath);
|
||||
void SpiceManager::unloadKernel(string filePath) {
|
||||
ghoul_assert(!filePath.empty(), "Empty filename");
|
||||
|
||||
string path = absPath(filePath);
|
||||
|
||||
auto it = std::find_if(_loadedKernels.begin(), _loadedKernels.end(),
|
||||
[&path](const KernelInformation& info) { return info.path == path; });
|
||||
|
||||
if (it != _loadedKernels.end()) {
|
||||
// If there is only one part interested in the kernel, we can unload it
|
||||
|
||||
if (it == _loadedKernels.end())
|
||||
throw SpiceKernelException("Kernel unloading failed");
|
||||
else {
|
||||
// If there was only one part interested in the kernel, we can unload it
|
||||
if (it->refCount == 1) {
|
||||
LINFO("Unloading SPICE kernel '" << path << "'");
|
||||
LINFO(format("Unloading SPICE kernel '{}'", path));
|
||||
unload_c(path.c_str());
|
||||
_loadedKernels.erase(it);
|
||||
}
|
||||
else {
|
||||
// Otherwise, we hold on to it, but reduce the reference counter by 1
|
||||
it->refCount--;
|
||||
LDEBUG("Reducing reference counter. New reference count: " << it->refCount);
|
||||
LDEBUG(format("Reducing reference counter to: {}", it->refCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool SpiceManager::hasValue(int naifId, const std::string& item) const {
|
||||
return (bodfnd_c(naifId, item.c_str()) == SPICETRUE);
|
||||
bool SpiceManager::hasSpkCoverage(const string& target, double et) const {
|
||||
ghoul_assert(!target.empty(), "Empty target");
|
||||
|
||||
int id = naifId(target);
|
||||
auto it = _spkIntervals.find(id);
|
||||
if (it != _spkIntervals.end()) {
|
||||
std::vector<std::pair<double, double>> intervalVector = it->second;
|
||||
for (const auto& vecElement : intervalVector) {
|
||||
if (vecElement.first < et && vecElement.second > et)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpiceManager::hasValue(const std::string& body, const std::string& item) const {
|
||||
int id;
|
||||
bool success = getNaifId(body, id);
|
||||
if (success)
|
||||
return hasValue(id, item);
|
||||
else
|
||||
return false;
|
||||
bool SpiceManager::hasCkCoverage(const string& frame, double et) const {
|
||||
ghoul_assert(!frame.empty(), "Empty target");
|
||||
|
||||
int id = frameId(frame);
|
||||
|
||||
auto it = _ckIntervals.find(id);
|
||||
if (it != _ckIntervals.end()) {
|
||||
std::vector<std::pair<double, double>> intervalVector = it->second;
|
||||
for (const auto& i : intervalVector) {
|
||||
if (i.first < et && i.second > et)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpiceManager::getNaifId(const std::string& body, int& id) const {
|
||||
if (body.empty()) {
|
||||
LERROR("No body was provided");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
SpiceBoolean success;
|
||||
// SpiceInt sid = id;
|
||||
bods2c_c(body.c_str(), &id, &success);
|
||||
// id = sid;
|
||||
if (success == SPICEFALSE)
|
||||
LERROR("Could not find NAIF ID of body '" + body + "'");
|
||||
return (success == SPICETRUE);
|
||||
}
|
||||
bool SpiceManager::hasValue(int naifId, const string& item) const {
|
||||
return bodfnd_c(naifId, item.c_str());
|
||||
}
|
||||
|
||||
bool SpiceManager::getFrameId(const std::string& frame, int& id) const {
|
||||
if (frame.empty()) {
|
||||
LERROR("No frame was provided");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
namfrm_c(frame.c_str(), &id);
|
||||
bool hasError = SpiceManager::checkForError("Error getting id for frame '" + frame + "'");
|
||||
return !hasError;
|
||||
}
|
||||
bool SpiceManager::hasValue(const string& body, const string& item) const {
|
||||
ghoul_assert(!body.empty(), "Empty body");
|
||||
ghoul_assert(!item.empty(), "Empty item");
|
||||
|
||||
int id = naifId(body);
|
||||
return hasValue(id, item);
|
||||
}
|
||||
|
||||
bool getValueInternal(const std::string& body, const std::string& value, int S,
|
||||
int SpiceManager::naifId(const string& body) const {
|
||||
ghoul_assert(!body.empty(), "Empty body");
|
||||
|
||||
SpiceBoolean success;
|
||||
int id;
|
||||
bods2c_c(body.c_str(), &id, &success);
|
||||
if (!success)
|
||||
throw SpiceKernelException(format("Could not find NAIF ID of body '{}'", body));
|
||||
return id;
|
||||
}
|
||||
|
||||
bool SpiceManager::hasNaifId(const string& body) const {
|
||||
ghoul_assert(!body.empty(), "Empty body");
|
||||
|
||||
SpiceBoolean success;
|
||||
int id;
|
||||
bods2c_c(body.c_str(), &id, &success);
|
||||
return success;
|
||||
}
|
||||
|
||||
int SpiceManager::frameId(const string& frame) const {
|
||||
ghoul_assert(!frame.empty(), "Empty frame");
|
||||
|
||||
int id;
|
||||
namfrm_c(frame.c_str(), &id);
|
||||
if (id == 0)
|
||||
throw SpiceKernelException(format("Could not find NAIF ID of frame '{}'", frame));
|
||||
return id;
|
||||
}
|
||||
|
||||
bool SpiceManager::hasFrameId(const string& frame) const {
|
||||
ghoul_assert(!frame.empty(), "Empty frame");
|
||||
|
||||
int id;
|
||||
namfrm_c(frame.c_str(), &id);
|
||||
return id != 0;
|
||||
}
|
||||
|
||||
void getValueInternal(const string& body, const string& value, int size,
|
||||
double* v)
|
||||
{
|
||||
|
||||
if (body.empty()) {
|
||||
LERROR("No body was provided");
|
||||
return false;
|
||||
}
|
||||
if (value.empty()) {
|
||||
LERROR("No value was provided");
|
||||
return false;
|
||||
}
|
||||
ghoul_assert(!body.empty(), "Empty body");
|
||||
ghoul_assert(!value.empty(), "Empty value");
|
||||
ghoul_assert(v != nullptr, "Empty value pointer");
|
||||
|
||||
SpiceInt n;
|
||||
bodvrd_c(body.c_str(), value.c_str(), S, &n, v);
|
||||
bodvrd_c(body.c_str(), value.c_str(), size, &n, v);
|
||||
|
||||
bool hasError = SpiceManager::checkForError("Error getting value '" + value +
|
||||
throwOnSpiceError("Error getting value '" + value +
|
||||
"' for body '" + body + "'");
|
||||
return !hasError;
|
||||
}
|
||||
|
||||
bool SpiceManager::getValue(const std::string& body, const std::string& value,
|
||||
double& v) const
|
||||
void SpiceManager::getValue(const string& body, const string& value, double& v) const {
|
||||
getValueInternal(body, value, 1, &v);
|
||||
}
|
||||
|
||||
void SpiceManager::getValue(const string& body, const string& value,
|
||||
glm::dvec3& v) const
|
||||
{
|
||||
return getValueInternal(body, value, 1, &v);
|
||||
getValueInternal(body, value, 3, glm::value_ptr(v));
|
||||
}
|
||||
|
||||
bool SpiceManager::getValue(const std::string& body, const std::string& value,
|
||||
glm::dvec3& v) const
|
||||
{
|
||||
return getValueInternal(body, value, 3, glm::value_ptr(v));
|
||||
}
|
||||
|
||||
bool SpiceManager::getValue(const std::string& body, const std::string& value,
|
||||
void SpiceManager::getValue(const string& body, const string& value,
|
||||
glm::dvec4& v) const
|
||||
{
|
||||
return getValueInternal(body, value, 4, glm::value_ptr(v));
|
||||
getValueInternal(body, value, 4, glm::value_ptr(v));
|
||||
}
|
||||
|
||||
bool SpiceManager::getValue(const std::string& body, const std::string& value,
|
||||
void SpiceManager::getValue(const string& body, const string& value,
|
||||
std::vector<double>& v) const
|
||||
{
|
||||
if (body.empty()) {
|
||||
LERROR("No body was provided");
|
||||
return false;
|
||||
}
|
||||
if (value.empty()) {
|
||||
LERROR("No value was provided");
|
||||
return false;
|
||||
}
|
||||
if (v.size() == 0) {
|
||||
LERROR("Array for values has to be preallocaed");
|
||||
return false;
|
||||
}
|
||||
|
||||
SpiceInt n;
|
||||
bodvrd_c(body.c_str(), value.c_str(), static_cast<SpiceInt>(v.size()), &n, &v[0]);
|
||||
|
||||
bool hasError = checkForError("Error getting value '" + value + "' for body '" +
|
||||
body + "'");
|
||||
return !hasError;
|
||||
ghoul_assert(!v.empty(), "Array for values has to be preallocaed");
|
||||
getValueInternal(body, value, v.size(), v.data());
|
||||
}
|
||||
|
||||
bool SpiceManager::spacecraftClockToET(const std::string& craftIdCode, double& craftTicks, double& et){
|
||||
int craftID = -1;
|
||||
getNaifId(craftIdCode, craftID);
|
||||
sct2e_c(craftID, craftTicks, &et);
|
||||
bool hasError = checkForError("Error transforming spacecraft clock of '" + craftIdCode + "' at time " + std::to_string(craftTicks));
|
||||
return !hasError;
|
||||
double SpiceManager::spacecraftClockToET(const string& craft, double craftTicks) {
|
||||
ghoul_assert(!craft.empty(), "Empty craft");
|
||||
int craftId = naifId(craft);
|
||||
double et;
|
||||
sct2e_c(craftId, craftTicks, &et);
|
||||
throwOnSpiceError(format(
|
||||
"Error transforming spacecraft clock of '{}' at time {}",
|
||||
craft, craftTicks)
|
||||
);
|
||||
return et;
|
||||
}
|
||||
|
||||
bool SpiceManager::getETfromDate(const std::string& timeString,
|
||||
@@ -416,8 +335,8 @@ bool SpiceManager::getETfromDate(const std::string& timeString,
|
||||
}
|
||||
|
||||
str2et_c(timeString.c_str(), &ephemerisTime);
|
||||
bool hasError = checkForError("Error converting date '" + timeString + "'");
|
||||
return !hasError;
|
||||
throwOnSpiceError("Error converting date '" + timeString + "'");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpiceManager::getDateFromET(double ephemerisTime, std::string& date,
|
||||
@@ -432,13 +351,13 @@ bool SpiceManager::getDateFromET(double ephemerisTime, std::string& date,
|
||||
SpiceChar buffer[BufferSize];
|
||||
|
||||
timout_c(ephemerisTime, format.c_str(), BufferSize - 1, buffer);
|
||||
bool hasError = checkForError(
|
||||
"Error converting ephemeris time '" +
|
||||
std::to_string(ephemerisTime) +
|
||||
"' to date with format '" + format + "'");
|
||||
if (!hasError)
|
||||
date = std::string(buffer);
|
||||
return !hasError;
|
||||
throwOnSpiceError("Error converting ephemeris time '" +
|
||||
std::to_string(ephemerisTime) +
|
||||
"' to date with format '" + format + "'"
|
||||
);
|
||||
|
||||
date = std::string(buffer);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpiceManager::getTargetPosition(const std::string& target,
|
||||
@@ -514,7 +433,8 @@ bool SpiceManager::getEstimatedPosition(const double time, const std::string tar
|
||||
{
|
||||
|
||||
int idTarget, idObserver;
|
||||
bool targetFound = getNaifId(target, idTarget);
|
||||
bool targetFound = hasNaifId(target);
|
||||
idTarget = naifId(target);
|
||||
if (idTarget == 0) { //SOLAR SYSTEM BARYCENTER special case, no def. in kernels
|
||||
targetPosition[0] = 0.f;
|
||||
targetPosition[1] = 0.f;
|
||||
@@ -525,7 +445,8 @@ bool SpiceManager::getEstimatedPosition(const double time, const std::string tar
|
||||
|
||||
double pos[3] = { 0.0, 0.0, 0.0 };
|
||||
|
||||
bool observerFound = getNaifId(observer, idObserver);
|
||||
bool observerFound = hasNaifId(observer);
|
||||
idObserver = naifId(observer);
|
||||
if (!targetFound || !observerFound || (idTarget == idObserver)) {
|
||||
return false;
|
||||
}
|
||||
@@ -571,7 +492,7 @@ bool SpiceManager::getEstimatedPosition(const double time, const std::string tar
|
||||
|
||||
|
||||
targetPosition = PowerScaledCoordinate::CreatePowerScaledCoordinate(pos[0], pos[1], pos[2]);
|
||||
checkForError("Error estimating positin for target: " + target + ", or observer: " + observer);
|
||||
throwOnSpiceError("Error estimating positin for target: " + target + ", or observer: " + observer);
|
||||
|
||||
return targetFound && observerFound;
|
||||
}
|
||||
@@ -584,11 +505,9 @@ bool SpiceManager::frameConversion(glm::dvec3& v, const std::string& from, const
|
||||
// get rotation matrix from frame A - frame B
|
||||
pxform_c(from.c_str(), to.c_str(), ephemerisTime, (double(*)[3])glm::value_ptr(transform));
|
||||
|
||||
bool hasError = checkForError("Error converting from frame '" + from +
|
||||
throwOnSpiceError("Error converting from frame '" + from +
|
||||
"' to frame '" + to + "' at time " + std::to_string(ephemerisTime));
|
||||
if (hasError)
|
||||
return false;
|
||||
// re-express vector in new frame
|
||||
// re-express vector in new frame
|
||||
mxv_c((double(*)[3])glm::value_ptr(transform), glm::value_ptr(v), glm::value_ptr(v));
|
||||
return true;
|
||||
}
|
||||
@@ -620,10 +539,10 @@ bool SpiceManager::targetWithinFieldOfView(const std::string& instrument,
|
||||
&visible);
|
||||
isVisible = (visible == SPICETRUE);
|
||||
|
||||
bool hasError = checkForError("Checking if target '" + target +
|
||||
throwOnSpiceError("Checking if target '" + target +
|
||||
"' is in view of instrument '" + instrument + "' failed");
|
||||
|
||||
return !hasError;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpiceManager::targetWithinFieldOfView(const std::string& instrument,
|
||||
@@ -649,10 +568,10 @@ bool SpiceManager::targetWithinFieldOfView(const std::string& instrument,
|
||||
&visible);
|
||||
isVisible = (visible == SPICETRUE);
|
||||
|
||||
bool hasError = checkForError("Checking if target '" + target +
|
||||
throwOnSpiceError("Checking if target '" + target +
|
||||
"' is in view of instrument '" + instrument + "' failed");
|
||||
|
||||
return !hasError;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -704,14 +623,11 @@ bool SpiceManager::getSurfaceIntercept(const std::string& target,
|
||||
|
||||
isVisible = (found == SPICETRUE);
|
||||
|
||||
bool hasError = checkForError("Error retrieving surface intercept on target '" + target + "'" +
|
||||
throwOnSpiceError("Error retrieving surface intercept on target '" + target + "'" +
|
||||
"viewed from observer '" + observer + "' in " +
|
||||
"reference frame '" + bodyfixed + "' at time '" +
|
||||
std::to_string(ephemerisTime) + "'");
|
||||
|
||||
if (hasError)
|
||||
return false;
|
||||
|
||||
if (convert)
|
||||
frameConversion(srfvec, bodyfixed, referenceFrame, ephemerisTime);
|
||||
|
||||
@@ -738,15 +654,13 @@ bool SpiceManager::getTargetState(const std::string& target,
|
||||
spkezr_c(target.c_str(), ephemerisTime, referenceFrame.c_str(),
|
||||
aberrationCorrection.c_str(), observer.c_str(), buffer, &lightTime);
|
||||
|
||||
bool hasError = checkForError("Error retrieving state of target '" + target + "'" +
|
||||
throwOnSpiceError("Error retrieving state of target '" + target + "'" +
|
||||
"viewed from observer '" + observer + "' in " +
|
||||
"reference frame '" + referenceFrame + "' at time '" +
|
||||
std::to_string(ephemerisTime) + "'");
|
||||
if (!hasError) {
|
||||
memmove(glm::value_ptr(targetPosition), buffer, sizeof(double) * 3);
|
||||
memmove(glm::value_ptr(targetVelocity), buffer + 3, sizeof(double) * 3);
|
||||
}
|
||||
return !hasError;
|
||||
memmove(glm::value_ptr(targetPosition), buffer, sizeof(double) * 3);
|
||||
memmove(glm::value_ptr(targetVelocity), buffer + 3, sizeof(double) * 3);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not called at the moment @AA
|
||||
@@ -765,22 +679,15 @@ bool SpiceManager::getTargetState(const std::string& target,
|
||||
spkezr_c(target.c_str(), ephemerisTime, referenceFrame.c_str(),
|
||||
aberrationCorrection.c_str(), observer.c_str(), state, &lightTime);
|
||||
|
||||
bool hasError = checkForError("Error retrieving state of target '" + target + "'" +
|
||||
throwOnSpiceError("Error retrieving state of target '" + target + "'" +
|
||||
"viewed from observer '" + observer + "' in " +
|
||||
"reference frame '" + referenceFrame + "' at time '" +
|
||||
std::to_string(ephemerisTime) + "'");
|
||||
|
||||
if (!hasError) {
|
||||
position = PowerScaledCoordinate::CreatePowerScaledCoordinate(state[0], state[1], state[2]);
|
||||
velocity = PowerScaledCoordinate::CreatePowerScaledCoordinate(state[3], state[4], state[5]);
|
||||
}
|
||||
else
|
||||
{
|
||||
position = PowerScaledCoordinate::CreatePowerScaledCoordinate(0.0, 0.0, 0.0);
|
||||
velocity = PowerScaledCoordinate::CreatePowerScaledCoordinate(0, 0, 0);
|
||||
}
|
||||
position = PowerScaledCoordinate::CreatePowerScaledCoordinate(state[0], state[1], state[2]);
|
||||
velocity = PowerScaledCoordinate::CreatePowerScaledCoordinate(state[3], state[4], state[5]);
|
||||
|
||||
return !hasError;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Not called at the moment @AA
|
||||
@@ -792,10 +699,10 @@ bool SpiceManager::getStateTransformMatrix(const std::string& fromFrame,
|
||||
sxform_c(fromFrame.c_str(), toFrame.c_str(),
|
||||
ephemerisTime, (double(*)[6])stateMatrix.data());
|
||||
|
||||
bool hasError = checkForError("Error retrieved state transform matrix from frame '" +
|
||||
throwOnSpiceError("Error retrieved state transform matrix from frame '" +
|
||||
fromFrame + "' to frame '" + toFrame + "' at time '" +
|
||||
std::to_string(ephemerisTime) + "'");
|
||||
return !hasError;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SpiceManager::getPositionTransformMatrix(const std::string& fromFrame,
|
||||
@@ -803,21 +710,14 @@ bool SpiceManager::getPositionTransformMatrix(const std::string& fromFrame,
|
||||
double ephemerisTime,
|
||||
glm::dmat3& positionMatrix) const
|
||||
{
|
||||
bool success = false, estimated = false;
|
||||
bool estimated = false;
|
||||
pxform_c(fromFrame.c_str(), toFrame.c_str(),
|
||||
ephemerisTime, (double(*)[3])glm::value_ptr(positionMatrix));
|
||||
|
||||
success = !(failed_c());
|
||||
SpiceBoolean success = !(failed_c());
|
||||
reset_c();
|
||||
if (!success) {
|
||||
reset_c();
|
||||
estimated = getEstimatedTransformMatrix(ephemerisTime, fromFrame, toFrame, positionMatrix);
|
||||
}
|
||||
if (_showErrors) {
|
||||
bool hasError = checkForError("Error retrieving position transform matrix from "
|
||||
"frame '" + fromFrame + "' to frame '" + toFrame +
|
||||
"' at time '" + std::to_string(ephemerisTime));
|
||||
if (hasError)
|
||||
return false;
|
||||
estimated = getEstimatedTransformMatrix(ephemerisTime, fromFrame, toFrame, positionMatrix);
|
||||
}
|
||||
|
||||
positionMatrix = glm::transpose(positionMatrix);
|
||||
@@ -834,13 +734,13 @@ bool SpiceManager::getPositionTransformMatrix(const std::string& fromFrame,
|
||||
|
||||
pxfrm2_c(fromFrame.c_str(), toFrame.c_str(), ephemerisTimeFrom, ephemerisTimeTo, (double(*)[3])glm::value_ptr(positionMatrix));
|
||||
|
||||
bool hasError = checkForError("Error retrieving position transform matrix from "
|
||||
throwOnSpiceError("Error retrieving position transform matrix from "
|
||||
"frame '" + fromFrame + "' to frame '" + toFrame +
|
||||
"' from time '" + std::to_string(ephemerisTimeFrom) + " to time '"
|
||||
+ std::to_string(ephemerisTimeTo) + "'");
|
||||
positionMatrix = glm::transpose(positionMatrix);
|
||||
|
||||
return !hasError;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -849,11 +749,13 @@ bool SpiceManager::getEstimatedTransformMatrix(const double time, const std::str
|
||||
{
|
||||
int idFrame;
|
||||
|
||||
bool frameFound = getFrameId(fromFrame, idFrame);
|
||||
bool frameFound = hasFrameId(fromFrame);
|
||||
if (!frameFound) {
|
||||
return false;
|
||||
}
|
||||
if (_ckCoverageTimes.find(idFrame) == _ckCoverageTimes.end()){ // no coverage
|
||||
idFrame = frameId(fromFrame);
|
||||
|
||||
if (_ckCoverageTimes.find(idFrame) == _ckCoverageTimes.end()){ // no coverage
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -892,10 +794,10 @@ bool SpiceManager::getEstimatedTransformMatrix(const double time, const std::str
|
||||
}
|
||||
}
|
||||
}
|
||||
bool hasError = checkForError("Error estimating transform matrix from frame: "
|
||||
throwOnSpiceError("Error estimating transform matrix from frame: "
|
||||
+ fromFrame + ", to frame: " + toFrame);
|
||||
|
||||
return !hasError;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -904,10 +806,11 @@ bool SpiceManager::getFieldOfView(const std::string& instrument, std::string& fo
|
||||
std::vector<glm::dvec3>& bounds) const
|
||||
{
|
||||
int id;
|
||||
bool success = getNaifId(instrument, id);
|
||||
bool success = hasNaifId(instrument);
|
||||
if (!success)
|
||||
return false;
|
||||
else
|
||||
id = naifId(instrument);
|
||||
return getFieldOfView(id, fovShape, frameName, boresightVector, bounds);
|
||||
}
|
||||
|
||||
@@ -937,10 +840,8 @@ bool SpiceManager::getFieldOfView(int instrument,
|
||||
(double(*)[3])boundsArr // the bounds
|
||||
);
|
||||
|
||||
bool hasError = checkForError("Error getting Field-of-View parameters for "
|
||||
throwOnSpiceError("Error getting Field-of-View parameters for "
|
||||
"instrument '" + std::to_string(instrument) + "'");
|
||||
if (hasError)
|
||||
return false;
|
||||
|
||||
bounds.resize(nrReturned);
|
||||
for (int i = 0; i < nrReturned; ++i) {
|
||||
@@ -980,10 +881,8 @@ bool SpiceManager::getTerminatorEllipse(const int numberOfPoints,
|
||||
glm::value_ptr(observerPosition),
|
||||
(double(*)[3])tpoints.data() );
|
||||
|
||||
bool hasError = checkForError("Error getting " + terminatorType +
|
||||
throwOnSpiceError("Error getting " + terminatorType +
|
||||
"terminator for'" + target + "'");
|
||||
if (hasError)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < numberOfPoints; i++){
|
||||
psc point = psc::CreatePowerScaledCoordinate(tpoints[i][0], tpoints[i][1], tpoints[i][2]);
|
||||
@@ -995,7 +894,6 @@ bool SpiceManager::getTerminatorEllipse(const int numberOfPoints,
|
||||
}
|
||||
|
||||
std::string SpiceManager::frameFromBody(const std::string body) const {
|
||||
|
||||
for (auto pair : _frameByBody) {
|
||||
if (pair.first == body) {
|
||||
return pair.second;
|
||||
@@ -1022,34 +920,12 @@ bool SpiceManager::addFrame(const std::string body, const std::string frame) {
|
||||
}
|
||||
}
|
||||
|
||||
bool SpiceManager::checkForError(std::string errorMessage) {
|
||||
|
||||
int failed = failed_c();
|
||||
if (failed && _showErrors) {
|
||||
static char msg[1024];
|
||||
if (!errorMessage.empty()) {
|
||||
getmsg_c("LONG", 1024, msg);
|
||||
LWARNING(errorMessage);
|
||||
LWARNING("Spice reported: " + std::string(msg));
|
||||
}
|
||||
reset_c();
|
||||
return true;
|
||||
}
|
||||
else if (failed) {
|
||||
reset_c();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpiceManager::getPlanetEllipsoid(std::string planetName, float &a, float &b, float &c) {
|
||||
|
||||
SpiceDouble radii[3];
|
||||
SpiceInt n = -1;
|
||||
int id = -1;
|
||||
|
||||
getNaifId(planetName, id);
|
||||
id = naifId(planetName);
|
||||
if (bodfnd_c(id, "RADII")) {
|
||||
bodvrd_c(planetName.c_str(), "RADII", 3, &n, radii);
|
||||
a = static_cast<float>(radii[0]);
|
||||
@@ -1063,8 +939,82 @@ bool SpiceManager::getPlanetEllipsoid(std::string planetName, float &a, float &b
|
||||
c = 1.f;
|
||||
}
|
||||
|
||||
bool hasError = checkForError("Error retrieving planet radii of " + planetName);
|
||||
return !hasError;
|
||||
throwOnSpiceError("Error retrieving planet radii of " + planetName);
|
||||
return true;
|
||||
}
|
||||
|
||||
void SpiceManager::findCkCoverage(const std::string& path) {
|
||||
ghoul_assert(!path.empty(), "Empty file path");
|
||||
ghoul_assert(FileSys.fileExists(path), format("File '{}' does not exist", path));
|
||||
|
||||
const unsigned int MaxObj = 64;
|
||||
const unsigned int WinSiz = 10000;
|
||||
|
||||
SPICEINT_CELL(ids, MaxObj);
|
||||
SPICEDOUBLE_CELL(cover, WinSiz);
|
||||
|
||||
ckobj_c(path.c_str(), &ids);
|
||||
throwOnSpiceError("Error finding Ck Converage");
|
||||
|
||||
for (SpiceInt i = 0; i < card_c(&ids); ++i) {
|
||||
SpiceInt frame = SPICE_CELL_ELEM_I(&ids, i);
|
||||
|
||||
scard_c(0, &cover);
|
||||
ckcov_c(path.c_str(), frame, SPICEFALSE, "SEGMENT", 0.0, "TDB", &cover);
|
||||
throwOnSpiceError("Error finding Ck Converage");
|
||||
|
||||
//Get the number of intervals in the coverage window.
|
||||
SpiceInt numberOfIntervals = wncard_c(&cover);
|
||||
|
||||
for (SpiceInt j = 0; j < numberOfIntervals; ++j) {
|
||||
//Get the endpoints of the jth interval.
|
||||
SpiceDouble b, e;
|
||||
wnfetd_c(&cover, j, &b, &e);
|
||||
throwOnSpiceError("Error finding Ck Converage");
|
||||
|
||||
_ckCoverageTimes[frame].insert(e);
|
||||
_ckCoverageTimes[frame].insert(b);
|
||||
_ckIntervals[frame].emplace_back(b, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpiceManager::findSpkCoverage(const std::string& path) {
|
||||
ghoul_assert(!path.empty(), "Empty file path");
|
||||
ghoul_assert(FileSys.fileExists(path), format("File '{}' does not exist", path));
|
||||
|
||||
const unsigned int MaxObj = 64;
|
||||
const unsigned int WinSiz = 10000;
|
||||
|
||||
SPICEINT_CELL(ids, MaxObj);
|
||||
SPICEDOUBLE_CELL(cover, WinSiz);
|
||||
|
||||
spkobj_c(path.c_str(), &ids);
|
||||
throwOnSpiceError("Error finding Spk Converage");
|
||||
|
||||
for (SpiceInt i = 0; i < card_c(&ids); ++i) {
|
||||
SpiceInt obj = SPICE_CELL_ELEM_I(&ids, i);
|
||||
|
||||
scard_c(0, &cover);
|
||||
spkcov_c(path.c_str(), obj, &cover);
|
||||
throwOnSpiceError("Error finding Spk Converage");
|
||||
|
||||
//Get the number of intervals in the coverage window.
|
||||
SpiceInt numberOfIntervals = wncard_c(&cover);
|
||||
|
||||
for (SpiceInt j = 0; j < numberOfIntervals; ++j) {
|
||||
//Get the endpoints of the jth interval.
|
||||
SpiceDouble b, e;
|
||||
wnfetd_c(&cover, j, &b, &e);
|
||||
throwOnSpiceError("Error finding Spk Converage");
|
||||
|
||||
//insert all into coverage time set, the windows could be merged @AA
|
||||
_spkCoverageTimes[obj].insert(e);
|
||||
_spkCoverageTimes[obj].insert(b);
|
||||
_spkIntervals[obj].emplace_back(b, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user