mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-05 19:19:39 -06:00
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.
This commit is contained in:
@@ -23,9 +23,7 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
|
||||
#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<double> 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<double> 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];
|
||||
|
||||
}
|
||||
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<glm::dvec3> 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());
|
||||
}
|
||||
|
||||
@@ -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 <map>
|
||||
|
||||
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<double>& 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<glm::vec3>& bounds) const;
|
||||
std::string& fovShape,
|
||||
std::string& frameName,
|
||||
double boresightVector[],
|
||||
std::vector<glm::dvec3>& 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<spiceKernel> _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 <code>transformMatrix</code>
|
||||
* and after its been passed to either <code>getStateTransformMatrix</code>
|
||||
* or <code>getPositionTransformMatrix</code> 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
|
||||
Reference in New Issue
Block a user