diff --git a/include/openspace/rendering/model/renderablemodel.h b/include/openspace/rendering/model/renderablemodel.h index 41b22dea0e..288451053d 100644 --- a/include/openspace/rendering/model/renderablemodel.h +++ b/include/openspace/rendering/model/renderablemodel.h @@ -62,6 +62,7 @@ private: modelgeometry::ModelGeometry* _geometry; + float _alpha; glm::dmat3 _stateMatrix; std::string _source; diff --git a/include/openspace/rendering/planets/renderableplanet.h b/include/openspace/rendering/planets/renderableplanet.h index 34299e55a2..f0cc725b87 100644 --- a/include/openspace/rendering/planets/renderableplanet.h +++ b/include/openspace/rendering/planets/renderableplanet.h @@ -67,6 +67,7 @@ private: planetgeometry::PlanetGeometry* _geometry; properties::BoolProperty _performShading; properties::IntProperty _rotation; + float _alpha; glm::dmat3 _stateMatrix; diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index ef7c228232..99d9fed3d8 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -69,6 +69,8 @@ public: virtual void update(const UpdateData& data); bool isVisible() const; + bool hasTimeInterval(); + bool getInterval(double& start, double& end); protected: std::string findPath(const std::string& path); @@ -79,6 +81,9 @@ private: PowerScaledScalar boundingSphere_; std::string _relativePath; + std::string _startTime; + std::string _endTime; + bool _hasTimeInterval; }; } // namespace openspace diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index f528c8d2ff..cc0829f521 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -68,6 +68,8 @@ public: void addNode(SceneGraphNode* child); void setParent(SceneGraphNode* parent); + bool abandonChild(SceneGraphNode* child); + const psc& position() const; psc worldPosition() const; diff --git a/include/openspace/util/spicemanager.h b/include/openspace/util/spicemanager.h index 167610b335..7c73f4d3f4 100644 --- a/include/openspace/util/spicemanager.h +++ b/include/openspace/util/spicemanager.h @@ -38,6 +38,7 @@ #include #include #include +#include namespace openspace { @@ -76,15 +77,51 @@ public: */ KernelIdentifier loadKernel(const std::string& filePath); + /** + * Function to find and store the intervals covered by a ck file, this is done + * by using mainly the ckcov_c and ckobj_c functions. + * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/ckobj_c.html , + * 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 + */ + bool findCkCoverage(std::string& path); /** - * Unloads a SPICE kernel identified by the kernelId which was returned - * by the loading call to loadKernel. The unloading is done by calling the - * unload_c 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 + * Function to find and store the intervals covered by a spk file, this is done + * by using mainly the spkcov_c and spkobj_c functions. + * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/spkobj_c.html , + * 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 + */ + bool findSpkCoverage(std::string& path); + + /** + * \return true if SPK kernels have been loaded to cover target + * for time et + * \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 frame + * for time et + * \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 kernelId which was returned + * by the loading call to loadKernel. The unloading is done by calling the + * unload_c 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 + */ void unloadKernel(KernelIdentifier kernelId); /** @@ -134,6 +171,19 @@ public: */ bool getNaifId(const std::string& body, int& id) 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 id 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 frame will be stored in this variable. The + * value will only be changed if the retrieval was successful + * \return true if the frame was found, false + * otherwise + */ + bool getFrameId(const std::string& frame, int& id) const; + /** * Retrieves a single value for a certain body. This method * succeeds iff body is the name of a valid body, value @@ -252,26 +302,8 @@ public: * \return true if the conversion succeeded, false otherwise */ bool getDateFromET(double ephemerisTime, std::string& date, - const std::string& format = "YYYY MON DDTHR:MN:SC.### ::RND"); + const std::string& format = "YYYY MON DDTHR:MN:SC.### ::RND") const; - /** - * This helper method converts a 3 dimensional vector from one reference frame to another. - * \param v The vector to be converted - * \param from The frame to be converted from - * \param to The frame to be converted to - * \param ephemerisTime Time at which to get rotational matrix that transforms vector - * \return true if the conversion succeeded, false otherwise - */ - bool frameConversion(glm::dvec3& v, const std::string& from, const std::string& to, double ephemerisTime) const; - - /** - * Finds the projection of one vector onto another vector. - * All vectors are 3-dimensional. - * \param v1 The vector to be projected. - * \param v2 The vector onto which v1 is to be projected. - * \return The projection of v1 onto v2. - */ - glm::dvec3 orthogonalProjection(glm::dvec3& v1, glm::dvec3& v2); /** * Returns the position of a target body relative to an @@ -313,6 +345,39 @@ public: psc& position, double& lightTime) const; + /** + * If a position is requested for an uncovered time in the SPK kernels, + * this function will insert a position in modelPosition. + * If the coverage has not yet started, the first position will be retrieved, + * If the coverage has ended, the last position will be retrieved + * If time is in a coverage gap, the position will be interpolated + * \param time, for which an estimated position is desirable + * \param target, the body which is missing SPK data for this time + * \param origin, the observer, the position will be retrieved in relation to this body + * \param modelPosition, the position of the body, passed by reference + * \return true if an estimated position is found + */ + bool getEstimatedPosition(const double time, const std::string target, const std::string origin, psc& modelPosition) const; + + /** + * This helper method converts a 3 dimensional vector from one reference frame to another. + * \param v The vector to be converted + * \param from The frame to be converted from + * \param to The frame to be converted to + * \param ephemerisTime Time at which to get rotational matrix that transforms vector + * \return true if the conversion succeeded, false otherwise + */ + bool frameConversion(glm::dvec3& v, const std::string& from, const std::string& to, double ephemerisTime) const; + + /** + * Finds the projection of one vector onto another vector. + * All vectors are 3-dimensional. + * \param v1 The vector to be projected. + * \param v2 The vector onto which v1 is to be projected. + * \return The projection of v1 onto v2. + */ + glm::dvec3 orthogonalProjection(glm::dvec3& v1, glm::dvec3& v2); + /** * Given an observer and a direction vector defining a ray, compute * the surface intercept of the ray on a target body at a specified @@ -488,11 +553,21 @@ public: 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; + - bool getPositionPrimeMeridian(const std::string& sourceFrame, - const std::string& destinationFrame, - double ephemerisTime, - glm::dmat3& transformationMatrix) const; /** * Applies the transformationMatrix retrieved from @@ -555,88 +630,6 @@ public: */ bool getFieldOfView(int instrument, std::string& fovShape, std::string& frameName, glm::dvec3& boresightVector, std::vector& bounds) const; - - /** - * Converts planeto-centric latitude and longitude of a - * surface point on a specified body to rectangular - * coordinates. For further details, refer to - * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/srfrec_c.html. - * \param body The body on which the longitude and latitude - * are defined. This body needs to have a defined radius for this function to work - * \param longitude The longitude of the point on the body in radians - * \param latitude The latitude of the point on the body in radians - * \param coordinates The output containing the rectangular coordinates of the point - * defined by longitude and latitude on the - * body. If the method fails, the coordinate are unchanged - * \return true if the function was successful, false - * otherwise - */ - bool geographicToRectangular(const std::string& body, double longitude, - double latitude, glm::dvec3& coordinates) const; - - /** - * Converts planeto-centric latitude and longitude of a - * surface point on a body with the NAIF ID of id to rectangular - * coordinates. For further details, refer to - * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/srfrec_c.html. - * \param id The body on which the longitude and latitude - * are defined. This body needs to have a defined radius for this function to work - * \param longitude The longitude of the point on the body in radians - * \param latitude The latitude of the point on the body in radians - * \param coordinates The output containing the rectangular coordinates of the point - * defined by longitude and latitude on the - * body. If the method fails, the coordinate are unchanged - * \return true if the function was successful, false - * otherwise - */ - bool geographicToRectangular(int id, double longitude, double latitude, - glm::dvec3& coordinates) const; - /** - * Compute the rectangular coordinates of the sub-observer point of an - * observer on a target body at a specified - * ephemerisTime, optionally corrected for light time and stellar - * aberration. For further details, refer to - * http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/subpnt_c.html. - * Example: If the sub-observer point on Mars for MRO is requested, the - * target would be Mars and the observer would - * be MRO. - * \param target The name of the target body on which the sub-observer point lies - * \param observer The name of the ephemeris object whose sub-observer point should be - * retrieved - * \param computationMethod The computation method used for the sub-observer point. - * Must be one of Near point: ellipsoid or - * Intercept: ellipsoid and it determines the interpretation of the - * results; see http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/subpnt_c.html - * for detailed description on the computation methods - * \param bodyFixedFrame The body-fixed, body-centered frame belonging to the - * target - * \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 ephemerisTime The ephemeris time for which the sub-observer point should be - * retrieved - * \param subObserverPoint The output containing the observer's sub-observer point on - * the target body. If the method fails, the value remains unchanged - * \param targetEphemerisTime The output containing the target's ephemeris time - * accounting for the aberration, if an aberrationCorrection value - * different from NONE is chosen. If the method fails, the value remains - * unchanged - * \param vectorToSurfacePoint The output containing the vector from the observer to - * the, potentially aberration corrected, sub-observer point. If the method fails the - * value remains unchanged - * \return true if the function was successful, false - * otherwise - */ - bool getSubObserverPoint(const std::string& target, - const std::string& observer, - const std::string& computationMethod, - const std::string& bodyFixedFrame, - const std::string& aberrationCorrection, - double ephemerisTime, - glm::dvec3& subObserverPoint, - double& targetEphemerisTime, - glm::dvec3& vectorToSurfacePoint) const; /** * This method checks if one of the previous SPICE methods has failed. If it has, the @@ -675,6 +668,11 @@ private: /// A list of all loaded kernels std::vector _loadedKernels; + // Map: id, vector of pairs. Pair: Start time, end time; + std::map > > _ckIntervals; + std::map > > _spkIntervals; + std::map > _ckCoverageTimes; + std::map > _spkCoverageTimes; /// The last assigned kernel-id, used to determine the next free kernel id KernelIdentifier _lastAssignedKernel; @@ -684,4 +682,4 @@ private: } // namespace openspace -#endif // __SPICEMANAGER_H__ +#endif // __SPICEMANAGER_H__ \ No newline at end of file diff --git a/shaders/pscstandard_fs.glsl b/shaders/pscstandard_fs.glsl index a1787bf8b2..8842f959a1 100644 --- a/shaders/pscstandard_fs.glsl +++ b/shaders/pscstandard_fs.glsl @@ -31,7 +31,7 @@ uniform vec4 objpos; uniform vec3 sun_pos; uniform bool _performShading = true; - +uniform float transparency; uniform int shadows; uniform float time; @@ -66,7 +66,7 @@ void main() float shine = 0.0001; vec4 specular = vec4(0.5); - vec4 ambient = vec4(0.0,0.0,0.0,1); + vec4 ambient = vec4(0.0,0.0,0.0,transparency); /* if(intensity > 0.f){ // halfway vector @@ -77,12 +77,13 @@ void main() } */ diffuse = max(intensity * diffuse, ambient); - //diffuse = vec4(1); + diffuse[3] = transparency; ABufferStruct_t frag = createGeometryFragment(diffuse, position, depth); addToBuffer(frag); } else { + diffuse[3] = transparency; ABufferStruct_t frag = createGeometryFragment(diffuse, position, depth); addToBuffer(frag); } diff --git a/src/rendering/model/renderablemodel.cpp b/src/rendering/model/renderablemodel.cpp index 2e33dcc240..b266f7acd2 100644 --- a/src/rendering/model/renderablemodel.cpp +++ b/src/rendering/model/renderablemodel.cpp @@ -40,12 +40,15 @@ #include #include +#include "imgui.h" namespace { -const std::string _loggerCat = "RenderableModel"; + const std::string _loggerCat = "RenderableModel"; const std::string keySource = "Rotation.Source"; const std::string keyDestination = "Rotation.Destination"; const std::string keyBody = "Body"; + const std::string keyStart = "StartTime"; + const std::string keyEnd = "EndTime"; } namespace openspace { @@ -57,6 +60,7 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary) , _texture(nullptr) , _geometry(nullptr) , _performShading("performShading", "Perform Shading", true) + , _alpha(1.f) { std::string name; bool success = dictionary.getValue(constants::scenegraphnode::keyName, name); @@ -139,9 +143,19 @@ void RenderableModel::render(const RenderData& data) { tmp[i][j] = static_cast(_stateMatrix[i][j]); } } - transform *= tmp; + double time = openspace::Time::ref().currentTime(); + bool targetPositionCoverage = openspace::SpiceManager::ref().hasSpkCoverage(_target, time); + if (!targetPositionCoverage){ + int frame = ImGui::GetFrameCount() % 180; + float fadingFactor = sin((frame * pi_c()) / 180); + _alpha = 0.5f + fadingFactor*0.5f; + //_texture = ""; + } + else + _alpha = 1.0f; + _programObject->setUniform("transparency", _alpha); _programObject->setUniform("sun_pos", _sunPosition.vec3()); _programObject->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _programObject->setUniform("ModelTransform", transform); diff --git a/src/rendering/planets/renderableplanet.cpp b/src/rendering/planets/renderableplanet.cpp index 322c9b69d8..958507d87d 100644 --- a/src/rendering/planets/renderableplanet.cpp +++ b/src/rendering/planets/renderableplanet.cpp @@ -61,6 +61,7 @@ RenderablePlanet::RenderablePlanet(const ghoul::Dictionary& dictionary) , _geometry(nullptr) , _performShading("performShading", "Perform Shading", true) , _rotation("rotation", "Rotation", 0, 0, 360) + , _alpha(1.f) { std::string name; bool success = dictionary.getValue(constants::scenegraphnode::keyName, name); @@ -172,6 +173,7 @@ void RenderablePlanet::render(const RenderData& data) // setup the data to the shader // _programObject->setUniform("camdir", camSpaceEye); + _programObject->setUniform("transparency", _alpha); _programObject->setUniform("ViewProjection", data.camera.viewProjectionMatrix()); _programObject->setUniform("ModelTransform", transform); setPscUniforms(_programObject, &data.camera, data.position); diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index 29a6886fb0..3ed7ed06f0 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // ghoul #include @@ -36,6 +37,9 @@ namespace { const std::string _loggerCat = "Renderable"; +const std::string keyBody = "Body"; +const std::string keyStart = "StartTime"; +const std::string keyEnd = "EndTime"; } namespace openspace { @@ -67,7 +71,10 @@ Renderable* Renderable::createFromDictionary(const ghoul::Dictionary& dictionary } Renderable::Renderable(const ghoul::Dictionary& dictionary) - : _enabled("enabled", "Is Enabled", true) + : _enabled("enabled", "Is Enabled", true), + _hasTimeInterval(false), + _startTime(""), + _endTime("") { setName("renderable"); #ifndef NDEBUG @@ -86,6 +93,12 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) if (success) _relativePath += ghoul::filesystem::FileSystem::PathSeparator; + dictionary.getValue(keyStart, _startTime); + dictionary.getValue(keyEnd, _endTime); + + if (_startTime != "" && _endTime != "") + _hasTimeInterval = true; + addProperty(_enabled); } @@ -135,6 +148,20 @@ bool Renderable::isVisible() const { return _enabled; } +bool Renderable::hasTimeInterval() { + return _hasTimeInterval; +} + +bool Renderable::getInterval(double& start, double& end) { + if (_startTime != "" && _endTime != "") { + bool successStart = openspace::SpiceManager::ref().getETfromDate(_startTime, start); + bool successEnd = openspace::SpiceManager::ref().getETfromDate(_endTime, end); + return successStart && successEnd; + } + else + return false; +} + bool Renderable::isReady() const { return true; } diff --git a/src/rendering/renderablepath.cpp b/src/rendering/renderablepath.cpp index 1b56f1be7a..3eb2dfe2f0 100644 --- a/src/rendering/renderablepath.cpp +++ b/src/rendering/renderablepath.cpp @@ -83,7 +83,7 @@ bool RenderablePath::fullYearSweep(){ double lightTime = 0.0; SpiceManager::ref().getETfromDate("2006 jan 20 19:00:00", _time); - std::cout << _time << std::endl; + //std::cout << _time << std::endl; // -------------------------------------- ^ this has to be simulation start-time, not passed in here though -- //SpiceManager::ref().getETfromDate("2008 apr 01 00:00:00", et2); @@ -100,7 +100,7 @@ bool RenderablePath::fullYearSweep(){ int indx = 0; for (int i = 0; i < segments + 1; i++){ - std::cout << i << std::endl; + //std::cout << i << std::endl; bool gotData = SpiceManager::ref().getTargetPosition(_target, _observer, _frame, "LT+S", et, _pscpos, lightTime); #ifndef NDEBUG @@ -249,7 +249,7 @@ void RenderablePath::update(const UpdateData& data){ _time = data.time; _delta = static_cast(data.delta); - SpiceManager::ref().getTargetState(_target, _observer, _frame, "LT+S", data.time, _pscpos, _pscvel, lightTime); + SpiceManager::ref().getTargetPosition(_target, _observer, _frame, "NONE", data.time, _pscpos, lightTime); } diff --git a/src/rendering/renderabletrail.cpp b/src/rendering/renderabletrail.cpp index 044932897c..8ec8658672 100644 --- a/src/rendering/renderabletrail.cpp +++ b/src/rendering/renderabletrail.cpp @@ -78,13 +78,12 @@ RenderableTrail::RenderableTrail(const ghoul::Dictionary& dictionary) glm::vec3 color(0.f); if (dictionary.hasKeyAndValue(keyColor)) dictionary.getValue(keyColor, color); - _lineColor = color; - + + _lineColor = color; _lineColor.setViewOption(properties::Property::ViewOptions::Color); + addProperty(_lineColor); - addProperty(_lineFade); - addProperty(_lineWidth); } @@ -151,7 +150,7 @@ void RenderableTrail::render(const RenderData& data) { } void RenderableTrail::update(const UpdateData& data) { - if (data.isTimeJump) + if (data.isTimeJump) _needsSweep = true; if (_needsSweep) { @@ -166,7 +165,14 @@ void RenderableTrail::update(const UpdateData& data) { _programIsDirty = false; } double lightTime = 0.0; - psc pscPos, pscVel; + psc pscPos; + + bool intervalSet = hasTimeInterval(); + double start = DBL_MIN; + double end = DBL_MAX; + if (intervalSet) { + getInterval(start, end); + } // Points in the vertex array should always have a fixed distance. For this reason we // keep the first entry in the array floating and always pointing to the current date @@ -176,9 +182,13 @@ void RenderableTrail::update(const UpdateData& data) { int nValues = floor(deltaTime / _increment); // Update the floating current time - // Is 'CN+S' correct? It has to be chosen to be the same as in SpiceEphemeris, but - // unsure if it is correct ---abock - SpiceManager::ref().getTargetState(_target, _observer, _frame, "NONE", data.time, pscPos, pscVel, lightTime); + if (start > data.time) + SpiceManager::ref().getTargetPosition(_target, _observer, _frame, "NONE", start, pscPos, lightTime); + else if (end < data.time) + SpiceManager::ref().getTargetPosition(_target, _observer, _frame, "NONE", end, pscPos, lightTime); + else + SpiceManager::ref().getTargetPosition(_target, _observer, _frame, "NONE", data.time, pscPos, lightTime); + pscPos[3] += 3; // KM to M _vertexArray[0] = { pscPos[0], pscPos[1], pscPos[2], pscPos[3] }; @@ -193,8 +203,12 @@ void RenderableTrail::update(const UpdateData& data) { for (int i = nValues; i > 0; --i) { double et = _oldTime + i * _increment; - SpiceManager::ref().getTargetState(_target, _observer, _frame, "CN+S", et, pscPos, pscVel, lightTime); - pscPos[3] += 3; + if (start > et) + et = start; + else if (end < et) + et = end; + SpiceManager::ref().getTargetPosition(_target, _observer, _frame, "NONE", et, pscPos, lightTime); + pscPos[3] += 3; _vertexArray[i] = { pscPos[0], pscPos[1], pscPos[2], pscPos[3] }; } @@ -222,15 +236,28 @@ void RenderableTrail::fullYearSweep(double time) { float planetYear = SecondsPerEarthYear * _ratio; int segments = static_cast(_tropic); + bool intervalSet = hasTimeInterval(); + double start = DBL_MIN; + double end = DBL_MAX; + if (intervalSet) { + getInterval(start, end); + } + _increment = planetYear / _tropic; _oldTime = time; psc pscPos, pscVel; + bool validPosition = true; _vertexArray.resize(segments+2); - for (int i = 0; i < segments+2; i++){ - SpiceManager::ref().getTargetState(_target, _observer, _frame, "CN+S", time, pscPos, pscVel, lightTime); - pscPos[3] += 3; + for (int i = 0; i < segments+2; i++) { + if (start > time) + time = start; + else if (end < time) + time = end; + + SpiceManager::ref().getTargetPosition(_target, _observer, _frame, "NONE", time, pscPos, lightTime); + pscPos[3] += 3; _vertexArray[i] = {pscPos[0], pscPos[1], pscPos[2], pscPos[3]}; time -= _increment; diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index a9655b9938..a24dcce3c6 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -966,10 +966,16 @@ void RenderEngine::changeViewPoint(std::string origin) { SceneGraphNode* plutoBarycenterNode = scene()->sceneGraphNode("PlutoBarycenter"); SceneGraphNode* newHorizonsNode = scene()->sceneGraphNode("NewHorizons"); SceneGraphNode* jupiterBarycenterNode = scene()->sceneGraphNode("JupiterBarycenter"); + //SceneGraphNode* dawnNode = scene()->sceneGraphNode("Dawn"); + //SceneGraphNode* vestaNode = scene()->sceneGraphNode("Vesta"); - if (solarSystemBarycenterNode == nullptr || plutoBarycenterNode == nullptr || newHorizonsNode == nullptr || jupiterBarycenterNode == nullptr) { - LERROR("WTF"); - return; + if (solarSystemBarycenterNode == nullptr || plutoBarycenterNode == nullptr || + newHorizonsNode == nullptr || jupiterBarycenterNode == nullptr + //|| dawnNode == nullptr + //|| vestaNode == nullptr + ) { + LERROR("Necessary nodes does not exist"); + return; } if (origin == "Pluto") { @@ -1004,6 +1010,26 @@ void RenderEngine::changeViewPoint(std::string origin) { }; newHorizonsNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary)); + //ghoul::Dictionary dawnDictionary = + //{ + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("DAWN") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("PLUTO BARYCENTER") }, + // { std::string("Kernels"), ghoul::Dictionary() } + //}; + //dawnNode->setEphemeris(new SpiceEphemeris(dawnDictionary)); + // + //ghoul::Dictionary vestaDictionary = + //{ + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("VESTA") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("PLUTO BARYCENTER") }, + // { std::string("Kernels"), ghoul::Dictionary() } + //}; + //vestaNode->setEphemeris(new SpiceEphemeris(vestaDictionary)); + return; } if (origin == "Sun") { @@ -1037,7 +1063,28 @@ void RenderEngine::changeViewPoint(std::string origin) { { std::string("Kernels"), ghoul::Dictionary() } }; newHorizonsNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary)); - return; + + //ghoul::Dictionary dawnDictionary = + //{ + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("DAWN") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("SUN") }, + // { std::string("Kernels"), ghoul::Dictionary() } + //}; + //dawnNode->setEphemeris(new SpiceEphemeris(dawnDictionary)); + // + //ghoul::Dictionary vestaDictionary = + //{ + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("VESTA") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("SUN") }, + // { std::string("Kernels"), ghoul::Dictionary() } + //}; + //vestaNode->setEphemeris(new SpiceEphemeris(vestaDictionary)); + + return; } if (origin == "Jupiter") { ghoul::Dictionary plutoDictionary = @@ -1070,8 +1117,83 @@ void RenderEngine::changeViewPoint(std::string origin) { { std::string("Kernels"), ghoul::Dictionary() } }; newHorizonsNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary)); + + //ghoul::Dictionary dawnDictionary = + //{ + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("DAWN") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("JUPITER BARYCENTER") }, + // { std::string("Kernels"), ghoul::Dictionary() } + //}; + //dawnNode->setEphemeris(new SpiceEphemeris(dawnDictionary)); + // + //ghoul::Dictionary vestaDictionary = + //{ + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("VESTA") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("JUPITER BARYCENTER") }, + // { std::string("Kernels"), ghoul::Dictionary() } + //}; + //vestaNode->setEphemeris(new SpiceEphemeris(vestaDictionary)); + return; } + //if (origin == "Vesta") { + // ghoul::Dictionary plutoDictionary = + // { + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("PLUTO BARYCENTER") }, + // { std::string("Reference"), std::string("ECLIPJ2000") }, + // { std::string("Observer"), std::string("VESTA") }, + // { std::string("Kernels"), ghoul::Dictionary() } + // }; + // ghoul::Dictionary solarDictionary = + // { + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("SUN") }, + // { std::string("Reference"), std::string("ECLIPJ2000") }, + // { std::string("Observer"), std::string("VESTA") }, + // { std::string("Kernels"), ghoul::Dictionary() } + // }; + // + // ghoul::Dictionary jupiterDictionary = + // { + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("JUPITER BARYCENTER") }, + // { std::string("Reference"), std::string("ECLIPJ2000") }, + // { std::string("Observer"), std::string("VESTA") }, + // { std::string("Kernels"), ghoul::Dictionary() } + // }; + // + // solarSystemBarycenterNode->setEphemeris(new SpiceEphemeris(solarDictionary)); + // plutoBarycenterNode->setEphemeris(new SpiceEphemeris(plutoDictionary)); + // jupiterBarycenterNode->setEphemeris(new SpiceEphemeris(jupiterDictionary)); + // + // ghoul::Dictionary newHorizonsDictionary = + // { + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("NEW HORIZONS") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("VESTA") }, + // { std::string("Kernels"), ghoul::Dictionary() } + // }; + // newHorizonsNode->setEphemeris(new SpiceEphemeris(newHorizonsDictionary)); + // + // ghoul::Dictionary dawnDictionary = + // { + // { std::string("Type"), std::string("Spice") }, + // { std::string("Body"), std::string("DAWN") }, + // { std::string("Reference"), std::string("GALACTIC") }, + // { std::string("Observer"), std::string("VESTA") }, + // { std::string("Kernels"), ghoul::Dictionary() } + // }; + // dawnNode->setEphemeris(new SpiceEphemeris(dawnDictionary)); + // vestaNode->setEphemeris(new StaticEphemeris); + // + // return; + //} ghoul_assert(false, "This function is being misused"); } diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index fc299d7aea..ef4c1c9913 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -37,6 +37,8 @@ #include #include +#include + #include #include "ghoul/io/texture/texturereader.h" #include diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index a04d989221..84154f01ef 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -291,6 +291,17 @@ void SceneGraphNode::setParent(SceneGraphNode* parent) _parent = parent; } +bool SceneGraphNode::abandonChild(SceneGraphNode* child) { + std::vector < SceneGraphNode* >::iterator it = std::find(_children.begin(), _children.end(), child); + + if (it != _children.end()){ + _children.erase(it); + return true; + } + + return false; +} + const psc& SceneGraphNode::position() const { return _ephemeris->position(); diff --git a/src/scene/spiceephemeris.cpp b/src/scene/spiceephemeris.cpp index dd234f5442..e794521e8a 100644 --- a/src/scene/spiceephemeris.cpp +++ b/src/scene/spiceephemeris.cpp @@ -76,12 +76,12 @@ void SpiceEphemeris::update(const UpdateData& data) { SpiceManager::ref().getTargetPosition(_targetName, _originName, "GALACTIC", "NONE", data.time, position, lightTime); - if (_targetName == "NEW HORIZONS"){ + /*if (_targetName == "NEW HORIZONS"){ // In order to properly draw the viewfrustrum, the craft might have to be // positioned using the X-variations of aberration methods (ongoing investigation). SpiceManager::ref().getTargetPosition(_targetName, _originName, "GALACTIC", "NONE", data.time, position, lightTime); - } + }*/ _position = psc::CreatePowerScaledCoordinate(position.x, position.y, position.z); _position[3] += 3; diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index a6d6a89723..304cee4447 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -31,6 +31,8 @@ #include +#define MAXOBJ 1000 +#define WINSIZ 10000 namespace { const std::string _loggerCat = "SpiceManager"; @@ -75,6 +77,7 @@ SpiceManager::KernelIdentifier SpiceManager::loadKernel(const std::string& fileP } std::string&& path = absPath(filePath); + if (!FileSys.fileExists(path)) { LERROR("Kernel file '" << path << "' does not exist"); return KernelFailed; @@ -112,7 +115,16 @@ SpiceManager::KernelIdentifier SpiceManager::loadKernel(const std::string& fileP LINFO("Loading SPICE kernel '" << path << "'"); // Load the kernel furnsh_c(path.c_str()); - + + std::string fileExtension = path.substr(path.size() - 3); + if (fileExtension == ".bc" || fileExtension == ".BC") { // binary ck kernel + findCkCoverage(path); + } + else if (fileExtension == "bsp" || fileExtension == "BSP") { // binary spk kernel + findSpkCoverage(path); + } + + // Reset the current directory to the previous one FileSys.setCurrentDirectory(currentDirectory); int failed = failed_c(); @@ -135,6 +147,111 @@ SpiceManager::KernelIdentifier SpiceManager::loadKernel(const std::string& fileP } } +bool SpiceManager::findCkCoverage(std::string& path) { + SpiceInt frame, numberOfIntervals; + SpiceDouble b, e; + std::pair tempInterval; + SPICEINT_CELL(ids, MAXOBJ); + SPICEDOUBLE_CELL(cover, WINSIZ); + + ckobj_c(path.c_str(), &ids); + + for (SpiceInt i = 0; i < card_c(&ids); ++i) { + 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. + 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); + + _ckCoverageTimes[frame].insert(e); + _ckCoverageTimes[frame].insert(b); + _ckIntervals[frame].push_back(tempInterval); + } + } + return true; +} + +bool SpiceManager::findSpkCoverage(std::string& path) { + SpiceInt obj, numberOfIntervals; + SpiceDouble b, e; + std::pair 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); + } + } + return true; +} + +bool SpiceManager::hasSpkCoverage(std::string target, double& et) const +{ + int id; + bool idSuccess = getNaifId(target, id); + bool hasCoverage = false; + + std::vector< std::pair > 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 > 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; +} + void SpiceManager::unloadKernel(KernelIdentifier kernelId) { auto it = std::find_if(_loadedKernels.begin(), _loadedKernels.end(), [&kernelId](const KernelInformation& info) { return info.id == kernelId ; }); @@ -209,6 +326,20 @@ bool SpiceManager::getNaifId(const std::string& body, int& id) const { } } +bool SpiceManager::getFrameId(const std::string& frame, int& id) const { + if (frame.empty()) { + LERROR("No frame was provided"); + return false; + } + else { + SpiceInt sid = id; + namfrm_c(frame.c_str(), &sid); + id = sid; + bool hasError = SpiceManager::checkForError("Error getting id for frame '" + frame + "'"); + return !hasError; + } +} + bool getValueInternal(const std::string& body, const std::string& value, int S, double* v) { @@ -294,7 +425,7 @@ bool SpiceManager::getETfromDate(const std::string& timeString, } bool SpiceManager::getDateFromET(double ephemerisTime, std::string& date, - const std::string& format) + const std::string& format) const { static const int BufferSize = 256; @@ -322,15 +453,32 @@ bool SpiceManager::getTargetPosition(const std::string& target, glm::dvec3& position, double& lightTime) const { - spkpos_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), - aberrationCorrection.c_str(), observer.c_str(), glm::value_ptr(position), - &lightTime); + psc pscPosition = PowerScaledCoordinate::CreatePowerScaledCoordinate(position[0], position[1], position[2]); - bool hasError = checkForError("Error retrieving position of target '" + target + "'" + - " viewed from observer '" + observer + "' in reference"+ - " frame '" + referenceFrame + "' at time '" + - std::to_string(ephemerisTime) + "'"); - return !hasError; + bool targetHasCoverage = hasSpkCoverage(target, ephemerisTime); + bool observerHasCoverage = hasSpkCoverage(observer, ephemerisTime); + if (!targetHasCoverage && !observerHasCoverage){ + return false; + } + else if (targetHasCoverage && observerHasCoverage){ + spkpos_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), + aberrationCorrection.c_str(), observer.c_str(), glm::value_ptr(position), + &lightTime); + } + else if (targetHasCoverage) {// observer has no coverage + getEstimatedPosition(ephemerisTime, observer, target, pscPosition); + pscPosition = pscPosition*(-1.f); // inverse estimated position because the observer is "target" argument in funciton + position = pscPosition.vec3(); + } + else { // target has no coverage + getEstimatedPosition(ephemerisTime, target, observer, pscPosition); + position = pscPosition.vec3(); + } + + if (position[0] == 0.0 || position[1] == 0.0 || position[2] == 0.0) + return false; + + return targetHasCoverage && observerHasCoverage; } bool SpiceManager::getTargetPosition(const std::string& target, @@ -343,15 +491,92 @@ bool SpiceManager::getTargetPosition(const std::string& target, { double pos[3] = { 0.0, 0.0, 0.0}; - spkpos_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), - aberrationCorrection.c_str(), observer.c_str(), pos, &lightTime); - - if (pos[0] == 0.0 || pos[1] == 0.0|| pos[2] == 0.0) + bool targetHasCoverage = hasSpkCoverage(target, ephemerisTime); + bool observerHasCoverage = hasSpkCoverage(observer, ephemerisTime); + if (!targetHasCoverage && !observerHasCoverage){ + position = PowerScaledCoordinate::CreatePowerScaledCoordinate(pos[0], pos[1], pos[2]); return false; + } + else if (targetHasCoverage && observerHasCoverage){ + spkpos_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), + aberrationCorrection.c_str(), observer.c_str(), pos, &lightTime); + position = PowerScaledCoordinate::CreatePowerScaledCoordinate(pos[0], pos[1], pos[2]); + } + else if (targetHasCoverage) {// observer has no coverage + getEstimatedPosition(ephemerisTime, observer, target, position); + position = position*(-1.f); // inverse estimated position because the observer is "target" argument in funciton + } + else {// target has no coverage + getEstimatedPosition(ephemerisTime, target, observer, position); + } - position = PowerScaledCoordinate::CreatePowerScaledCoordinate(pos[0], pos[1], pos[2]); + return targetHasCoverage && observerHasCoverage; +} - return true; +bool SpiceManager::getEstimatedPosition(const double time, const std::string target, + const std::string observer, psc& targetPosition) const +{ + + int idTarget, idObserver; + bool targetFound = getNaifId(target, idTarget); + if (idTarget == 0) { //SOLAR SYSTEM BARYCENTER special case, no def. in kernels + targetPosition[0] = 0.f; + targetPosition[1] = 0.f; + targetPosition[2] = 0.f; + targetPosition[3] = 0.f; + return true; + } + + double pos[3] = { 0.0, 0.0, 0.0 }; + + bool observerFound = getNaifId(observer, idObserver); + if (!targetFound || !observerFound || (idTarget == idObserver)) { + return false; + } + double lt, earlier, later, difference, quote; + double pos_earlier[3] = { 0.0, 0.0, 0.0 }; + double pos_later[3] = { 0.0, 0.0, 0.0 }; + if (_spkCoverageTimes.find(idTarget) == _spkCoverageTimes.end()){ // no coverage + LWARNING("No position for " + target + " at any time, was the correct SPK Kernels loaded?"); + targetPosition = PowerScaledCoordinate::CreatePowerScaledCoordinate(pos[0], pos[1], pos[2]); + return false; + } + + std::set coveredTimes = _spkCoverageTimes.find(idTarget)->second; + + std::set::iterator first = coveredTimes.begin(); + std::set::iterator last = coveredTimes.end(); + + if (coveredTimes.lower_bound(time) == first) { // coverage later, fetch first position + spkpos_c(target.c_str(), (*first), "GALACTIC", + "NONE", observer.c_str(), pos, <); + } + else if (coveredTimes.upper_bound(time) == last) { // coverage earlier, fetch last position + spkpos_c(target.c_str(), *(coveredTimes.rbegin()), "GALACTIC", + "NONE", observer.c_str(), pos, <); + + } + else { // coverage both earlier and later, interpolate these positions + earlier = *std::prev((coveredTimes.lower_bound(time))); + later = *(coveredTimes.upper_bound(time)); + + spkpos_c(target.c_str(), earlier, "GALACTIC", + "NONE", observer.c_str(), pos_earlier, <); + spkpos_c(target.c_str(), later, "GALACTIC", + "NONE", observer.c_str(), pos_later, <); + + //linear interpolation + difference = later - earlier; + quote = (time - earlier) / difference; + pos[0] = (pos_earlier[0]*(1-quote) + pos_later[0]*quote); + pos[1] = (pos_earlier[1]*(1-quote) + pos_later[1]*quote); + pos[2] = (pos_earlier[2]*(1-quote) + pos_later[2]*quote); + } + + + targetPosition = PowerScaledCoordinate::CreatePowerScaledCoordinate(pos[0], pos[1], pos[2]); + + return targetFound && observerFound; } // do NOT remove this method. @@ -359,6 +584,12 @@ bool SpiceManager::frameConversion(glm::dvec3& v, const std::string& from, const glm::dmat3 transform; // get rotation matrix from frame A - frame B pxform_c(from.c_str(), to.c_str(), ephemerisTime, (double(*)[3])glm::value_ptr(transform)); + bool success = !failed_c(); + if (!success){ + reset_c(); + return false; + } + bool hasError = checkForError("Error converting from frame '" + from + "' to frame '" + to + "' at time " + std::to_string(ephemerisTime)); if (hasError) @@ -384,7 +615,6 @@ bool SpiceManager::targetWithinFieldOfView(const std::string& instrument, bool& isVisible ) const { - int visible; fovtrg_c(instrument.c_str(), target.c_str(), @@ -396,6 +626,12 @@ bool SpiceManager::targetWithinFieldOfView(const std::string& instrument, &visible); isVisible = (visible == SPICETRUE); + bool success = !failed_c(); + if (!success){ + reset_c(); + return false; + } + bool hasError = checkForError("Checking if target '" + target + "' is in view of instrument '" + instrument + "' failed"); @@ -426,6 +662,12 @@ bool SpiceManager::targetWithinFieldOfView(const std::string& instrument, &visible); isVisible = (visible == SPICETRUE); + bool success = !failed_c(); + if (!success){ + reset_c(); + return false; + } + bool hasError = checkForError("Checking if target '" + target + "' is in view of instrument '" + instrument + "' failed"); @@ -481,6 +723,12 @@ bool SpiceManager::getSurfaceIntercept(const std::string& target, isVisible = (found == SPICETRUE); + bool success = !failed_c(); + if (!success){ + reset_c(); + return false; + } + bool hasError = checkForError("Error retrieving surface intercept on target '" + target + "'" + "viewed from observer '" + observer + "' in " + "reference frame '" + bodyfixed + "' at time '" + @@ -500,6 +748,7 @@ bool SpiceManager::getSurfaceIntercept(const std::string& target, return true; } +// Not called at the moment @AA bool SpiceManager::getTargetState(const std::string& target, const std::string& observer, const std::string& referenceFrame, @@ -525,6 +774,7 @@ bool SpiceManager::getTargetState(const std::string& target, return !hasError; } +// Not called at the moment @AA bool SpiceManager::getTargetState(const std::string& target, const std::string& observer, const std::string& referenceFrame, @@ -540,12 +790,25 @@ bool SpiceManager::getTargetState(const std::string& target, spkezr_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), aberrationCorrection.c_str(), observer.c_str(), state, &lightTime); - position = PowerScaledCoordinate::CreatePowerScaledCoordinate(state[0], state[1], state[2]); - velocity = PowerScaledCoordinate::CreatePowerScaledCoordinate(state[3], state[4], state[5]); + bool hasError = checkForError("Error retrieving state of target '" + target + "'" + + "viewed from observer '" + observer + "' in " + + "reference frame '" + referenceFrame + "' at time '" + + std::to_string(ephemerisTime) + "'"); - return true; + 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); + } + + return !hasError; } +// Not called at the moment @AA bool SpiceManager::getStateTransformMatrix(const std::string& fromFrame, const std::string& toFrame, double ephemerisTime, @@ -560,58 +823,98 @@ bool SpiceManager::getStateTransformMatrix(const std::string& fromFrame, return !hasError; } -// I honestly dont even think we need this, deprecatable relic from previous crunch time. -bool SpiceManager::getPositionPrimeMeridian(const std::string& fromFrame, - const std::string& body, - double ephemerisTime, - glm::dmat3& positionMatrix) const{ - - int id; - getNaifId(body, id); - tipbod_c(fromFrame.c_str(), id, ephemerisTime, (double(*)[3])glm::value_ptr(positionMatrix)); - - bool hasError = checkForError("Error retrieving position transform matrix from " - "frame '" + fromFrame + "' to frame '" + body + - "at time '" + std::to_string(ephemerisTime) + "' for prime meridian"); - positionMatrix = glm::transpose(positionMatrix); - - return !hasError; -} - bool SpiceManager::getPositionTransformMatrix(const std::string& fromFrame, const std::string& toFrame, double ephemerisTime, - glm::dmat3& positionMatrix) const{ + glm::dmat3& positionMatrix) const +{ + bool success, estimated = false; pxform_c(fromFrame.c_str(), toFrame.c_str(), - ephemerisTime, (double(*)[3])glm::value_ptr(positionMatrix)); - - bool hasError = checkForError("Error retrieving position transform matrix from " - "frame '" + fromFrame + "' to frame '" + toFrame + - "' at time '" + std::to_string(ephemerisTime) + "'"); + ephemerisTime, (double(*)[3])glm::value_ptr(positionMatrix)); + + success = !(failed_c()); + if (!success) { + reset_c(); + estimated = getEstimatedTransformMatrix(ephemerisTime, fromFrame, toFrame, positionMatrix); + } + positionMatrix = glm::transpose(positionMatrix); - return !hasError; + return estimated || success; } - +// 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{ + 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)); bool hasError = checkForError("Error retrieving position transform matrix from " "frame '" + fromFrame + "' to frame '" + toFrame + "' from time '" + std::to_string(ephemerisTimeFrom) + " to time '" - + std::to_string(ephemerisTimeTo) + "'"); + + std::to_string(ephemerisTimeTo) + "'"); positionMatrix = glm::transpose(positionMatrix); return !hasError; } +bool SpiceManager::getEstimatedTransformMatrix(const double time, const std::string fromFrame, + const std::string toFrame, glm::dmat3& positionMatrix) const +{ + int idFrame; + + bool frameFound = getFrameId(fromFrame, idFrame); + if (!frameFound) { + return false; + } + if (_ckCoverageTimes.find(idFrame) == _ckCoverageTimes.end()){ // no coverage + return false; + } + + 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); + } + } + } + + return true; +} + + bool SpiceManager::getFieldOfView(const std::string& instrument, std::string& fovShape, std::string& frameName, glm::dvec3& boresightVector, std::vector& bounds) const @@ -649,6 +952,13 @@ bool SpiceManager::getFieldOfView(int instrument, &nrReturned, // the number of array values returned for the bounds (double(*)[3])boundsArr // the bounds ); + + bool success = !failed_c(); + if (!success){ + reset_c(); + return false; + } + bool hasError = checkForError("Error getting Field-of-View parameters for " "instrument '" + std::to_string(instrument) + "'"); if (hasError) @@ -667,89 +977,6 @@ bool SpiceManager::getFieldOfView(int instrument, return true; } -bool SpiceManager::geographicToRectangular(const std::string& body, - double longitude, - double latitude, - glm::dvec3& coordinates) const -{ - int id; - bool success = getNaifId(body, id); - if (!success) - return false; - else - return geographicToRectangular(id, longitude, latitude, coordinates); -} - -bool SpiceManager::geographicToRectangular(int id, double longitude, double latitude, - glm::dvec3& coordinates) const -{ - srfrec_c(id, longitude*rpd_c(), latitude*rpd_c(), glm::value_ptr(coordinates)); - bool hasError = checkForError("Error transforming geographic coordinates for '" + - std::to_string(id) + "'"); - return !hasError; -} - -bool SpiceManager::getSubObserverPoint(const std::string& target, - const std::string& observer, - const std::string& computationMethod, - const std::string& bodyFixedFrame, - const std::string& aberrationCorrection, - double ephemerisTime, - glm::dvec3& subObserverPoint, - double& targetEphemerisTime, - glm::dvec3& vectorToSurfacePoint) const -{ - if (target.empty()) { - LERROR("No target was provided"); - return false; - } - if (observer.empty()) { - LERROR("No observer was provided"); - return false; - } - if (computationMethod.empty()) { - LERROR("No computation method was provided"); - return false; - } - if (bodyFixedFrame.empty()) { - LERROR("No body fixed frame was provided"); - return false; - } - if (aberrationCorrection.empty()) { - LERROR("No aberration correction was provided"); - return false; - } - - subpnt_c(computationMethod.c_str(), - target.c_str(), - ephemerisTime, - bodyFixedFrame.c_str(), - aberrationCorrection.c_str(), - observer.c_str(), - glm::value_ptr(subObserverPoint), - &targetEphemerisTime, - glm::value_ptr(vectorToSurfacePoint) - ); - - bool hasError = checkForError("Error retrieving subobserver point on target '" + - target + "' of observer '" + observer + "' for computation method '" + - computationMethod + "' and body fixed frame '" + bodyFixedFrame + "'"); - return !hasError; -} - -void SpiceManager::applyTransformationMatrix(glm::dvec3& position, - glm::dvec3& velocity, - const TransformMatrix& transformationMatrix) -{ - double input[6]; - double output[6]; - memmove(input, glm::value_ptr(position), 3 * sizeof(glm::dvec3::value_type)); - memmove(input + 3, glm::value_ptr(velocity), 3 * sizeof(glm::dvec3::value_type)); - mxvg_c(transformationMatrix.data(), input, 6, 6, output); - memmove(glm::value_ptr(position), output, 3 * sizeof(glm::dvec3::value_type)); - memmove(glm::value_ptr(velocity), output + 3, 3 * sizeof(glm::dvec3::value_type)); -} - bool SpiceManager::checkForError(std::string errorMessage) { int failed = failed_c(); @@ -757,8 +984,8 @@ bool SpiceManager::checkForError(std::string errorMessage) { static char msg[1024]; if (!errorMessage.empty()) { getmsg_c("LONG", 1024, msg); - LERROR(errorMessage); - LERROR("Spice reported: " + std::string(msg)); + LWARNING(errorMessage); + LWARNING("Spice reported: " + std::string(msg)); } reset_c(); return true; @@ -775,9 +1002,9 @@ bool SpiceManager::getPlanetEllipsoid(std::string planetName, float &a, float &b getNaifId(planetName, id); if (bodfnd_c(id, "RADII")) { bodvrd_c(planetName.c_str(), "RADII", 3, &n, radii); - a = radii[0]; - b = radii[1]; - c = radii[2]; + a = static_cast(radii[0]); + b = static_cast(radii[1]); + c = static_cast(radii[2]); } else { LWARNING("Could not find SPICE data for the shape of " + planetName + ", using modfile value"); @@ -790,28 +1017,4 @@ bool SpiceManager::getPlanetEllipsoid(std::string planetName, float &a, float &b return !hasError; } -//bool SpiceManager::getSubSolarPoint(std::string computationMethod, -// std::string target, -// double ephemeris, -// std::string bodyFixedFrame, -// std::string aberrationCorrection, -// std::string observer, -// glm::dvec3& subSolarPoint, -// double& targetEpoch, -// glm::dvec3& vectorToSurfacePoint) const{ -// double subPoint[3], vecToSurf[3]; -// -// subslr_c(computationMethod.c_str(), -// target.c_str(), -// ephemeris, -// bodyFixedFrame.c_str(), -// aberrationCorrection.c_str(), -// observer.c_str(), subPoint, &targetEpoch, vecToSurf); -// -// memcpy(&subSolarPoint, subPoint, sizeof(double)* 3); -// memcpy(&vectorToSurfacePoint, vecToSurf, sizeof(double)* 3); -// -// return true; -//} - -} +} \ No newline at end of file diff --git a/tests/test_spicemanager.inl b/tests/test_spicemanager.inl index 16b23ad093..7be7a8f5d6 100644 --- a/tests/test_spicemanager.inl +++ b/tests/test_spicemanager.inl @@ -306,7 +306,6 @@ TEST_F(SpiceManagerTest, getStateTransformMatrix){ } mxvg_c(referenceMatrix, state, 6, 6, state_t); - openspace::SpiceManager::ref().applyTransformationMatrix(position, velocity, stateMatrix); for (int i = 0; i < 3; i++){ EXPECT_DOUBLE_EQ(position[i], state_t[i]) << "Position vector differs from its reference"; @@ -388,92 +387,3 @@ TEST_F(SpiceManagerTest, getFieldOfView){ } unload_c(META.c_str()); } -// Try to convert planetocentric coordinates to rectangular -TEST_F(SpiceManagerTest, planetocentricToRectangular){ - loadPCKKernel(); - - double lat = -35.0; //initial values - double lon = 100.0; - double rectangular_ref[3]; - SpiceInt naifId; - SpiceBoolean foundSpice; - - bodn2c_c("EARTH", &naifId, &foundSpice); - ASSERT_TRUE(foundSpice == SPICETRUE); - srfrec_c(naifId, lon*rpd_c(), lat*rpd_c(), rectangular_ref); - - glm::dvec3 rectangular; - bool found = openspace::SpiceManager::ref().geographicToRectangular("EARTH", lon, lat, rectangular); - ASSERT_TRUE(found); - - for (int i = 0; i < 3; i++){ - EXPECT_EQ(rectangular[i], rectangular_ref[i]) << "Rectangular coordinates differ from expected output"; - } - unload_c(PCK.c_str()); -} -// Try getting sub-observer point -TEST_F(SpiceManagerTest, getSubObserverPoint){ - loadMetaKernel(); - - double et; - double targetEt_ref; - double targetEt; - double subObserverPoint_ref[3]; - double vectorToSurfacePoint_ref[3]; - static SpiceChar* method[2] = { static_cast("Intercept: ellipsoid"), static_cast("Near point: ellipsoid") }; - - str2et_c("2004 jun 11 19:32:00", &et); - - glm::dvec3 subObserverPoint; - glm::dvec3 vectorToSurfacePoint; - - for (int i = 0; i < 2; i++){ - subpnt_c(method[i], "phoebe", et, "iau_phoebe", - "lt+s", "earth", subObserverPoint_ref, &targetEt_ref, vectorToSurfacePoint_ref); - - bool found = openspace::SpiceManager::ref().getSubObserverPoint( - "phoebe", "earth", method[i], "iau_phoebe", "lt+s", et, subObserverPoint, - targetEt, vectorToSurfacePoint); - ASSERT_TRUE(found); - EXPECT_EQ(targetEt_ref, targetEt); - for (int i = 0; i < 3; i++){ - EXPECT_EQ(subObserverPoint_ref[i], subObserverPoint[i]) - << "Sub-observer vector differs from its reference"; - EXPECT_EQ(vectorToSurfacePoint_ref[i], vectorToSurfacePoint[i]) - << "Observer to surface point vector differs from its reference"; - } - } - unload_c(META.c_str()); -} -// Try getting sub-solar point -//TEST_F(SpiceManagerTest, getSubSolarPoint){ -// loadMetaKernel(); -// -// double et, targetEt_ref, targetEt; -// double subSolarPoint_ref[3]; -// double vectorToSurfacePoint_ref[3]; -// static SpiceChar * method[2] = { "Intercept: ellipsoid", "Near point: ellipsoid" }; -// -// str2et_c("2004 jun 11 19:32:00", &et); -// -// glm::dvec3 subSolarPoint; -// glm::dvec3 vectorToSurfacePoint; -// -// for (int i = 0; i < 2; i++){ -// subslr_c(method[i], "phoebe", et, "iau_phoebe", -// "lt+s", "earth", subSolarPoint_ref, &targetEt_ref, vectorToSurfacePoint_ref); -// -// bool found = openspace::SpiceManager::ref().getSubSolarPoint(method[i], "phoebe", et, "iau_phoebe", -// "lt+s", "earth", subSolarPoint, -// targetEt, vectorToSurfacePoint); -// ASSERT_TRUE(found); -// EXPECT_EQ(targetEt_ref, targetEt); -// for (int i = 0; i < 3; i++){ -// EXPECT_EQ(subSolarPoint_ref[i], subSolarPoint[i]) -// << "Sub-solar vector differs from its reference"; -// EXPECT_EQ(vectorToSurfacePoint_ref[i], vectorToSurfacePoint[i]) -// << "Observer to surface point vector differs from its reference"; -// } -// } -// unload_c(META.c_str()); -//}