From aba319cbba71129282e1c208502ea745b7355f02 Mon Sep 17 00:00:00 2001 From: Michal Marcinkowski Date: Mon, 4 Aug 2014 20:43:23 +0200 Subject: [PATCH] Added SPICE C++ wrapper library with google tests and kernels At this moment only the (by NAIF considered) most cruicial c_spice API's have been covered, such as getting state vectors from one reference frame to another, simple time conversions, load/unload of single and multiple kernels etc. All of which as described in: http://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/info/mostused.html Also added linker flag to except the LIBCMTD.lib as it caused conflicts on Windows. --- CMakeLists.txt | 2 + include/openspace/tests/test_spicemanager.inl | 436 +++++++--- include/openspace/util/spicemanager.h | 180 ++-- .../SpiceTest/spicekernels/cas_iss_v09.ti | 779 ++++++++++++++++++ .../SpiceTest/spicekernels/metaKernel.tm | 3 +- src/tests/main.cpp | 18 +- src/util/spicemanager.cpp | 211 ++++- 7 files changed, 1401 insertions(+), 228 deletions(-) create mode 100644 src/tests/SpiceTest/spicekernels/cas_iss_v09.ti diff --git a/CMakeLists.txt b/CMakeLists.txt index 65c4d73523..3e2ce9a511 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,6 +30,8 @@ cmake_minimum_required (VERSION 2.8) project (OpenSpace) +SET(CMAKE_EXE_LINKER_FLAGS /NODEFAULTLIB:\"LIBCMTD.lib\") + set(OPENSPACE_BASE_DIR "${PROJECT_SOURCE_DIR}") set(OPENSPACE_EXT_DIR "${OPENSPACE_BASE_DIR}/ext") diff --git a/include/openspace/tests/test_spicemanager.inl b/include/openspace/tests/test_spicemanager.inl index 2a54d2c643..24e62103fc 100644 --- a/include/openspace/tests/test_spicemanager.inl +++ b/include/openspace/tests/test_spicemanager.inl @@ -23,9 +23,7 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #include - #include "gtest/gtest.h" - #include "openspace/util/spicemanager.h" class SpiceManagerTest : public testing::Test{ @@ -40,12 +38,10 @@ protected: void reset() { openspace::SpiceManager::deinitialize(); openspace::SpiceManager::initialize(); - - // in the reset method, deinitialize it and - // initialize it again to remove all kernels } }; +//global constants #define FILLEN 128 #define TYPLEN 32 #define SRCLEN 128 @@ -54,37 +50,42 @@ const int nrMetaKernels = 9; int which, handle, count = 0; char file[FILLEN], filtyp[TYPLEN], source[SRCLEN]; int found; +double abs_error = 0.00001; -//TODO: not hardcoded path cpck05Mar2004.tpc +// Shorthand-path definitions #define LSK absPath("${TESTDIR}/SpiceTest/spicekernels/naif0008.tls") #define PCK absPath("${TESTDIR}/SpiceTest/spicekernels/cpck05Mar2004.tpc") #define META absPath("${TESTDIR}/SpiceTest/spicekernels/metaKernel.tm") +// In this testclass only a handset of the testfunctions require a single kernel. +// The remaining methods rely on multiple kernels, loaded as a SPICE 'meta-kernel'. +#define KERNEL(param, name) int kernelID = -1; \ + kernelID = openspace::SpiceManager::ref().loadKernel(param, name); \ + EXPECT_TRUE(kernelID != -1) << "loadKernel did not return proper id"; \ + return kernelID; \ + +int loadMetaKernel() { KERNEL(META , "METAKERNEL" ); } +int loadLSKKernel() { KERNEL(LSK , "LEAPSECONDS"); } +int loadPCKKernel() { KERNEL(PCK , "CASSINI_PCK"); } + std::string fileType(char type[]){ std::string str(type); return str; } - +// Try loading single kernel TEST_F(SpiceManagerTest, loadSingleKernel){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(LSK, "LEAPSECONDS"); - EXPECT_TRUE( kernelID == 1 ) << "loadKernel did not return proper id"; - + loadLSKKernel(); //naif0008.tls is a text file, check if loaded. kdata_c(0, "text", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); - EXPECT_TRUE(found) << "Kernel not loaded"; + ASSERT_TRUE(found) << "Kernel not loaded"; unload_c(LSK.c_str()); } - +// Try loading multiple kernels via META file TEST_F(SpiceManagerTest, loadMetaKernel){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(META, "LEAPSECONDS"); - EXPECT_TRUE(kernelID != -1) << "loadKernel did not return proper id"; - - + loadMetaKernel(); // typeArr[] has values ordered to match each type of kernel // as specified in the 'metaKernel.tm' file std::string typeArr[nrMetaKernels] = { "META", "TEXT", "TEXT", @@ -97,49 +98,44 @@ TEST_F(SpiceManagerTest, loadMetaKernel){ } unload_c(META.c_str()); } - +// Try unloading kernel using user assigned keyword TEST_F(SpiceManagerTest, unloadKernelString){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(LSK, "LEAPSECONDS"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; - + loadLSKKernel(); //naif0008.tls is a text file, check if loaded. kdata_c(0, "text", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); - EXPECT_TRUE(found); + ASSERT_TRUE(found); + //unload using string keyword bool unloaded = openspace::SpiceManager::ref().unloadKernel("LEAPSECONDS"); EXPECT_TRUE(unloaded); kdata_c(0, "text", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); EXPECT_FALSE(found); } - +// Try unloading kernel using integer as ID TEST_F(SpiceManagerTest, unloadKernelInteger){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(LSK, "LEAPSECONDS"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; - + int kernelID = loadLSKKernel(); //naif0008.tls is a text file, check if loaded. kdata_c(0, "text", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); - EXPECT_TRUE(found); + ASSERT_TRUE(found); + //unload using unique int ID bool unloaded = openspace::SpiceManager::ref().unloadKernel(kernelID); - EXPECT_TRUE(unloaded); + EXPECT_TRUE(unloaded) << "Kernel did not unload"; kdata_c(0, "text", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); - EXPECT_FALSE(found); + EXPECT_FALSE(found) << "One or more kernels still present in kernel-pool"; } - +// Try unloading multiple kernels TEST_F(SpiceManagerTest, unloadMetaKernel){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(META, "METAKERNEL"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; - + loadMetaKernel(); + // The metakernel loads these kerneltypes in the exact order as in typeArr std::string typeArr[nrMetaKernels] = { "META", "TEXT", "TEXT", "SPK", "SPK", "SPK", "TEXT", "CK", "TEXT" }; for (int i = 0; i < nrMetaKernels; i++){ + // check kernelpool against typeArr kdata_c(i, "all", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); EXPECT_EQ(fileType(filtyp), typeArr[i]) << "One or more kernels did not load properly"; } @@ -147,46 +143,42 @@ TEST_F(SpiceManagerTest, unloadMetaKernel){ EXPECT_TRUE(unloaded); for (int i = 0; i < nrMetaKernels; i++){ + // the values should by now be unloaded kdata_c(i, "all", FILLEN, TYPLEN, SRCLEN, file, filtyp, source, &handle, &found); EXPECT_FALSE(found) << "Failed unloading kernel"; } unload_c(META.c_str()); } - +// Attempt finding a value in kernelpool TEST_F(SpiceManagerTest, hasValue){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(PCK, "CASSINI_PCK"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; + loadPCKKernel(); - SpiceInt n; - SpiceInt naifId = 399; //Earth - SpiceDouble radii[3]; + int n; + int naifId = 399; //Earth + double radii[3]; std::string kernelPoolValue = "RADII"; found = openspace::SpiceManager::ref().hasValue(naifId, kernelPoolValue); - EXPECT_TRUE(found); - unload_c(META.c_str()); + ASSERT_TRUE(found) << "Could not find value for specified kernel"; + unload_c(PCK.c_str()); } - +// Get 1dim value from kernelpool TEST_F(SpiceManagerTest, getValueFromID_1D){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(PCK, "CASSINI_PCK"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; + loadPCKKernel(); std::string target = "EARTH"; std::string value1D = "MAG_NORTH_POLE_LAT"; double return1D; - openspace::SpiceManager::ref().getValueFromID(target, value1D, return1D); - EXPECT_EQ(return1D, 78.565); - unload_c(META.c_str()); + found = openspace::SpiceManager::ref().getValueFromID(target, value1D, return1D); + ASSERT_TRUE(found) << "Could not retrieve value"; + EXPECT_EQ(return1D, 78.565) << "Value not found / differs from expected return"; + unload_c(PCK.c_str()); } - +// Get 2dim value from kernelpool TEST_F(SpiceManagerTest, getValueFromID_3D){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(PCK, "CASSINI_PCK"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; + loadPCKKernel(); std::string target = "EARTH"; std::string value3D = "RADII"; @@ -194,16 +186,14 @@ TEST_F(SpiceManagerTest, getValueFromID_3D){ glm::dvec3 return3D; openspace::SpiceManager::ref().getValueFromID(target, value3D, return3D); - EXPECT_EQ(return3D.x, 6378.14); - EXPECT_EQ(return3D.y, 6378.14); - EXPECT_EQ(return3D.z, 6356.75); - unload_c(META.c_str()); + EXPECT_EQ(return3D.x, 6378.14) << "Value not found / differs from expected return"; + EXPECT_EQ(return3D.y, 6378.14) << "Value not found / differs from expected return"; + EXPECT_EQ(return3D.z, 6356.75) << "Value not found / differs from expected return"; + unload_c(PCK.c_str()); } - +// Get Ndim value from kernelpool TEST_F(SpiceManagerTest, getValueFromID_ND){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(PCK, "CASSINI_PCK"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; + loadPCKKernel(); std::string target = "SATURN"; std::string valueND = "RING6_A"; @@ -211,7 +201,7 @@ TEST_F(SpiceManagerTest, getValueFromID_ND){ std::vector returnND; unsigned int nr = 5; found = openspace::SpiceManager::ref().getValueFromID(target, valueND, returnND, nr); - EXPECT_TRUE(found); + ASSERT_TRUE(found) << "Could not retrieve value for specified kernel"; std::vector controlVec{ 189870.0, 256900.0, 9000.0, 9000.0, 0.000003 }; @@ -220,13 +210,11 @@ TEST_F(SpiceManagerTest, getValueFromID_ND){ for (int i = 0; i < nr; i++){ EXPECT_EQ(controlVec[i], returnND[i]) << "Vector value not equal"; } - unload_c(META.c_str()); + unload_c(PCK.c_str()); } - +// Try converting string to Ephemeris time TEST_F(SpiceManagerTest, stringToEphemerisTime){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(LSK, "LEAPSECONDS"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; + loadLSKKernel(); double ephemerisTime; double control_ephemerisTime; @@ -235,14 +223,12 @@ TEST_F(SpiceManagerTest, stringToEphemerisTime){ ephemerisTime = openspace::SpiceManager::ref().stringToEphemerisTime(date); - EXPECT_EQ(ephemerisTime, control_ephemerisTime); - unload_c(META.c_str()); + EXPECT_EQ(ephemerisTime, control_ephemerisTime) << "Ephemeries times differ / not found"; + unload_c(LSK.c_str()); } - +// Try getting positional vector of target TEST_F(SpiceManagerTest, getTargetPosition){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(META, "METAKERNEL"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; + loadMetaKernel(); double et; double pos[3]; @@ -252,86 +238,304 @@ TEST_F(SpiceManagerTest, getTargetPosition){ str2et_c(utctime, &et); spkpos_c("EARTH", et, "J2000", "LT+S", "CASSINI", pos, <); - glm::dvec3 targetPosition; double lightTime = 0.0; found = openspace::SpiceManager::ref().getTargetPosition("EARTH", et, "J2000", "LT+S", "CASSINI", targetPosition, lightTime); ASSERT_TRUE(found); - EXPECT_DOUBLE_EQ(pos[0], targetPosition[0]); - EXPECT_DOUBLE_EQ(pos[1], targetPosition[1]); - EXPECT_DOUBLE_EQ(pos[2], targetPosition[2]); + EXPECT_DOUBLE_EQ(pos[0], targetPosition[0]) << "Position not found or differs from expected return"; + EXPECT_DOUBLE_EQ(pos[1], targetPosition[1]) << "Position not found or differs from expected return"; + EXPECT_DOUBLE_EQ(pos[2], targetPosition[2]) << "Position not found or differs from expected return"; unload_c(META.c_str()); } - +// Try getting position & velocity vectors of target TEST_F(SpiceManagerTest, getTargetState){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(META, "METAKERNEL"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; + loadMetaKernel(); - SpiceDouble et; - SpiceDouble state[6]; - SpiceDouble lt; - SpiceChar utctime[SRCLEN] = "2004 jun 11 19:32:00"; + double et; + double state[6]; + double lt; + char utctime[SRCLEN] = "2004 jun 11 19:32:00"; str2et_c(utctime, &et); spkezr_c("EARTH", et, "J2000", "LT+S", "CASSINI", state, <); - glm::dvec3 targetPosition; glm::dvec3 targetVelocity; double lightTime = 0.0; found = openspace::SpiceManager::ref().getTargetState("EARTH", et, "J2000", "LT+S", "CASSINI", - targetPosition, targetVelocity, lightTime); + targetPosition, targetVelocity, lightTime); ASSERT_TRUE(found); //x,y,z for (int i = 0; i < 3; i++){ - EXPECT_DOUBLE_EQ(state[i], targetPosition[i]) << "Position vector is wrong"; - EXPECT_DOUBLE_EQ(state[i+3], targetVelocity[i]) << "Velocity vector is wrong"; + EXPECT_DOUBLE_EQ(state[i], targetPosition[i]) << "Position not found or differs from expected return"; + EXPECT_DOUBLE_EQ(state[i+3], targetVelocity[i]) << "Velocity not found or differs from expected return"; } unload_c(META.c_str()); } +// Try getting transformation matrix and transform position and velocity into new reference frame +TEST_F(SpiceManagerTest, getStateTransformMatrix){ + loadMetaKernel(); -TEST_F(SpiceManagerTest, getPositionTransformMatrix){ - int kernelID = -1; - kernelID = openspace::SpiceManager::ref().loadKernel(META, "METAKERNEL"); - EXPECT_TRUE(kernelID == 1) << "loadKernel did not return proper id"; - - SpiceDouble et; - SpiceDouble state[6]; - SpiceDouble state_t[6]; - SpiceDouble lt; - SpiceDouble referenceMatrix[6][6]; - + double et; + double state[6]; + double state_t[6]; + double lt; + double referenceMatrix[6][6]; str2et_c("2004 jun 11 19:32:00", &et); spkezr_c("PHOEBE", et, "J2000", "LT+S", "CASSINI", state, <); sxform_c("J2000", "IAU_PHOEBE", et, referenceMatrix); - glm::mat3x3 positionMatrix; - glm::mat3x3 velocityMatrix; + glm::dvec3 position(state[0], state[1], state[2]); + glm::dvec3 velocity(state[3], state[4], state[5]); - openspace::mat6x6 stateMatrix; + openspace::transformMatrix stateMatrix(6); found = openspace::SpiceManager::ref().getStateTransformMatrix("J2000", "IAU_PHOEBE", et, - stateMatrix); + stateMatrix); ASSERT_TRUE(found); - double absolute_range = 0.00000001; - //check for matrix consistency for (int i = 0; i < 6; i++){ for (int j = 0; j < 6; j++){ - ASSERT_NEAR(referenceMatrix[i][j], stateMatrix[i][j], absolute_range) - << "Assertion failed at [" << i << ", " << j << "]"<< std::endl; + EXPECT_DOUBLE_EQ(referenceMatrix[i][j], stateMatrix(i, j)) << "State-matrix not set or has wrong values"; } } + mxvg_c(referenceMatrix, state, 6, 6, state_t); - openspace::matrix6 abc; + stateMatrix.transform(position, velocity); - abc.data[0][0] = 10; + for (int i = 0; i < 3; i++){ + EXPECT_DOUBLE_EQ(position[i], state_t[i]) << "Position vector differs from its reference"; + EXPECT_DOUBLE_EQ(velocity[i], state_t[i + 3]) << "Velocity vector differs from its reference"; + } + unload_c(META.c_str()); } +// Try getting transformation matrix and transform the position only into new reference frame +TEST_F(SpiceManagerTest, getPositionTransformMatrix){ + loadMetaKernel(); -TEST_F(SpiceManagerTest, dontknowyet){ + double et; + double lt; + double state[3] = { 1.0, 1.0, 1.0 }; + double state_t[3]; + double referenceMatrix[3][3]; -} \ No newline at end of file + str2et_c("2004 jun 11 19:32:00", &et); + pxform_c("CASSINI_HGA", "J2000", et, referenceMatrix); + + openspace::transformMatrix positionMatrix(3); + glm::dvec3 position(state[0], state[1], state[2]); + found = openspace::SpiceManager::ref().getPositionTransformMatrix("CASSINI_HGA", + "J2000", + et, + positionMatrix); + ASSERT_TRUE(found); + //check for matrix consistency + for (int i = 0; i < 3; i++){ + for (int j = 0; j < 3; j++){ + EXPECT_DOUBLE_EQ(referenceMatrix[i][j], positionMatrix(i, j)) << "Position-matrix not set or has wrong values"; + } + } + //transform reference position into new frame + mxvg_c(referenceMatrix, state, 3, 3, state_t); + + positionMatrix.transform(position); + //check transformed values match + for (int i = 0; i < 3; i++){ + EXPECT_DOUBLE_EQ(position[i], state_t[i]) << "Position vector differs from its reference"; + } + unload_c(META.c_str()); +} +// Try to get boresight vector and instrument field of view boundary vectors +TEST_F(SpiceManagerTest, getFieldOfView){ + loadMetaKernel(); + + int n; + int cassini_ID; + double et; + double lt; + double boresight[3]; + double bounds_ref[5][3]; + char shape_ref[TYPLEN]; + char name_ref[FILLEN]; + + str2et_c("2004 jun 11 19:32:00", &et); + bodn2c_c("CASSINI_ISS_NAC", &cassini_ID, &found); + if (!found){ + printf("error cannot locate ID for Cassini \n"); + } + getfov_c(cassini_ID, 5, TYPLEN, TYPLEN, shape_ref, name_ref, boresight, &n, bounds_ref); + + std::string shape, name; + shape.resize(32); + name.resize(32); + std::vector bounds; + int nrReturned; + found = openspace::SpiceManager::ref().getFieldOfView("CASSINI_ISS_NAC", + shape, + name, + boresight, + bounds, + nrReturned); + ASSERT_TRUE(found); + //check vectors have correct values + for (int i = 0; i < nrReturned; i++){ + for (int j = 0; j < 3; j++){ + EXPECT_DOUBLE_EQ(bounds_ref[i][j], bounds[i][j]) << "One or more Field of View Boundary vectors \ + differ from expected output"; + } + } + unload_c(META.c_str()); +} +// Try converting rectangular coordinates to latitudal +TEST_F(SpiceManagerTest, rectangularToLatitudal){ + loadMetaKernel(); + + char frame[FILLEN], shape[FILLEN]; + double lat, lon; + double bounds[4][3], bsight[3], + obspos[3], point_ref[3]; + double dist, et, radius_ref, trgepc; + int n, naifId; + int found; + + // First, find an intersection point to convert to rectangular coordinates + str2et_c("2004 jun 11 19:32:00", &et); + bodn2c_c("CASSINI_ISS_NAC", &naifId, &found); + getfov_c(naifId, 4, FILLEN, FILLEN, shape, frame, bsight, &n, bounds); + srfxpt_c("Ellipsoid", "PHOEBE", et, "LT+S", "CASSINI", frame, bsight, + point_ref, &dist, &trgepc, obspos, &found); + + reclat_c(point_ref, &radius_ref, &lon, &lat); + glm::dvec3 point(point_ref[0], point_ref[1], point_ref[2]); + double radius, longitude, latitude; + found = openspace::SpiceManager::ref().rectangularToLatitudal(point, radius, longitude, latitude); + + ASSERT_TRUE(found); + ASSERT_NEAR(radius, radius_ref, abs_error) << "radius is not set / has incorrect values"; + ASSERT_NEAR(longitude, lon, abs_error) << "longitude is not set / has incorrect values"; + ASSERT_NEAR(latitude, lat, abs_error) << "latitude is not set / has incorrect values"; + unload_c(META.c_str()); +} +// Try converting latitudinal coordinates to rectangular +TEST_F(SpiceManagerTest, latitudinalToRectangular){ + loadMetaKernel(); + + char frame[FILLEN], shape[FILLEN]; + double lat, lon; + double bounds[4][3], bsight[3], + obspos[3], point_ref[3]; + double dist, et, radius_ref, trgepc; + int n, naifId; + + // First, find an intersection point to convert to latitudinal coordinates // + str2et_c("2004 jun 11 19:32:00", &et); + bodn2c_c("CASSINI_ISS_NAC", &naifId, &found); + getfov_c(naifId, 4, FILLEN, FILLEN, shape, frame, bsight, &n, bounds); + srfxpt_c("Ellipsoid", "PHOEBE", et, "LT+S", "CASSINI", frame, bsight, + point_ref, &dist, &trgepc, obspos, &found); + + reclat_c(point_ref, &radius_ref, &lon, &lat); + + lat *= rpd_c(); + lon *= rpd_c(); + + double lat_ref = lat; + double lon_ref = lon; + + double rectangular_ref[3]; + latrec_c(radius_ref, lon, lat, rectangular_ref); + + glm::dvec3 coordinates; + found = openspace::SpiceManager::ref().latidudinalToRectangular(radius_ref, lon, lat, coordinates); + + ASSERT_TRUE(found); + ASSERT_NEAR(lon_ref, lon, abs_error) << "longitude is not set / has incorrect values"; + ASSERT_NEAR(lat_ref, lat, abs_error) << "latitude is not set / has incorrect values"; + 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]; + double radius; + int naifId; + + bodn2c_c("EARTH", &naifId, &found); + srfrec_c(naifId, lon*rpd_c(), lat*rpd_c(), rectangular_ref); + + glm::dvec3 rectangular; + found = openspace::SpiceManager::ref().planetocentricToRectangular("EARTH", lon, lat, rectangular); + + 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, targetEt_ref, targetEt; + double radii[3], subObserverPoint_ref[3], vectorToSurfacePoint_ref[3]; + static SpiceChar * method[2] = { "Intercept: ellipsoid", "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); + + found = openspace::SpiceManager::ref().getSubObserverPoint(method[i], "phoebe", et, "iau_phoebe", + "lt+s", "earth", 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 radii[3], subSolarPoint_ref[3], 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); + + 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()); +} diff --git a/include/openspace/util/spicemanager.h b/include/openspace/util/spicemanager.h index 8c7f0d48f0..7490e008c8 100644 --- a/include/openspace/util/spicemanager.h +++ b/include/openspace/util/spicemanager.h @@ -21,7 +21,6 @@ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ - #ifndef __SPICEWRAPPER_H__ #define __SPICEWRAPPER_H__ @@ -33,23 +32,10 @@ #include namespace openspace{ - -//just a typedef for now.. -typedef double mat6x6[6][6]; - -class matrix6{ -private: - int row, col; - double data[6][6]; -public: - matrix6& operator= (const matrix6& lhs){ - if (this != &lhs) - } -}; - +class transformMatrix; class SpiceManager{ public: -// Initialization +// Initialization ----------------------------------------------------------------------- // /** * Static initializer that initializes the static member. */ @@ -79,12 +65,13 @@ public: * * \param either correspondign unique ID or shorthand with * which the kernel was loaded and is to be unloaded. + * \return Whether the function succeeded or not */ bool unloadKernel(const std::string& shorthand); bool unloadKernel(int kernelId); -// Acessing Kernel Data - Constants and Ids +// Acessing Kernel Data - Constants and Ids --------------------------------------------- // /** * Determine whether values exist for some item for any body in the kernel pool. @@ -92,6 +79,7 @@ public: * * \param naifId ID code of body. * \param item Item to find ("RADII", "NUT_AMP_RA", etc.). + * \return Whether the function succeeded or not */ bool hasValue(int naifId, const std::string& kernelPoolValueName) const; @@ -100,28 +88,27 @@ public: * item associated with a body. * For further details, please refer to 'bodvrd_c' in SPICE Docummentation * - * \param bodyName Body name. + * \param bodyName Body name. * \param kernelPoolValueName Item for which values are desired. ("RADII", "NUT_PREC_ANGLES", etc. ) - */ + * \return Whether the function succeeded or not + */ bool SpiceManager::getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, double& value) const; - /* - bool SpiceManager::getValueFromID(const std::string& bodyname, - const std::string& kernelPoolValueName, - glm::dvec2& value) const; - */ + /* Overloaded method for 3dim vectors, see above specification.*/ bool SpiceManager::getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, glm::dvec3& value) const; + /* Overloaded method for 4dim vectors, see above specification.*/ bool SpiceManager::getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, glm::dvec4& value) const; + /* Overloaded method for Ndim vectors, see above specification.*/ bool SpiceManager::getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, std::vector& values, unsigned int num) const; -// Converting between UTC and Ephemeris Time (LSK) +// Converting between UTC and Ephemeris Time (LSK) ------------------------------------- // /** * Convert a string representing an epoch to a double precision @@ -134,7 +121,7 @@ public: */ double stringToEphemerisTime(const std::string& epochString) const; -// Computing Positions of Spacecraft and Natural Bodies(SPK) +// Computing Positions of Spacecraft and Natural Bodies(SPK) ---------------------------- // /** * Return the position of a target body relative to an observing @@ -158,7 +145,6 @@ public: const std::string& observer, glm::dvec3& targetPosition, double lightTime) const; - /** * Return the state (position and velocity) of a target body * relative to an observing body, optionally corrected for light @@ -184,7 +170,7 @@ public: glm::dvec3& targetVelocity, double lightTime) const; -// Computing Transformations Between Frames (FK) +// Computing Transformations Between Frames (FK) -------------------------------------- // /** * Return the state transformation matrix from one frame to @@ -200,15 +186,7 @@ public: bool getStateTransformMatrix(const std::string& fromFrame, const std::string& toFrame, double ephemerisTime, - mat6x6& stateMatrix) const; - - - /** - * Multiply the 6x6 stateTransformMatrix and two 3D vector, postion and velocity. - */ - bool multiplyWithStateTransmMat6x6(mat6x6 stateMatrix, - glm::dvec3 position, - glm::dvec3 velocity) const; + transformMatrix& stateMatrix) const; /** * Return the matrix that transforms position vectors from one @@ -224,9 +202,9 @@ public: bool getPositionTransformMatrix(const std::string& fromFrame, const std::string& toFrame, double ephemerisTime, - glm::mat3x3& positionTransformationMatrix) const; + transformMatrix& positionMatrix) const; -// Retrieving Instrument Parameters (IK) +// Retrieving Instrument Parameters (IK) ------------------------------------------ // /** * This routine returns the field-of-view (FOV) parameters for a @@ -239,15 +217,17 @@ public: * \param boresightVector Boresight vector. * \param numberOfBoundaryVectors Number of boundary vectors returned. * \param bounds Field Of View boundary vectors + * \param room Maximum number of vectors that can be returned. * \return Whether the function succeeded or not */ bool getFieldOfView(const std::string& naifInstrumentId, - std::string& instrumentFovShape, - std::string& nameOfFrame, - double boresightVector, - std::vector& bounds) const; + std::string& fovShape, + std::string& frameName, + double boresightVector[], + std::vector& bounds, + int& nrReturned) const; -// Computing Planetocentric, Planetodetic, and Planetographic Coordinates +// Computing Planetocentric, Planetodetic, and Planetographic Coordinates ---------- // /** * Convert from rectangular coordinates to latitudinal coordinates. @@ -259,13 +239,13 @@ public: * \param latitude Latitude of the point in radians. The range is [-pi/2, pi/2]. * \return Whether the function succeeded or not */ - bool rectangularToLatitudal(const glm::vec3 coordinates, + bool rectangularToLatitudal(const glm::dvec3 coordinates, double& radius, double& longitude, double& latitude) const; /** * Convert from latitudinal coordinates to rectangular coordinates. - * For further details, please refer to 'reclat_c ' in SPICE Docummentation + * For further details, please refer to 'latrec_c ' in SPICE Docummentation * * \param radius Distance of a point from the origin. * \param longitude Longitude of point in radians. @@ -276,7 +256,7 @@ public: bool latidudinalToRectangular(double radius, double& longitude, double& latitude, - glm::vec3& coordinates) const; + glm::dvec3& coordinates) const; /** * Convert planetocentric latitude and longitude of a surface @@ -289,12 +269,12 @@ public: * \param coordinates Rectangular coordinates of the point. * \return Whether the function succeeded or not */ - bool planetocentricToRectangular(int naif_id, + bool planetocentricToRectangular(const std::string& naifName, double& longitude, double& latitude, - glm::vec3& coordinates) const; + glm::dvec3& coordinates) const; -// Computing Sub - observer and Sub - solar Points +// Computing Sub - observer and Sub - solar Points --------------------------------- // /** * Compute the rectangular coordinates of the sub-observer point on @@ -319,9 +299,9 @@ public: std::string bodyFixedFrame, std::string aberrationCorrection, std::string observer, - glm::vec3& subObserverPoint, + glm::dvec3& subObserverPoint, double& targetEpoch, - glm::vec3& vectorToSurfacePoint) const; + glm::dvec3& vectorToSurfacePoint) const; /** * Compute the rectangular coordinates of the sub-observer point on @@ -342,34 +322,102 @@ public: */ bool getSubSolarPoint(std::string computationMethod, std::string target, - double ephemeris, + double ephemeris, std::string bodyFixedFrame, std::string aberrationCorrection, std::string observer, - glm::vec3& subObserverPoint, - double& targetEpoch, - glm::vec3& vectorToSurfacePoint) const; - - - //TODO: add additional functions for 'mxvg_c' - + glm::dvec3& subSolarPoint, + double& targetEpoch, + glm::dvec3& vectorToSurfacePoint) const; private: SpiceManager() = default; ~SpiceManager(); - SpiceManager(const SpiceManager& c) = delete; - static SpiceManager* _manager; - struct spiceKernel { std::string path; std::string name; int id; }; - std::vector _loadedKernels; - unsigned int kernelCount = 0; + unsigned int _kernelCount = 0; }; -} +/** +* SpiceManager helper class, a storage container used to +* transform state vectors from one reference frame to another. +* The client creates an instance of transformMatrix +* and after its been passed to either getStateTransformMatrix +* or getPositionTransformMatrix the instantiated object +* can transform position and velocity to any specified reference frame. +* +* Client-sied example: +* openspace::transformMatrix m(6); +* openspace::SpiceManager::ref().getStateTransformMatrix("J2000", +* "IAU_PHOEBE", +* et, +* stateMatrix); +* stateMatrix.transform(position, velocity); +* (or if transformMatrix is 3x3:) +* stateMatrix.transform(position); +*/ +#define COPY(to, from) memcpy(to, from, sizeof(double)* 3); +class transformMatrix{ +private: + int N; + double *data; + bool empty; + double* ptr() { + empty = false; + return data; + } + friend class SpiceManager; +public: + /* default constructor */ + transformMatrix(); + /* default destructor */ + ~transformMatrix(){ delete[] data; }; + /* allocation of memory */ + transformMatrix(int n) : N(n){ + data = new double[N*N]; + empty = true; + } + /** As the spice function mxvg_c requires a 6dim vector + * the two 3dim state vectors are packed into 'state'. + * Transformed values are then copied back from state_t + * to each corresponding statevector. + * + * \param position, positional vector to be expressed in + * the new reference frame. + * \param velocity, (optional) velocity input is only + * transformed in conjunction with a 6x6 matrix, otherwise + * the method ignores its second argument. + */ + void transform(glm::dvec3& position, + glm::dvec3& velocity = glm::dvec3()){ + assert(("transformation matrix is empty", !empty)); + + double *state; + double *state_t; + state = new double[N]; + state_t = new double[N]; + + COPY(state, &position); + if (N == 6) COPY(state + velocity.length(), &velocity); + + mxvg_c(data, state, N, N, state_t); + + COPY(&position, state_t); + if (N == 6) COPY(&velocity, state_t + velocity.length()); + } + /* overloaded operator() + * asserts matrix has been filled + */ + inline double operator()(int i, int j) const{ + assert(("transformation matrix is empty", !empty)); + return data[j + i*N]; + } +}; +#undef COPY +} #endif \ No newline at end of file diff --git a/src/tests/SpiceTest/spicekernels/cas_iss_v09.ti b/src/tests/SpiceTest/spicekernels/cas_iss_v09.ti new file mode 100644 index 0000000000..0746112565 --- /dev/null +++ b/src/tests/SpiceTest/spicekernels/cas_iss_v09.ti @@ -0,0 +1,779 @@ +KPL/IK + + +ISS Instrument Kernel +============================================================================== + + This instrument kernel (I-kernel) contains references to the mounting + alignment, internal and FOV geometry for the Cassini Imaging Science + Subsystem (ISS) instruments. + + +Version and Date +---------------------------------------------------------- + + The TEXT_KERNEL_ID stores version information of loaded project text + kernels. Each entry associated with the keyword is a string that consists + of four parts: the kernel name, version, entry date, and type. For example, + the ISS I-kernel might have an entry as follows: + + TEXT_KERNEL_ID += 'CASSINI_ISS V0.0.0 29-SEPTEMBER-1999 IK' + | | | | + | | | | + KERNEL NAME <-------+ | | | + | | V + VERSION <-------+ | KERNEL TYPE + | + V + ENTRY DATE + + ISS I-Kernel Version: + + \begindata + + TEXT_KERNEL_ID += 'CASSINI_ISS V0.9.0 23-JANUARY-2004 IK' + + \begintext + + Version 0.9 -- January 23, 2004 -- Josh Riley and Lee Elson + + -- Updated focal lengths using inflight calibration results. + + Version 0.8 -- April 23, 2001 -- Scott Turner + + -- Updated kernel to utilize new FOV ANGLES specification. + + Version 0.7 -- September 27, 2000 -- Scott Turner + + -- The value of IFOV for the NAC recorded in previous kernels as + 60 should have been 6. The value associated with + INS-82360_IFOV and the table in the documentation have been + updated to reflect this correction. + + Version 0.6 -- August 15, 2000 -- Scott Turner + + -- Recalculated the FOV definitions to enhance precision. + + Version 0.5 -- June 7, 2000 -- Scott Turner + + -- Changed the INS[#]_FOV_CENTER_PIXEL keyword to reflect + changes in the I-kernel SIS. + + Version 0.4 -- March 27, 2000 -- Scott Turner + + -- Included sample code in FORTRAN and C for computing the + angular extents of the ISS fields of view. + + -- Added the TEXT_KERNEL_ID keyword. + + -- Minor cosmetic alterations to the structure of the kernel to + improve readability. + + Version 0.3 -- March 17, 2000 -- Scott Turner + + -- This I-kernel reflects changes discussed at the SPICE team + meeting on 3/16/2000. + + -- All of the INS[ID]_SEQ_[WORD] keywords were eliminated. + + -- INS[ID]_SEQ_FOV_CENTER is now keyed to + INS[ID]_FOV_CENTER_PIXEL. + + Version 0.2 -- March 6, 2000 -- Scott Turner + + -- Fixed a few errors in the comment text describing the ISS and + this kernel's intended usage. + + -- Removed 'NAC' and 'WAC' from keywords. These values were + necessary when both the NAC and WAC shared a single + instrument ID code. + + -- Added 'SEQ_' to the FOV keywords that are to be used by PDT + and possibly other sequence tools. + + -- Added name to ID code mappings for 'CASSINI_ISS_NAC' and + 'CASSINI_ISS_WAC' + + -- Added the keywords 'INS-82360_SEQ_PIXEL_SIZE', + 'INS-82361_SEQ_PIXEL_SIZE', 'INS-82360_FOV_NAME', + 'INS-82361_FOV_NAME', 'INS-82360_BORESIGHT_ID', + 'INS-82361_BORESIGHT_ID', 'INS-82360_BORESIGHT_NAME', + 'INS-82361_BORESIGHT_NAME' + + Version 0.1 -- October 8, 1999 -- Scott Turner + + -- Added an additional set of keywords that describe the FOVs of + the instruments to maintain compatibility with previously + discussed standards. These keywords may change or be + eliminated when the kernel evolves. Placeholders for the NAC + and WAC radiators were also placed into keywords conforming + to this standard. + + -- Altered the NAC/WAC FOV definition parameters to conform with + GETFOV's expectations. Added documentation describing the + parameters. + + -- Changed NAC and WAC ID codes from -82010 and -82020 to -82360 + and -82361 respectively. + + -- Altered reference No. 4 to include proper document title and + project document number. + + -- Added a section for data to store instrument mode timing. The + values present are just place holders until the actual ones + are uncovered. + + Version 0.0 -- June 21, 1999 -- Scott Turner + + -- Initial Prototype Release for Review. + + +References +---------------------------------------------------------- + + 1. ``Cassini Science Instruments and Investigations'', Revised + Second Printing. Stephen J. Edberg. + + 2. Cassini Spacecraft Frames Definition Kernel. + + 3. JPL Cassini Project Web Page describing the instruments. + + 4. Cassini Document No. 699-416 Imaging Science Subsystem + Calibration Report + + 5. Email from Jeff Boyer regarding necessary data for footprint + calculations. + + 6. Email discussion with Vance Haemmerle regarding the location + of the (0,0) pixel on the CCD and it's correlation to the NAC + and WAC FOV definition. + + 7. Cassini/NAIF SPICE Workshop, November 8-9, 1999. + + 8. Email from Vance Haemmerle regarding an incorrect value + recorded for the NAC IFOV parameter. + + 9. Memo from P. Thomas "Geometric calibration of the ISS NAC and + WAC", December 18, 2002. + + +Contact Information +---------------------------------------------------------- + + Direct questions, comments or concerns about the contents of this kernel + to: + + Lee Elson, NAIF/JPL, (818)-354-4223, Lee.Elson@jpl.nasa.gov + + +Implementation Notes +---------------------------------------------------------- + + This file is used by the SPICE system as follows: programs that make use of + this instrument kernel must ``load'' the kernel, normally during program + initialization. Loading the kernel associates data items with their names + in a data structure called the ``kernel pool''. The SPICELIB routine FURNSH + and CSPICE routine furnsh_c load SPICE kernels as shown below: + + FORTRAN (SPICELIB) + + CALL FURNSH ( 'kernel_name' ) + + C (CSPICE) + + furnsh_c ( "kernel_name" ) + + In order for a program or subroutine to extract data from the pool, the + SPICELIB routines GDPOOL and GIPOOL are used. See [2] for details. + + This file was created and may be updated with a text editor or word + processor. + + +Naming Conventions +---------------------------------------------------------- + + All names referencing values in this I-kernel start with the characters + `INS' followed by the NAIF Cassini spacecraft ID number (-82) followed by a + NAIF three digit ID code for the ISS instruments. (NAC = 360, WAC = 361). + + The remainder of the name is an underscore character followed by the unique + name of the data item. For example, the ISS NAC boresight direction in the + ISS NAC optics frame (``CASSINI_ISS_NAC'' -- see [2]) is specified by: + + INS-82360_BORESIGHT + + The upper bound on the length of the name of any data item is 32 + characters. + + If the same item is included in more than one file, or if the same item + appears more than once within a single file, the latest value supersedes + any earlier values. + + +ISS description +---------------------------------------------------------- + + From [3]: + + ``IMAGING SCIENCE SUBSYSTEM (ISS) + + The Cassini orbiter imaging experiments will encompass a wide variety of + targets (Saturn, the rings, Titan, the icy satellites, and star fields) and + a wide range of observing distances for various scientific purposes. The + science objectives include studying the atmospheres of Saturn and Titan, + the rings of Saturn and their interactions with the planet's satellites, + and the surface characteristics of the satellites, including Titan. Because + of these multiple objectives, the Imaging Science Subsystem (ISS) has two + separate camera designs. The first is a narrow-angle camera (NAC) design + that will obtain high-resolution images of the target of interest. The + second is a wide-angle camera (WAC) design that provides a different scale + of image resolution and more complete coverage spatially. The spacecraft + will carry one NAC and one WAC. The NAC is also used to obtain optical + navigation images for the mission with the WAC acting as a functionally + redundant backup unit for this purpose. + + The cameras are charge-coupled device (CCD) imagers. A CCD is essentially a + large-scale integrated circuit (IC) that has a two-dimensional array of + hundreds or thousands of charge-isolated wells, each representing a picture + element or "pixel." Light falling on a well is absorbed by a + photoconductive substrate, such as silicon, which releases a quantity of + electrons proportional to the intensity of the light. The CCD detects and + stores an accumulated electrical charge representing the light level on + each well. These charges are subsequently read out for conversion to + digital data. CCDs are much more sensitive to light of a wider spectrum + than vidicon tube-type imagers, and they are less massive, require less + energy, and interface more easily with digital circuitry. + + The Cassini imagers differ primarily in the design of the optics. The NAC + has a focal length of 2000 mm, and the WAC , which uses optics inherited + from the Voyager mission, has a focal length of 200 mm. The cameras each + have a focal plane shutter of the same type as used on both Voyager and + Galileo, and they have a two-wheel filter-changing mechanism derived from + the Hubble Space Telescope Wide Field/Planetary Camera (WF/PC) design. The + CCD detector is cooled to suppress dark current (residual current in the + CCD beyond that released by incident light), which is dependent upon + temperature. It is also shielded from ionizing radiation. + + The CCD detector design is a square array of 1024x1024 pixels, each pixel + 12 micrometers on a side. The IC chip will use three-phase, + front-side-illuminated architecture, with a coating of lumogen phosphor to + provide ultraviolet response. The detector is passively cooled by a + radiator to approximately 10 degrees C below its nominal operating + temperature (approximately minus 90 degrees C), and then it is controlled + to the operating temperature by a proportional control heater. To minimize + radiator size and heater power, the detector/radiator combination is + thermally isolated from the rest of the camera head assembly (CHA). + + The entire NAC is thermally isolated from the remote sensing pallet (RSP) + on which it is mounted in order to minimize the effects of RSP thermal + variations on NAC image quality. The WAC, being an inherited design with + less stringent imaging requirements, is not thermally isolated. + + The electronics for each camera are identical. All ISS command and + telemetry functions will be handled by the electronics, including receipt + of commands from the Command and Data Subsystem, expansion of commands, and + collection and transmission of imaging data and telemetry to the CDS. + + The ISS controls the amount of power it draws from the spacecraft during + operations. To accomplish this, the profile of ISS command timing is + structured to reduce the power the ISS requires for certain internal + functions (e.g., shutter or filter wheel movement). When the filter is + moving, the power from the optical heater (if present) in the active camera + is turned off. When the movement is complete, the optical heater is turned + on (if needed). In addition, simultaneous filter positioning within a + single camera, either the WAC or NAC, is not permitted. + + During the cruise phase of the mission, the cameras will periodically be + turned on for maintenance, calibration, and monitoring of instrument health + and performance. Other than these specified times, the ISS will be off and + replacement heaters will be on. In addition, decontamination/radiation + heater 1 will be on throughout most of the cruise. + + Upon arrival at the Saturnian system, the cameras will be on most of the + time. Spacecraft power limitations will be the controlling parameter + determining whether the ISS will be turned off or put into a low-power + state. During the Saturn tour, high-activity periods for Saturn and its + rings will be clustered around periapsis (the point in the orbit closest to + the planet); for the satellites, the high-activity periods will be when the + spacecraft is closest to them. At these times, high-resolution images of + all targets will be acquired through various camera filters, and the data + will be stored in the spacecraft solid-state recorder (SSR). During lower + activity periods (i.e., when the spacecraft is orbiting farther from the + targets), long-term atmospheric and ring monitoring will take place, and + ISS calibrations will be performed.'' + + +ISS First Order Optical Parameters +---------------------------------------------------------- + + The first order optical parameters for the two cameras that constitute the + ISS detectors: + + -- Narrow Angle Camera + + -- Wide Angle Camera + + as provided by [4 and 9] for the CL filter combinations compiled into the + following table: + + ------------------------------ ----------- ----------- + parameter NAC WAC + ------------------------------ ----------- ----------- + Effective Focal Length, mm 2003.44 200.77 + Estimated Uncertainty, mm 0.03 0.01 + Spectral Band, nm 200-1100 400-1000 + F/number 10.5 3.44 + ------------------------------ ----------- ----------- + + These values are given in the keywords below in the same units as the table + above: + + Narrow Angle Camera (NAC): + + \begindata + + INS-82360_FOCAL_LENGTH = ( 2003.44 ) + INS-82360_FL_UNCERTAINTY = ( 0.03 ) + INS-82360_WAVELENGTH_RANGE = ( 200, 1100 ) + INS-82360_F/NUMBER = ( 10.5 ) + + \begintext + + Wide Angle Camera (WAC): + + \begindata + + INS-82361_FOCAL_LENGTH = ( 200.77 ) + INS-82361_FL_UNCERTAINTY = ( 0.01 ) + INS-82361_WAVELENGTH_RANGE = ( 400, 1000 ) + INS-82361_F/NUMBER = ( 3.44 ) + + \begintext + + +ISS Field of View Parameters +---------------------------------------------------------- + + +FOV Sizes (in degrees) + + Spacecraft Frame: + + Xsc + ^ + | + | + o-----> + Ysc Zsc + + + ^ + Samples | Ycm + (0,0) + + + > | + + \_____________________________________________________ ___ + + | | | + + | Samples | | + V | (0,0) + + + > | | + Lines | + \_____________________________ ___ | | + | + | | | | | + | + | | | | | + | V | | | | | + | Lines | | | | | + | | | | | | + <--- | | x | 0.35 | 3.4 + Xcm | | Zcm | | | | + | | | | | | + | | | | | | + | | | | | | + | |_____________________________| _|_ | | + | NAC | | + | |------------0.35-------------| | | + | | | + |_____________________________________________________| _|_ + WAC + |------------------------3.48-------------------------| + + + Note that although the above diagram suggests that the NAC and WAC + boresights are co-aligned, this is not the case. As [1] and [2] point out, + the NAC and WAC are both mounted to the Remote Sensing Palette in different + locations. From [6], the CCD samples and lines increase with decreasing X + and Y in the NAC and WAC frames. Thus the (0,0) corners of the CCDs are as + illustrated on the diagram above. + + The FOVs of the ISS detectors have the following angular sizes (from [4]): + + ------------ ---------------- ---------------- + Detector Horizontal Vertical + ------------ ---------------- ---------------- + NAC 0.35 degrees 0.35 degrees + + WAC 3.48 degrees 3.48 degrees + ------------ ---------------- ---------------- + + The CCD geometry parameters as presented in [1] and [4] are provided below: + + ------------------------------ ----------- ----------- + parameter NAC WAC + ------------------------------ ----------- ----------- + Detector Array Size 1024x1024 1024x1024 + Pixel Size, microns 12x12 12x12 + FOV Angular Size, degrees 0.35x0.35 3.48x3.48 + IFOV, microradian/pixel 6 60 + ------------------------------ ----------- ----------- + + With the keywords and their values: + + Narrow Angle Camera (NAC): + + \begindata + + INS-82360_PIXEL_SAMPLES = ( 1024 ) + INS-82360_PIXEL_LINES = ( 1024 ) + INS-82360_PIXEL_SIZE = ( 12 ) + INS-82360_CCD_CENTER = ( 512.5, 512.5 ) + INS-82360_IFOV = ( 6 ) + + \begintext + + Wide Angle Camera (WAC): + + \begindata + + INS-82361_PIXEL_SAMPLES = ( 1024 ) + INS-82361_PIXEL_LINES = ( 1024 ) + INS-82361_PIXEL_SIZE = ( 12 ) + INS-82361_CCD_CENTER = ( 512.5, 512.5 ) + INS-82361_IFOV = ( 60 ) + + \begintext + + The keywords INS[ID]_FOV_FRAME, INS[ID]_FOV_SHAPE, INS[ID]_BORESIGHT, and + FOV ANGLES specification keywords defined below are used to describe the + instrument field of view. Since both the NAC and WAC have square fields of + view, the INS[ID]_FOV_SHAPE keyword will always be 'RECTANGLE', and GETFOV + will return the four vectors in the instrument frame that describe the + edges of the FOV cone. Both the NAC and WAC boresights lie along the + Z-axis. + + +Narrow Angle Camera (NAC) FOV Definition + + Since the NAC's angular separation is 0.35 degrees, looking up the Y-axis + in the CASSINI_ISS_NAC frame we have: (Note we are arbitrarily choosing + vectors that terminate in the Z=1 plane.) + + + ^ X + | ins + | + | /| + | / | + | / | + | / o | + |/ 0.175 | + o---------------> + Y \ | Z + ins \ | ins + \ | + \ | + \| + + |-- 1.0 --| + Plane Y = 0 + + + Now from here we see that the X components of the boundary corners are: + + X Component = +/- 1.0 * tan ( 0.175 degrees ) = +/- 0.003054335689 + + Since the field of view is square this holds for the Y components as well. + + These FOV values as well as the values from the preceding table are given + in the keywords below in the same units as listed above: + + Narrow Angle Camera (NAC): + + \begindata + + INS-82360_FOV_FRAME = 'CASSINI_ISS_NAC' + INS-82360_FOV_SHAPE = 'RECTANGLE' + INS-82360_BORESIGHT = ( + + 0.0000000000000000 0.0000000000000000 +1.0000000000000000 + + ) + INS-82360_FOV_CLASS_SPEC = 'ANGLES' + INS-82360_FOV_REF_VECTOR = ( + + +1.0000000000000000 0.0000000000000000 0.0000000000000000 + + ) + INS-82360_FOV_REF_ANGLE = ( 0.175 ) + INS-82360_FOV_CROSS_ANGLE = ( 0.175 ) + INS-82360_FOV_ANGLE_UNITS = 'DEGREES' + + \begintext + + +Wide Angle Camera (WAC) FOV Definition + + Since the WAC is also a square field of view, similar calculations as to + those made for the NAC hold. The half angle of interest is 1.74 degrees as + opposed to 0.175. Looking up the Y-axis in the CASSINI_ISS_WAC frame we + have: (Note we are arbitrarily choosing vectors that terminate in the Z=1 + plane.) + + + ^ X + | ins + | + | /| + | / | + | / | + | / o | + |/ 1.740 | + o---------------> + Y \ | Z + ins \ | ins + \ | + \ | + \| + + |-- 1.0 --| + Plane Y = 0 + + + Now from here we see that the X components of the boundary corners are: + + X Component = +/- 1.0 * tan ( 1.74 degrees ) = +/- 0.030378068382 + + Since the field of view is square this holds for the Y components as well. + + Again since the field of view is square this computation holds for the Y + components as well. All of these values are collected in the FOV keywords + defined below. Utilizing the ANGLES FOV specification: + + Wide Angle Camera (WAC): + + \begindata + + INS-82361_FOV_FRAME = 'CASSINI_ISS_WAC' + INS-82361_FOV_SHAPE = 'RECTANGLE' + INS-82361_BORESIGHT = ( + + 0.0000000000000000 0.0000000000000000 +1.0000000000000000 + + ) + INS-82361_FOV_CLASS_SPEC = 'ANGLES' + INS-82361_FOV_REF_VECTOR = ( + + +1.0000000000000000 0.0000000000000000 0.0000000000000000 + + ) + INS-82361_FOV_REF_ANGLE = ( 1.74 ) + INS-82361_FOV_CROSS_ANGLE = ( 1.74 ) + INS-82361_FOV_ANGLE_UNITS = 'DEGREES' + + \begintext + + +ISS Radiator FOV Definitions + + The FOV values for the ISS radiators are place holders until a time when + real values are provided. + + Narrow Angle Camera Radiator (NAC_RAD): + + \begindata + + INS-82368_FOV_FRAME = 'CASSINI_ISS_NAC_RAD' + INS-82368_FOV_SHAPE = 'CIRCLE' + INS-82368_BORESIGHT = ( + + 0.0000000000000000 0.0000000000000000 +1.0000000000000000 + + ) + INS-82368_FOV_CLASS_SPEC = 'ANGLES' + INS-82368_FOV_REF_VECTOR = ( + + 0.0000000000000000 +1.0000000000000000 +0.0000000000000001 + + ) + INS-82368_FOV_REF_ANGLE = ( 90.0 ) + INS-82368_FOV_ANGLE_UNITS = 'DEGREES' + + \begintext + + Wide Angle Camera Radiator (WAC_RAD): + + \begindata + + INS-82369_FOV_FRAME = 'CASSINI_ISS_WAC_RAD' + INS-82369_FOV_SHAPE = 'CIRCLE' + INS-82369_BORESIGHT = ( + + 0.0000000000000000 0.0000000000000000 +1.0000000000000000 + + ) + INS-82369_FOV_CLASS_SPEC = 'ANGLES' + INS-82369_FOV_REF_VECTOR = ( + + 0.0000000000000000 +1.0000000000000000 +0.0000000000000001 + + ) + INS-82369_FOV_REF_ANGLE = ( 90.0 ) + INS-82369_FOV_ANGLE_UNITS = 'DEGREES' + + \begintext + + +Pixel Parameters +---------------------------------------------------------- + + These parameters describe the pixel structure associated with the + instruments and their fields of views. In some cases this is a + generalization of the notion of pixel, in that instead of representing + pixels on a CCD they may represent a collection of individual detectors. + + The FOV_CENTER_PIXEL keyword is precisely the same as the CCD_CENTER + defined in the CCD geometry keywords above. + + +Narrow Angle Camera (NAC) + + \begindata + + INS-82360_FOV_CENTER_PIXEL = ( 511.5, 511.5 ) + + \begintext + + +Wide Angle Camera (WAC) + + \begindata + + INS-82361_FOV_CENTER_PIXEL = ( 511.5, 511.5 ) + + \begintext + + +Narrow Angle Camera Radiator (NAC_RAD) + + \begindata + + INS-82368_FOV_CENTER_PIXEL = ( 0, 0 ) + INS-82368_PIXEL_SAMPLES = ( 1 ) + INS-82368_PIXEL_LINES = ( 1 ) + + + \begintext + + +Wide Angle Camera Radiator (WAC_RAD) + + \begindata + + INS-82369_FOV_CENTER_PIXEL = ( 0, 0 ) + INS-82369_PIXEL_SAMPLES = ( 1 ) + INS-82369_PIXEL_LINES = ( 1 ) + + \begintext + + +Instrument Mode Timing +---------------------------------------------------------- + + The following values were provided as samples in [5]. The values are + defined in [5] as follows: + + + ``The initial values for the following keywords are given + per instrument number: + + INS[instrument number]_[instrument acronym]_MODE_NAME + INS[instrument number]_[instrument acronym]_TRIGGER_OFFSET + INS[instrument number]_[instrument acronym]_CYCLE_DURATION + + INS..._MODE_NAME contains the name of the instrument mode for + the INS..._TRIGGER_OFFSET and INS..._CYCLE_DURATION + keywords. + + INS..._TRIGGER_OFFSET specifies the reference time of the + first instrument frame (to be calculated for a footprint) + relative to the time of transacting the corresponding TRIGGER + command. The units are SFOC duration. + + INS..._CYCLE_DURATION specifies the duration between successive + instrument frames (from the first one) for the INS..._MODE_NAME.'' + + + +NAC Mode Timing + + The following values define the instrument modes and timing for the ISS + NAC. + + \begindata + + INS-82360_MODE_NAME = 'NOMINAL' + INS-82360_TRIGGER_OFFSET = '0:01:00.0' + INS-82360_CYCLE_DURATION = '0:01:00.0' + + \begintext + + +WAC Mode Timing + + The following values define the instrument modes and timing for the ISS + WAC. + + \begindata + + INS-82361_MODE_NAME = 'NOMINAL' + INS-82361_TRIGGER_OFFSET = '0:01:00.0' + INS-82361_CYCLE_DURATION = '0:01:00.0' + + \begintext + + +NAIF ID Code to Name Mapping +---------------------------------------------------------- + + The following keywords define names for the corresponding ID Codes. See + [10] for details. + + \begindata + + NAIF_BODY_NAME += ( 'CASSINI_ISS_NAC' ) + NAIF_BODY_CODE += ( -82360 ) + + NAIF_BODY_NAME += ( 'CASSINI_ISS_WAC' ) + NAIF_BODY_CODE += ( -82361 ) + + NAIF_BODY_NAME += ( 'CASSINI_ISS_NAC_RAD' ) + NAIF_BODY_CODE += ( -82368 ) + + NAIF_BODY_NAME += ( 'CASSINI_ISS_WAC_RAD' ) + NAIF_BODY_CODE += ( -82369 ) + + \begintext + + +Platform ID +---------------------------------------------------------- + + The ISS instrument is mounted on the Remote Sensing Palette, which is + connected to the Cassini Spacecraft body. Therefore the value in the + keywords below is -82000. + + \begindata + + INS-82360_PLATFORM_ID = ( -82000 ) + INS-82361_PLATFORM_ID = ( -82000 ) + INS-82368_PLATFORM_ID = ( -82000 ) + INS-82369_PLATFORM_ID = ( -82000 ) + + \begintext + diff --git a/src/tests/SpiceTest/spicekernels/metaKernel.tm b/src/tests/SpiceTest/spicekernels/metaKernel.tm index 9d4507ceb0..074f42b530 100644 --- a/src/tests/SpiceTest/spicekernels/metaKernel.tm +++ b/src/tests/SpiceTest/spicekernels/metaKernel.tm @@ -9,5 +9,6 @@ KPL/MK '030201AP_SK_SM546_T45.bsp' 'cas_v37.tf', '04135_04171pc_psiv2.bc', - 'cpck05Mar2004.tpc') + 'cpck05Mar2004.tpc', + 'cas_iss_v09.ti') \begintext \ No newline at end of file diff --git a/src/tests/main.cpp b/src/tests/main.cpp index d1c806d33f..43f4fe2c2f 100644 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -32,9 +32,14 @@ #include #include -#include -#include +#include +//#include +//#include #include +#include +#include +#include +#include #include @@ -57,6 +62,7 @@ int main(int argc, char** argv) { LFATAL("Could not find OpenSpace configuration file!"); assert(false); } + LINFO("Configuration file found: " << FileSys.absolutePath(configurationFilePath)); LDEBUG("registering base path"); if( ! openspace::OpenSpaceEngine::registerBasePathFromConfigurationFile(configurationFilePath)) { @@ -66,16 +72,16 @@ int main(int argc, char** argv) { ghoul::Dictionary configuration; ghoul::lua::loadDictionaryFromFile(configurationFilePath, configuration); - if(configuration.hasKey("paths")) { + if (configuration.hasKey(openspace::constants::openspaceengine::keyPaths)) { ghoul::Dictionary pathsDictionary; - if(configuration.getValue("paths", pathsDictionary)) { + if (configuration.getValue(openspace::constants::openspaceengine::keyPaths, pathsDictionary)) { openspace::OpenSpaceEngine::registerPathsFromDictionary(pathsDictionary); } } - openspace::Time::init(); + /*openspace::Time::init(); openspace::Spice::init(); - openspace::Spice::ref().loadDefaultKernels(); + openspace::Spice::ref().loadDefaultKernels();*/ openspace::FactoryManager::initialize(); testing::InitGoogleTest(&argc, argv); diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index 580835896e..18302d4002 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -32,8 +32,6 @@ #include "openspace/util/spicemanager.h" #include "ghoul/filesystem/filesystem.h" -#define BUFSIZE 64 - namespace { const std::string _loggerCat = "SpiceManager"; } @@ -63,8 +61,7 @@ SpiceManager& SpiceManager::ref() { } int SpiceManager::loadKernel(const std::string& fullPath, const std::string& shorthand){ - - unsigned int kernelId = ++kernelCount; + unsigned int kernelId = ++_kernelCount; assert(kernelId > 0); std::string currentDirectory = FileSys.currentDirectory(); @@ -77,8 +74,8 @@ int SpiceManager::loadKernel(const std::string& fullPath, const std::string& sho FileSys.setCurrentDirectory(currentDirectory); spiceKernel current = { fullPath, - shorthand, - kernelId }; + shorthand, + kernelId }; _loadedKernels.push_back(current); @@ -118,8 +115,8 @@ bool SpiceManager::getValueFromID(const std::string& bodyname, const std::string& kernelPoolValue, double& value) const{ int n; - SpiceInt code; - SpiceBoolean found; + int code; + int found; bodn2c_c(bodyname.c_str(), &code, &found); if (!found) return false; @@ -133,9 +130,9 @@ bool SpiceManager::getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, glm::dvec2& value) const{ int n; - SpiceDouble val[2]; - SpiceInt code; - SpiceBoolean found; + double val[2]; + int code; + int found; bodn2c_c(bodyname.c_str(), &code, &found); if (!found) return false; @@ -153,17 +150,15 @@ bool SpiceManager::getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, glm::dvec3& value) const{ int n; - SpiceDouble val[3]; - SpiceInt code; - SpiceBoolean found; + double val[3]; + int code; + int found; bodn2c_c(bodyname.c_str(), &code, &found); if (!found) return false; bodvrd_c(bodyname.c_str(), kernelPoolValueName.c_str(), 3, &n, val); - value[0] = val[0]; - value[1] = val[1]; - value[2] = val[2]; + memcpy(&value, val, sizeof(double)* 3); return true; } @@ -173,9 +168,9 @@ bool SpiceManager::getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, glm::dvec4& value) const{ int n; - SpiceDouble val[4]; - SpiceInt code; - SpiceBoolean found; + double val[4]; + int code; + int found; bodn2c_c(bodyname.c_str(), &code, &found); if (!found) return false; @@ -192,12 +187,13 @@ bool SpiceManager::getValueFromID(const std::string& bodyname, // ND bool SpiceManager::getValueFromID(const std::string& bodyname, const std::string& kernelPoolValueName, - std::vector& values, unsigned int num) const{ - SpiceInt n; - SpiceDouble *val; - val = (SpiceDouble*)malloc(num*sizeof(SpiceDouble)); - SpiceInt code; - SpiceBoolean found; + std::vector& values, + unsigned int num) const{ + int n; + double *val; + val = (double*)malloc(num*sizeof(double)); + int code; + int found; bodn2c_c(bodyname.c_str(), &code, &found); if (!found) return false; @@ -211,7 +207,7 @@ bool SpiceManager::getValueFromID(const std::string& bodyname, } double SpiceManager::stringToEphemerisTime(const std::string& epochString) const{ - SpiceDouble et; + double et; str2et_c(epochString.c_str(), &et); return et; } @@ -224,17 +220,14 @@ bool SpiceManager::getTargetPosition(const std::string& target, glm::dvec3& targetPosition, double lightTime) const{ double pos[3] = { NULL, NULL, NULL }; + //method to put error out... spkpos_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), aberrationCorrection.c_str(), observer.c_str(), pos, &lightTime); - if (pos[0] == NULL || - pos[1] == NULL || - pos[2] == NULL) + if (pos[0] == NULL || pos[1] == NULL || pos[2] == NULL) return false; - targetPosition[0] = pos[0]; - targetPosition[1] = pos[1]; - targetPosition[2] = pos[2]; + memcpy(&targetPosition, pos, sizeof(double)* 3); return true; } @@ -250,14 +243,14 @@ bool SpiceManager::getTargetState(const std::string& target, std::fill_n(state, 6, NULL); spkezr_c(target.c_str(), ephemerisTime, referenceFrame.c_str(), - aberrationCorrection.c_str(), observer.c_str(), state, &lightTime); + aberrationCorrection.c_str(), observer.c_str(), state, &lightTime); for (int i = 0; i < 3; i++){ if (state[i] == NULL || state[i + 3] == NULL){ return false; } - targetPosition[i] = state[i]; - targetVelocity[i] = state[i+3]; + memcpy(&targetPosition, state , sizeof(double)* 3); + memcpy(&targetVelocity, state +3, sizeof(double)* 3); } return true; } @@ -265,12 +258,152 @@ bool SpiceManager::getTargetState(const std::string& target, bool SpiceManager::getStateTransformMatrix(const std::string& fromFrame, const std::string& toFrame, double ephemerisTime, - mat6x6& stateMatrix) const{ + transformMatrix& stateMatrix) const{ + sxform_c(fromFrame.c_str(), toFrame.c_str(), + ephemerisTime, (double(*)[6])stateMatrix.ptr()); + return true; +} + +bool SpiceManager::getPositionTransformMatrix(const std::string& fromFrame, + const std::string& toFrame, + double ephemerisTime, + transformMatrix& positionMatrix) const{ + + pxform_c(fromFrame.c_str(), toFrame.c_str(), + ephemerisTime, (double(*)[3])positionMatrix.ptr()); - sxform_c(fromFrame.c_str(), toFrame.c_str(), ephemerisTime, stateMatrix); - //error handling? return true; } +bool SpiceManager::getFieldOfView(const std::string& naifInstrumentId, + std::string& fovShape, + std::string& frameName, + double boresightVector[], + std::vector& bounds, + int& nrReturned) const{ + int n; + int found; + int naifId; + int maxVectors = 12; + double *boundsArr = new double[maxVectors * 3]; + + for (int i = 0; i < maxVectors; i++){ + for (int j = 0; j < 3; j++){ + boundsArr[j + i*3] = NULL; + } + } + + bodn2c_c(naifInstrumentId.c_str(), &naifId, &found); + if (!found) return false; + + if (fovShape.size() != 0 && frameName.size() != 0){ + getfov_c(naifId, + maxVectors, + fovShape.size(), + frameName.size(), + const_cast(fovShape.c_str()), + const_cast(frameName.c_str()), + boresightVector, + &nrReturned, + (double(*)[3])boundsArr); + }else{ + std::cout << "Frame name and FOV shape \ + need to be preallocated" << std::endl; + return false; + } + + for (int i = 0; i < nrReturned; i++){ + glm::dvec3 tmp; + for (int j = 0; j < 3; j++){ + tmp[j] = boundsArr[j + i*3]; + } + bounds.push_back(tmp); + } + return true; +} + +bool SpiceManager::rectangularToLatitudal(const glm::dvec3 coordinates, + double& radius, + double& longitude, + double& latitude) const{ + double point[3] = { coordinates.x, coordinates.y, coordinates.z }; + reclat_c(point, &radius, &longitude, &latitude); + //check if returns values + return (radius && longitude && latitude); +} + +bool SpiceManager::latidudinalToRectangular(double radius, + double& longitude, + double& latitude, + glm::dvec3& coordinates) const{ + double point[3] = { coordinates.x, coordinates.y, coordinates.z }; + latrec_c(radius, longitude, latitude, point); + //check if returns values + return (radius && longitude && latitude); +} + +bool SpiceManager::planetocentricToRectangular(const std::string& naifName, + double& longitude, + double& latitude, + glm::dvec3& coordinates) const{ + int naifId; + int found; + double rectangular[3]; + + bodn2c_c(naifName.c_str(), &naifId, &found); + if (!found) return false; + srfrec_c(naifId, longitude*rpd_c(), latitude*rpd_c(), rectangular); + + memcpy(&coordinates, rectangular, sizeof(double) * 3); + + return true; +} + +bool SpiceManager::getSubObserverPoint(std::string computationMethod, + std::string target, + double ephemeris, + std::string bodyFixedFrame, + std::string aberrationCorrection, + std::string observer, + glm::dvec3& subObserverPoint, + double& targetEpoch, + glm::dvec3& vectorToSurfacePoint) const{ + double subPoint[3], vecToSurf[3]; + + subpnt_c(computationMethod.c_str(), + target.c_str(), + ephemeris, + bodyFixedFrame.c_str(), + aberrationCorrection.c_str(), + observer.c_str(), subPoint, &targetEpoch, vecToSurf); + + memcpy(&subObserverPoint , subPoint , sizeof(double) * 3); + memcpy(&vectorToSurfacePoint, vecToSurf, sizeof(double) * 3); + + return true; +} +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; +} }