From 2c84368b0b98244dec6980e24cb52c030bbdd46c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 19 Nov 2015 23:35:09 -0500 Subject: [PATCH] More cleaning of SpiceManager --- include/openspace/util/spicemanager.h | 368 +++++++------ modules/base/ephemeris/spiceephemeris.cpp | 3 +- .../renderableconstellationbounds.cpp | 5 +- modules/base/rendering/renderablemodel.cpp | 9 +- modules/base/rendering/renderablepath.cpp | 2 +- modules/base/rendering/renderableplanet.cpp | 4 +- .../rendering/renderablesphericalgrid.cpp | 5 +- modules/base/rendering/renderabletrail.cpp | 10 +- .../rendering/renderablecrawlingline.cpp | 3 +- .../newhorizons/rendering/renderablefov.cpp | 117 +++- modules/newhorizons/rendering/renderablefov.h | 1 - .../rendering/renderablemodelprojection.cpp | 11 +- .../rendering/renderableplaneprojection.cpp | 6 +- .../rendering/renderableplanetprojection.cpp | 6 +- .../rendering/renderableshadowcylinder.cpp | 6 +- modules/newhorizons/util/hongkangparser.cpp | 14 +- src/rendering/renderengine.cpp | 2 +- src/util/spicemanager.cpp | 500 +++++++++--------- 18 files changed, 588 insertions(+), 484 deletions(-) diff --git a/include/openspace/util/spicemanager.h b/include/openspace/util/spicemanager.h index cb0ce77afa..e01f29e51e 100644 --- a/include/openspace/util/spicemanager.h +++ b/include/openspace/util/spicemanager.h @@ -115,6 +115,12 @@ public: Direction direction = Direction::Reception; }; + /// The possible values for the method parameter of the targetInFieldOfView method + enum class FieldOfViewMethod { + Ellipsoid = 0, + Point + }; + /** * 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 @@ -448,192 +454,218 @@ public: glm::dmat3 frameTransformationMatrix(const std::string& from, const std::string& to, double ephemerisTime) const; + /// Struct that is used as the return value from the #getSurfaceIntercept method + struct SurfaceInterceptResult { + /** + * The closest surface intercept point on the target body in Cartesian Coordinates + * relative to the reference frame. + */ + glm::dvec3 surfaceIntercept; + + /** + * If the aberration correction is not AberrationCorrection::Type::None, this + * value contains the time for which the intercept was computed. Otherwise it is + * the same as the ephemerisTime. + */ + double interceptEpoch; + + /** + * The vector from the observer's position to the \p surfaceIntercept position in + * the provided reference frame. + */ + glm::dvec3 surfaceVector; + + /// true if the ray intersects the body, false otherwise + bool interceptFound; + }; + /** - * Given an \p observer and a direction vector \p directionVector defining a ray, - * compute the surface intercept of the ray on a \p target body at a specified + * Given an \p observer and a probing direction vector \p directionVector defining a + * ray, compute the surface intercept of the ray on a \p target body at a specified * \p targetEpoch, optionally corrected for aberrations (\p aberrationCorrection). - * \param target Name of target body - * \param observer Name of observing body + * \param target The name of target body + * \param observer The name of the observer * \param fovFrame Reference frame of the ray's direction vector - * \param bodyFixedFrame Body-fixed, body-centered target body frame - * \param method Computation method - * \param aberrationCorrection Aberration correction + * \param referenceFrame The reference frame in which the surface intercept and the + * surface vector are expressed + * \param aberrationCorrection The aberration correction method that is applied to + * compute the intercept * \param ephemerisTime Intercept time in ephemeris seconds past J2000 TDB - * \param directionVector Ray's direction vector + * \param directionVector Probing ray's direction * \param surfaceIntercept Surface intercept point on the target body * \param surfaceVector Vector from observer to intercept point * \param isVisible Flag indicating whether intercept was found * \return true if not error occurred, false otherwise - * For further details, refer to - * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sincpt_c.html + * \throws SpiceKernelException If the \p target or \p observer do not name the same + * NAIF object, the \p target or \p observer name the same NAIF object or are in the + * same location, the \p referenceFrame or \p fovFrame are not recognized, + * insufficient kernel information has been loaded. + * \pre \p target must not be empty. + * \pre \p observer must not be empty. + * \pre \p The \p target and \p observer must be different strings + * \pre \p fovFrame must not be empty. + * \pre \p referenceFrame must not be empty. + * \pre \p directionVector must not be the null vector + * \post The SurfaceInterceptResult does not contain any uninitialized values. + * \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sincpt_c.html */ - bool getSurfaceIntercept(const std::string& target, - const std::string& observer, - const std::string& fovFrame, - const std::string& bodyFixedFrame, - AberrationCorrection aberrationCorrection, - double ephemerisTime, - glm::dvec3& directionVector, - glm::dvec3& surfaceIntercept, - glm::dvec3& surfaceVector, - bool& isVisible - ) const; + SurfaceInterceptResult getSurfaceIntercept(const std::string& target, + const std::string& observer, const std::string& fovFrame, + const std::string& referenceFrame, AberrationCorrection aberrationCorrection, + double ephemerisTime, const glm::dvec3& directionVector) const; /** - * Determine if a specified ephemeris object is within the - * field-of-view (FOV) of a specified instrument at a given time. - * \param instrument Name or ID code string of the instrument. - * \param target Name or ID code string of the target. - * \param observer Name or ID code string of the observer. - * \param aberrationCorrection Aberration correction method. - * \param method Type of shape model used for the target. - * \param referenceFrame Body-fixed, body-centered frame for target body. - * \param targetEpoch Time of the observation (seconds past J2000). - * \param isVisible true if the target is visible - * \return The success of the function - * For further detail, refer to - * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/fovtrg_c.html + * Determine whether a specific \p target is in the field-of-view of a specified + * \p instrument or an \p observer at a given time, using the reference frame + * \p referenceFrame. + * \param target The name or NAIF ID code string of the target + * \param observer The name or NAIF ID code string of the observer + * \param referenceFrame Body-fixed, body-centered frame for target body + * \param instrument The name or NAIF ID code string of the instrument + * \param method The type of shape model used for the target + * \param aberrationCorrection The aberration correction method + * \param ephemerisTime Time of the observation (seconds past J2000) + * \return true if the target is visible, false otherwise + * \throws SpiceKernelException If the \p target or \p observer do not name valid + * NAIF objects, the \p target or \p observer name the same NAIF object, the + * \p instrument does not name a valid NAIF object, or insufficient kernel information + * has been loaded. + * \pre \p target must not be empty. + * \pre \p observer must not be empty. + * \pre \p target and \p observer must not be different strings + * \pre \p referenceFrame must not be empty. + * \pre \p instrument must not be empty. + * \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/fovtrg_c.html */ - bool targetWithinFieldOfView(const std::string& instrument, - const std::string& target, - const std::string& observer, - const std::string& method, - const std::string& referenceFrame, - const std::string& aberrationCorrection, - double& targetEpoch, - bool& isVisible - ) const; + bool isTargetInFieldOfView(const std::string& target, const std::string& observer, + const std::string& referenceFrame, const std::string& instrument, + FieldOfViewMethod method, AberrationCorrection aberrationCorrection, + double& ephemerisTime) const; + /** - * This method performs the same computation as the function its overloading - * with the exception that in doing so it assumes the inertial bodyfixed frame - * is that of 'IAU' type, allowing the client to omitt the - * referenceFrame for planetary objects. + * Determine whether a specific \p target is in the field-of-view of a specified + * \p instrument or an \p observer at a given time. The reference frame used is + * derived from the \p target by converting it into an IAU inertial + * reference frame. + * \param target The name or NAIF ID code string of the target + * \param observer The name or NAIF ID code string of the observer + * \param instrument The name or NAIF ID code string of the instrument + * \param method The type of shape model used for the target + * \param aberrationCorrection The aberration correction method + * \param ephemerisTime Time of the observation (seconds past J2000) + * \return true if the target is visible, false otherwise + * \throws SpiceKernelException If the \p target or \p observer do not name valid + * NAIF objects, the \p target or \p observer name the same NAIF object, the + * \p instrument does not name a valid NAIF object, or insufficient kernel information + * has been loaded. + * \pre \p target must not be empty. + * \pre \p observer must not be empty. + * \pre \p target and \p observer must not be different strings + * \pre \p referenceFrame must not be empty. + * \pre \p instrument must not be empty. + * \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/fovtrg_c.html */ - bool targetWithinFieldOfView(const std::string& instrument, - const std::string& target, - const std::string& observer, - const std::string& method, - const std::string& aberrationCorrection, - double& targetEpoch, - bool& isVisible - ) const; - + bool isTargetInFieldOfView(const std::string& target, const std::string& observer, + const std::string& instrument, FieldOfViewMethod method, + AberrationCorrection aberrationCorrection, double& ephemerisTime) const; + + /// Struct that is used as the return value from the #getTargetState method + struct TargetStateResult { + /// The target position + glm::dvec3 position; + + /// The target velocity + glm::dvec3 velocity; + + /// One-way light time between target and observer if + /// the aberration correction is enabled + double lightTime; + }; + /** - * Returns the state vector (position and velocity) of a - * target body relative to an observer in a specific - * referenceFrame, optionally corrected for light time (planetary - * aberration) and stellar aberration (aberrationCorrection). For further - * details, refer to - * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkezr_c.html. For more - * information on NAIF IDs, refer to - * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/naif_ids.html + * Returns the state vector (position and velocity) of a \p target body relative to an + * \p observer in a specific \p referenceFrame, optionally corrected for aberration + * (\p aberrationCorrection). * \param target The target body name or the target body's NAIF ID * \param observer The observing body name or the observing body's NAIF ID * \param referenceFrame The reference frame of the output position vector - * \param aberrationCorrection The aberration correction flag out of the list of - * values (NONE, LT, LT+S, CN, - * CN+S for the reception case or XLT, XLT+S, - * XCN, or XCN+S for the transmission case. + * \param aberrationCorrection The aberration correction method * \param ephemerisTime The time at which the position is to be queried - * \param position The output containing the position of the target; if the method - * fails, the position is unchanged - * \param velocity The output containing the velocity of the target; if the method - * fails, the velocity is unchanged - * \param lightTime If the aberrationCorrection is different from - * NONE, this variable will contain the one-way light time between the - * observer and the target.If the method fails, the lightTime is unchanged - * \return true if the function was successful, false - * otherwise + * \return A TargetStateResult object that contains the position>, containing + * the position of the target; the velocity, containing the velocity of + * the target; and the lightTime, containing the one-way light time + * between the \p target and the \p observer. This method is only set if the + * \p aberrationCorrection is set to a valid different from AberrationCorrection::None + * \throws SpiceKernelException If the \p target or \p observer do not name a valid + * NAIF object, the \p referenceFrame is not a valid frame, or if there is + * insufficient kernel information. + * \pre \p target must not be empty. + * \pre \p observer must not be empty. + * \pre \p referenceFrame must not be empty. + * \post The resulting TargetStateResult is set to valid values; the + * lightTime is only set to a valid different from 0.0 if + * the \p aberrationCorrection is not AberrationCorrection::None. + * \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkezr_c.html + * \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/naif_ids.html */ - bool getTargetState(const std::string& target, - const std::string& observer, - const std::string& referenceFrame, - const std::string& aberrationCorrection, - double ephemerisTime, - glm::dvec3& position, - glm::dvec3& velocity, - double& lightTime) const; - - bool getTargetState(const std::string& target, - const std::string& observer, - const std::string& referenceFrame, - const std::string& aberrationCorrection, - double ephemerisTime, - PowerScaledCoordinate& position, - PowerScaledCoordinate& velocity, - double& lightTime) const; + TargetStateResult getTargetState(const std::string& target, + const std::string& observer, const std::string& referenceFrame, + AberrationCorrection aberrationCorrection, double ephemerisTime) const; /** - * Returns the state transformation matrix used to convert from one frame to another - * at a specified ephemerisTime. For further details, please refer to - * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sxform_c.html. + * Returns the state transformation matrix used to convert from the \p sourceFrame to + * the \p destinationFrame at a specific \p ephemerisTime. + * \param sourceFrame The name of the source reference frame + * \param destinationFrame The name of the destination reference frame + * \param ephemerisTime The time for which the transformation matrix should be + * returned + * \return The TransformMatrix containing the transformation matrix that defines the + * transformation from the \p sourceFrame to the \p destinationFrame + * \throws SpiceKernelException If the \p sourceFrame or the \p destinationFrame is + * not a valid frame + * \pre \p sourceFrame must not be empty. + * \pre \p destinatoinFrame must not be empty. + * \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/sxform_c.html + */ + TransformMatrix getStateTransformMatrix(const std::string& sourceFrame, + const std::string& destinationFrame, double ephemerisTime) const; + + /** + * Returns the matrix that transforms position vectors from the source reference frame + * \p sourceFrame to the destination reference frame \p destinationFrame at the + * specific \p ephemerisTime. * \param sourceFrame The name of the source reference frame * \param destinationFrame The name of the destination reference frame * \param ephemerisTime The time at which the transformation matrix is to be queried - * \param transformationMatrix The output containing the TransformMatrix containing - * the transformation matrix that defines the transformation from the - * sourceFrame to the destinationFrame. If the method fails - * the transformationMatrix is unchanged - * \return true if the function was successful, false - * otherwise + * \return The transformation matrix that defines the transformation from the + * \p sourceFrame to the \p destinationFrame + * \throws SpiceKernelException If there is no coverage available for the specified + * \p sourceFrame, \p destinationFrame, \p ephemerisTime combination + * \pre \p sourceFrame must not be empty + * \pre \p destinationFrame must not be empty + * \sa http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/pxform_c.html */ - bool getStateTransformMatrix(const std::string& sourceFrame, - const std::string& destinationFrame, - double ephemerisTime, - TransformMatrix& transformationMatrix) const; + glm::dmat3 getPositionTransformMatrix(const std::string& sourceFrame, + const std::string& destinationFrame, double ephemerisTime) const; /** - * Returns the matrix that transforms position vectors from one reference frame to - * another at a specified ephemerisTime. For further details, please refer to - * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/pxform_c.html. + * Returns the transformation matrix that transforms position vectors from the + * \p sourceFrame at the time \p ephemerisTimeFrom to the \p destinationFrame at the + * time \p ephemerisTimeTo. * \param sourceFrame The name of the source reference frame * \param destinationFrame The name of the destination reference frame - * \param ephemerisTime The time at which the transformation matrix is to be queried - * \param transformationMatrix The output containing the transformation matrix that - * defines the transformation from the sourceFrame to the - * destinationFrame. If the method fails the - * transformationMatrix is unchanged - * \return true if the function was successful, false - * otherwise + * \param ephemerisTimeFrom The time for the source reference frame + * \param ephemerisTimeTo The time for the destination reference frame + * \return Thetransformation matrix that maps between the \p sourceFrame at time + * \p ephemerisTimeFrom to the \p destinationFrame at the time \p ephemerisTimeTo. + * \throws SpiceKernelException If there is no coverage available for the specified + * \p sourceFrame and \p destinationFrame + * \pre \p sourceFrame must not be empty. + * \pre \p destinationFrame must not be empty. */ - bool getPositionTransformMatrix(const std::string& sourceFrame, - const std::string& destinationFrame, - double ephemerisTime, - glm::dmat3& transformationMatrix) const; - - /** - * The following overloaded function performs similar to its default - the exception being - * that it computes transformationMatrix with respect to local time offset - * between an observer and its target. This allows for the accountance of light travel of - * photons, e.g to account for instrument pointing offsets due to said phenomenon. - * \param sourceFrame The name of the source reference frame - * \param destinationFrame The name of the destination reference frame - * \param ephemerisTimeFrom Recorded/observed observation time - * \param ephemerisTimeTo Emission local target-time - * \param transformationMatrix The output containing the transformation matrix that - */ - - bool getPositionTransformMatrix(const std::string& sourceFrame, - const std::string& destinationFrame, - double ephemerisTimeFrom, - double ephemerisTimeTo, - glm::dmat3& transformationMatrix) const; - - /** - * If a transform matrix is requested for an uncovered time in the CK kernels, - * this function will insert a transform matrix in positionMatrix. - * If the coverage has not yet started, the first transform matrix will be retrieved, - * If the coverage has ended, the last transform matrix will be retrieved - * If time is in a coverage gap, the transform matrix will be interpolated - * \param time, for which an estimated transform matrix is desirable - * \param fromFrame, the transform matrix will be retrieved in relation to this frame - * \param toFrame, the frame missing CK data for this time - * \param positionMatrix, the estimated transform matrix of the frame, passed by reference - * \return true if an estimated transform matrix is found - */ - bool getEstimatedTransformMatrix(const double time, const std::string fromFrame, const std::string toFrame, glm::dmat3& positionMatrix) const; - - + glm::dmat3 getPositionTransformMatrix(const std::string& sourceFrame, + const std::string& destinationFrame, double ephemerisTimeFrom, + double ephemerisTimeTo) const; /** * Applies the transformationMatrix retrieved from @@ -823,9 +855,29 @@ private: * \post If an exception is thrown, \p lightTime will not be modified */ glm::dvec3 getEstimatedPosition(const std::string& target, - const std::string& observer, const std::string& referenceFrame, - AberrationCorrection aberrationCorrection, double ephemerisTime, - double& lightTime) const; + const std::string& observer, const std::string& referenceFrame, + AberrationCorrection aberrationCorrection, double ephemerisTime, + double& lightTime) const; + + /** + * If a transform matrix is requested for an uncovered time in the CK kernels, this + * function will an estimated matrix. If the coverage has not yet started, the first + * transform matrix will be retrieved. If the coverage has ended, the last transform + * matrix will be retrieved. If time is in a coverage gap, the transform + * matrix will be interpolated. + * \param fromFrame The transform matrix will be retrieved in relation to this frame + * \param toFrame The reference frame into which the resulting matrix will transformed + * \param time The time for which an estimated transform matrix is requested + * \return The estimated transform matrix of the frame + * \throws SpiceKernelException If there is no coverage available for the specified + * \p sourceFrame and \p destinationFrame or the reference frames do not name a valid + * NAIF frame. + * \pre \p fromFrame must not be empty + * \pre \p toFrame must not be empty + */ + glm::dmat3 getEstimatedTransformMatrix(const std::string& fromFrame, + const std::string& toFrame, double time) const; + /// A list of all loaded kernels std::vector _loadedKernels; diff --git a/modules/base/ephemeris/spiceephemeris.cpp b/modules/base/ephemeris/spiceephemeris.cpp index 85e12f474f..e687a512e2 100644 --- a/modules/base/ephemeris/spiceephemeris.cpp +++ b/modules/base/ephemeris/spiceephemeris.cpp @@ -82,8 +82,7 @@ void SpiceEphemeris::update(const UpdateData& data) { return; double lightTime = 0.0; - glm::dvec3 position = SpiceManager::ref().targetPosition(_targetName, _originName, - "GALACTIC", SpiceManager::AberrationCorrection(), data.time, lightTime); + glm::dvec3 position = SpiceManager::ref().targetPosition(_targetName, _originName, "GALACTIC", {}, data.time, lightTime); //double interval = openspace::ImageSequencer2::ref().getIntervalLength(); //if (_ghosting == "TRUE" && interval > 60){ diff --git a/modules/base/rendering/renderableconstellationbounds.cpp b/modules/base/rendering/renderableconstellationbounds.cpp index 52fa9785a7..558803e3ae 100644 --- a/modules/base/rendering/renderableconstellationbounds.cpp +++ b/modules/base/rendering/renderableconstellationbounds.cpp @@ -179,11 +179,10 @@ void RenderableConstellationBounds::update(const UpdateData& data) { if (_program->isDirty()) _program->rebuildFromFile(); - SpiceManager::ref().getPositionTransformMatrix( + _stateMatrix = SpiceManager::ref().getPositionTransformMatrix( _originReferenceFrame, "GALACTIC", - data.time, - _stateMatrix + data.time ); } diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index d76787cf3b..db13df15ae 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -184,7 +184,7 @@ void RenderableModel::render(const RenderData& data) { _alpha = 1.0f; glm::dvec3 p = - SpiceManager::ref().targetPosition(_target, "SUN", "GALACTIC", SpiceManager::AberrationCorrection(), time, lt); + SpiceManager::ref().targetPosition(_target, "SUN", "GALACTIC", {}, time, lt); psc tmppos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); glm::vec3 cam_dir = glm::normalize(data.camera.position().vec3() - tmppos.vec3()); _programObject->setUniform("cam_dir", cam_dir); @@ -242,12 +242,13 @@ void RenderableModel::update(const UpdateData& data) { //} // set spice-orientation in accordance to timestamp - if (!_source.empty()) - openspace::SpiceManager::ref().getPositionTransformMatrix(_source, _destination, _time, _stateMatrix); + if (!_source.empty()) { + _stateMatrix = SpiceManager::ref().getPositionTransformMatrix(_source, _destination, _time); + } double lt; glm::dvec3 p = - openspace::SpiceManager::ref().targetPosition("SUN", _target, "GALACTIC", SpiceManager::AberrationCorrection(), _time, lt); + openspace::SpiceManager::ref().targetPosition("SUN", _target, "GALACTIC", {}, _time, lt); _sunPosition = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); } diff --git a/modules/base/rendering/renderablepath.cpp b/modules/base/rendering/renderablepath.cpp index 784caa4ba2..ebefd57a2e 100644 --- a/modules/base/rendering/renderablepath.cpp +++ b/modules/base/rendering/renderablepath.cpp @@ -223,7 +223,7 @@ void RenderablePath::calculatePath(std::string observer) { //float b = _lineColor[2]; for (int i = 0; i < segments; i++) { glm::dvec3 p = - SpiceManager::ref().targetPosition(_target, observer, _frame, SpiceManager::AberrationCorrection(), currentTime, lightTime); + SpiceManager::ref().targetPosition(_target, observer, _frame, {}, currentTime, lightTime); pscPos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); pscPos[3] += 3; diff --git a/modules/base/rendering/renderableplanet.cpp b/modules/base/rendering/renderableplanet.cpp index 7ef837325c..9f074f0365 100644 --- a/modules/base/rendering/renderableplanet.cpp +++ b/modules/base/rendering/renderableplanet.cpp @@ -183,7 +183,7 @@ void RenderablePlanet::render(const RenderData& data) double lt; glm::dvec3 p = - SpiceManager::ref().targetPosition("SUN", _target, "GALACTIC", SpiceManager::AberrationCorrection(), _time, lt); + SpiceManager::ref().targetPosition("SUN", _target, "GALACTIC", {}, _time, lt); psc sun_pos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); // setup the data to the shader @@ -217,7 +217,7 @@ void RenderablePlanet::render(const RenderData& data) void RenderablePlanet::update(const UpdateData& data){ // set spice-orientation in accordance to timestamp - openspace::SpiceManager::ref().getPositionTransformMatrix(_frame, "GALACTIC", data.time, _stateMatrix); + _stateMatrix = SpiceManager::ref().getPositionTransformMatrix(_frame, "GALACTIC", data.time); _time = data.time; } diff --git a/modules/base/rendering/renderablesphericalgrid.cpp b/modules/base/rendering/renderablesphericalgrid.cpp index a1d0bce088..ff35d37c16 100644 --- a/modules/base/rendering/renderablesphericalgrid.cpp +++ b/modules/base/rendering/renderablesphericalgrid.cpp @@ -227,9 +227,8 @@ void RenderableSphericalGrid::render(const RenderData& data){ _gridProgram->deactivate(); } -void RenderableSphericalGrid::update(const UpdateData& data){ - - openspace::SpiceManager::ref().getPositionTransformMatrix("IAU_JUPITER", "GALACTIC", data.time, _parentMatrix); +void RenderableSphericalGrid::update(const UpdateData& data) { + _parentMatrix = SpiceManager::ref().getPositionTransformMatrix("IAU_JUPITER", "GALACTIC", data.time); } } \ No newline at end of file diff --git a/modules/base/rendering/renderabletrail.cpp b/modules/base/rendering/renderabletrail.cpp index 9ce516c87b..4bb2d5b9f8 100644 --- a/modules/base/rendering/renderabletrail.cpp +++ b/modules/base/rendering/renderabletrail.cpp @@ -219,11 +219,11 @@ void RenderableTrail::update(const UpdateData& data) { glm::dvec3 p; // Update the floating current time if (start > data.time) - p = SpiceManager::ref().targetPosition(_target, _observer, _frame, SpiceManager::AberrationCorrection(), start, lightTime); + p = SpiceManager::ref().targetPosition(_target, _observer, _frame, {}, start, lightTime); else if (end < data.time) - p = SpiceManager::ref().targetPosition(_target, _observer, _frame, SpiceManager::AberrationCorrection(), end, lightTime); + p = SpiceManager::ref().targetPosition(_target, _observer, _frame, {}, end, lightTime); else - p = SpiceManager::ref().targetPosition(_target, _observer, _frame, SpiceManager::AberrationCorrection(), data.time, lightTime); + p = SpiceManager::ref().targetPosition(_target, _observer, _frame, {}, data.time, lightTime); psc pscPos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); @@ -247,7 +247,7 @@ void RenderableTrail::update(const UpdateData& data) { else if (end < et) et = end; glm::dvec3 p = - SpiceManager::ref().targetPosition(_target, _observer, _frame, SpiceManager::AberrationCorrection(), et, lightTime); + SpiceManager::ref().targetPosition(_target, _observer, _frame, {}, et, lightTime); pscPos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); pscPos[3] += 3; _vertexArray[i] = { pscPos[0], pscPos[1], pscPos[2], pscPos[3] }; @@ -300,7 +300,7 @@ void RenderableTrail::fullYearSweep(double time) { try { p = - SpiceManager::ref().targetPosition(_target, _observer, _frame, SpiceManager::AberrationCorrection(), time, lightTime); + SpiceManager::ref().targetPosition(_target, _observer, _frame, {}, time, lightTime); } catch (const SpiceManager::SpiceKernelException& e) { // This fires for PLUTO BARYCENTER and SUN and uses the only value sometimes? diff --git a/modules/newhorizons/rendering/renderablecrawlingline.cpp b/modules/newhorizons/rendering/renderablecrawlingline.cpp index cfe9d7d6a2..2ed7a2aa49 100644 --- a/modules/newhorizons/rendering/renderablecrawlingline.cpp +++ b/modules/newhorizons/rendering/renderablecrawlingline.cpp @@ -148,8 +148,7 @@ void RenderableCrawlingLine::render(const RenderData& data) { void RenderableCrawlingLine::update(const UpdateData& data) { if (_program->isDirty()) _program->rebuildFromFile(); - glm::dmat3 transformMatrix = glm::dmat3(1); - openspace::SpiceManager::ref().getPositionTransformMatrix(_source, _referenceFrame, data.time, transformMatrix); + glm::dmat3 transformMatrix = SpiceManager::ref().getPositionTransformMatrix(_source, _referenceFrame, data.time); glm::mat4 tmp = glm::mat4(1); for (int i = 0; i < 3; i++) { diff --git a/modules/newhorizons/rendering/renderablefov.cpp b/modules/newhorizons/rendering/renderablefov.cpp index 1d0f6c5ffb..9649a5036b 100644 --- a/modules/newhorizons/rendering/renderablefov.cpp +++ b/modules/newhorizons/rendering/renderablefov.cpp @@ -78,8 +78,8 @@ RenderableFov::RenderableFov(const ghoul::Dictionary& dictionary) success = dictionary.getValue(keyInstrument, _instrumentID); ghoul_assert(success, ""); - success = dictionary.getValue(keyInstrumentMethod, _method); - ghoul_assert(success, ""); +// success = dictionary.getValue(keyInstrumentMethod, _method); +// ghoul_assert(success, ""); std::string a = "NONE"; success = dictionary.getValue(keyInstrumentAberration, a); @@ -231,11 +231,24 @@ glm::dvec3 RenderableFov::interpolate(glm::dvec3 p0, glm::dvec3 p1, float t) { // This method is the current bottleneck. psc RenderableFov::checkForIntercept(glm::dvec3 ray) { - bool intercepted = false; - openspace::SpiceManager::ref().getSurfaceIntercept(_fovTarget, _spacecraft, _instrumentID, - _frame, _aberrationCorrection, - _time, ray, ipoint, ivec, intercepted); - + std::string bodyfixed = "IAU_"; + bool convert = (_frame.find(bodyfixed) == std::string::npos); + if (convert) + bodyfixed = SpiceManager::ref().frameFromBody(_fovTarget); + else + bodyfixed = _frame; + + SpiceManager::SurfaceInterceptResult result = SpiceManager::ref().getSurfaceIntercept( + _fovTarget, _spacecraft, _instrumentID, bodyfixed, _aberrationCorrection, _time, ray); + + if (convert) { + result.surfaceVector = SpiceManager::ref().frameTransformationMatrix(bodyfixed, _frame, _time) * result.surfaceVector; + } + + ipoint = result.surfaceIntercept; + ivec = result.surfaceVector; + bool intercepted = result.interceptFound; + ivec *= 0.9999;// because fov lands exactly on top of surface we need to move it out slightly _interceptVector = PowerScaledCoordinate::CreatePowerScaledCoordinate(ivec[0], ivec[1], ivec[2]); _interceptVector[3] += 3; @@ -258,10 +271,26 @@ psc RenderableFov::orthogonalProjection(glm::dvec3 vecFov) { glm::dvec3 RenderableFov::bisection(glm::dvec3 p1, glm::dvec3 p2, double tolerance) { //check if point is on surface glm::dvec3 half = interpolate(p1, p2, 0.5f); - bool intercepted = false; - openspace::SpiceManager::ref().getSurfaceIntercept(_fovTarget, _spacecraft, _instrumentID, - _frame, _aberrationCorrection, - _time, half, ipoint, ivec, intercepted); + + std::string bodyfixed = "IAU_"; + bool convert = (_frame.find(bodyfixed) == std::string::npos); + if (convert) + bodyfixed = SpiceManager::ref().frameFromBody(_fovTarget); + else + bodyfixed = _frame; + + + SpiceManager::SurfaceInterceptResult result = SpiceManager::ref().getSurfaceIntercept( + _fovTarget, _spacecraft, _instrumentID, bodyfixed, _aberrationCorrection, _time, half); + + if (convert) { + result.surfaceVector = SpiceManager::ref().frameTransformationMatrix(bodyfixed, _frame, _time) * result.surfaceVector; + } + + ipoint = result.surfaceIntercept; + ivec = result.surfaceVector; + bool intercepted = result.interceptFound; + if (glm::distance(_previousHalf, half) < tolerance){ _previousHalf = glm::dvec3(0); return half; @@ -301,10 +330,28 @@ void RenderableFov::fovSurfaceIntercept(bool H[], std::vector bounds // IFF incident point is also non-interceptive BUT something is within FOV // we need then to check if this segment makes contact with surface glm::dvec3 half = interpolate(current, next, 0.5f); - bool intercepted; - openspace::SpiceManager::ref().getSurfaceIntercept(_fovTarget, _spacecraft, _instrumentID, - _frame, _aberrationCorrection, - _time, half, ipoint, ivec, intercepted); + + std::string bodyfixed = "IAU_"; + bool convert = (_frame.find(bodyfixed) == std::string::npos); + if (convert) + bodyfixed = SpiceManager::ref().frameFromBody(_fovTarget); + else + bodyfixed = _frame; + + + SpiceManager::SurfaceInterceptResult res = + SpiceManager::ref().getSurfaceIntercept(_fovTarget, _spacecraft, + _instrumentID, bodyfixed, _aberrationCorrection, _time, half); + + if (convert) { + res.surfaceVector = SpiceManager::ref().frameTransformationMatrix(bodyfixed, _frame, _time) * res.surfaceVector; + } + + ipoint = res.surfaceIntercept; + ivec = res.surfaceVector; + bool intercepted = res.interceptFound; + + if (intercepted){ // find the two outer most points of intersection glm::dvec3 root1 = bisection(half, current, tolerance); @@ -396,15 +443,15 @@ void RenderableFov::computeColors() { void RenderableFov::determineTarget(){ _fovTarget = _potentialTargets[0]; //default; for (int i = 0; i < _potentialTargets.size(); i++){ - bool success = openspace::SpiceManager::ref().targetWithinFieldOfView( + _withinFOV = openspace::SpiceManager::ref().isTargetInFieldOfView( + _potentialTargets[i], _spacecraft, + _instrumentID, - _potentialTargets[i], - _spacecraft, - _method, - std::string(_aberrationCorrection), - _time, - _withinFOV); - if (success && _withinFOV){ + SpiceManager::FieldOfViewMethod::Ellipsoid, + _aberrationCorrection, + _time + ); + if (_withinFOV){ _fovTarget = _potentialTargets[i]; break; } @@ -417,9 +464,25 @@ void RenderableFov::computeIntercepts(const RenderData& data){ for (int i = 0; i <= _bounds.size(); i++){ int r = (i == _bounds.size()) ? 0 : i; // compute surface intercept - openspace::SpiceManager::ref().getSurfaceIntercept(_fovTarget, _spacecraft, _instrumentID, - _frame, _aberrationCorrection, - _time, _bounds[r], ipoint, ivec, _interceptTag[r]); + std::string bodyfixed = "IAU_"; + bool convert = (_frame.find(bodyfixed) == std::string::npos); + if (convert) + bodyfixed = SpiceManager::ref().frameFromBody(_fovTarget); + else + bodyfixed = _frame; + + SpiceManager::SurfaceInterceptResult res = + SpiceManager::ref().getSurfaceIntercept(_fovTarget, _spacecraft, + _instrumentID, bodyfixed, _aberrationCorrection, _time, _bounds[r]); + + if (convert) { + res.surfaceVector = SpiceManager::ref().frameTransformationMatrix(bodyfixed, _frame, _time) * res.surfaceVector; + } + + ipoint = res.surfaceIntercept; + ivec = res.surfaceVector; + _interceptTag[r] = res.interceptFound; + // if not found, use the orthogonal projected point if (!_interceptTag[r]) _projectionBounds[r] = orthogonalProjection(_bounds[r]); @@ -510,7 +573,7 @@ void RenderableFov::render(const RenderData& data) { void RenderableFov::update(const UpdateData& data) { _time = data.time; - openspace::SpiceManager::ref().getPositionTransformMatrix(_instrumentID, _frame, data.time, _stateMatrix); + _stateMatrix = SpiceManager::ref().getPositionTransformMatrix(_instrumentID, _frame, data.time); _spacecraftRotation = glm::mat4(1); for (int i = 0; i < 3; i++){ for (int j = 0; j < 3; j++){ diff --git a/modules/newhorizons/rendering/renderablefov.h b/modules/newhorizons/rendering/renderablefov.h index d1290351f7..2327dc6cf6 100644 --- a/modules/newhorizons/rendering/renderablefov.h +++ b/modules/newhorizons/rendering/renderablefov.h @@ -96,7 +96,6 @@ public: std::string _observer; std::string _frame; std::string _instrumentID; - std::string _method; SpiceManager::AberrationCorrection _aberrationCorrection; std::string _fovTarget; glm::dvec3 ipoint, ivec; diff --git a/modules/newhorizons/rendering/renderablemodelprojection.cpp b/modules/newhorizons/rendering/renderablemodelprojection.cpp index a2670285b0..d6d4eaa7a1 100644 --- a/modules/newhorizons/rendering/renderablemodelprojection.cpp +++ b/modules/newhorizons/rendering/renderablemodelprojection.cpp @@ -351,12 +351,13 @@ void RenderableModelProjection::update(const UpdateData& data) { } // set spice-orientation in accordance to timestamp - if (!_source.empty()) - openspace::SpiceManager::ref().getPositionTransformMatrix(_source, _destination, _time, _stateMatrix); + if (!_source.empty()) { + _stateMatrix = SpiceManager::ref().getPositionTransformMatrix(_source, _destination, _time); + } double lt; glm::dvec3 p = - openspace::SpiceManager::ref().targetPosition("SUN", _target, "GALACTIC", SpiceManager::AberrationCorrection(), _time, lt); + openspace::SpiceManager::ref().targetPosition("SUN", _target, "GALACTIC", {}, _time, lt); _sunPosition = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); } @@ -406,8 +407,8 @@ void RenderableModelProjection::imageProjectGPU() { } void RenderableModelProjection::attitudeParameters(double time) { - openspace::SpiceManager::ref().getPositionTransformMatrix(_source, _destination, time, _stateMatrix); - openspace::SpiceManager::ref().getPositionTransformMatrix(_instrumentID, _destination, time, _instrumentMatrix); + _stateMatrix = SpiceManager::ref().getPositionTransformMatrix(_source, _destination, time); + _instrumentMatrix = SpiceManager::ref().getPositionTransformMatrix(_instrumentID, _destination, time); _transform = glm::mat4(1); diff --git a/modules/newhorizons/rendering/renderableplaneprojection.cpp b/modules/newhorizons/rendering/renderableplaneprojection.cpp index 3d25ded0a4..552ad2d7b6 100644 --- a/modules/newhorizons/rendering/renderableplaneprojection.cpp +++ b/modules/newhorizons/rendering/renderableplaneprojection.cpp @@ -166,7 +166,7 @@ void RenderablePlaneProjection::update(const UpdateData& data) { else _hasImage = true; - openspace::SpiceManager::ref().getPositionTransformMatrix(_target.frame, GalacticFrame, time, _stateMatrix); + _stateMatrix = SpiceManager::ref().getPositionTransformMatrix(_target.frame, GalacticFrame, time); double timePast = abs(img.startTime - _previousTime); @@ -331,7 +331,7 @@ std::string RenderablePlaneProjection::findClosestTarget(double currentTime) { double lt; glm::dvec3 p = - SpiceManager::ref().targetPosition(_spacecraft, "SSB", GalacticFrame, SpiceManager::AberrationCorrection(), currentTime, lt); + SpiceManager::ref().targetPosition(_spacecraft, "SSB", GalacticFrame, {}, currentTime, lt); psc spacecraftPos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); @@ -341,7 +341,7 @@ std::string RenderablePlaneProjection::findClosestTarget(double currentTime) { if (possibleTarget != nullptr) { hasBody = possibleTarget->hasBody(); if (hasBody && possibleTarget->getBody(targetBody)) { - openspace::SpiceManager::ref().targetWithinFieldOfView(_instrument, targetBody, _spacecraft, "ELLIPSOID", "NONE", currentTime, found); + found = SpiceManager::ref().isTargetInFieldOfView(targetBody, _spacecraft, _instrument, SpiceManager::FieldOfViewMethod::Ellipsoid, {}, currentTime); if (found){ targets.push_back(node->name()); // get name from propertyOwner distance = (node->worldPosition() - spacecraftPos).length(); diff --git a/modules/newhorizons/rendering/renderableplanetprojection.cpp b/modules/newhorizons/rendering/renderableplanetprojection.cpp index 3bca6c46c6..4ee9f68761 100644 --- a/modules/newhorizons/rendering/renderableplanetprojection.cpp +++ b/modules/newhorizons/rendering/renderableplanetprojection.cpp @@ -408,8 +408,8 @@ glm::mat4 RenderablePlanetProjection::computeProjectorMatrix(const glm::vec3 loc void RenderablePlanetProjection::attitudeParameters(double time){ // precomputations for shader - openspace::SpiceManager::ref().getPositionTransformMatrix(_frame, _mainFrame, _time, _stateMatrix); - openspace::SpiceManager::ref().getPositionTransformMatrix(_instrumentID, _mainFrame, time, _instrumentMatrix); + _stateMatrix = SpiceManager::ref().getPositionTransformMatrix(_frame, _mainFrame, _time); + _instrumentMatrix = SpiceManager::ref().getPositionTransformMatrix(_instrumentID, _mainFrame, time); _transform = glm::mat4(1); //90 deg rotation w.r.t spice req. @@ -512,7 +512,7 @@ void RenderablePlanetProjection::render(const RenderData& data){ double lt; glm::dvec3 p = - openspace::SpiceManager::ref().targetPosition("SUN", _projecteeID, "GALACTIC", SpiceManager::AberrationCorrection(), _time, lt); + openspace::SpiceManager::ref().targetPosition("SUN", _projecteeID, "GALACTIC", {}, _time, lt); psc sun_pos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); // Main renderpass diff --git a/modules/newhorizons/rendering/renderableshadowcylinder.cpp b/modules/newhorizons/rendering/renderableshadowcylinder.cpp index 1e60f381c9..71d67d3ffd 100644 --- a/modules/newhorizons/rendering/renderableshadowcylinder.cpp +++ b/modules/newhorizons/rendering/renderableshadowcylinder.cpp @@ -132,7 +132,7 @@ void RenderableShadowCylinder::render(const RenderData& data){ } void RenderableShadowCylinder::update(const UpdateData& data) { - openspace::SpiceManager::ref().getPositionTransformMatrix(_bodyFrame, _mainFrame, data.time, _stateMatrix); + _stateMatrix = SpiceManager::ref().getPositionTransformMatrix(_bodyFrame, _mainFrame, data.time); _time = data.time; if (_shader->isDirty()) _shader->rebuildFromFile(); @@ -172,10 +172,8 @@ void RenderableShadowCylinder::createCylinder() { glm::dvec3 vecLightSource = SpiceManager::ref().targetPosition(_body, _lightSource, _mainFrame, _aberration, _time, lt); - glm::dmat3 _stateMatrix; - openspace::SpiceManager::ref().getPositionTransformMatrix(_bodyFrame, _mainFrame, _time, _stateMatrix); + glm::dmat3 _stateMatrix = glm::inverse(SpiceManager::ref().getPositionTransformMatrix(_bodyFrame, _mainFrame, _time)); - _stateMatrix = glm::inverse(_stateMatrix); vecLightSource = _stateMatrix * vecLightSource; vecLightSource *= _shadowLength; diff --git a/modules/newhorizons/util/hongkangparser.cpp b/modules/newhorizons/util/hongkangparser.cpp index 04be8da049..757bb6a0e4 100644 --- a/modules/newhorizons/util/hongkangparser.cpp +++ b/modules/newhorizons/util/hongkangparser.cpp @@ -286,14 +286,14 @@ bool HongKangParser::augmentWithSpice(Image& image, double time = image.startTime; for (int k = 0; k < exposureTime; k++){ time += k; - success = openspace::SpiceManager::ref().targetWithinFieldOfView( + _withinFOV = SpiceManager::ref().isTargetInFieldOfView( + potentialTargets[i], + spacecraft, image.activeInstruments[j], - potentialTargets[i], - spacecraft, - "ELLIPSOID", - "NONE", - time, - _withinFOV); + SpiceManager::FieldOfViewMethod::Ellipsoid, + {}, + time + ); if (_withinFOV){ image.target = potentialTargets[i]; _withinFOV = false; diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 64ec5b4b04..63f7d9cc2b 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -453,7 +453,7 @@ void RenderEngine::render(const glm::mat4 &projectionMatrix, const glm::mat4 &vi double lt; glm::dvec3 p = - SpiceManager::ref().targetPosition("PLUTO", "NEW HORIZONS", "GALACTIC", SpiceManager::AberrationCorrection(), currentTime, lt); + SpiceManager::ref().targetPosition("PLUTO", "NEW HORIZONS", "GALACTIC", {}, currentTime, lt); psc nhPos = PowerScaledCoordinate::CreatePowerScaledCoordinate(p.x, p.y, p.z); float a, b, c; SpiceManager::ref().getPlanetEllipsoid("PLUTO", a, b, c); diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index 3e6e96e4f4..36d116a2a2 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -55,6 +55,15 @@ namespace { ); } } + + const char* toString(openspace::SpiceManager::FieldOfViewMethod m) { + switch (m) { + case openspace::SpiceManager::FieldOfViewMethod::Ellipsoid: + return "ELLIPSOID"; + case openspace::SpiceManager::FieldOfViewMethod::Point: + return "POINT"; + } + } } using fmt::format; @@ -506,290 +515,194 @@ glm::dmat3 SpiceManager::frameTransformationMatrix(const std::string& from, return glm::transpose(transform); } -bool SpiceManager::getSurfaceIntercept(const std::string& target, - const std::string& observer, - const std::string& fovFrame, - const std::string& referenceFrame, - AberrationCorrection aberrationCorrection, - double ephemerisTime, - glm::dvec3& directionVector, - glm::dvec3& surfaceIntercept, - glm::dvec3& surfaceVector, - bool& isVisible - ) const +SpiceManager::SurfaceInterceptResult SpiceManager::getSurfaceIntercept( + const std::string& target, const std::string& observer, const std::string& fovFrame, + const std::string& referenceFrame, AberrationCorrection aberrationCorrection, + double ephemerisTime, const glm::dvec3& directionVector) const { + ghoul_assert(!target.empty(), "Target must not be empty"); + ghoul_assert(!observer.empty(), "Observer must not be empty"); + ghoul_assert(target != observer, "Target and observer must be different"); + ghoul_assert(!fovFrame.empty(), "FOV frame must not be empty"); + ghoul_assert(!referenceFrame.empty(), "Reference frame must not be empty"); + ghoul_assert(directionVector != glm::dvec3(0.0), "Direction vector must not be zero"); + const std::string ComputationMethod = "ELLIPSOID"; - // make pretty latr - double dvec[3], spoint[3], et; - glm::dvec3 srfvec; - int found; - bool convert; - - dvec[0] = directionVector[0]; - dvec[1] = directionVector[1]; - dvec[2] = directionVector[2]; - - // allow client specify non-inertial frame. - std::string bodyfixed = "IAU_"; - convert = (referenceFrame.find(bodyfixed) == std::string::npos); - if (convert) { - bodyfixed = frameFromBody(target); - } else { - bodyfixed = referenceFrame; - } + SurfaceInterceptResult result; + SpiceBoolean found; sincpt_c(ComputationMethod.c_str(), - target.c_str(), - ephemerisTime, - bodyfixed.c_str(), - aberrationCorrection, - observer.c_str(), - fovFrame.c_str(), - dvec, - spoint, - &et, - glm::value_ptr(srfvec), - &found); + target.c_str(), + ephemerisTime, + referenceFrame.c_str(), + aberrationCorrection, + observer.c_str(), + fovFrame.c_str(), + glm::value_ptr(directionVector), + glm::value_ptr(result.surfaceIntercept), + &result.interceptEpoch, + glm::value_ptr(result.surfaceVector), + &found + ); + result.interceptFound = (found == SPICETRUE); - isVisible = (found == SPICETRUE); - - throwOnSpiceError("Error retrieving surface intercept on target '" + target + "'" + - "viewed from observer '" + observer + "' in " + - "reference frame '" + bodyfixed + "' at time '" + - std::to_string(ephemerisTime) + "'"); - - if (convert) - srfvec = SpiceManager::ref().frameTransformationMatrix(bodyfixed, referenceFrame, ephemerisTime) * srfvec; - - if (found){ - memcpy(glm::value_ptr(directionVector), dvec, sizeof(dvec)); - memcpy(glm::value_ptr(surfaceIntercept), spoint, sizeof(spoint)); - surfaceVector = srfvec; - } - return true; + throwOnSpiceError(format( + "Error retrieving surface intercept on target '{}' viewed from observer '{}' in " + "reference frame '{}' at time '{}'", + target, observer, referenceFrame, ephemerisTime + )); + + return result; } - -bool SpiceManager::targetWithinFieldOfView(const std::string& instrument, - const std::string& target, - const std::string& observer, - const std::string& method, - const std::string& referenceFrame, - const std::string& aberrationCorrection, - double& targetEpoch, - bool& isVisible - ) const +bool SpiceManager::isTargetInFieldOfView(const std::string& target, + const std::string& observer, const std::string& referenceFrame, + const std::string& instrument, FieldOfViewMethod method, + AberrationCorrection aberrationCorrection, double& ephemerisTime) const { + ghoul_assert(!target.empty(), "Target must not be empty"); + ghoul_assert(!observer.empty(), "Observer must not be empty"); + ghoul_assert(target != observer, "Target and observer must be different"); + ghoul_assert(!referenceFrame.empty(), "Reference frame must not be empty"); + ghoul_assert(!instrument.empty(), "Instrument must not be empty"); + int visible; fovtrg_c(instrument.c_str(), - target.c_str(), - method.c_str(), - referenceFrame.c_str(), - aberrationCorrection.c_str(), - observer.c_str(), - &targetEpoch, - &visible); - isVisible = (visible == SPICETRUE); + target.c_str(), + toString(method), + referenceFrame.c_str(), + aberrationCorrection, + observer.c_str(), + &ephemerisTime, + &visible + ); - throwOnSpiceError("Checking if target '" + target + - "' is in view of instrument '" + instrument + "' failed"); + throwOnSpiceError(format( + "Checking if target '{}' is in view of instrument '{}' failed", + target, instrument + )); - return true; + return visible == SPICETRUE; } -bool SpiceManager::targetWithinFieldOfView(const std::string& instrument, - const std::string& target, - const std::string& observer, - const std::string& method, - const std::string& aberrationCorrection, - double& targetEpoch, - bool& isVisible - ) const{ - - int visible; - - std::string frame = frameFromBody(target); - - fovtrg_c(instrument.c_str(), - target.c_str(), - method.c_str(), - frame.c_str(), - aberrationCorrection.c_str(), - observer.c_str(), - &targetEpoch, - &visible); - isVisible = (visible == SPICETRUE); - - throwOnSpiceError("Checking if target '" + target + - "' is in view of instrument '" + instrument + "' failed"); - - return true; -} - - -// Not called at the moment @AA -bool SpiceManager::getTargetState(const std::string& target, - const std::string& observer, - const std::string& referenceFrame, - const std::string& aberrationCorrection, - double ephemerisTime, - glm::dvec3& targetPosition, - glm::dvec3& targetVelocity, - double& lightTime) const +bool SpiceManager::isTargetInFieldOfView(const std::string& target, + const std::string& observer, const std::string& instrument, + FieldOfViewMethod method, AberrationCorrection aberrationCorrection, + double& ephemerisTime) const { + return isTargetInFieldOfView( + target, + observer, + frameFromBody(target), + instrument, + method, + aberrationCorrection, + ephemerisTime + ); +} + +SpiceManager::TargetStateResult SpiceManager::getTargetState(const std::string& target, + const std::string& observer, const std::string& referenceFrame, + AberrationCorrection aberrationCorrection, double ephemerisTime) const +{ + ghoul_assert(!target.empty(), "Target must not be empty"); + ghoul_assert(!observer.empty(), "Observer must not be empty"); + ghoul_assert(!referenceFrame.empty(), "Reference frame must not be empty"); + + TargetStateResult result; + result.lightTime = 0.0; + double buffer[6]; + + spkezr_c( + target.c_str(), + ephemerisTime, + referenceFrame.c_str(), + aberrationCorrection, + observer.c_str(), + buffer, + &result.lightTime + ); + + throwOnSpiceError(format( + "Error retrieving state of target '{}' viewed from observer '{}' in reference " + "frame '{}' at time '{}'", + target, observer, referenceFrame, ephemerisTime + )); + + memmove(glm::value_ptr(result.position), buffer, sizeof(double) * 3); + memmove(glm::value_ptr(result.velocity), buffer + 3, sizeof(double) * 3); + return result; +} + +SpiceManager::TransformMatrix SpiceManager::getStateTransformMatrix( + const std::string& fromFrame, const std::string& toFrame, double ephemerisTime) const +{ + ghoul_assert(!fromFrame.empty(), "fromFrame must not be empty"); + ghoul_assert(!toFrame.empty(), "toFrame must not be empty"); - spkezr_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), - aberrationCorrection.c_str(), observer.c_str(), buffer, &lightTime); - - throwOnSpiceError("Error retrieving state of target '" + target + "'" + - "viewed from observer '" + observer + "' in " + - "reference frame '" + referenceFrame + "' at time '" + - std::to_string(ephemerisTime) + "'"); - memmove(glm::value_ptr(targetPosition), buffer, sizeof(double) * 3); - memmove(glm::value_ptr(targetVelocity), buffer + 3, sizeof(double) * 3); - return true; + TransformMatrix m; + sxform_c( + fromFrame.c_str(), + toFrame.c_str(), + ephemerisTime, + reinterpret_cast(m.data()) + ); + throwOnSpiceError(format( + "Error retrieved state transform matrix from frame '{}' to frame '{}' at time " + "'{}'", + fromFrame, toFrame, ephemerisTime + )); + return m; } -// Not called at the moment @AA -bool SpiceManager::getTargetState(const std::string& target, - const std::string& observer, - const std::string& referenceFrame, - const std::string& aberrationCorrection, - double ephemerisTime, - PowerScaledCoordinate& position, - PowerScaledCoordinate& velocity, - double& lightTime) const +glm::dmat3 SpiceManager::getPositionTransformMatrix(const std::string& fromFrame, + const std::string& toFrame, double ephemerisTime) const { - double state[6]; - std::fill_n(state, 6, NULL); - - spkezr_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), - aberrationCorrection.c_str(), observer.c_str(), state, &lightTime); - - throwOnSpiceError("Error retrieving state of target '" + target + "'" + - "viewed from observer '" + observer + "' in " + - "reference frame '" + referenceFrame + "' at time '" + - std::to_string(ephemerisTime) + "'"); - - position = PowerScaledCoordinate::CreatePowerScaledCoordinate(state[0], state[1], state[2]); - velocity = PowerScaledCoordinate::CreatePowerScaledCoordinate(state[3], state[4], state[5]); - - return true; -} - -// Not called at the moment @AA -bool SpiceManager::getStateTransformMatrix(const std::string& fromFrame, - const std::string& toFrame, - double ephemerisTime, - TransformMatrix& stateMatrix) const -{ - sxform_c(fromFrame.c_str(), toFrame.c_str(), - ephemerisTime, (double(*)[6])stateMatrix.data()); + ghoul_assert(!fromFrame.empty(), "fromFrame must not be empty"); + ghoul_assert(!toFrame.empty(), "toFrame must not be empty"); - throwOnSpiceError("Error retrieved state transform matrix from frame '" + - fromFrame + "' to frame '" + toFrame + "' at time '" + - std::to_string(ephemerisTime) + "'"); - return true; -} - -bool SpiceManager::getPositionTransformMatrix(const std::string& fromFrame, - const std::string& toFrame, - double ephemerisTime, - glm::dmat3& positionMatrix) const -{ - bool estimated = false; - pxform_c(fromFrame.c_str(), toFrame.c_str(), - ephemerisTime, (double(*)[3])glm::value_ptr(positionMatrix)); + glm::dmat3 result; + pxform_c( + fromFrame.c_str(), + toFrame.c_str(), + ephemerisTime, + reinterpret_cast(glm::value_ptr(result)) + ); SpiceBoolean success = !(failed_c()); reset_c(); - if (!success) { - estimated = getEstimatedTransformMatrix(ephemerisTime, fromFrame, toFrame, positionMatrix); - } + bool estimated = false; + if (!success) + result = getEstimatedTransformMatrix(fromFrame, toFrame, ephemerisTime); - positionMatrix = glm::transpose(positionMatrix); - - return estimated || success; + return glm::transpose(result); } -// Not called at the moment @AA -bool SpiceManager::getPositionTransformMatrix(const std::string& fromFrame, - const std::string& toFrame, - double ephemerisTimeFrom, - double ephemerisTimeTo, - glm::dmat3& positionMatrix) const{ - - pxfrm2_c(fromFrame.c_str(), toFrame.c_str(), ephemerisTimeFrom, ephemerisTimeTo, (double(*)[3])glm::value_ptr(positionMatrix)); - - 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 true; -} - - -bool SpiceManager::getEstimatedTransformMatrix(const double time, const std::string fromFrame, - const std::string toFrame, glm::dmat3& positionMatrix) const +glm::dmat3 SpiceManager::getPositionTransformMatrix(const std::string& fromFrame, + const std::string& toFrame, double ephemerisTimeFrom, double ephemerisTimeTo) const { - int idFrame; - - bool frameFound = hasFrameId(fromFrame); - if (!frameFound) { - return false; - } - idFrame = frameId(fromFrame); + ghoul_assert(!fromFrame.empty(), "fromFrame must not be empty"); + ghoul_assert(!toFrame.empty(), "toFrame must not be empty"); - if (_ckCoverageTimes.find(idFrame) == _ckCoverageTimes.end()){ // no coverage - return false; - } + glm::dmat3 result; - double earlier, later, difference, quote; - - std::set coveredTimes = _ckCoverageTimes.find(idFrame)->second; - - std::set::iterator first = coveredTimes.begin(); - std::set::iterator last = coveredTimes.end(); - - if (coveredTimes.lower_bound(time) == first) { // coverage later, fetch first transform - pxform_c(fromFrame.c_str(), toFrame.c_str(), - *first, (double(*)[3])glm::value_ptr(positionMatrix)); - } - else if (coveredTimes.upper_bound(time) == last) { // coverage earlier, fetch last transform - pxform_c(fromFrame.c_str(), toFrame.c_str(), - *(coveredTimes.rbegin()), (double(*)[3])glm::value_ptr(positionMatrix)); - } - else { // coverage both earlier and later, interpolate these transformations - earlier = *std::prev((coveredTimes.lower_bound(time))); - later = *(coveredTimes.upper_bound(time)); - - glm::dmat3 earlierTransform, laterTransform; - - pxform_c(fromFrame.c_str(), toFrame.c_str(), - earlier, (double(*)[3])glm::value_ptr(earlierTransform)); - pxform_c(fromFrame.c_str(), toFrame.c_str(), - later, (double(*)[3])glm::value_ptr(laterTransform)); - - difference = later - earlier; - quote = (time - earlier) / difference; - - for (int i = 0; i < 3; ++i) { - for (int j = 0; j < 3; ++j) { - positionMatrix[i][j] = (earlierTransform[i][j] * (1 - quote) + laterTransform[i][j] * quote); - } - } - } - throwOnSpiceError("Error estimating transform matrix from frame: " - + fromFrame + ", to frame: " + toFrame); - - return true; + pxfrm2_c( + fromFrame.c_str(), + toFrame.c_str(), + ephemerisTimeFrom, + ephemerisTimeTo, + reinterpret_cast(glm::value_ptr(result)) + ); + throwOnSpiceError(format( + "Error retrieving position transform matrix from '{}' at time '{}' to frame '{}' " + "at time '{}'", + fromFrame, ephemerisTimeFrom, toFrame, ephemerisTimeTo + )); + return glm::transpose(result); } - bool SpiceManager::getFieldOfView(const std::string& instrument, std::string& fovShape, std::string& frameName, glm::dvec3& boresightVector, std::vector& bounds) const @@ -1101,13 +1014,94 @@ glm::dvec3 SpiceManager::getEstimatedPosition(const std::string& target, )); // linear interpolation - double timeDifference = timeLater - timeEarlier; - double t = (ephemerisTime - timeEarlier) / timeDifference; + double t = (ephemerisTime - timeEarlier) / (timeLater - timeEarlier); pos = posEarlier * (1.0 - t) + posLater * t; lightTime = ltEarlier * (1.0 - t) + ltLater * t; } return pos; } + +glm::dmat3 SpiceManager::getEstimatedTransformMatrix(const std::string& fromFrame, + const std::string& toFrame, + double time) const +{ + glm::dmat3 result; + int idFrame = frameId(fromFrame); + + if (_ckCoverageTimes.find(idFrame) == _ckCoverageTimes.end()) { + // no coverage + throw SpiceKernelException(format( + "No data available for the transform matrix from '{}' to '{}' at any time", + fromFrame, toFrame + )); + } + + std::set coveredTimes = _ckCoverageTimes.find(idFrame)->second; + + if (coveredTimes.lower_bound(time) == coveredTimes.begin()) { + // coverage later, fetch first transform + pxform_c( + fromFrame.c_str(), + toFrame.c_str(), + *(coveredTimes.begin()), + reinterpret_cast(glm::value_ptr(result)) + ); + throwOnSpiceError(format( + "Error estimating transform matrix from frame '{}' to from '{}' at time '{}'", + fromFrame, toFrame, time + )); + + } + else if (coveredTimes.upper_bound(time) == coveredTimes.end()) { + // coverage earlier, fetch last transform + pxform_c( + fromFrame.c_str(), + toFrame.c_str(), + *(coveredTimes.rbegin()), + reinterpret_cast(glm::value_ptr(result)) + ); + throwOnSpiceError(format( + "Error estimating transform matrix from frame '{}' to from '{}' at time '{}'", + fromFrame, toFrame, time + )); + } + else { + // coverage both earlier and later, interpolate these transformations + double earlier = *std::prev((coveredTimes.lower_bound(time))); + double later = *(coveredTimes.upper_bound(time)); + + glm::dmat3 earlierTransform; + pxform_c( + fromFrame.c_str(), + toFrame.c_str(), + earlier, + reinterpret_cast(glm::value_ptr(earlierTransform)) + ); + throwOnSpiceError(format( + "Error estimating transform matrix from frame '{}' to from '{}' at time '{}'", + fromFrame, toFrame, time + )); + + glm::dmat3 laterTransform; + pxform_c( + fromFrame.c_str(), + toFrame.c_str(), + later, + reinterpret_cast(glm::value_ptr(laterTransform)) + ); + throwOnSpiceError(format( + "Error estimating transform matrix from frame '{}' to from '{}' at time '{}'", + fromFrame, toFrame, time + )); + + double t = (time - earlier) / (later - earlier); + result = earlierTransform * (1.0 - t) + laterTransform * t; + } + + return result; +} + + } // namespace openspace