|
Isis 3.0 Application Source Code Reference |
Home |
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, <); 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 }