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