USGS

Isis 3.0 Application Source Code Reference

Home

LineScanCameraRotation.cpp

Go to the documentation of this file.
00001 #include <string>
00002 #include <algorithm>
00003 #include <vector>
00004 #include <cfloat>
00005 #include <cmath>
00006 #include <iomanip>
00007 
00008 #include "LineScanCameraRotation.h"
00009 #include "Quaternion.h"
00010 #include "LineEquation.h"
00011 #include "BasisFunction.h"
00012 #include "LeastSquares.h"
00013 #include "BasisFunction.h"
00014 #include "PolynomialUnivariate.h"
00015 #include "IString.h"
00016 #include "iTime.h"
00017 #include "IException.h"
00018 #include "Table.h"
00019 #include "NaifStatus.h"
00020 
00021 // Declarations for binding for Naif Spicelib routine refchg_ that does not have
00022 // a wrapper
00023 extern int refchg_(integer *frame1, integer *frame2, doublereal *et,
00024                    doublereal *rotate);
00025 
00026 namespace Isis {
00027   /**
00028    * Construct an empty SpiceRotation class using a valid Naif frame code to
00029    * set up for getting rotation from Spice kernels.  See required reading
00030    * ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/ascii/individual_docs/naif_ids.req
00031    *
00032    * @param frameCode Valid naif frame code.
00033    */
00034   LineScanCameraRotation::LineScanCameraRotation(int frameCode, Isis::Pvl &lab, std::vector<double> timeCache, double tol) : SpiceRotation(frameCode) {
00035     // Initialize optional paramters;
00036     p_pitchRate = 0.;
00037     p_yaw = 0.;
00038 
00039     // Load the Spice kernels to get state matrices
00040     p_spi = 0;
00041     p_spi = new Isis::Spice(lab);
00042 
00043     // Make sure the kernels are written to the labels and not just the tables (blobs)
00044     if(!p_spi->hasKernels(lab)) {
00045       QString msg = "The master file must contain the kernel files.  Rerun spiceinit with attach=no";
00046       throw IException(IException::User, msg, _FILEINFO_);
00047     }
00048 
00049     // Get the kernel group and save the instrument pointing keyword
00050     Isis::PvlGroup kernels = lab.FindGroup("Kernels", Isis::Pvl::Traverse);
00051     p_ckKeyword = kernels["InstrumentPointing"];
00052 
00053     p_cacheTime = timeCache;
00054 //    std::cout<<std::setprecision(24);
00055 //    std::cout<<timeCache.at(0)<<"-"<<timeCache.at(50000)<<std::endl;
00056 
00057     InitConstantRotation(p_cacheTime[0]);
00058 
00059     p_cachesLoaded = false;
00060     p_spi->instrumentRotation()->SetFrame(frameCode);
00061     p_crot = p_spi->instrumentRotation();
00062     p_prot = p_spi->bodyRotation();
00063     p_spos = p_spi->instrumentPosition();
00064     // Load the line scan specific rotation matrix caches before loading the regular Spice caches because
00065     // the CreateCache method will unload all the kernels after the caches are created
00066     LoadCache();
00067     p_spi->createCache(timeCache[0], timeCache[timeCache.size()-1], timeCache.size(), tol);
00068   }
00069 
00070 
00071 
00072   /**
00073    *  Destroys the LineScanComeraRotation object
00074    */
00075   LineScanCameraRotation::~LineScanCameraRotation() {
00076     if(p_spi != 0) delete p_spi;
00077   }
00078 
00079 
00080 
00081   /** Cache J2000 rotation quaternion over a time range.
00082    *
00083    * This method will load an internal cache with frames over a time
00084    * range.  This prevents the NAIF kernels from being read over-and-over
00085    * again and slowing an application down due to I/O performance.  Once the
00086    * cache has been loaded then the kernels can be unloaded from the NAIF
00087    * system.
00088    *
00089    * @internal
00090    * @history 2010-12-23  Debbie A. Cook Added set of full cache time
00091    *                       parameters
00092    */
00093   void LineScanCameraRotation::LoadCache() {
00094     NaifStatus::CheckErrors();
00095 
00096     double startTime = p_cacheTime[0];
00097     int size = p_cacheTime.size();
00098     double endTime = p_cacheTime[size-1];
00099     SetFullCacheParameters(startTime, endTime, size);
00100 
00101     // TODO  Add a label value to indicate pointing is already decomposed to line scan angles
00102     // and set p_pointingDecomposition=none,framing angles, or line scan angles.
00103     // Also add a label value to indicate jitterOffsets=jitterFileName
00104     // Then we can decide whether to simply grab the crot angles or do new decomposition and whether
00105     // to apply jitter or throw an error because jitter has already been applied.
00106 
00107     // *** May need to do a frame trace and load the frames (at least the constant ones) ***
00108 
00109     // Loop and load the cache
00110     double state[6];
00111     double lt;
00112     NaifStatus::CheckErrors();
00113 
00114     double R[3];  // Direction of radial axis of line scan camera
00115     double C[3];  // Direction of cross-track axis
00116     double I[3];  // Direction of in-track axis
00117     double *velocity;
00118     std::vector<double> IB(9);
00119     std::vector<double> CI(9);
00120     SpiceRotation *prot = p_spi->bodyRotation();
00121     SpiceRotation *crot = p_spi->instrumentRotation();
00122 
00123     for(std::vector<double>::iterator i = p_cacheTime.begin(); i < p_cacheTime.end(); i++) {
00124       double et = *i;
00125 
00126       prot->SetEphemerisTime(et);
00127       crot->SetEphemerisTime(et);
00128 
00129       // The following code will be put into method LoadIBcache()
00130       spkezr_c("MRO", et, "IAU_MARS", "NONE", "MARS", state, &lt);
00131       NaifStatus::CheckErrors();
00132 
00133       // Compute the direction of the radial axis (3) of the line scan camera
00134       vscl_c(1. / vnorm_c(state), state, R); // vscl and vnorm only operate on first 3 members of state
00135 
00136       // Compute the direction of the cross-track axis (2) of the line scan camera
00137       velocity  =  state + 3;
00138       vscl_c(1. / vnorm_c(velocity), velocity, C);
00139       vcrss_c(R, C, C);
00140 
00141       // Compute the direction of the in-track axis (1) of the line scan camera
00142       vcrss_c(C, R, I);
00143 
00144       // Load the matrix IB and enter it into the cache
00145       vequ_c(I, (SpiceDouble( *)) &IB[0]);
00146       vequ_c(C, (SpiceDouble( *)) &IB[3]);
00147       vequ_c(R, (SpiceDouble( *)) &IB[6]);
00148       p_cacheIB.push_back(IB);
00149       // end IB code
00150 
00151       // Compute the CIcr matrix - in-track, cross-track, radial frame to constant frame
00152       mxmt_c((SpiceDouble( *)[3]) & (crot->TimeBasedMatrix())[0], (SpiceDouble( *)[3]) & (prot->Matrix())[0],
00153              (SpiceDouble( *)[3]) &CI[0]);
00154 
00155       // Put CI into parent cache to use the parent class methods on it
00156       mxmt_c((SpiceDouble( *)[3]) &CI[0], (SpiceDouble( *)[3]) &IB[0], (SpiceDouble( *)[3]) &CI[0]);
00157       p_cache.push_back(CI);
00158     }
00159     p_cachesLoaded = true;
00160     SetSource(Memcache);
00161 
00162     NaifStatus::CheckErrors();
00163   }
00164 
00165   /** Cache J2000 rotation over existing cached time range using polynomials
00166    *
00167    * This method will reload an internal cache with matrices
00168    * formed from rotation angles fit to polynomials over a time
00169    * range.
00170    *
00171    * @param function1   The first polynomial function used to
00172    *                    find the rotation angles
00173    * @param function2   The second polynomial function used to
00174    *                    find the rotation angles
00175    * @param function3   The third polynomial function used to
00176    *                    find the rotation angles
00177    */
00178   void LineScanCameraRotation::ReloadCache() {
00179     NaifStatus::CheckErrors();
00180 
00181     // Make sure caches are already loaded
00182     if(!p_cachesLoaded) {
00183       QString msg = "A LineScanCameraRotation cache has not been loaded yet";
00184       throw IException(IException::Programmer, msg, _FILEINFO_);
00185     }
00186 
00187     // Clear existing matrices from cache
00188     p_cache.clear();
00189 
00190     // Create polynomials fit to angles & use to reload cache
00191     Isis::PolynomialUnivariate function1(p_degree);
00192     Isis::PolynomialUnivariate function2(p_degree);
00193     Isis::PolynomialUnivariate function3(p_degree);
00194 
00195     // Get the coefficients of the polynomials already fit to the angles of rotation defining [CI]
00196     std::vector<double> coeffAng1;
00197     std::vector<double> coeffAng2;
00198     std::vector<double> coeffAng3;
00199     GetPolynomial(coeffAng1, coeffAng2, coeffAng3);
00200 
00201     // Reset linear term to center around zero -- what works best is either roll-avg & pitchavg+ or pitchavg+ & yawavg-
00202 //    coeffAng1[1] -= 0.0000158661225;
00203 //    coeffAng2[1] = 0.0000308433;
00204 //    coeffAng3[0] = -0.001517547;
00205     if(p_pitchRate)  coeffAng2[1] = p_pitchRate;
00206     if(p_yaw)  coeffAng3[0] = p_yaw;
00207 
00208     // Load the functions with the coefficients
00209     function1.SetCoefficients(coeffAng1);
00210     function2.SetCoefficients(coeffAng2);
00211     function3.SetCoefficients(coeffAng3);
00212 
00213     double CI[3][3];
00214     double IJ[3][3];
00215     std::vector<double> rtime;
00216     SpiceRotation *prot = p_spi->bodyRotation();
00217     std::vector<double> CJ;
00218     CJ.resize(9);
00219 
00220     for(std::vector<double>::size_type pos = 0; pos < p_cacheTime.size(); pos++) {
00221       double et = p_cacheTime.at(pos);
00222       rtime.push_back((et - GetBaseTime()) / GetTimeScale());
00223       double angle1 = function1.Evaluate(rtime);
00224       double angle2 = function2.Evaluate(rtime);
00225       double angle3 = function3.Evaluate(rtime);
00226       rtime.clear();
00227 
00228 // Get the first angle back into the range Naif expects [180.,180.]
00229       if(angle1 < -1 * pi_c()) {
00230         angle1 += twopi_c();
00231       }
00232       else if(angle1 > pi_c()) {
00233         angle1 -= twopi_c();
00234       }
00235 
00236       eul2m_c((SpiceDouble) angle3, (SpiceDouble) angle2, (SpiceDouble) angle1,
00237               p_axis3,                    p_axis2,                    p_axis1,
00238               CI);
00239       mxm_c((SpiceDouble( *)[3]) & (p_jitter->SetEphemerisTimeHPF(et))[0], CI, CI);
00240 
00241       prot->SetEphemerisTime(et);
00242       mxm_c((SpiceDouble( *)[3]) & (p_cacheIB.at(pos))[0], (SpiceDouble( *)[3]) & (prot->Matrix())[0], IJ);
00243       mxm_c(CI, IJ, (SpiceDouble( *)[3]) &CJ[0]);
00244 
00245       p_cache.push_back(CJ);   // J2000 to constant frame
00246     }
00247 
00248     // Set source to cache to get updated values
00249     SetSource(SpiceRotation::Memcache);
00250 
00251     // Make sure SetEphemerisTime updates the matrix by resetting it twice (in case the first one
00252     // matches the current et.  p_et is private and not available from the child class
00253     NaifStatus::CheckErrors();
00254     SetEphemerisTime(p_cacheTime[0]);
00255     SetEphemerisTime(p_cacheTime[1]);
00256 
00257     NaifStatus::CheckErrors();
00258   }
00259 
00260 }