celestia/src/celephem/spiceinterface.cpp

116 lines
3.0 KiB
C++

// spiceinterface.cpp
//
// Interface to the SPICE Toolkit
//
// Copyright (C) 2006, Chris Laurel <claurel@shatters.net>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include "SpiceUsr.h"
#include "spiceinterface.h"
#include <iostream>
#include <cstdio>
#include <set>
using namespace std;
// Track loaded SPICE kernels in order to avoid loading the same kernel
// multiple times. This is a global variable because SPICE uses a global
// kernel pool.
static set<string> ResidentSpiceKernels;
/*! Perform one-time initialization of SPICE.
*/
bool
InitializeSpice()
{
// Set the error behavior to the RETURN action, so that
// Celestia do its own handling of SPICE errors.
erract_c("SET", 0, (SpiceChar*)"RETURN");
return true;
}
/*! Convert an object name to a NAIF integer ID. Return true if the name
* refers to a known object, false if not. Both names and numeric IDs are
* accepted in the string.
*/
bool GetNaifId(const string& name, int* id)
{
SpiceInt spiceID = 0;
SpiceBoolean found = SPICEFALSE;
// Don't call bodn2c on an empty string because SPICE generates
// an error if we do.
if (!name.empty())
{
bodn2c_c(name.c_str(), &spiceID, &found);
if (found)
{
*id = (int) spiceID;
}
else // Is it a numeric ID?
{
// SpiceInt maps to an int on those architectures where sizeof(long) != sizeof(double)/2.
// Otherwise it maps to a long. This avoids GCC complaints about type mismatches:
long spiceIDlng;
if (sscanf(name.c_str(), " %ld", &spiceIDlng) == 1)
{
*id = (int) spiceIDlng;
found = SPICETRUE;
}
}
}
return found == SPICETRUE;
}
/*! Return true if a SPICE kernel has already been loaded, false if not.
*/
bool IsSpiceKernelLoaded(const string& filepath)
{
return ResidentSpiceKernels.find(filepath) != ResidentSpiceKernels.end();
}
/*! Load a SPICE kernel file of any type into the kernel pool. If the kernel
* is already resident, it will not be reloaded.
*/
bool LoadSpiceKernel(const string& filepath)
{
// Only load the kernel if it is not already resident. Note that this detection
// of duplicate kernels will not work if a file was originally loaded through
// a metakernel.
if (IsSpiceKernelLoaded(filepath))
return true;
ResidentSpiceKernels.insert(filepath);
furnsh_c(filepath.c_str());
// If there was an error loading the kernel, dump the error message.
if (failed_c())
{
char errMsg[1024];
getmsg_c("long", sizeof(errMsg), errMsg);
clog << errMsg << "\n";
// Reset the SPICE error state so that future calls to
// SPICE can still succeed.
reset_c();
return false;
}
else
{
clog << "Loaded SPK file " << filepath << "\n";
return true;
}
}