Isis 3.0 Programmer Reference
Back | Home
SpiceRotation.cpp
1 #include "SpiceRotation.h"
2 
3 #include <algorithm>
4 #include <cfloat>
5 #include <cmath>
6 #include <iomanip>
7 #include <string>
8 #include <vector>
9 
10 #include <QDebug>
11 #include <QString>
12 
13 #include <SpiceUsr.h>
14 #include <SpiceZfc.h>
15 #include <SpiceZmc.h>
16 
17 #include "BasisFunction.h"
18 #include "IException.h"
19 #include "IString.h"
20 #include "LeastSquares.h"
21 #include "LineEquation.h"
22 #include "NaifStatus.h"
23 #include "PolynomialUnivariate.h"
24 #include "Quaternion.h"
25 #include "Table.h"
26 #include "TableField.h"
27 
28 // Declarations for bindings for Naif Spicelib routines that do not have
29 // a wrapper
30 extern int refchg_(integer *frame1, integer *frame2, doublereal *et,
31  doublereal *rotate);
32 extern int frmchg_(integer *frame1, integer *frame2, doublereal *et,
33  doublereal *rotate);
34 extern int invstm_(doublereal *mat, doublereal *invmat);
35 // Temporary declarations for bindings for Naif supportlib routines
36 
37 // These three declarations should be removed once supportlib is in Isis3
38 extern int ck3sdn(double sdntol, bool avflag, int *nrec,
39  double *sclkdp, double *quats, double *avvs,
40  int nints, double *starts, double *dparr,
41  int *intarr);
42 
43 namespace Isis {
52  p_constantFrames.push_back(frameCode);
53  p_timeBias = 0.0;
54  p_source = Spice;
55  p_CJ.resize(9);
56  p_matrixSet = false;
57  p_et = -DBL_MAX;
58  p_degree = 2;
59  p_degreeApplied = false;
60  p_noOverride = true;
61  p_axis1 = 3;
62  p_axis2 = 1;
63  p_axis3 = 3;
65  p_hasAngularVelocity = false;
66  p_av.resize(3);
69  p_fullCacheSize = 0;
72  }
73 
74 
85  SpiceRotation::SpiceRotation(int frameCode, int targetCode) {
87 
88  p_constantFrames.push_back(frameCode);
89  p_targetCode = targetCode;
90  p_timeBias = 0.0;
91  p_source = Nadir;
92  p_CJ.resize(9);
93  p_matrixSet = false;
94  p_et = -DBL_MAX;
95  p_axisP = 3;
96  p_degree = 2;
97  p_degreeApplied = false;
98  p_noOverride = true;
99  p_axis1 = 3;
100  p_axis2 = 1;
101  p_axis3 = 3;
103  p_hasAngularVelocity = false;
104  p_av.resize(3);
106  p_fullCacheEndTime = 0;
107 
108  p_fullCacheSize = 0;
109  m_frameType = DYN;
110  m_tOrientationAvailable = false;
111 
112  // Determine the axis for the velocity vector
113  QString key = "INS" + toString(frameCode) + "_TRANSX";
114  SpiceDouble transX[2];
115  SpiceInt number;
116  SpiceBoolean found;
117  //Read starting at element 1 (skipping element 0)
118  gdpool_c(key.toLatin1().data(), 1, 2, &number, transX, &found);
119 
120  if (!found) {
121  QString msg = "Cannot find [" + key + "] in text kernels";
122  throw IException(IException::Io, msg, _FILEINFO_);
123  }
124 
125  p_axisV = 2;
126  if (transX[0] < transX[1]) p_axisV = 1;
127 
129  }
130 
131 
138  p_cacheTime = rotToCopy.p_cacheTime;
139  p_cache = rotToCopy.p_cache;
140  p_cacheAv = rotToCopy.p_cacheAv;
141  p_av = rotToCopy.p_av;
142  p_degree = rotToCopy.p_degree;
143  p_axis1 = rotToCopy.p_axis1;
144  p_axis2 = rotToCopy.p_axis2;
145  p_axis3 = rotToCopy.p_axis3;
146 
148  p_timeFrames = rotToCopy.p_timeFrames;
149  p_timeBias = rotToCopy.p_timeBias;
150 
151  p_et = rotToCopy.p_et;
152  p_quaternion = rotToCopy.p_quaternion;
153  p_matrixSet = rotToCopy.p_matrixSet;
154  p_source = rotToCopy.p_source;
155  p_axisP = rotToCopy.p_axisP;
156  p_axisV = rotToCopy.p_axisV;
157  p_targetCode = rotToCopy.p_targetCode;
158  p_baseTime = rotToCopy.p_baseTime;
159  p_timeScale = rotToCopy.p_timeScale;
160  p_degreeApplied = rotToCopy.p_degreeApplied;
161 
162 // for (std::vector<double>::size_type i = 0; i < rotToCopy.p_coefficients[0].size(); i++)
163  for (int i = 0; i < 3; i++)
164  p_coefficients[i] = rotToCopy.p_coefficients[i];
165 
166  p_noOverride = rotToCopy.p_noOverride;
169  p_minimizeCache = rotToCopy.p_minimizeCache;
172  p_fullCacheSize = rotToCopy.p_fullCacheSize;
173  p_TC = rotToCopy.p_TC;
174 
175  p_CJ = rotToCopy.p_CJ;
176  p_degree = rotToCopy.p_degree;
178  m_frameType = rotToCopy.m_frameType;
179 
180  }
181 
182 
187  }
188 
189 
196  void SpiceRotation::SetFrame(int frameCode) {
197  p_constantFrames[0] = frameCode;
198  }
199 
200 
208  return p_constantFrames[0];
209  }
210 
211 
224  void SpiceRotation::SetTimeBias(double timeBias) {
225  p_timeBias = timeBias;
226  }
227 
228 
243 
244  // Save the time
245  if (p_et == et) return;
246  p_et = et;
247 
248  // Read from the cache
249  if (p_source == Memcache) {
251  }
252 
253  // Apply coefficients defining a function for each of the three camera angles and angular
254  // velocity if available
255  else if (p_source == PolyFunction) {
257  }
258  // Apply coefficients defining a function for each of the three camera angles and angular
259  // velocity if available
260  else if (p_source == PolyFunctionOverSpice) {
262  }
263  // Read from the kernel
264  else if (p_source == Spice) {
266  // Retrieve the J2000 (code=1) to reference rotation matrix
267  }
268  // Apply coefficients from PCK version of IAU solution for target body orientation and angular
269  // velocity???
270  else if (p_source == PckPolyFunction) {
272  }
273  // Compute from Nadir
274  else {
276  }
277 
278  // Set the quaternion for this rotation
279 // p_quaternion.Set ( p_CJ );
280  }
281 
282 
289  return p_et;
290  }
291 
292 
298  bool SpiceRotation::IsCached() const {
299  return (p_cache.size() > 0);
300  }
301 
302 
309  p_minimizeCache = status;
310  }
311 
312 
331  void SpiceRotation::LoadCache(double startTime, double endTime, int size) {
332 
333  // Check for valid arguments
334  if (size <= 0) {
335  QString msg = "Argument cacheSize must not be less or equal to zero";
337  }
338 
339  if (startTime > endTime) {
340  QString msg = "Argument startTime must be less than or equal to endTime";
342  }
343 
344  if ((startTime != endTime) && (size == 1)) {
345  QString msg = "Cache size must be more than 1 if startTime and endTime differ";
347  }
348 
349  // Make sure cache isn't already loaded
350  if (p_source == Memcache) {
351  QString msg = "A SpiceRotation cache has already been created";
353  }
354 
355  // Save full cache parameters
356  p_fullCacheStartTime = startTime;
357  p_fullCacheEndTime = endTime;
358  p_fullCacheSize = size;
359 
360  // Make sure the constant frame is loaded. This method also does the frame trace.
361  if (p_timeFrames.size() == 0) InitConstantRotation(startTime);
362 
363  // Set the frame type. If the frame class is PCK, load the constants.
364  if (p_source == Spice) {
365  setFrameType();
366  }
367 
368  LoadTimeCache();
369  int cacheSize = p_cacheTime.size();
370 
371  // Loop and load the cache
372  for (int i = 0; i < cacheSize; i++) {
373  double et = p_cacheTime[i];
374  SetEphemerisTime(et);
375  p_cache.push_back(p_CJ);
376  if (p_hasAngularVelocity) p_cacheAv.push_back(p_av);
377  }
378  p_source = Memcache;
379 
380  // Downsize already loaded caches (both time and quats)
381  if (p_minimizeCache == Yes && cacheSize > 5) {
382  LoadTimeCache();
383  }
384  }
385 
386 
400  void SpiceRotation::LoadCache(double time) {
401  LoadCache(time, time, 1);
402  }
403 
404 
430  // Clear any existing cached data to make it reentrant (KJB 2011-07-20).
431  p_timeFrames.clear();
432  p_TC.clear();
433  p_cache.clear();
434  p_cacheTime.clear();
435  p_cacheAv.clear();
436  p_hasAngularVelocity = false;
437 
438  // Load the constant and time-based frame traces and the constant rotation
439  if (table.Label().hasKeyword("TimeDependentFrames")) {
440  PvlKeyword labelTimeFrames = table.Label()["TimeDependentFrames"];
441  for (int i = 0; i < labelTimeFrames.size(); i++) {
442  p_timeFrames.push_back(toInt(labelTimeFrames[i]));
443  }
444  }
445  else {
446  p_timeFrames.push_back(p_constantFrames[0]);
447  p_timeFrames.push_back(J2000Code);
448  }
449 
450  if (table.Label().hasKeyword("ConstantRotation")) {
451  PvlKeyword labelConstantFrames = table.Label()["ConstantFrames"];
452  p_constantFrames.clear();
453 
454  for (int i = 0; i < labelConstantFrames.size(); i++) {
455  p_constantFrames.push_back(toInt(labelConstantFrames[i]));
456  }
457  PvlKeyword labelConstantRotation = table.Label()["ConstantRotation"];
458 
459  for (int i = 0; i < labelConstantRotation.size(); i++) {
460  p_TC.push_back(toDouble(labelConstantRotation[i]));
461  }
462  }
463  else {
464  p_TC.resize(9);
465  ident_c((SpiceDouble( *)[3]) &p_TC[0]);
466  }
467 
468  // Load the full cache time information from the label if available
469  if (table.Label().hasKeyword("CkTableStartTime")) {
470  p_fullCacheStartTime = toDouble(table.Label().findKeyword("CkTableStartTime")[0]);
471  }
472  if (table.Label().hasKeyword("CkTableEndTime")) {
473  p_fullCacheEndTime = toDouble(table.Label().findKeyword("CkTableEndTime")[0]);
474  }
475  if (table.Label().hasKeyword("CkTableOriginalSize")) {
476  p_fullCacheSize = toInt(table.Label().findKeyword("CkTableOriginalSize")[0]);
477  }
478 
479  // Load FrameTypeCode from labels if available and the planetary constants keywords
480  if (table.Label().hasKeyword("FrameTypeCode")) {
481  m_frameType = (FrameType) toInt(table.Label().findKeyword("FrameTypeCode")[0]);
482  }
483  else {
485  }
486 
487  if (m_frameType == PCK) {
488  loadPCFromTable(table.Label());
489  }
490 
491  int recFields = table[0].Fields();
492 
493  // Loop through and move the table to the cache. Retrieve the first record to
494  // establish the type of cache and then use the appropriate loop.
495 
496  // list table of quaternion and time
497  if (recFields == 5) {
498  for (int r = 0; r < table.Records(); r++) {
499  TableRecord &rec = table[r];
500 
501  if (rec.Fields() != recFields) {
502  // throw and error
503  }
504 
505  std::vector<double> j2000Quat;
506  j2000Quat.push_back((double)rec[0]);
507  j2000Quat.push_back((double)rec[1]);
508  j2000Quat.push_back((double)rec[2]);
509  j2000Quat.push_back((double)rec[3]);
510 
511  Quaternion q(j2000Quat);
512  std::vector<double> CJ = q.ToMatrix();
513  p_cache.push_back(CJ);
514  p_cacheTime.push_back((double)rec[4]);
515  }
516  p_source = Memcache;
517  }
518 
519  // list table of quaternion, angular velocity vector, and time
520  else if (recFields == 8) {
521  for (int r = 0; r < table.Records(); r++) {
522  TableRecord &rec = table[r];
523 
524  if (rec.Fields() != recFields) {
525  // throw and error
526  }
527 
528  std::vector<double> j2000Quat;
529  j2000Quat.push_back((double)rec[0]);
530  j2000Quat.push_back((double)rec[1]);
531  j2000Quat.push_back((double)rec[2]);
532  j2000Quat.push_back((double)rec[3]);
533 
534 
535  Quaternion q(j2000Quat);
536  std::vector<double> CJ = q.ToMatrix();
537  p_cache.push_back(CJ);
538 
539  std::vector<double> av;
540  av.push_back((double)rec[4]);
541  av.push_back((double)rec[5]);
542  av.push_back((double)rec[6]);
543  p_cacheAv.push_back(av);
544 
545  p_cacheTime.push_back((double)rec[7]);
546  p_hasAngularVelocity = true;
547  }
548  p_source = Memcache;
549  }
550 
551  // coefficient table for angle1, angle2, and angle3
552  else if (recFields == 3) {
553  std::vector<double> coeffAng1, coeffAng2, coeffAng3;
554 
555  for (int r = 0; r < table.Records() - 1; r++) {
556  TableRecord &rec = table[r];
557 
558  if (rec.Fields() != recFields) {
559  // throw an error
560  }
561  coeffAng1.push_back((double)rec[0]);
562  coeffAng2.push_back((double)rec[1]);
563  coeffAng3.push_back((double)rec[2]);
564  }
565 
566  // Take care of time parameters
567  TableRecord &rec = table[table.Records()-1];
568  double baseTime = (double)rec[0];
569  double timeScale = (double)rec[1];
570  double degree = (double)rec[2];
571  SetPolynomialDegree((int) degree);
572  SetOverrideBaseTime(baseTime, timeScale);
573  SetPolynomial(coeffAng1, coeffAng2, coeffAng3);
575  if (degree > 0) p_hasAngularVelocity = true;
576  if (degree == 0 && p_cacheAv.size() > 0) p_hasAngularVelocity = true;
577  }
578  else {
579  QString msg = "Expecting either three, five, or eight fields in the SpiceRotation table";
581  }
582  }
583 
584 
595  // Save current et
596  double et = p_et;
597  p_et = -DBL_MAX;
598 
599  if (p_source == PolyFunction) {
600  // Clear existing matrices from cache
601  p_cacheTime.clear();
602  p_cache.clear();
603 
604  // Clear the angular velocity cache if we can calculate it instead. It can't be calculated
605  // for functions of degree 0 (framing cameras), so keep the original av. It is better than
606  // nothing.
607  if (p_degree > 0 && p_cacheAv.size() > 1) p_cacheAv.clear();
608 
609  // Load the time cache first
611  LoadTimeCache();
612 
613  if (p_fullCacheSize > 1) {
614  // Load the matrix and av caches
615  for (std::vector<double>::size_type pos = 0; pos < p_cacheTime.size(); pos++) {
616  SetEphemerisTime(p_cacheTime.at(pos));
617  p_cache.push_back(p_CJ);
618  p_cacheAv.push_back(p_av);
619  }
620  }
621  else {
622  // Load the matrix for the single updated time instance
624  p_cache.push_back(p_CJ);
625  }
626  }
627  else if (p_source == PolyFunctionOverSpice) {
628  SpiceRotation tempRot(*this);
629 
630  std::vector<double>::size_type maxSize = p_fullCacheSize;
631 
632  // Clear the existing caches
633  p_cache.clear();
634  p_cacheTime.clear();
635  p_cacheAv.clear();
636 
637  // Reload the time cache first
639  LoadTimeCache();
640 
641  for (std::vector<double>::size_type pos = 0; pos < maxSize; pos++) {
642  tempRot.SetEphemerisTime(p_cacheTime.at(pos));
643  p_cache.push_back(tempRot.TimeBasedMatrix());
644  if (p_hasAngularVelocity) p_cacheAv.push_back(tempRot.AngularVelocity());
645  }
646  }
647  else { //(p_source < PolyFunction)
648  QString msg = "The SpiceRotation has not yet been fit to a function";
650  }
651 
652  // Set source to cache and reset current et
653  // Make sure source is Memcache now
654  p_source = Memcache;
655  p_et = -DBL_MAX;
656  SetEphemerisTime(et);
657  }
658 
659 
674  Table SpiceRotation::LineCache(const QString &tableName) {
675 
676  // Apply the function and fill the caches
678 
679  if (p_source != Memcache) {
680  QString msg = "Only cached rotations can be returned as a line cache of quaternions and time";
682  }
683  // Load the table and return it to caller
684  return Cache(tableName);
685  }
686 
687 
710  Table SpiceRotation::Cache(const QString &tableName) {
711  // First handle conversion of PolyFunctionOverSpiceConstant
712  // by converting it to the full Memcache and try to downsize it
714  LineCache(tableName);
715 
716  //std::cout << "Full cache size is " << p_cache.size() << endl;
717 
719  LoadTimeCache();
720 
721  //std::cout << "Minimized cache size is " << p_cache.size() << endl;
722  }
723 
724  // Load the list of rotations and their corresponding times
725  if (p_source == Memcache) {
726  TableField q0("J2000Q0", TableField::Double);
727  TableField q1("J2000Q1", TableField::Double);
728  TableField q2("J2000Q2", TableField::Double);
729  TableField q3("J2000Q3", TableField::Double);
731 
732  TableRecord record;
733  record += q0;
734  record += q1;
735  record += q2;
736  record += q3;
737  int timePos = 4;
738 
739  if (p_hasAngularVelocity) {
740  TableField av1("AV1", TableField::Double);
741  TableField av2("AV2", TableField::Double);
742  TableField av3("AV3", TableField::Double);
743  record += av1;
744  record += av2;
745  record += av3;
746  timePos = 7;
747  }
748 
749  record += t;
750  Table table(tableName, record);
751 
752  for (int i = 0; i < (int)p_cache.size(); i++) {
753  Quaternion q(p_cache[i]);
754  std::vector<double> v = q.GetQuaternion();
755  record[0] = v[0];
756  record[1] = v[1];
757  record[2] = v[2];
758  record[3] = v[3];
759 
760  if (p_hasAngularVelocity) {
761  record[4] = p_cacheAv[i][0];
762  record[5] = p_cacheAv[i][1];
763  record[6] = p_cacheAv[i][2];
764  }
765 
766  record[timePos] = p_cacheTime[i];
767  table += record;
768  }
769 
770  CacheLabel(table);
771  return table;
772  }
773  // Just load the position for the single epoch
774  else if (p_source == PolyFunction && p_degree == 0 && p_fullCacheSize == 1) {
775  return LineCache(tableName);
776  }
777  // Load the coefficients for the curves fit to the 3 camera angles
778  else if (p_source == PolyFunction) {
779  TableField angle1("J2000Ang1", TableField::Double);
780  TableField angle2("J2000Ang2", TableField::Double);
781  TableField angle3("J2000Ang3", TableField::Double);
782 
783  TableRecord record;
784  record += angle1;
785  record += angle2;
786  record += angle3;
787 
788  Table table(tableName, record);
789 
790  for (int cindex = 0; cindex < p_degree + 1; cindex++) {
791  record[0] = p_coefficients[0][cindex];
792  record[1] = p_coefficients[1][cindex];
793  record[2] = p_coefficients[2][cindex];
794  table += record;
795  }
796 
797  // Load one more table entry with the time adjustments for the fit equation
798  // t = (et - baseTime)/ timeScale
799  record[0] = p_baseTime;
800  record[1] = p_timeScale;
801  record[2] = (double) p_degree;
802 
803  table += record;
804  CacheLabel(table);
805  return table;
806  }
807  else {
808  // throw an error -- should not get here -- invalid Spice Source
809  QString msg = "To create table source of data must be either Memcache or PolyFunction";
811  }
812  }
813 
814 
822  void SpiceRotation::loadPCFromSpice(int centerBody) {
824  SpiceInt centerBodyCode = (SpiceInt) centerBody;
825 
826  // Retrieve the frame class from Naif. We distinguish PCK types into text PCK,
827  // binary PCK, and PCK not referenced to J2000. Isis binary PCK can
828  // not be used to solve for target body orientation because of the variety and
829  // complexity models used with binary PCK. Currently ISIS does not solve for
830  // target body orientation on bodies not referenced to J2000, but it could be
831  // changed to handle that case.
833 
834  if (m_frameType == PCK) {
835  // Make sure the reference frame is J2000. We will need to modify FrameTrace and
836  // the pck methods in this class to handle this case. At the time this method was
837  // added, this case is not being used in the pck file. It is mentioned in the Naif required
838  // reading file, pck.req, as a possibility for future pck files.
839  // Look for a reference frame keyword for the body. The default is J2000.
840  QString naifKeyword = "BODY" + toString(centerBodyCode) + "_CONSTANTS_REF_FRAME" ;
841  SpiceInt numExpected;
842  SpiceInt numReturned;
843  SpiceChar naifType;
844  SpiceDouble relativeFrameCode = 0;
845  SpiceBoolean found;
846  dtpool_c(naifKeyword.toLatin1().data(), &found, &numExpected, &naifType);
847 
848  if (found) {
849  // Go get the frame name if it is not the default J2000
850  SpiceDouble relativeFrameCode;
851  bodvcd_c(centerBodyCode, "CONSTANTS_REF_FRAME", 1,
852  &numReturned, &relativeFrameCode);
853  }
854 
855  if (!found || relativeFrameCode == 1) { // We only work with J2000 relative frames for now
856 
857  // Make sure the standard coefficients are available for the body code by
858  // checking for ra
859  naifKeyword = "BODY" + toString(centerBodyCode) + "_POLE_RA" ;
860  dtpool_c(naifKeyword.toLatin1().data(), &found, &numExpected, &naifType);
861 
862  if (found) {
863  std::vector<SpiceDouble> d(3);
864  m_raPole.resize(numExpected);
865  m_decPole.resize(numExpected);
866  m_pm.resize(numExpected);
867 
868  bodvcd_c(centerBodyCode, "POLE_RA", numExpected, &numReturned, &d[0]);
869  m_raPole[0].setDegrees(d[0]);
870  m_raPole[1].setDegrees(d[1]);
871  m_raPole[2].setDegrees(d[2]);
872 
873  bodvcd_c(centerBodyCode, "POLE_DEC", numExpected, &numReturned, &d[0]);
874  m_decPole[0].setDegrees(d[0]);
875  m_decPole[1].setDegrees(d[1]);
876  m_decPole[2].setDegrees(d[2]);
877 
878  bodvcd_c(centerBodyCode, "PM", numExpected, &numReturned, &d[0]);
879  m_pm[0].setDegrees(d[0]);
880  m_pm[1].setDegrees(d[1]);
881  m_pm[2].setDegrees(d[2]);
882 
883  // ***TODO*** Get long axis value
885 
886  // Now check for nutation/precession terms. Check for nut/prec ra values
887  // first to see if the terms are even used for this body.
888  naifKeyword = "BODY" + toString(centerBodyCode) + "_NUT_PREC_RA" ;
889  dtpool_c(naifKeyword.toLatin1().data(), &found, &numReturned, &naifType);
890  if (found) {
891  // Get the barycenter (bc) linear coefficients first (2 for each period).
892  // Then we can get the maximum expected coefficients.
893  SpiceInt bcCode = centerBodyCode/100; // Ex: bc code for Jupiter (599) & its moons is 5
894  naifKeyword = "BODY" + toString(bcCode) + "_NUT_PREC_ANGLES" ;
895  dtpool_c(naifKeyword.toLatin1().data(), &found, &numExpected, &naifType);
896  std::vector<double>npAngles(numExpected, 0.);
897  bodvcd_c(bcCode, "NUT_PREC_ANGLES", numExpected, &numReturned, &npAngles[0]);
898  numExpected /= 2.;
899  m_raNutPrec.resize(numExpected, 0.);
900  m_decNutPrec.resize(numExpected, 0.);
901  m_pmNutPrec.resize(numExpected, 0.);
902 
903  std::vector<SpiceDouble> angles(numExpected);
904  bodvcd_c(centerBodyCode, "NUT_PREC_RA", numExpected, &numReturned, &m_raNutPrec[0]);
905  bodvcd_c(centerBodyCode, "NUT_PREC_DEC", numExpected, &numReturned, &m_decNutPrec[0]);
906  bodvcd_c(centerBodyCode, "NUT_PREC_PM", numExpected, &numReturned, &m_pmNutPrec[0]);
907 
908  // Finally get the system linear terms separated into vectors of the constants and the
909  // linear coefficients
910 
911  for (int i = 0; i < numExpected; i++) {
912  m_sysNutPrec0.push_back(Angle(npAngles[i*2], Angle::Degrees));
913  m_sysNutPrec1.push_back(Angle(npAngles[i*2+1], Angle::Degrees));
914  }
915  } // barycenter terms
916  } // PCK constants available
917  } // Relative to J2000
918  else {
920  }
921  } // PCK
922 
924  }
925 
926 
936 
937  // First clear existing cached data
938  m_raPole.clear();
939  m_decPole.clear();
940  m_pm.clear();
941  m_raNutPrec.clear();
942  m_decNutPrec.clear();
943  m_sysNutPrec0.clear();
944  m_sysNutPrec1.clear();
945  int numLoaded = 0;
946 
947  // Load the PCK coeffcients if they are on the label
948  if (label.hasKeyword("PoleRa")) {
949  PvlKeyword labelCoeffs = label["PoleRa"];
950  for (int i = 0; i < labelCoeffs.size(); i++){
951  m_raPole.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees));
952  }
953  numLoaded += 1;
954  }
955  if (label.hasKeyword("PoleDec")) {
956  PvlKeyword labelCoeffs = label["PoleDec"];
957  for (int i = 0; i < labelCoeffs.size(); i++){
958  m_decPole.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees));
959  }
960  numLoaded += 1;
961  }
962  if (label.hasKeyword("PrimeMeridian")) {
963  PvlKeyword labelCoeffs = label["PrimeMeridian"];
964  for (int i = 0; i < labelCoeffs.size(); i++){
965  m_pm.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees));
966  }
967  numLoaded += 1;
968  }
969  if (numLoaded > 2) m_tOrientationAvailable = true;
970 
971  if (label.hasKeyword("PoleRaNutPrec")) {
972  PvlKeyword labelCoeffs = label["PoleRaNutPrec"];
973  for (int i = 0; i < labelCoeffs.size(); i++){
974  m_raNutPrec.push_back(toDouble(labelCoeffs[i]));
975  }
976  }
977  if (label.hasKeyword("PoleDecNutPrec")) {
978  PvlKeyword labelCoeffs = label["PoleDecNutPrec"];
979  for (int i = 0; i < labelCoeffs.size(); i++){
980  m_decNutPrec.push_back(toDouble(labelCoeffs[i]));
981  }
982  }
983  if (label.hasKeyword("PmNutPrec")) {
984  PvlKeyword labelCoeffs = label["PmNutPrec"];
985  for (int i = 0; i < labelCoeffs.size(); i++){
986  m_pmNutPrec.push_back(toDouble(labelCoeffs[i]));
987  }
988  }
989  if (label.hasKeyword("SysNutPrec0")) {
990  PvlKeyword labelCoeffs = label["SysNutPrec0"];
991  for (int i = 0; i < labelCoeffs.size(); i++){
992  m_sysNutPrec0.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees));
993  }
994  }
995  if (label.hasKeyword("SysNutPrec1")) {
996  PvlKeyword labelCoeffs = label["SysNutPrec1"];
997  for (int i = 0; i < labelCoeffs.size(); i++){
998  m_sysNutPrec1.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees));
999  }
1000  }
1001 
1003  }
1004 
1005 
1015  // Load the constant and time-based frame traces and the constant rotation
1016  // into the table as labels
1017  if (p_timeFrames.size() > 1) {
1018  table.Label() += PvlKeyword("TimeDependentFrames");
1019 
1020  for (int i = 0; i < (int) p_timeFrames.size(); i++) {
1021  table.Label()["TimeDependentFrames"].addValue(toString(p_timeFrames[i]));
1022  }
1023  }
1024 
1025  if (p_constantFrames.size() > 1) {
1026  table.Label() += PvlKeyword("ConstantFrames");
1027 
1028  for (int i = 0; i < (int) p_constantFrames.size(); i++) {
1029  table.Label()["ConstantFrames"].addValue(toString(p_constantFrames[i]));
1030  }
1031 
1032  table.Label() += PvlKeyword("ConstantRotation");
1033 
1034  for (int i = 0; i < (int) p_TC.size(); i++) {
1035  table.Label()["ConstantRotation"].addValue(toString(p_TC[i]));
1036  }
1037  }
1038 
1039  // Write original time coverage
1040  if (p_fullCacheStartTime != 0) {
1041  table.Label() += PvlKeyword("CkTableStartTime");
1042  table.Label()["CkTableStartTime"].addValue(toString(p_fullCacheStartTime));
1043  }
1044  if (p_fullCacheEndTime != 0) {
1045  table.Label() += PvlKeyword("CkTableEndTime");
1046  table.Label()["CkTableEndTime"].addValue(toString(p_fullCacheEndTime));
1047  }
1048  if (p_fullCacheSize != 0) {
1049  table.Label() += PvlKeyword("CkTableOriginalSize");
1050  table.Label()["CkTableOriginalSize"].addValue(toString(p_fullCacheSize));
1051  }
1052 
1053  // Begin section added 06-20-2015 DAC
1054  table.Label() += PvlKeyword("FrameTypeCode");
1055  table.Label()["FrameTypeCode"].addValue(toString(m_frameType));
1056 
1057  if (m_frameType == PCK) {
1058  // Write out all the body orientation constants
1059  // Pole right ascension coefficients for a quadratic equation
1060  table.Label() += PvlKeyword("PoleRa");
1061 
1062  for (int i = 0; i < (int) m_raPole.size(); i++) {
1063  table.Label()["PoleRa"].addValue(toString(m_raPole[i].degrees()));
1064  }
1065 
1066  // Pole right ascension, declination coefficients for a quadratic equation
1067  table.Label() += PvlKeyword("PoleDec");
1068  for (int i = 0; i < (int) m_decPole.size(); i++) {
1069  table.Label()["PoleDec"].addValue(toString(m_decPole[i].degrees()));
1070  }
1071 
1072  // Prime meridian coefficients for a quadratic equation
1073  table.Label() += PvlKeyword("PrimeMeridian");
1074  for (int i = 0; i < (int) m_pm.size(); i++) {
1075  table.Label()["PrimeMeridian"].addValue(toString(m_pm[i].degrees()));
1076  }
1077 
1078  if (m_raNutPrec.size() > 0) {
1079  // Pole right ascension nutation precision coefficients to the trig terms
1080  table.Label() += PvlKeyword("PoleRaNutPrec");
1081  for (int i = 0; i < (int) m_raNutPrec.size(); i++) {
1082  table.Label()["PoleRaNutPrec"].addValue(toString(m_raNutPrec[i]));
1083  }
1084 
1085  // Pole declination nutation precision coefficients to the trig terms
1086  table.Label() += PvlKeyword("PoleDecNutPrec");
1087  for (int i = 0; i < (int) m_decNutPrec.size(); i++) {
1088  table.Label()["PoleDecNutPrec"].addValue(toString(m_decNutPrec[i]));
1089  }
1090 
1091  // Prime meridian nutation precision coefficients to the trig terms
1092  table.Label() += PvlKeyword("PmNutPrec");
1093  for (int i = 0; i < (int) m_pmNutPrec.size(); i++) {
1094  table.Label()["PmNutPrec"].addValue(toString(m_pmNutPrec[i]));
1095  }
1096 
1097  // System nutation precision constant terms of linear model of periods
1098  table.Label() += PvlKeyword("SysNutPrec0");
1099  for (int i = 0; i < (int) m_sysNutPrec0.size(); i++) {
1100  table.Label()["SysNutPrec0"].addValue(toString(m_sysNutPrec0[i].degrees()));
1101  }
1102 
1103  // System nutation precision linear terms of linear model of periods
1104  table.Label() += PvlKeyword("SysNutPrec1");
1105  for (int i = 0; i < (int) m_sysNutPrec1.size(); i++) {
1106  table.Label()["SysNutPrec1"].addValue(toString(m_sysNutPrec1[i].degrees()));
1107  }
1108  }
1109  }
1110  // End section added 06-20-2015 DAC
1111 
1113  }
1114 
1115 
1121  std::vector<double> SpiceRotation::GetCenterAngles() {
1122  // Compute the center time
1123  double etCenter = (p_fullCacheEndTime + p_fullCacheStartTime) / 2.;
1124  SetEphemerisTime(etCenter);
1125 
1126  return Angles(p_axis3, p_axis2, p_axis1);
1127  }
1128 
1129 
1140  std::vector<double> SpiceRotation::Angles(int axis3, int axis2, int axis1) {
1142 
1143  SpiceDouble ang1, ang2, ang3;
1144  m2eul_c((SpiceDouble *) &p_CJ[0], axis3, axis2, axis1, &ang3, &ang2, &ang1);
1145 
1146  std::vector<double> angles;
1147  angles.push_back(ang1);
1148  angles.push_back(ang2);
1149  angles.push_back(ang3);
1150 
1152  return angles;
1153  }
1154 
1155 
1156 
1167  void SpiceRotation::SetAngles(std::vector<double> angles, int axis3, int axis2, int axis1) {
1168  eul2m_c(angles[2], angles[1], angles[0], axis3, axis2, axis1, (SpiceDouble (*)[3]) &(p_CJ[0]));
1169  p_cache[0] = p_CJ;
1170  // Reset to get the new values
1171  p_et = -DBL_MAX;
1173  }
1174 
1175 
1181  std::vector<double> SpiceRotation::AngularVelocity() {
1182  return p_av;
1183  }
1184 
1185 
1193  return p_constantFrames;
1194  }
1195 
1196 
1202  std::vector<int> SpiceRotation::TimeFrameChain() {
1203  return p_timeFrames;
1204  }
1205 
1206 
1213  return p_hasAngularVelocity;
1214  }
1215 
1216 
1224  std::vector<double> SpiceRotation::J2000Vector(const std::vector<double> &rVec) {
1226 
1227  std::vector<double> jVec;
1228 
1229  if (rVec.size() == 3) {
1230  double TJ[3][3];
1231  mxm_c((SpiceDouble *) &p_TC[0], (SpiceDouble *) &p_CJ[0], TJ);
1232  jVec.resize(3);
1233  mtxv_c(TJ, (SpiceDouble *) &rVec[0], (SpiceDouble *) &jVec[0]);
1234  }
1235 
1236  else if (rVec.size() == 6) {
1237  // See Naif routine frmchg for the format of the state matrix. The constant rotation, TC,
1238  // has a derivative with respect to time of I.
1239  if (!p_hasAngularVelocity) {
1240  // throw an error
1241  }
1242  std::vector<double> stateTJ(36);
1243  stateTJ = StateTJ();
1244 
1245  // Now invert (inverse of a state matrix is NOT simply the transpose)
1246  xpose6_c(&stateTJ[0], (SpiceDouble( *) [6]) &stateTJ[0]);
1247  double stateJT[6][6];
1248  invstm_((doublereal *) &stateTJ[0], (doublereal *) stateJT);
1249  xpose6_c(stateJT, stateJT);
1250  jVec.resize(6);
1251 
1252  mxvg_c(stateJT, (SpiceDouble *) &rVec[0], 6, 6, (SpiceDouble *) &jVec[0]);
1253  }
1254 
1256  return (jVec);
1257  }
1258 
1259 
1275  std::vector<Angle> SpiceRotation::poleRaCoefs() {
1276  return m_raPole;
1277  }
1278 
1279 
1295  std::vector<Angle> SpiceRotation::poleDecCoefs() {
1296  return m_decPole;
1297  }
1298 
1299 
1314  std::vector<Angle> SpiceRotation::pmCoefs() {
1315  return m_pm;
1316  }
1317 
1318 
1332  std::vector<double> SpiceRotation::poleRaNutPrecCoefs() {
1333  return m_raNutPrec;
1334  }
1335 
1336 
1349  std::vector<double> SpiceRotation::poleDecNutPrecCoefs() {
1350  return m_decNutPrec;
1351  }
1352 
1353 
1366  std::vector<double> SpiceRotation::pmNutPrecCoefs() {
1367  return m_pmNutPrec;
1368  }
1369 
1370 
1383  std::vector<Angle> SpiceRotation::sysNutPrecConstants() {
1384  return m_sysNutPrec0;
1385  }
1386 
1387 
1401  std::vector<Angle> SpiceRotation::sysNutPrecCoefs() {
1402  return m_sysNutPrec1;
1403  }
1404 
1405 
1425  std::vector<double> SpiceRotation::toJ2000Partial(const std::vector<double> &lookT,
1426  SpiceRotation::PartialType partialVar,
1427  int coeffIndex) {
1429 
1430  std::vector<double> jVec;
1431 
1432  // Get the rotation angles and form the derivative matrix for the partialVar
1433  std::vector<double> angles = Angles(p_axis3, p_axis2, p_axis1);
1434  int angleIndex = partialVar;
1435  int axes[3] = {p_axis1, p_axis2, p_axis3};
1436 
1437  double angle = angles.at(angleIndex);
1438 
1439  // Get TJ and apply the transpose to the input vector to get it to J2000
1440  double dmatrix[3][3];
1441  drotat_(&angle, (integer *) axes + angleIndex, (doublereal *) dmatrix);
1442  // Transpose to obtain row-major order
1443  xpose_c(dmatrix, dmatrix);
1444 
1445  // Get the derivative of the polynomial with respect to partialVar
1446  double dpoly = 0.;
1447  QString msg;
1448  switch (m_frameType) {
1449  case CK:
1450  dpoly = DPolynomial(coeffIndex);
1451  break;
1452  case PCK:
1453  dpoly = DPckPolynomial(partialVar, coeffIndex);
1454  break;
1455  case BPC:
1456  msg = "Body rotation uses a binary PCK. Solutions for this model are not supported";
1457  throw IException(IException::User, msg, _FILEINFO_);
1458  break;
1459  case NOTJ2000PCK:
1460  msg = "Body rotation uses a PCK not referenced to J2000. "
1461  "Solutions for this model are not supported";
1462  throw IException(IException::User, msg, _FILEINFO_);
1463  break;
1464  default:
1465  msg = "Solutions are not supported for this frame type.";
1466  throw IException(IException::User, msg, _FILEINFO_);
1467  }
1468 
1469  // Multiply dpoly to complete dmatrix
1470  for (int row = 0; row < 3; row++) {
1471  for (int col = 0; col < 3; col++) {
1472  dmatrix[row][col] *= dpoly;
1473  }
1474  }
1475 
1476  // Apply the other 2 angles and chain them all together to get J2000 to constant frame
1477  double dCJ[3][3];
1478  switch (angleIndex) {
1479  case 0:
1480  rotmat_c(dmatrix, angles[1], axes[1], dCJ);
1481  rotmat_c(dCJ, angles[2], axes[2], dCJ);
1482  break;
1483  case 1:
1484  rotate_c(angles[0], axes[0], dCJ);
1485  mxm_c(dmatrix, dCJ, dCJ);
1486  rotmat_c(dCJ, angles[2], axes[2], dCJ);
1487  break;
1488  case 2:
1489  rotate_c(angles[0], axes[0], dCJ);
1490  rotmat_c(dCJ, angles[1], axes[1], dCJ);
1491  mxm_c(dmatrix, dCJ, dCJ);
1492  break;
1493  }
1494 
1495  // Multiply the constant matrix to rotate to target reference frame
1496  double dTJ[3][3];
1497  mxm_c((SpiceDouble *) &p_TC[0], dCJ[0], dTJ);
1498 
1499  // Finally rotate the target vector with the transpose of the
1500  // derivative matrix, dTJ to get a J2000 vector
1501  std::vector<double> lookdJ(3);
1502 
1503  mtxv_c(dTJ, (const SpiceDouble *) &lookT[0], (SpiceDouble *) &lookdJ[0]);
1504 
1506  return (lookdJ);
1507  }
1508 
1509 
1517  std::vector<double> SpiceRotation::ReferenceVector(const std::vector<double> &jVec) {
1519 
1520  std::vector<double> rVec(3);
1521 
1522  if (jVec.size() == 3) {
1523  double TJ[3][3];
1524  mxm_c((SpiceDouble *) &p_TC[0], (SpiceDouble *) &p_CJ[0], TJ);
1525  rVec.resize(3);
1526  mxv_c(TJ, (SpiceDouble *) &jVec[0], (SpiceDouble *) &rVec[0]);
1527  }
1528  else if (jVec.size() == 6) {
1529  // See Naif routine frmchg for the format of the state matrix. The constant rotation, TC,
1530  // has a derivative with respect to time of I.
1531  if (!p_hasAngularVelocity) {
1532  // throw an error
1533  }
1534  std::vector<double> stateTJ(36);
1535  stateTJ = StateTJ();
1536  rVec.resize(6);
1537  mxvg_c((SpiceDouble *) &stateTJ[0], (SpiceDouble *) &jVec[0], 6, 6, (SpiceDouble *) &rVec[0]);
1538  }
1539 
1541  return (rVec);
1542  }
1543 
1544 
1558  std::vector<double> coeffAng1, coeffAng2, coeffAng3;
1559 
1560  // Rotation is already stored as a polynomial -- throw an error
1561  if (p_source == PolyFunction) {
1562  // Nothing to do
1563  return;
1564 // QString msg = "Rotation already fit to a polynomial -- spiceint first to refit";
1565 // throw IException(IException::User,msg,_FILEINFO_);
1566  }
1567 
1568  // Adjust degree of polynomial on available data
1569  if (p_cache.size() == 1) {
1570  p_degree = 0;
1571  }
1572  else if (p_cache.size() == 2) {
1573  p_degree = 1;
1574  }
1575 
1576  //Check for polynomial over original pointing constant and initialize coefficients
1577  if (type == PolyFunctionOverSpice) {
1578  coeffAng1.assign(p_degree + 1, 0.);
1579  coeffAng2.assign(p_degree + 1, 0.);
1580  coeffAng3.assign(p_degree + 1, 0.);
1581  SetPolynomial(coeffAng1, coeffAng2, coeffAng3, type);
1582  return;
1583  }
1584 
1588  //
1589  LeastSquares *fitAng1 = new LeastSquares(function1);
1590  LeastSquares *fitAng2 = new LeastSquares(function2);
1591  LeastSquares *fitAng3 = new LeastSquares(function3);
1592 
1593  // Compute the base time
1594  ComputeBaseTime();
1595  std::vector<double> time;
1596 
1597  if (p_cache.size() == 1) {
1598  double t = p_cacheTime.at(0);
1599  SetEphemerisTime(t);
1600  std::vector<double> angles = Angles(p_axis3, p_axis2, p_axis1);
1601  coeffAng1.push_back(angles[0]);
1602  coeffAng2.push_back(angles[1]);
1603  coeffAng3.push_back(angles[2]);
1604  }
1605  else if (p_cache.size() == 2) {
1606 // Load the times and get the corresponding rotation angles
1607  p_degree = 1;
1608  double t1 = p_cacheTime.at(0);
1609  SetEphemerisTime(t1);
1610  t1 -= p_baseTime;
1611  t1 = t1 / p_timeScale;
1612  std::vector<double> angles1 = Angles(p_axis3, p_axis2, p_axis1);
1613  double t2 = p_cacheTime.at(1);
1614  SetEphemerisTime(t2);
1615  t2 -= p_baseTime;
1616  t2 = t2 / p_timeScale;
1617  std::vector<double> angles2 = Angles(p_axis3, p_axis2, p_axis1);
1618  angles2[0] = WrapAngle(angles1[0], angles2[0]);
1619  angles2[2] = WrapAngle(angles1[2], angles2[2]);
1620  double slope[3];
1621  double intercept[3];
1622 
1623 // Compute the linear equation for each angle and save them
1624  for (int angleIndex = 0; angleIndex < 3; angleIndex++) {
1625  Isis::LineEquation angline(t1, angles1[angleIndex], t2, angles2[angleIndex]);
1626  slope[angleIndex] = angline.Slope();
1627  intercept[angleIndex] = angline.Intercept();
1628  }
1629  coeffAng1.push_back(intercept[0]);
1630  coeffAng1.push_back(slope[0]);
1631  coeffAng2.push_back(intercept[1]);
1632  coeffAng2.push_back(slope[1]);
1633  coeffAng3.push_back(intercept[2]);
1634  coeffAng3.push_back(slope[2]);
1635  }
1636  else {
1637  // Load the known values to compute the fit equation
1638  double start1 = 0.; // value of 1st angle1 in cache
1639  double start3 = 0.; // value of 1st angle1 in cache
1640 
1641  for (std::vector<double>::size_type pos = 0; pos < p_cacheTime.size(); pos++) {
1642  double t = p_cacheTime.at(pos);
1643  time.push_back((t - p_baseTime) / p_timeScale);
1644  SetEphemerisTime(t);
1645  std::vector<double> angles = Angles(p_axis3, p_axis2, p_axis1);
1646 
1647 // Fix 180/-180 crossovers on angles 1 and 3 before doing fit.
1648  if (pos == 0) {
1649  start1 = angles[0];
1650  start3 = angles[2];
1651  }
1652  else {
1653  angles[0] = WrapAngle(start1, angles[0]);
1654  angles[2] = WrapAngle(start3, angles[2]);
1655  }
1656 
1657  fitAng1->AddKnown(time, angles[0]);
1658  fitAng2->AddKnown(time, angles[1]);
1659  fitAng3->AddKnown(time, angles[2]);
1660  time.clear();
1661 
1662  }
1663  //Solve the equations for the coefficients
1664  fitAng1->Solve();
1665  fitAng2->Solve();
1666  fitAng3->Solve();
1667 
1668  // Delete the least squares objects now that we have all the coefficients
1669  delete fitAng1;
1670  delete fitAng2;
1671  delete fitAng3;
1672 
1673  // For now assume all three angles are fit to a polynomial. Later they may
1674  // each be fit to a unique basis function.
1675  // Fill the coefficient vectors
1676 
1677  for (int i = 0; i < function1.Coefficients(); i++) {
1678  coeffAng1.push_back(function1.Coefficient(i));
1679  coeffAng2.push_back(function2.Coefficient(i));
1680  coeffAng3.push_back(function3.Coefficient(i));
1681  }
1682 
1683  }
1684 
1685  // Now that the coefficients have been calculated set the polynomial with them
1686  SetPolynomial(coeffAng1, coeffAng2, coeffAng3);
1687 
1689  return;
1690  }
1691 
1692 
1707  void SpiceRotation::SetPolynomial(const std::vector<double> &coeffAng1,
1708  const std::vector<double> &coeffAng2,
1709  const std::vector<double> &coeffAng3,
1710  const Source type) {
1711 
1716 
1717  // Load the functions with the coefficients
1718  function1.SetCoefficients(coeffAng1);
1719  function2.SetCoefficients(coeffAng2);
1720  function3.SetCoefficients(coeffAng3);
1721 
1722  // Compute the base time
1723  ComputeBaseTime();
1724 
1725  // Save the current coefficients
1726  p_coefficients[0] = coeffAng1;
1727  p_coefficients[1] = coeffAng2;
1728  p_coefficients[2] = coeffAng3;
1729 
1730  // Set the flag indicating p_degree has been applied to the camera angles, the
1731  // coefficients of the polynomials have been saved, and the cache reloaded from
1732  // the polynomials
1733  p_degreeApplied = true;
1734  // p_source = PolyFunction;
1735  p_source = type;
1736 
1737  // Update the current rotation
1738  double et = p_et;
1739  p_et = -DBL_MAX;
1740  SetEphemerisTime(et);
1741 
1743  return;
1744  }
1745 
1746 
1765 
1766  // Check to see if rotation is already stored as a polynomial
1767  if (p_source == PckPolyFunction) {
1768  p_hasAngularVelocity = true;
1769  return;
1770  }
1771 
1772  // No target body orientation information available -- throw an error
1773  if (!m_tOrientationAvailable) {
1774  QString msg = "Target body orientation information not available. Rerun spiceinit.";
1775  throw IException(IException::User, msg, _FILEINFO_);
1776  }
1777 
1778  /* I think we have nothing to do, but check for available coefficients and set the Source
1779  // Set the scales
1780  p_dscale = 0.000011574074074; // seconds to days conversion
1781  p_tscale = 3.1688087814029D-10; // seconds to Julian centuries conversion
1782  //Set the quadratic part of the equations
1783  //TODO consider just hard coding this part in evaluate
1784  Isis::PolynomialUnivariate functionRa(p_degree); // Basis function fit to target body pole ra
1785  Isis::PolynomialUnivariate functionDec(p_degree); // Basis function fit to target body pole dec
1786  Isis::PolynomialUnivariate functionPm(p_degree); // Basis function fit to target body pm
1787 
1788  // Load the functions with the coefficients
1789  function1.SetCoefficients(p_raPole);
1790  function2.SetCoefficients(p_decPole);
1791  function3.SetCoefficients(p_pm);
1792 
1793  int numNutPrec = p_sysNutPrec0.size;
1794  if (numNutPrec > 0) {
1795  // Set the trigonometric part of the equation
1796  Isis::TrigBasis functionRaNutPrec("raNutPrec", Isis::TrigBasis::Sin, numNutPrec);
1797  Isis::TrigBasis functionRaNutPrec("decNutPrec", Isis::TrigBasis::Cos, numNutPrec);
1798  Isis::TrigBasis functionRaNutPrec("pmNutPrec", Isis::TrigBasis::Sin, numNutPrec);
1799  // Load the functions with the coefficients
1800  functionRaNutPrec.SetTCoefficients(p_raNutPrec);
1801  functionDecNutPrec.SetTCoefficients(p_decNutPrec);
1802  functionPmNutPrec.SetTCoefficients(p_pmNutPrec);
1803  functionRaNutPrec.SetConstants(p_sysNutPrec0);
1804  functionDecNutPrec.SetConstants(p_sysNutPrec0);
1805  functionPmNutPrec.SetConstants(p_sysNutPrec0);
1806  functionRaNutPrec.SetLCoefficients(p_sysNutPrec1);
1807  functionDecNutPrec.SetLCoefficients(p_sysNutPrec1);
1808  functionPmNutPrec.SetLCoefficients(p_sysNutPrec1);
1809  }
1810  */
1811 
1812  // Set the flag indicating p_degree has been applied to the planet angles, the
1813  // coefficients of the polynomials have been saved, and the cache reloaded from
1814  // TODO cache reloaded???
1815  // the polynomials.
1816  // ****At least for the planet angles, I don't think we want to reload the cache until just
1817  // before we write out the table
1818  p_degreeApplied = true;
1819  p_hasAngularVelocity = true;
1821  return;
1822  }
1823 
1824 
1844  void SpiceRotation::setPckPolynomial(const std::vector<Angle> &raCoeff,
1845  const std::vector<Angle> &decCoeff,
1846  const std::vector<Angle> &pmCoeff) {
1847  // Just set the constants and let usePckPolynomial() do the rest
1848  m_raPole = raCoeff;
1849  m_decPole = decCoeff;
1850  m_pm = pmCoeff;
1851  usePckPolynomial();
1852  // Apply new function parameters
1854  }
1855 
1856 
1867  void SpiceRotation::GetPolynomial(std::vector<double> &coeffAng1,
1868  std::vector<double> &coeffAng2,
1869  std::vector<double> &coeffAng3) {
1870  coeffAng1 = p_coefficients[0];
1871  coeffAng2 = p_coefficients[1];
1872  coeffAng3 = p_coefficients[2];
1873 
1874  return;
1875  }
1876 
1877 
1889  void SpiceRotation::getPckPolynomial(std::vector<Angle> &raCoeff,
1890  std::vector<Angle> &decCoeff,
1891  std::vector<Angle> &pmCoeff) {
1892  raCoeff = m_raPole;
1893  decCoeff = m_decPole;
1894  pmCoeff = m_pm;
1895 
1896  return;
1897  }
1898 
1899 
1904  if (p_noOverride) {
1905  p_baseTime = (p_cacheTime.at(0) + p_cacheTime.at(p_cacheTime.size() - 1)) / 2.;
1907  // Take care of case where 1st and last times are the same
1908  if (p_timeScale == 0) p_timeScale = 1.0;
1909  }
1910  else {
1913  }
1914 
1915  return;
1916  }
1917 
1918 
1926  void SpiceRotation::SetOverrideBaseTime(double baseTime, double timeScale) {
1927  p_overrideBaseTime = baseTime;
1928  p_overrideTimeScale = timeScale;
1929  p_noOverride = false;
1930  return;
1931  }
1932 
1933 
1947  double SpiceRotation::DPolynomial(const int coeffIndex) {
1948  double derivative;
1949  double time = (p_et - p_baseTime) / p_timeScale;
1950 
1951  if (coeffIndex > 0 && coeffIndex <= p_degree) {
1952  derivative = pow(time, coeffIndex);
1953  }
1954  else if (coeffIndex == 0) {
1955  derivative = 1;
1956  }
1957  else {
1958  QString msg = "Unable to evaluate the derivative of the SPICE rotation fit polynomial for "
1959  "the given coefficient index [" + toString(coeffIndex) + "]. "
1960  "Index is negative or exceeds degree of polynomial ["
1961  + toString(p_degree) + "]";
1963  }
1964  return derivative;
1965  }
1966 
1967 
1983  const int coeffIndex) {
1984  const double p_dayScale = 86400; // number of seconds in a day
1985  // Number of 24 hour days in a Julian century = 36525
1986  const double p_centScale = p_dayScale * 36525;
1987  double time = 0.;
1988 
1989  switch (partialVar) {
1990  case WRT_RightAscension:
1991  case WRT_Declination:
1992  time = p_et / p_centScale;
1993  break;
1994  case WRT_Twist:
1995  time = p_et / p_dayScale;
1996  break;
1997  }
1998 
1999  double derivative;
2000 
2001  switch (coeffIndex) {
2002  case 0:
2003  derivative = 1;
2004  break;
2005  case 1:
2006  case 2:
2007  derivative = pow(time, coeffIndex);
2008  break;
2009  default:
2010  QString msg = "Unable to evaluate the derivative of the target body rotation fit polynomial "
2011  "for the given coefficient index [" + toString(coeffIndex) + "]. "
2012  "Index is negative or exceeds degree of polynomial ["
2013  + toString(p_degree) + "]";
2015  }
2016 
2017  // Now apply any difference to the partials due to building the rotation matrix on the angles
2018  // 90. + ra, 90. - dec, and pm. The only partial that changes is dec.
2019  if (partialVar == WRT_Declination) {
2020  derivative = -derivative;
2021  }
2022 
2023  return derivative;
2024  }
2025 
2026 
2042  std::vector<double> SpiceRotation::ToReferencePartial(std::vector<double> &lookJ,
2043  SpiceRotation::PartialType partialVar,
2044  int coeffIndex) {
2046  //TODO** To save time possibly save partial matrices
2047 
2048  // Get the rotation angles and form the derivative matrix for the partialVar
2049  std::vector<double> angles = Angles(p_axis3, p_axis2, p_axis1);
2050  int angleIndex = partialVar;
2051  int axes[3] = {p_axis1, p_axis2, p_axis3};
2052 
2053  double angle = angles.at(angleIndex);
2054 
2055  double dmatrix[3][3];
2056  drotat_(&angle, (integer *) axes + angleIndex, (doublereal *) dmatrix);
2057  // Transpose to obtain row-major order
2058  xpose_c(dmatrix, dmatrix);
2059 
2060  // Get the derivative of the polynomial with respect to partialVar
2061  double dpoly = 0.;
2062  switch (m_frameType) {
2063  case UNKNOWN: // For now let everything go through for backward compatability
2064  case CK:
2065  dpoly = DPolynomial(coeffIndex);
2066  break;
2067  case PCK:
2068  dpoly = DPckPolynomial(partialVar, coeffIndex);
2069  break;
2070  default:
2071  QString msg = "Only CK and PCK partials can be calculated";
2073  }
2074 
2075  // Multiply dpoly to complete dmatrix
2076  for (int row = 0; row < 3; row++) {
2077  for (int col = 0; col < 3; col++) {
2078  dmatrix[row][col] *= dpoly;
2079  }
2080  }
2081 
2082  // Apply the other 2 angles and chain them all together
2083  double dCJ[3][3];
2084  switch (angleIndex) {
2085  case 0:
2086  rotmat_c(dmatrix, angles[1], axes[1], dCJ);
2087  rotmat_c(dCJ, angles[2], axes[2], dCJ);
2088  break;
2089  case 1:
2090  rotate_c(angles[0], axes[0], dCJ);
2091  mxm_c(dmatrix, dCJ, dCJ);
2092  rotmat_c(dCJ, angles[2], axes[2], dCJ);
2093  break;
2094  case 2:
2095  rotate_c(angles[0], axes[0], dCJ);
2096  rotmat_c(dCJ, angles[1], axes[1], dCJ);
2097  mxm_c(dmatrix, dCJ, dCJ);
2098  break;
2099  }
2100 
2101  // Multiply the constant matrix to rotate to the targeted reference frame
2102  double dTJ[3][3];
2103  mxm_c((SpiceDouble *) &p_TC[0], dCJ[0], dTJ);
2104 
2105  // Finally rotate the J2000 vector with the derivative matrix, dTJ to
2106  // get the vector in the targeted reference frame.
2107  std::vector<double> lookdT(3);
2108 
2109  mxv_c(dTJ, (const SpiceDouble *) &lookJ[0], (SpiceDouble *) &lookdT[0]);
2110 
2112  return lookdT;
2113  }
2114 
2115 
2124  double SpiceRotation::WrapAngle(double compareAngle, double angle) {
2126  double diff1 = compareAngle - angle;
2127 
2128  if (diff1 < -1 * pi_c()) {
2129  angle -= twopi_c();
2130  }
2131  else if (diff1 > pi_c()) {
2132  angle += twopi_c();
2133  }
2134 
2136  return angle;
2137  }
2138 
2139 
2153  // Adjust the degree for the data
2154  if (p_fullCacheSize == 1) {
2155  degree = 0;
2156  }
2157  else if (p_fullCacheSize == 2) {
2158  degree = 1;
2159  }
2160  // If polynomials have not been applied yet then simply set the degree and return
2161  if (!p_degreeApplied) {
2162  p_degree = degree;
2163  }
2164 
2165  // Otherwise the existing polynomials need to be either expanded ...
2166  else if (p_degree < degree) { // (increase the number of terms)
2167  std::vector<double> coefAngle1(p_coefficients[0]),
2168  coefAngle2(p_coefficients[1]),
2169  coefAngle3(p_coefficients[2]);
2170 
2171  for (int icoef = p_degree + 1; icoef <= degree; icoef++) {
2172  coefAngle1.push_back(0.);
2173  coefAngle2.push_back(0.);
2174  coefAngle3.push_back(0.);
2175  }
2176  p_degree = degree;
2177  SetPolynomial(coefAngle1, coefAngle2, coefAngle3, p_source);
2178  }
2179  // ... or reduced (decrease the number of terms)
2180  else if (p_degree > degree) {
2181  std::vector<double> coefAngle1(degree + 1),
2182  coefAngle2(degree + 1),
2183  coefAngle3(degree + 1);
2184 
2185  for (int icoef = 0; icoef <= degree; icoef++) {
2186  coefAngle1[icoef] = p_coefficients[0][icoef];
2187  coefAngle2[icoef] = p_coefficients[1][icoef];
2188  coefAngle3[icoef] = p_coefficients[2][icoef];
2189  }
2190  p_degree = degree;
2191  SetPolynomial(coefAngle1, coefAngle2, coefAngle3, p_source);
2192  }
2193  }
2194 
2195 
2202  return m_frameType;
2203  }
2204 
2205 
2212  return p_source;
2213  }
2214 
2215 
2222  p_source = source;
2223  return;
2224  }
2225 
2226 
2233  return p_baseTime;
2234  }
2235 
2236 
2243  return p_timeScale;
2244  }
2245 
2246 
2259  void SpiceRotation::SetAxes(int axis1, int axis2, int axis3) {
2260  if (axis1 < 1 || axis2 < 1 || axis3 < 1 || axis1 > 3 || axis2 > 3 || axis3 > 3) {
2261  QString msg = "A rotation axis is outside the valid range of 1 to 3";
2263  }
2264  p_axis1 = axis1;
2265  p_axis2 = axis2;
2266  p_axis3 = axis3;
2267  }
2268 
2269 
2283  int count = 0;
2284 
2285  double observStart = p_fullCacheStartTime + p_timeBias;
2286  double observEnd = p_fullCacheEndTime + p_timeBias;
2287  // Next line added 12-03-2009 to allow observations to cross segment boundaries
2288  double currentTime = observStart;
2289  bool timeLoaded = false;
2290 
2291  // Get number of ck loaded for this rotation. This method assumes only one SpiceRotation
2292  // object is loaded.
2294  ktotal_c("ck", (SpiceInt *) &count);
2295 
2296  // Downsize the loaded cache
2297  if ((p_source == Memcache) && p_minimizeCache == Yes) {
2298  // Multiple ck case, type 5 ck case, or PolyFunctionOverSpice
2299  // final step -- downsize loaded cache and reload
2300 
2301  if (p_fullCacheSize != (int) p_cache.size()) {
2302 
2303  QString msg =
2304  "Full cache size does NOT match cache size in LoadTimeCache -- should never happen";
2306  }
2307 
2308  SpiceDouble timeSclkdp[p_fullCacheSize];
2309  SpiceDouble quats[p_fullCacheSize][4];
2310  double avvs[p_fullCacheSize][3];// Angular velocity vector
2311 
2312  // We will treat et as the sclock time and avoid converting back and forth
2313  for (int r = 0; r < p_fullCacheSize; r++) {
2314  timeSclkdp[r] = p_cacheTime[r];
2315  SpiceDouble CJ[9] = { p_cache[r][0], p_cache[r][1], p_cache[r][2],
2316  p_cache[r][3], p_cache[r][4], p_cache[r][5],
2317  p_cache[r][6], p_cache[r][7], p_cache[r][8]
2318  };
2319  m2q_c(CJ, quats[r]);
2320  if (p_hasAngularVelocity) {
2321  vequ_c((SpiceDouble *) &p_cacheAv[r][0], avvs[r]);
2322  }
2323  }
2324 
2325  double cubeStarts = timeSclkdp[0]; //,timsSclkdp[ckBlob.Records()-1] };
2326  double radTol = 0.000000017453; //.000001 degrees Make this instrument dependent TODO
2327  SpiceInt avflag = 1; // Don't use angular velocity for now
2328  SpiceInt nints = 1; // Always make an observation a single interpolation interval
2329  double dparr[p_fullCacheSize]; // Double precision work array
2330  SpiceInt intarr[p_fullCacheSize]; // Integer work array
2331  SpiceInt sizOut = p_fullCacheSize; // Size of downsized cache
2332 
2333  ck3sdn(radTol, avflag, (int *) &sizOut, timeSclkdp, (doublereal *) quats,
2334  (SpiceDouble *) avvs, nints, &cubeStarts, dparr, (int *) intarr);
2335 
2336  // Clear full cache and load with downsized version
2337  p_cacheTime.clear();
2338  p_cache.clear();
2339  p_cacheAv.clear();
2340  std::vector<double> av;
2341  av.resize(3);
2342 
2343  for (int r = 0; r < sizOut; r++) {
2344  SpiceDouble et;
2345  // sct2e_c(spcode, timeSclkdp[r], &et);
2346  et = timeSclkdp[r];
2347  p_cacheTime.push_back(et);
2348  std::vector<double> CJ(9);
2349  q2m_c(quats[r], (SpiceDouble( *)[3]) &CJ[0]);
2350  p_cache.push_back(CJ);
2351  vequ_c(avvs[r], (SpiceDouble *) &av[0]);
2352  p_cacheAv.push_back(av);
2353  }
2354 
2355  timeLoaded = true;
2357  }
2358  else if (count == 1 && p_minimizeCache == Yes) {
2359  // case of a single ck -- read instances and data straight from kernel for given time range
2360  SpiceInt handle;
2361 
2362  // Define some Naif constants
2363  int FILESIZ = 128;
2364  int TYPESIZ = 32;
2365  int SOURCESIZ = 128;
2366 // double DIRSIZ = 100;
2367 
2368  SpiceChar file[FILESIZ];
2369  SpiceChar filtyp[TYPESIZ]; // kernel type (ck, ek, etc.)
2370  SpiceChar source[SOURCESIZ];
2371 
2372  SpiceBoolean found;
2373  bool observationSpansToNextSegment = false;
2374 
2375  double segStartEt;
2376  double segStopEt;
2377 
2378  kdata_c(0, "ck", FILESIZ, TYPESIZ, SOURCESIZ, file, filtyp, source, &handle, &found);
2379  dafbfs_c(handle);
2380  daffna_c(&found);
2381  int spCode = ((int)(p_constantFrames[0] / 1000)) * 1000;
2382 
2383  while (found) {
2384  observationSpansToNextSegment = false;
2385  double sum[10]; // daf segment summary
2386  double dc[2]; // segment starting and ending times in tics
2387  SpiceInt ic[6]; // segment summary values:
2388  // instrument code for platform,
2389  // reference frame code,
2390  // data type,
2391  // velocity flag,
2392  // offset to quat 1,
2393  // offset to end.
2394  dafgs_c(sum);
2395  dafus_c(sum, (SpiceInt) 2, (SpiceInt) 6, dc, ic);
2396 
2397  // Don't read type 5 ck here
2398  if (ic[2] == 5) break;
2399 //
2400  // Check times for type 3 ck segment if spacecraft matches
2401  if (ic[0] == spCode && ic[2] == 3) {
2402  sct2e_c((int) spCode / 1000, dc[0], &segStartEt);
2403  sct2e_c((int) spCode / 1000, dc[1], &segStopEt);
2405  double et;
2406 
2407  // Get times for this segment
2408  if (currentTime >= segStartEt && currentTime <= segStopEt) {
2409 
2410  // Check for a gap in the time coverage by making sure the time span of the observation
2411  // does not cross a segment unless the next segment starts where the current one ends
2412  if (observationSpansToNextSegment && currentTime > segStartEt) {
2413  QString msg = "Observation crosses segment boundary--unable to interpolate pointing";
2415  }
2416  if (observEnd > segStopEt) {
2417  observationSpansToNextSegment = true;
2418  }
2419 
2420  // Extract necessary header parameters
2421  int dovelocity = ic[3];
2422  int end = ic[5];
2423  double val[2];
2424  dafgda_c(handle, end - 1, end, val);
2425 // int nints = (int) val[0];
2426  int ninstances = (int) val[1];
2427  int numvel = dovelocity * 3;
2428  int quatnoff = ic[4] + (4 + numvel) * ninstances - 1;
2429 // int nrdir = (int) (( ninstances - 1 ) / DIRSIZ); /* sclkdp directory records */
2430  int sclkdp1off = quatnoff + 1;
2431  int sclkdpnoff = sclkdp1off + ninstances - 1;
2432 // int start1off = sclkdpnoff + nrdir + 1;
2433 // int startnoff = start1off + nints - 1;
2434  int sclkSpCode = spCode / 1000;
2435 
2436  // Now get the times
2437  std::vector<double> sclkdp(ninstances);
2438  dafgda_c(handle, sclkdp1off, sclkdpnoff, (SpiceDouble *) &sclkdp[0]);
2439 
2440  int instance = 0;
2441  sct2e_c(sclkSpCode, sclkdp[0], &et);
2442 
2443  while (instance < (ninstances - 1) && et < currentTime) {
2444  instance++;
2445  sct2e_c(sclkSpCode, sclkdp[instance], &et);
2446  }
2447 
2448  if (instance > 0) instance--;
2449  sct2e_c(sclkSpCode, sclkdp[instance], &et);
2450 
2451  while (instance < (ninstances - 1) && et < observEnd) {
2452  p_cacheTime.push_back(et - p_timeBias);
2453  instance++;
2454  sct2e_c(sclkSpCode, sclkdp[instance], &et);
2455  }
2456  p_cacheTime.push_back(et - p_timeBias);
2457 
2458  if (!observationSpansToNextSegment) {
2459  timeLoaded = true;
2461  break;
2462  }
2463  else {
2464  currentTime = segStopEt;
2465  }
2466  }
2467  }
2468  dafcs_c(handle); // Continue search in daf last searched
2469  daffna_c(&found); // Find next forward array in current daf
2470  }
2471  }
2472  else if (count == 0 && p_source != Nadir && p_minimizeCache == Yes) {
2473  QString msg = "No camera kernels loaded...Unable to determine time cache to downsize";
2474  throw IException(IException::User, msg, _FILEINFO_);
2475  }
2476 
2477  // Load times according to cache size (body rotations) -- handle first round of type 5 ck case
2478  // and multiple ck case --Load a time for every line scan line and downsize later
2479  if (!timeLoaded) {
2480  double cacheSlope = 0.0;
2481  if (p_fullCacheSize > 1)
2482  cacheSlope = (p_fullCacheEndTime - p_fullCacheStartTime) / (double)(p_fullCacheSize - 1);
2483  for (int i = 0; i < p_fullCacheSize; i++)
2484  p_cacheTime.push_back(p_fullCacheStartTime + (double) i * cacheSlope);
2485  if (p_source == Nadir) p_minimizeCache = No;
2486  }
2488  }
2489 
2490 
2498  std::vector<double> SpiceRotation::GetFullCacheTime() {
2499 
2500  // No time cache was initialized -- throw an error
2501  if (p_fullCacheSize < 1) {
2502  QString msg = "Time cache not available -- rerun spiceinit";
2503  throw IException(IException::User, msg, _FILEINFO_);
2504  }
2505 
2506  std::vector<double> fullCacheTime;
2507  double cacheSlope = 0.0;
2508  if (p_fullCacheSize > 1) {
2509  cacheSlope = (p_fullCacheEndTime - p_fullCacheStartTime) / (double)(p_fullCacheSize - 1);
2510  }
2511 
2512  for (int i = 0; i < p_fullCacheSize; i++)
2513  fullCacheTime.push_back(p_fullCacheStartTime + (double) i * cacheSlope);
2514 
2515  return fullCacheTime;
2516  }
2517 
2518 
2530  void SpiceRotation::FrameTrace(double et) {
2532  // The code for this method was extracted from the Naif routine rotget written by N.J. Bachman &
2533  // W.L. Taber (JPL)
2534  int center;
2535  FrameType type;
2536  int typid;
2537  SpiceBoolean found;
2538  int frmidx; // Frame chain index for current frame
2539  SpiceInt nextFrame; // Naif frame code of next frame
2541  std::vector<int> frameCodes;
2542  std::vector<int> frameTypes;
2543  frameCodes.push_back(p_constantFrames[0]);
2544 
2545  while (frameCodes[frameCodes.size()-1] != J2000Code) {
2546  frmidx = frameCodes.size() - 1;
2547  // First get the frame type (Note:: we may also need to save center if we use dynamic frames)
2548  // (Another note: the type returned is the Naif from type. This is not quite the same as the
2549  // SpiceRotation enumerated FrameType. The SpiceRotation FrameType differentiates between
2550  // pck types. FrameTypes of 2, 6, and 7 will all be considered to be Naif frame type 2. The
2551  // logic for FrameTypes in this method is correct for all types except type 7. Current pck
2552  // do not exercise this option. Should we ever use pck with a target body not referenced to
2553  // the J2000 frame and epoch, both this method and loadPCFromSpice will need to be modified.
2554  frinfo_c((SpiceInt) frameCodes[frmidx],
2555  (SpiceInt *) &center,
2556  (SpiceInt *) &type,
2557  (SpiceInt *) &typid, &found);
2558 
2559  if (!found) {
2560 
2561  if (p_source == Nadir) {
2562  frameTypes.push_back(0);
2563  break;
2564  }
2565 
2566  QString msg = "The frame" + toString((int) frameCodes[frmidx]) + " is not supported by Naif";
2568  }
2569 
2570  double matrix[3][3];
2571 
2572  // To get the next link in the frame chain, use the frame type
2573  if (type == INERTL || type == PCK) {
2574  nextFrame = J2000Code;
2575  }
2576  else if (type == CK) {
2577  ckfrot_((SpiceInt *) &typid, &et, (double *) matrix, &nextFrame, (logical *) &found);
2578 
2579  if (!found) {
2580 
2581  if (p_source == Nadir) {
2582  frameTypes.push_back(0);
2583  break;
2584  }
2585 
2586  QString msg = "The ck rotation from frame " + toString(frameCodes[frmidx]) + " can not "
2587  + "be found due to no pointing available at requested time or a problem with the "
2588  + "frame";
2590  }
2591  }
2592  else if (type == TK) {
2593  tkfram_((SpiceInt *) &typid, (double *) matrix, &nextFrame, (logical *) &found);
2594  if (!found) {
2595  QString msg = "The tk rotation from frame " + toString(frameCodes[frmidx]) +
2596  " can not be found";
2598  }
2599  }
2600  else if (type == DYN) {
2601  //
2602  // Unlike the other frame classes, the dynamic frame evaluation
2603  // routine ZZDYNROT requires the input frame ID rather than the
2604  // dynamic frame class ID. ZZDYNROT also requires the center ID
2605  // we found via the FRINFO call.
2606 
2607  zzdynrot_((SpiceInt *) &typid, (SpiceInt *) &center, &et, (double *) matrix, &nextFrame);
2608  }
2609 
2610  else {
2611  QString msg = "The frame " + toString(frameCodes[frmidx]) +
2612  " has a type " + toString(type) + " not supported by your version of Naif Spicelib."
2613  + "You need to update.";
2615 
2616  }
2617  frameCodes.push_back(nextFrame);
2618  frameTypes.push_back(type);
2619  }
2620 
2621  if ((int) frameCodes.size() == 1 && p_source != Nadir) { // Must be Sky
2622  p_constantFrames.push_back(frameCodes[0]);
2623  p_timeFrames.push_back(frameCodes[0]);
2624  return;
2625  }
2626 
2627  int nConstants = 0;
2628  p_constantFrames.clear();
2629  while (frameTypes[nConstants] == TK && nConstants < (int) frameTypes.size()) nConstants++;
2630 
2631 
2632  for (int i = 0; i <= nConstants; i++) {
2633  p_constantFrames.push_back(frameCodes[i]);
2634  }
2635 
2636  if (p_source != Nadir) {
2637  for (int i = nConstants; i < (int) frameCodes.size(); i++) {
2638  p_timeFrames.push_back(frameCodes[i]);
2639  }
2640  }
2641  else {
2642  // Nadir rotation is from spacecraft to J2000
2643  p_timeFrames.push_back(frameCodes[nConstants]);
2644  p_timeFrames.push_back(J2000Code);
2645  }
2647  }
2648 
2649 
2655  std::vector<double> SpiceRotation::Matrix() {
2657  std::vector<double> TJ;
2658  TJ.resize(9);
2659  mxm_c((SpiceDouble *) &p_TC[0], (SpiceDouble *) &p_CJ[0], (SpiceDouble( *) [3]) &TJ[0]);
2661  return TJ;
2662  }
2663 
2664 
2670  std::vector<double> SpiceRotation::ConstantRotation() {
2672  std::vector<double> q;
2673  q.resize(4);
2674  m2q_c((SpiceDouble( *)[3]) &p_TC[0], &q[0]);
2676  return q;
2677  }
2678 
2679 
2685  std::vector<double> &SpiceRotation::ConstantMatrix() {
2686  return p_TC;
2687  }
2688 
2689 
2695  void SpiceRotation::SetConstantMatrix(std::vector<double> constantMatrix) {
2696  p_TC = constantMatrix;
2697  return;
2698  }
2699 
2705  std::vector<double> SpiceRotation::TimeBasedRotation() {
2707  std::vector<double> q;
2708  q.resize(4);
2709  m2q_c((SpiceDouble( *)[3]) &p_CJ[0], &q[0]);
2711  return q;
2712  }
2713 
2714 
2720  std::vector<double> &SpiceRotation::TimeBasedMatrix() {
2721  return p_CJ;
2722  }
2723 
2724 
2730  void SpiceRotation::SetTimeBasedMatrix(std::vector<double> timeBasedMatrix) {
2731  p_CJ = timeBasedMatrix;
2732  return;
2733  }
2734 
2735 
2742  FrameTrace(et);
2743  // Get constant rotation which applies in all cases
2744  int targetFrame = p_constantFrames[0];
2745  int fromFrame = p_timeFrames[0];
2746  p_TC.resize(9);
2747  refchg_((SpiceInt *) &fromFrame, (SpiceInt *) &targetFrame, &et, (doublereal *) &p_TC[0]);
2748  // Transpose to obtain row-major order
2749  xpose_c((SpiceDouble( *)[3]) &p_TC[0], (SpiceDouble( *)[3]) &p_TC[0]);
2750  }
2751 
2752 
2774 
2775  // Make sure the angles have been fit to polynomials so we can calculate the derivative
2776  if (p_source < PolyFunction ) {
2777  QString msg = "The SpiceRotation pointing angles must be fit to polynomials in order to ";
2778  msg += "compute angular velocity.";
2780  }
2781  if (p_source == PckPolyFunction) {
2782  QString msg = "Planetary angular velocity must be fit computed with PCK polynomials ";
2784  }
2785  std::vector<double> dCJdt;
2786  dCJdt.resize(9);
2787 
2788  switch (m_frameType) {
2789  // Treat all cases the same except for target body rotations
2790  case UNKNOWN:
2791  case INERTL:
2792  case TK:
2793  case DYN:
2794  case CK:
2795  DCJdt(dCJdt);
2796  break;
2797  case PCK:
2798  case BPC:
2799  case NOTJ2000PCK:
2800  break;
2801  }
2802  double omega[3][3];
2803  mtxm_c((SpiceDouble( *)[3]) &dCJdt[0], (SpiceDouble( *)[3]) &p_CJ[0], omega);
2804  p_av[0] = omega[2][1];
2805  p_av[1] = omega[0][2];
2806  p_av[2] = omega[1][0];
2808  }
2809 
2810 
2817  void SpiceRotation::DCJdt(std::vector<double> &dCJ) {
2819 
2820  // Get the rotation angles and axes
2821  std::vector<double> angles = Angles(p_axis3, p_axis2, p_axis1);
2822  int axes[3] = {p_axis1, p_axis2, p_axis3};
2823 
2824  double dmatrix[3][3];
2825  double dangle;
2826  double wmatrix[3][3]; // work matrix
2827  dCJ.assign(9, 0.);
2828 
2829  for (int angleIndex = 0; angleIndex < 3; angleIndex++) {
2830  drotat_(&(angles[angleIndex]), (integer *) axes + angleIndex, (doublereal *) dmatrix);
2831  // Transpose to obtain row-major order
2832  xpose_c(dmatrix, dmatrix);
2833 
2834  // To get the derivative of the polynomial fit to the angle with respect to time
2835  // first create the function object for this angle and load its coefficients
2837  function.SetCoefficients(p_coefficients[angleIndex]);
2838 
2839  // Evaluate the derivative of function at p_et
2840  // dangle = function.DerivativeVar((p_et - p_baseTime) / p_timeScale);
2841  dangle = function.DerivativeVar((p_et - p_baseTime) / p_timeScale) / p_timeScale;
2842 
2843  // Multiply dangle to complete dmatrix
2844  for (int row = 0; row < 3; row++) {
2845  for (int col = 0; col < 3; col++) {
2846  dmatrix[row][col] *= dangle;
2847  }
2848  }
2849  // Apply the other 2 angles and chain them all together
2850  switch (angleIndex) {
2851  case 0:
2852  rotmat_c(dmatrix, angles[1], axes[1], dmatrix);
2853  rotmat_c(dmatrix, angles[2], axes[2], dmatrix);
2854  break;
2855  case 1:
2856  rotate_c(angles[0], axes[0], wmatrix);
2857  mxm_c(dmatrix, wmatrix, dmatrix);
2858  rotmat_c(dmatrix, angles[2], axes[2], dmatrix);
2859  break;
2860  case 2:
2861  rotate_c(angles[0], axes[0], wmatrix);
2862  rotmat_c(wmatrix, angles[1], axes[1], wmatrix);
2863  mxm_c(dmatrix, wmatrix, dmatrix);
2864  break;
2865  }
2866  int i, j;
2867  for (int index = 0; index < 9; index++) {
2868  i = index / 3;
2869  j = index % 3;
2870  dCJ[index] += dmatrix[i][j];
2871  }
2872  }
2873 
2875  }
2876 
2877 
2883  std::vector<double> SpiceRotation::StateTJ() {
2884  std::vector<double> stateTJ(36);
2885 
2886  // Build the state matrix for the time-based rotation from the matrix and angulary velocity
2887  double stateCJ[6][6];
2888  rav2xf_c(&p_CJ[0], &p_av[0], stateCJ);
2889 // (SpiceDouble (*) [3]) &p_CJ[0]
2890  int irow = 0;
2891  int jcol = 0;
2892  int vpos = 0;
2893 
2894  for (int row = 3; row < 6; row++) {
2895  irow = row - 3;
2896  vpos = irow * 3;
2897 
2898  for (int col = 0; col < 3; col++) {
2899  jcol = col + 3;
2900  // Fill the upper left corner
2901  stateTJ[irow*6 + col] = p_TC[vpos] * stateCJ[0][col] + p_TC[vpos+1] * stateCJ[1][col]
2902  + p_TC[vpos+2] * stateCJ[2][col];
2903  // Fill the lower left corner
2904  stateTJ[row*6 + col] = p_TC[vpos] * stateCJ[3][col] + p_TC[vpos+1] * stateCJ[4][col]
2905  + p_TC[vpos+2] * stateCJ[5][col];
2906  // Fill the upper right corner
2907  stateTJ[irow*6 + jcol] = 0;
2908  // Fill the lower right corner
2909  stateTJ[row*6 +jcol] = stateTJ[irow*6 + col];
2910  }
2911  }
2912  return stateTJ;
2913  }
2914 
2915 
2926  std::vector<double> SpiceRotation::Extrapolate(double timeEt) {
2928 
2929  if (!p_hasAngularVelocity) return p_CJ;
2930 
2931  double diffTime = timeEt - p_et;
2932  std::vector<double> CJ(9, 0.0);
2933  double dmat[3][3];
2934 
2935  // Create a rotation matrix for the axis and magnitude of the angular velocity multiplied by
2936  // the time difference
2937  axisar_c((SpiceDouble *) &p_av[0], diffTime*vnorm_c((SpiceDouble *) &p_av[0]), dmat);
2938 
2939  // Rotate from the current time to the desired time assuming constant angular velocity
2940  mxm_c(dmat, (SpiceDouble *) &p_CJ[0], (SpiceDouble( *)[3]) &CJ[0]);
2942  return CJ;
2943  }
2944 
2945 
2953  void SpiceRotation::SetFullCacheParameters(double startTime, double endTime, int cacheSize) {
2954  // Save full cache parameters
2955  p_fullCacheStartTime = startTime;
2956  p_fullCacheEndTime = endTime;
2957  p_fullCacheSize = cacheSize;
2958  }
2959 
2960 
2969  // Get a count of all the loaded kernels
2970  SpiceInt count;
2971  ktotal_c("PCK", &count);
2972 
2973  // Define some Naif constants
2974  int FILESIZ = 128;
2975  int TYPESIZ = 32;
2976  int SOURCESIZ = 128;
2977  SpiceChar file[FILESIZ];
2978  SpiceChar filetype[TYPESIZ];
2979  SpiceChar source[SOURCESIZ];
2980  SpiceInt handle;
2981  SpiceBoolean found;
2982 
2983  // Get the name of each loaded kernel. The accuracy of this test depends on the use of the
2984  // "bpc" suffix to name a binary pck. If a binary bpc does not have the "bpc" suffix, it will not
2985  // be found by this test. This test was suggested by Boris Semenov at Naif.
2986  for (SpiceInt knum = 0; knum < count; knum++){
2987  kdata_c(knum, "PCK", FILESIZ, TYPESIZ, SOURCESIZ, file, filetype, source, &handle, &found);
2988 
2989  // search file for "bpc"
2990  if (strstr(file, "bpc") != NULL) {
2991  m_frameType = BPC;
2992  }
2993  }
2994  }
2995 
2996 
3005  SpiceInt frameCode = p_constantFrames[0];
3006  SpiceBoolean found;
3007  SpiceInt centerBodyCode;
3008  SpiceInt frameClass;
3009  SpiceInt classId;
3010  frinfo_c(frameCode, &centerBodyCode, &frameClass, &classId, &found);
3011 
3012  if (found) {
3013  if (frameClass == 2 || centerBodyCode > 0) {
3014  m_frameType = PCK;
3015  // Load the PC information while it is available and set member values
3016  loadPCFromSpice(centerBodyCode);
3017  }
3018  else if (p_constantFrames.size() > 1) {
3019  for (std::vector<int>::size_type idx = 1; idx < p_constantFrames.size(); idx++) {
3020  frameCode = p_constantFrames[idx];
3021  frinfo_c(frameCode, &centerBodyCode, &frameClass, &classId, &found);
3022  if (frameClass == 3) m_frameType = CK;
3023  }
3024  }
3025  else {
3026  switch (frameClass) {
3027  case 1:
3028  m_frameType = INERTL;
3029  break;
3030  // case 2: handled in first if block
3031  case 3:
3032  m_frameType = CK;
3033  break;
3034  case 4:
3035  m_frameType = TK;
3036  break;
3037  case 5:
3038  m_frameType = DYN;
3039  break;
3040  default:
3041  m_frameType = UNKNOWN;
3042  }
3043  }
3044  }
3045  }
3046 
3047 
3057  // If the cache has only one rotation, set it
3059 
3060  if (p_cache.size() == 1) {
3061  /* p_quaternion = p_cache[0];*/
3062  p_CJ = p_cache[0];
3063 // p_CJ = p_quaternion.ToMatrix();
3064 
3065  if (p_hasAngularVelocity) {
3066  p_av = p_cacheAv[0];
3067  }
3068 
3069  }
3070 
3071  // Otherwise determine the interval to interpolate
3072  else {
3073  std::vector<double>::iterator pos;
3074  pos = upper_bound(p_cacheTime.begin(), p_cacheTime.end(), p_et);
3075 
3076  int cacheIndex;
3077 
3078  if (pos != p_cacheTime.end()) {
3079  cacheIndex = distance(p_cacheTime.begin(), pos);
3080  cacheIndex--;
3081  }
3082  else {
3083  cacheIndex = p_cacheTime.size() - 2;
3084  }
3085 
3086  if (cacheIndex < 0) cacheIndex = 0;
3087 
3088  // Interpolate the rotation
3089  double mult = (p_et - p_cacheTime[cacheIndex]) /
3090  (p_cacheTime[cacheIndex+1] - p_cacheTime[cacheIndex]);
3091  /* Quaternion Q2 (p_cache[cacheIndex+1]);
3092  Quaternion Q1 (p_cache[cacheIndex]);*/
3093  std::vector<double> CJ2(p_cache[cacheIndex+1]);
3094  std::vector<double> CJ1(p_cache[cacheIndex]);
3095  SpiceDouble J2J1[3][3];
3096  mtxm_c((SpiceDouble( *)[3]) &CJ2[0], (SpiceDouble( *)[3]) &CJ1[0], J2J1);
3097  SpiceDouble axis[3];
3098  SpiceDouble angle;
3099  raxisa_c(J2J1, axis, &angle);
3100  SpiceDouble delta[3][3];
3101  axisar_c(axis, angle * (SpiceDouble)mult, delta);
3102  mxmt_c((SpiceDouble *) &CJ1[0], delta, (SpiceDouble( *) [3]) &p_CJ[0]);
3103 
3104  if (p_hasAngularVelocity) {
3105  double v1[3], v2[3]; // Vectors surrounding desired time
3106  vequ_c((SpiceDouble *) &p_cacheAv[cacheIndex][0], v1);
3107  vequ_c((SpiceDouble *) &p_cacheAv[cacheIndex+1][0], v2);
3108  vscl_c((1. - mult), v1, v1);
3109  vscl_c(mult, v2, v2);
3110  vadd_c(v1, v2, (SpiceDouble *) &p_av[0]);
3111  }
3112  }
3114  }
3115 
3116 
3123  // TODO what about spk time bias and mission setting of light time corrections
3124  // That information has only been passed to the SpicePosition class and
3125  // is not available to this class, but probably should be applied to the
3126  // spkez call.
3127 
3128  // Make sure the constant frame is loaded. This method also does the frame trace.
3130  if (p_timeFrames.size() == 0) InitConstantRotation(p_et);
3131 
3132  SpiceDouble stateJ[6]; // Position and velocity vector in J2000
3133  SpiceDouble lt;
3134  SpiceInt spkCode = p_constantFrames[0] / 1000;
3135  spkez_c((SpiceInt) spkCode, p_et, "J2000", "LT+S",
3136  (SpiceInt) p_targetCode, stateJ, &lt);
3137  // reverse the position to be relative to the spacecraft. This may be
3138  // a mission dependent value and possibly the sense of the velocity as well.
3139  SpiceDouble sJ[3], svJ[3];
3140  vpack_c(-1 * stateJ[0], -1 * stateJ[1], -1 * stateJ[2], sJ);
3141  vpack_c(stateJ[3], stateJ[4], stateJ[5], svJ);
3142  twovec_c(sJ,
3143  p_axisP,
3144  svJ,
3145  p_axisV,
3146  (SpiceDouble( *)[3]) &p_CJ[0]);
3148  }
3149 
3150 
3163  SpiceInt j2000 = J2000Code;
3164 
3165  SpiceDouble time = p_et + p_timeBias;
3166 
3167  // Make sure the constant frame is loaded. This method also does the frame trace.
3168  if (p_timeFrames.size() == 0) InitConstantRotation(p_et);
3169  int toFrame = p_timeFrames[0];
3170 
3171  // First try getting the entire state matrix (6x6), which includes CJ and the angular velocity
3172  double stateCJ[6][6];
3173  frmchg_((integer *) &j2000, (integer *) &toFrame, &time, (doublereal *) stateCJ);
3174 
3175  // If Naif fails attempting to get the state matrix, assume the angular velocity vector is
3176  // not available and just get the rotation matrix. First turn off Naif error reporting and
3177  // return any error without printing them.
3178  SpiceBoolean ckfailure = failed_c();
3179  reset_c(); // Reset Naif error system to allow caller to recover
3180 
3181  if (!ckfailure) {
3182  xpose6_c(stateCJ, stateCJ);
3183  xf2rav_c(stateCJ, (SpiceDouble( *)[3]) &p_CJ[0], (SpiceDouble *) &p_av[0]);
3184  p_hasAngularVelocity = true;
3185  }
3186  else {
3187  refchg_((integer *) &j2000, (integer *) &toFrame, &time, (SpiceDouble *) &p_CJ[0]);
3188 
3189  if (failed_c()) {
3190  char naifstr[64];
3191  getmsg_c("SHORT", sizeof(naifstr), naifstr);
3192  reset_c(); // Reset Naif error system to allow caller to recover
3193 
3194  if (eqstr_c(naifstr, "SPICE(UNKNOWNFRAME)")) {
3195  Isis::IString msg = Isis::IString((int) p_constantFrames[0]) + " is an unrecognized " +
3196  "reference frame code. Has the mission frames kernel been loaded?";
3197  throw IException(IException::Io, msg, _FILEINFO_);
3198  }
3199  else {
3200  Isis::IString msg = "No pointing available at requested time [" +
3201  Isis::IString(p_et + p_timeBias) + "] for frame code [" +
3202  Isis::IString((int) p_constantFrames[0]) + "]";
3203  throw IException(IException::Io, msg, _FILEINFO_);
3204  }
3205  }
3206 
3207  // Transpose to obtain row-major order
3208  xpose_c((SpiceDouble( *)[3]) &p_CJ[0], (SpiceDouble( *)[3]) &p_CJ[0]);
3209  }
3211  }
3212 
3213 
3220  std::vector<double> SpiceRotation::EvaluatePolyFunction() {
3224 
3225  // Load the functions with the coefficients
3226  function1.SetCoefficients(p_coefficients[0]);
3227  function2.SetCoefficients(p_coefficients[1]);
3228  function3.SetCoefficients(p_coefficients[2]);
3229 
3230  std::vector<double> rtime;
3231  rtime.push_back((p_et - p_baseTime) / p_timeScale);
3232  std::vector<double> angles;
3233  angles.push_back(function1.Evaluate(rtime));
3234  angles.push_back(function2.Evaluate(rtime));
3235  angles.push_back(function3.Evaluate(rtime));
3236 
3237  // Get the first angle back into the range Naif expects [-180.,180.]
3238  if (angles[0] <= -1 * pi_c()) {
3239  angles[0] += twopi_c();
3240  }
3241  else if (angles[0] > pi_c()) {
3242  angles[0] -= twopi_c();
3243  }
3244  return angles;
3245  }
3246 
3247 
3259 
3260  // Load the functions with the coefficients
3261  function1.SetCoefficients(p_coefficients[0]);
3262  function2.SetCoefficients(p_coefficients[1]);
3263  function3.SetCoefficients(p_coefficients[2]);
3264 
3265  std::vector<double> rtime;
3266  rtime.push_back((p_et - p_baseTime) / p_timeScale);
3267  double angle1 = function1.Evaluate(rtime);
3268  double angle2 = function2.Evaluate(rtime);
3269  double angle3 = function3.Evaluate(rtime);
3270 
3271  // Get the first angle back into the range Naif expects [-180.,180.]
3272  if (angle1 < -1 * pi_c()) {
3273  angle1 += twopi_c();
3274  }
3275  else if (angle1 > pi_c()) {
3276  angle1 -= twopi_c();
3277  }
3278 
3279  eul2m_c((SpiceDouble) angle3, (SpiceDouble) angle2, (SpiceDouble) angle1,
3281  (SpiceDouble( *)[3]) &p_CJ[0]);
3282 
3283  if (p_hasAngularVelocity) {
3284  if ( p_degree == 0)
3285  p_av = p_cacheAv[0];
3286  else
3287  ComputeAv();
3288  }
3290  }
3291 
3292 
3302  std::vector<double> cacheAngles(3);
3303  std::vector<double> cacheVelocity(3);
3304  cacheAngles = Angles(p_axis3, p_axis2, p_axis1);
3305  cacheVelocity = p_av;
3307  std::vector<double> polyAngles(3);
3308  // The decomposition fails because the angles are outside the valid range for Naif
3309  // polyAngles = Angles(p_axis3, p_axis2, p_axis1);
3310  polyAngles = EvaluatePolyFunction();
3311  std::vector<double> polyVelocity(3);
3312  polyVelocity = p_av;
3313  std::vector<double> angles(3);
3314 
3315  for (int index = 0; index < 3; index++) {
3316  angles[index] = cacheAngles[index] + polyAngles[index];
3317  p_av[index] += cacheVelocity[index];
3318  }
3319 
3320  if (angles[0] <= -1 * pi_c()) {
3321  angles[0] += twopi_c();
3322  }
3323  else if (angles[0] > pi_c()) {
3324  angles[0] -= twopi_c();
3325  }
3326 
3327  if (angles[2] <= -1 * pi_c()) {
3328  angles[2] += twopi_c();
3329  }
3330  else if (angles[2] > pi_c()) {
3331  angles[2] -= twopi_c();
3332  }
3333 
3334  eul2m_c((SpiceDouble) angles[2], (SpiceDouble) angles[1], (SpiceDouble) angles[0],
3336  (SpiceDouble( *)[3]) &p_CJ[0]);
3337  }
3338 
3339 
3346  // Set the scales
3347  double dTime = p_et / 86400.; // seconds to days conversion
3348  double centTime = dTime / 36525; // seconds to Julian centuries conversion
3349  double secondsPerJulianCentury = 86400. * 36525.;
3350 
3351  // Calculate the quadratic part of the expression for the angles in degrees
3352  // Note: phi = ra + 90. and delta = 90 - dec for comparing results with older Isis 2 data
3353  Angle ra = m_raPole[0] + centTime*(m_raPole[1] + m_raPole[2]*centTime);
3354  Angle dec = m_decPole[0] + centTime*(m_decPole[1] + m_decPole[2]*centTime);
3355  Angle pm = m_pm[0] + dTime*(m_pm[1] + m_pm[2]*dTime);
3356  Angle dra = (m_raPole[1] + 2.*m_raPole[2]*centTime) / secondsPerJulianCentury;
3357  Angle ddec = (m_decPole[1] + 2.*m_decPole[2]*centTime) / secondsPerJulianCentury;
3358  Angle dpm = (m_pm[1] + 2.*m_pm[2]*dTime) / 86400;
3359 
3360  // Now add the nutation/precession (trig part) adjustment to the expression if any
3361  int numNutPrec = (int) m_raNutPrec.size();
3362  Angle theta;
3363  double dtheta;
3364  double costheta;
3365  double sintheta;
3366 
3367  for (int ia = 0; ia < numNutPrec; ia++) {
3368  theta = m_sysNutPrec0[ia] + m_sysNutPrec1[ia]*centTime;
3369  dtheta = m_sysNutPrec1[ia].degrees() * DEG2RAD;
3370  costheta = cos(theta.radians());
3371  sintheta = sin(theta.radians());
3372  ra += Angle(m_raNutPrec[ia] * sintheta, Angle::Degrees);
3373  dec += Angle(m_decNutPrec[ia] * costheta, Angle::Degrees);
3374  pm += Angle(m_pmNutPrec[ia] * sintheta, Angle::Degrees);
3375  dra += Angle(m_raNutPrec[ia] * dtheta / secondsPerJulianCentury * costheta, Angle::Degrees);
3376  ddec -= Angle(m_decNutPrec[ia] * dtheta / secondsPerJulianCentury * sintheta, Angle::Degrees);
3377  dpm += Angle(m_pmNutPrec[ia] * dtheta / secondsPerJulianCentury * costheta, Angle::Degrees);
3378  }
3379 
3380  // Get pm in correct range
3381  pm = Angle(fmod(pm.degrees(), 360), Angle::Degrees); // Get pm back into the domain range
3382 
3383  if (ra.radians() < -1 * pi_c()) {
3384  ra += Angle(twopi_c(), Angle::Radians);
3385  }
3386  else if (ra.radians() > pi_c()) {
3387  ra -= Angle(twopi_c(), Angle::Radians);
3388  }
3389 
3390  if (pm.radians() < -1 * pi_c()) {
3391  pm += Angle(twopi_c(), Angle::Radians);
3392  }
3393  else if (pm.radians() > pi_c()) {
3394  pm -= Angle(twopi_c(), Angle::Radians);
3395  }
3396 
3397  // Convert to Euler angles to get the matrix
3398  SpiceDouble phi = ra.radians() + HALFPI;
3399  SpiceDouble delta = HALFPI - dec.radians();
3400  SpiceDouble w = pm.radians();
3401  SpiceDouble dphi = dra.radians();
3402  SpiceDouble ddelta = -ddec.radians();
3403  SpiceDouble dw = dpm.radians();
3404 
3405  // Load the Euler angles and their derivatives into an array and create the state matrix
3406  SpiceDouble angsDangs[6];
3407  SpiceDouble BJs[6][6];
3408  vpack_c(w, delta, phi, angsDangs);
3409  vpack_c(dw, ddelta, dphi, &angsDangs[3]);
3410  eul2xf_c (angsDangs, p_axis3, p_axis2, p_axis1, BJs);
3411 
3412  // Decompose the state matrix to the rotation and its angular velocity
3413  xf2rav_c(BJs, (SpiceDouble( *)[3]) &p_CJ[0], (SpiceDouble *) &p_av[0]);
3414  }
3415 }
Table Cache(const QString &tableName)
Return a table with J2000 to reference rotations.
Isis specific code for binary pck.
Provide operations for quaternion arithmetic.
Definition: Quaternion.h:52
void SetOverrideBaseTime(double baseTime, double timeScale)
Set an override base time to be used with observations on scanners to allow all images in an observat...
int Records() const
Returns the number of records.
Definition: Table.cpp:224
void MinimizeCache(DownsizeStatus status)
Set the downsize status to minimize cache.
std::vector< double > EvaluatePolyFunction()
Evaluate the polynomial fit function for the three pointing angles for the current ephemeris time...
double DPckPolynomial(PartialType partialVar, const int coeffIndex)
Evaluate the derivative of the fit polynomial defined by the given coefficients with respect to the c...
int size() const
Returns the number of values stored in this keyword.
Definition: PvlKeyword.h:141
int Coefficients() const
Returns the number of coefficients for the equation.
Definition: BasisFunction.h:80
std::vector< double > p_cacheTime
iTime for corresponding rotation
std::vector< double > p_CJ
Rotation matrix from J2000 to first constant rotation.
std::vector< double > GetQuaternion() const
Return the quaternion as a vector.
Definition: Quaternion.h:70
double EphemerisTime() const
Accessor method to get current ephemeris time.
void SetCoefficients(const std::vector< double > &coefs)
Set the coefficients for the equation.
std::vector< double > Matrix()
Return the full rotation TJ as a matrix.
std::vector< Angle > m_pm
Coefficients of a quadratic polynomial fitting pole pm.
void SetPolynomialDegree(int degree)
Set the degree of the polynomials to be fit to the three camera angles for the time period covered by...
double radians() const
Convert an angle to a double.
Definition: Angle.h:239
std::vector< double > m_decNutPrec
Coefficients of pole decliniation nut/prec terms.
int p_axis3
Axis of rotation for angle 3 of rotation.
Utility class for creating and using cartesean line equations.
Definition: LineEquation.h:44
void GetPolynomial(std::vector< double > &abcAng1, std::vector< double > &abcAng2, std::vector< double > &abcAng3)
Return the coefficients of a polynomial fit to each of the three camera angles for the time period co...
void loadPCFromTable(const PvlObject &Label)
Initialize planetary orientation constants from an cube body rotation label.
int p_targetCode
For computing Nadir rotation only.
void SetAxes(int axis1, int axis2, int axis3)
Set the axes of rotation for decomposition of a rotation matrix into 3 angles.
bool m_tOrientationAvailable
Target orientation constants are available.
double Intercept()
Compute the intercept of the line.
std::vector< double > m_raNutPrec
Coefficients of pole right ascension nut/prec terms.
int p_degree
Degree of fit polynomial for angles.
void LoadCache(double startTime, double endTime, int size)
Cache J2000 rotation quaternion over a time range.
void setEphemerisTimePolyFunction()
When setting the ephemeris time, updates the rotation according to a polynomial that defines the thre...
Nth degree Polynomial with one variable.
int p_axis1
Axis of rotation for angle 1 of rotation.
void SetConstantMatrix(std::vector< double > constantMatrix)
Set the constant 3x3 rotation TC matrix from a vector of length 9.
int toInt(const QString &string)
Global function to convert from a string to an integer.
Definition: IString.cpp:108
void usePckPolynomial()
Set the coefficients of a polynomial fit to each of the three planet angles for the time period cover...
const double DEG2RAD(0.017453292519943295769237)
Multiplier for converting from degrees to radians.
bool p_hasAngularVelocity
Flag indicating whether the rotation includes angular velocity.
void SetEphemerisTime(double et)
Return the J2000 to reference frame quaternion at given time.
std::vector< double > p_TC
Rotation matrix from first constant rotation (after all time-based rotations in frame chain from J200...
std::vector< Angle > m_sysNutPrec0
Constants of planetary system nut/prec periods.
std::vector< double > AngularVelocity()
Accessor method to get the angular velocity.
DownsizeStatus p_minimizeCache
Status of downsizing the cache (set to No to ignore)
void LoadTimeCache()
Load the time cache.
bool IsCached() const
Checks if the cache is empty.
const double HALFPI(1.57079632679489661923)
The mathematical constant PI/2.
int Frame()
Accessor method that returns the frame code.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:226
void getPckPolynomial(std::vector< Angle > &raCoeff, std::vector< Angle > &decCoeff, std::vector< Angle > &pmCoeff)
Return the coefficients of a polynomial fit to each of the three planet angles.
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:164
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:154
A type of error that occurred when performing an actual I/O operation.
Definition: IException.h:163
std::vector< double > GetCenterAngles()
Return the camera angles at the center time of the observation.
std::vector< double > TimeBasedRotation()
Return time-based 3x3 rotation CJ matrix as a quaternion.
void setPckPolynomial(const std::vector< Angle > &raCoeff, const std::vector< Angle > &decCoeff, const std::vector< Angle > &pmCoeff)
Set the coefficients of a polynomial fit to each of the three planet angles for the time period cover...
double WrapAngle(double compareAngle, double angle)
Wrap the input angle to keep it within 2pi radians of the angle to compare.
std::vector< double > & TimeBasedMatrix()
Return time-based 3x3 rotation CJ matrix as a vector of length 9.
std::vector< Angle > poleRaCoefs()
Return the coefficients used to calculate the target body pole ra.
SpiceRotation(int frameCode)
Construct an empty SpiceRotation class using a valid Naif frame code to set up for getting rotation f...
Isis specific code for unknown frame type.
int p_axis2
Axis of rotation for angle 2 of rotation.
std::vector< double > Extrapolate(double timeEt)
Extrapolate pointing for a given time assuming a constant angular velocity.
double p_fullCacheStartTime
Initial requested starting time of cache.
PCK frame not referenced to J2000.
std::vector< double > p_av
Angular velocity for rotation at time p_et.
FrameType
Enumeration for the frame type of the rotation.
bool hasKeyword(const QString &kname, FindOptions opts) const
See if a keyword is in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within ...
Definition: PvlObject.cpp:207
void SetFrame(int frameCode)
Change the frame to the given frame code.
void loadPCFromSpice(int CenterBodyCode)
Initialize planetary orientation constants from Spice PCK.
double p_overrideTimeScale
Value set by caller to override computed time scale.
DownsizeStatus
Status of downsizing the cache.
bool p_noOverride
Flag to compute base time;.
double GetBaseTime()
Accessor method to get the rotation base time.
std::vector< double > poleDecNutPrecCoefs()
Return the coefficients used to calculate the target body pole dec nut/prec coefficients.
bool p_degreeApplied
Flag indicating whether or not a polynomial of degree p_degree has been created and used to fill the ...
void checkForBinaryPck()
Check loaded pck to see if any are binary and set frame type to indicate binary pck.
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition: Angle.h:69
void CacheLabel(Table &table)
Add labels to a SpiceRotation table.
std::vector< double > Angles(int axis3, int axis2, int axis1)
Return the camera angles (right ascension, declination, and twist) for the time-based matrix CJ...
std::vector< double > ReferenceVector(const std::vector< double > &jVec)
Given a direction vector in J2000, return a reference frame direction.
double p_baseTime
Base time used in fit equations.
int p_axisP
The axis defined by the spacecraft vector for defining a nadir rotation.
bool p_matrixSet
Flag indicating p_TJ has been set.
void SetTimeBias(double timeBias)
Apply a time bias when invoking SetEphemerisTime method.
int Fields() const
Returns the number of fields that are currently in the record.
Definition: TableRecord.cpp:94
PvlKeyword & findKeyword(const QString &kname, FindOptions opts)
Finds a keyword in the current PvlObject, or deeper inside other PvlObjects and Pvlgroups within this...
Definition: PvlObject.cpp:148
Source p_source
The source of the rotation data.
std::vector< double > GetFullCacheTime()
Return full listing (cache) of original time coverage requested.
double p_et
Current ephemeris time.
std::vector< int > TimeFrameChain()
Accessor method to get the frame chain for the rotation (begins in J2000).
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:38
With respect to Twist or Prime Meridian Rotation.
double p_overrideBaseTime
Value set by caller to override computed base time.
See Naif Frames.req document for.
void SetTimeBasedMatrix(std::vector< double > timeBasedMatrix)
Set the time-based 3x3 rotation CJ matrix from a vector of length 9.
A type of error that could only have occurred due to a mistake on the user&#39;s part (e...
Definition: IException.h:134
A single keyword-value pair.
Definition: PvlKeyword.h:98
std::vector< std::vector< double > > p_cache
Cached rotations, stored as rotation matrix from J2000 to 1st constant frame (CJ) or coefficients of ...
void SetFullCacheParameters(double startTime, double endTime, int cacheSize)
Set the full cache time parameters.
Do not downsize the cache.
void setEphemerisTimePolyFunctionOverSpice()
When setting the ephemeris time, updates the rotation state based on a polynomial fit over spice kern...
Kernels plus nth degree polynomial.
std::vector< Angle > sysNutPrecConstants()
Return the constants used to calculate the target body system nut/prec angles.
Source
The rotation can come from one of 3 places for an Isis cube.
std::vector< std::vector< double > > p_cacheAv
Cached angular velocities for corresponding rotactions in p_cache.
FrameType getFrameType()
Accessor method to get the rotation frame type.
std::vector< Angle > pmCoefs()
Return the coefficients used to calculate the target body prime meridian.
void FrameTrace(double et)
Compute frame trace chain from target frame to J2000.
Obtain SPICE rotation information for a body.
Generic least square fitting class.
Definition: LeastSquares.h:117
Quaternion p_quaternion
Quaternion for J2000 to reference rotation at et.
With respect to Declination.
The values in the field are 8 byte doubles.
Definition: TableField.h:70
PartialType
This enumeration indicates whether the partial derivative is taken with respect to Right Ascension...
double p_timeBias
iTime bias when reading kernels
double Coefficient(int i) const
Returns the ith coefficient.
std::vector< int > ConstantFrameChain()
Accessor method to get the frame chain for the constant part of the rotation (ends in target) ...
std::vector< double > pmNutPrecCoefs()
Return the coefficients used to calculate the target body pm nut/prec coefficients.
void ComputeBaseTime()
Compute the base time using cached times.
void setEphemerisTimeNadir()
When setting the ephemeris time, uses spacecraft nadir source to update the rotation state...
int p_fullCacheSize
Initial requested cache size.
void InitConstantRotation(double et)
Initialize the constant rotation.
double DPolynomial(const int coeffIndex)
Evaluate the derivative of the fit polynomial defined by the given coefficients with respect to the c...
void ReloadCache()
Cache J2000 rotation over existing cached time range using polynomials.
void ComputeAv()
Compute the angular velocity from the time-based functions fit to the pointing angles This method com...
Defines an angle and provides unit conversions.
Definition: Angle.h:58
void AddKnown(const std::vector< double > &input, double expected, double weight=1.0)
Invoke this method for each set of knowns.
Directly from the kernels.
void DCJdt(std::vector< double > &dRJ)
Compute the derivative of the 3x3 rotation matrix CJ with respect to time.
void SetSource(Source source)
Resets the source of the rotation to the given value.
std::vector< double > m_pmNutPrec
Coefficients of prime meridian nut/prec terms.
std::vector< double > ToMatrix()
Converts quaternion to 3x3 rotational matrix.
Definition: Quaternion.cpp:91
Downsize the cache.
std::vector< double > toJ2000Partial(const std::vector< double > &lookT, PartialType partialVar, int coeffIndex)
Given a direction vector in the reference frame, compute the derivative with respect to one of the co...
std::vector< double > StateTJ()
State matrix (6x6) for rotating state vectors from J2000 to target frame.
void setFrameType()
Set the frame type (m_frameType).
Class for storing Table blobs information.
Definition: Table.h:74
std::vector< double > J2000Vector(const std::vector< double > &rVec)
Given a direction vector in the reference frame, return a J2000 direction.
std::vector< Angle > m_sysNutPrec1
Linear terms of planetary system nut/prec periods.
Cache is downsized.
std::vector< Angle > sysNutPrecCoefs()
Return the coefficients used to calculate the target body system nut/prec angles. ...
double Evaluate(const std::vector< double > &vars)
Compute the equation using the input variables.
static void CheckErrors(bool resetNaif=true)
This method looks for any naif errors that might have occurred.
Definition: NaifStatus.cpp:43
FrameType m_frameType
The type of rotation frame.
Isis exception class.
Definition: IException.h:99
Adds specific functionality to C++ strings.
Definition: IString.h:179
std::vector< double > p_coefficients[3]
Coefficients defining functions fit to 3 pointing angles.
From nth degree polynomial.
std::vector< double > & ConstantMatrix()
Return the constant 3x3 rotation TC matrix as a vector of length 9.
Obtain SPICE information for a spacecraft.
Definition: Spice.h:282
Class for storing an Isis::Table&#39;s field information.
Definition: TableField.h:63
PvlObject & Label()
Accessor method that returns a PvlObject containing the Blob label.
Definition: Blob.cpp:167
Radians are generally used in mathematical equations, 0-2*PI is one circle, however these are more di...
Definition: Angle.h:76
void setEphemerisTimeSpice()
When setting the ephemeris time, updates the rotation state based on data read directly from NAIF ker...
int p_axisV
The axis defined by the velocity vector for defining a nadir rotation.
std::vector< Angle > poleDecCoefs()
Return the coefficients used to calculate the target body pole dec.
double GetTimeScale()
Accessor method to get the rotation time scale.
std::vector< double > poleRaNutPrecCoefs()
Return the coefficients used to calculate the target body pole ra nut/prec coefficients.
void setEphemerisTimeMemcache()
Updates rotation state based on the rotation cache.
double p_fullCacheEndTime
Initial requested ending time of cache.
void setEphemerisTimePckPolyFunction()
When setting the ephemeris time, updates the rotation state based on the PcK polynomial.
void SetPolynomial(const Source type=PolyFunction)
Set the coefficients of a polynomial fit to each of the three camera angles for the time period cover...
Contains Pvl Groups and Pvl Objects.
Definition: PvlObject.h:74
std::vector< int > p_constantFrames
Chain of Naif frame codes in constant rotation TC.
double Slope()
Compute the slope of the line.
double p_timeScale
Time scale used in fit equations.
int Solve(Isis::LeastSquares::SolveMethod method=SVD)
After all the data has been registered through AddKnown, invoke this method to solve the system of eq...
bool HasAngularVelocity()
Checks whether the rotation has angular velocities.
void SetAngles(std::vector< double > angles, int axis3, int axis2, int axis1)
Set the rotation angles (phi, delta, and w) for the current time to define the time-based matrix CJ...
Table LineCache(const QString &tableName)
Return a table with J2000 to reference rotations.
std::vector< int > p_timeFrames
Chain of Naif frame codes in time-based rotation CJ.
std::vector< double > ConstantRotation()
Return the constant 3x3 rotation TC matrix as a quaternion.
Quadratic polynomial function with linear trignometric terms.
virtual ~SpiceRotation()
Destructor for SpiceRotation object.
Source GetSource()
Accessor method to get the rotation source.
std::vector< double > ToReferencePartial(std::vector< double > &lookJ, PartialType partialVar, int coeffIndex)
Compute the derivative with respect to one of the coefficients in the angle polynomial fit equation o...
std::vector< Angle > m_raPole
Coefficients of a quadratic polynomial fitting pole ra.
With respect to Right Ascension.
std::vector< Angle > m_decPole
Coefficients of a quadratic polynomial fitting pole dec.

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the ISIS Support Center
File Modified: 07/12/2023 23:29:42