mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-27 14:39:20 -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:
@@ -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")
|
||||
|
||||
|
||||
@@ -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
|
||||
779
src/tests/SpiceTest/spicekernels/cas_iss_v09.ti
Normal file
779
src/tests/SpiceTest/spicekernels/cas_iss_v09.ti
Normal file
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -32,9 +32,14 @@
|
||||
#include <ghoul/lua/ghoul_lua.h>
|
||||
|
||||
#include <openspace/tests/test_common.inl>
|
||||
#include <openspace/tests/test_scenegraph.inl>
|
||||
#include <openspace/tests/test_powerscalecoordinates.inl>
|
||||
#include <openspace/tests/test_spicemanager.inl>
|
||||
//#include <openspace/tests/test_scenegraph.inl>
|
||||
//#include <openspace/tests/test_powerscalecoordinates.inl>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/util/constants.h>
|
||||
#include <openspace/util/factorymanager.h>
|
||||
#include <openspace/util/spice.h>
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<double>& values, unsigned int num) const{
|
||||
SpiceInt n;
|
||||
SpiceDouble *val;
|
||||
val = (SpiceDouble*)malloc(num*sizeof(SpiceDouble));
|
||||
SpiceInt code;
|
||||
SpiceBoolean found;
|
||||
std::vector<double>& 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<glm::dvec3>& 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<char*>(fovShape.c_str()),
|
||||
const_cast<char*>(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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user