celestia/src/celengine/spicerotation.cpp

187 lines
5.1 KiB
C++

// spicerotation.cpp
//
// Rotation model interface to the SPICE Toolkit
//
// Copyright (C) 2008, Celestia Development Team
// Initial implementation by Chris Laurel <claurel@gmail.com>
//
// 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 <iostream>
#include <cstdio>
#include <limits>
#include "SpiceUsr.h"
#include "astro.h"
#include "spicerotation.h"
#include "spiceinterface.h"
using namespace std;
static const double MILLISEC = astro::secsToDays(0.001);
static const Quatd Rx90 = Quatd::xrotation(PI / 2.0);
/*! Create a new rotation model based on a SPICE frame. The
* orientation of the rotation model is the orientation of the
* named SPICE frame relative to the base frame orientation.
* The rotation is valid during a time range between beginning
* and end. The period can be specified for periodic rotations
* (units are Julian days), or set to zero for aperiodic rotation
* models.
*/
SpiceRotation::SpiceRotation(const std::string& frameName,
const std::string& baseFrameName,
double period,
double beginning,
double ending) :
m_frameName(frameName),
m_baseFrameName(baseFrameName),
m_period(period),
m_spiceErr(false),
m_validIntervalBegin(beginning),
m_validIntervalEnd(ending),
m_useDefaultTimeInterval(false)
{
}
/*! Create a new rotation model based on a SPICE frame. The
* orientation of the rotation model is the orientation of the
* named SPICE frame relative to the base frame orientation.
* The rotation is valid during a time range between beginning
* and end. The period can be specified for periodic rotations
* (units are Julian days), or set to zero for aperiodic rotation
* models.
*/
SpiceRotation::SpiceRotation(const std::string& frameName,
const std::string& baseFrameName,
double period) :
m_frameName(frameName),
m_baseFrameName(baseFrameName),
m_period(period),
m_spiceErr(false),
m_validIntervalBegin(-numeric_limits<double>::infinity()),
m_validIntervalEnd(numeric_limits<double>::infinity()),
m_useDefaultTimeInterval(true)
{
}
SpiceRotation::~SpiceRotation()
{
}
bool
SpiceRotation::isPeriodic() const
{
return m_period != 0.0;
};
double
SpiceRotation::getPeriod() const
{
if (isPeriodic())
{
return m_period;
}
else
{
return m_validIntervalEnd - m_validIntervalBegin;
}
}
bool
SpiceRotation::init(const string& path,
const list<string>* requiredKernels)
{
// Load required kernel files
if (requiredKernels != NULL)
{
for (list<string>::const_iterator iter = requiredKernels->begin(); iter != requiredKernels->end(); iter++)
{
string filepath = path + string("/data/") + *iter;
if (!LoadSpiceKernel(filepath))
{
m_spiceErr = true;
break;
}
}
}
// Reduce valid interval by a millisecond at each end.
m_validIntervalBegin += MILLISEC;
m_validIntervalEnd -= MILLISEC;
// Test getting the frame rotation matrix to make sure that there's
// adequate data in the kernel.
double beginning = astro::daysToSecs(m_validIntervalBegin - astro::J2000);
double xform[3][3];
pxform_c(m_frameName.c_str(), m_frameName.c_str(), beginning, xform);
if (failed_c())
{
// Print the error message
char errMsg[1024];
getmsg_c("long", sizeof(errMsg), errMsg);
clog << errMsg << "\n";
m_spiceErr = true;
reset_c();
}
return !m_spiceErr;
}
Quatd
SpiceRotation::computeSpin(double jd) const
{
if (jd < m_validIntervalBegin)
jd = m_validIntervalBegin;
else if (jd > m_validIntervalEnd)
jd = m_validIntervalEnd;
if (m_spiceErr)
{
return Quatd(1.0);
}
else
{
// Input time for SPICE is seconds after J2000
double t = astro::daysToSecs(jd - astro::J2000);
double xform[3][3];
pxform_c(m_frameName.c_str(), m_baseFrameName.c_str(), t, xform);
if (failed_c())
{
// Print the error message
char errMsg[1024];
getmsg_c("long", sizeof(errMsg), errMsg);
clog << errMsg << "\n";
// Reset the error state
reset_c();
}
#if 1
Mat3d m(Vec3d(xform[0][0], xform[0][1], xform[0][2]),
Vec3d(xform[1][0], xform[1][1], xform[1][2]),
Vec3d(xform[2][0], xform[2][1], xform[2][2]));
#else
Mat3d m(Vec3d(xform[0][0], xform[1][0], xform[2][0]),
Vec3d(xform[0][1], xform[1][1], xform[2][1]),
Vec3d(xform[0][2], xform[1][2], xform[2][2]));
#endif
Quatd q = Quatd::matrixToQuaternion(m);
// Transform into Celestia's coordinate system
return Quatd::yrotation(PI) * Quatd::xrotation(-PI / 2.0) * ~q * Quatd::xrotation(PI / 2.0);
}
}