Isis 3 Programmer Reference
SpiceRotation.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include "SpiceRotation.h"
8 
9 #include <algorithm>
10 #include <cfloat>
11 #include <cmath>
12 #include <iomanip>
13 #include <string>
14 #include <vector>
15 
16 #include <QDebug>
17 #include <QString>
18 #include <SpiceUsr.h>
19 #include <SpiceZfc.h>
20 #include <SpiceZmc.h>
21 
22 #include "BasisFunction.h"
23 #include "IException.h"
24 #include "IString.h"
25 #include "LeastSquares.h"
26 #include "LineEquation.h"
27 #include "NaifStatus.h"
28 #include "PolynomialUnivariate.h"
29 #include "Quaternion.h"
30 #include "Table.h"
31 #include "TableField.h"
32 
33 using json = nlohmann::json;
34 
35 // Declarations for bindings for Naif Spicelib routines that do not have
36 // a wrapper
37 extern int refchg_(integer *frame1, integer *frame2, doublereal *et,
38  doublereal *rotate);
39 extern int frmchg_(integer *frame1, integer *frame2, doublereal *et,
40  doublereal *rotate);
41 extern int invstm_(doublereal *mat, doublereal *invmat);
42 // Temporary declarations for bindings for Naif supportlib routines
43 
44 // These three declarations should be removed once supportlib is in Isis3
45 extern int ck3sdn(double sdntol, bool avflag, int *nrec,
46  double *sclkdp, double *quats, double *avvs,
47  int nints, double *starts, double *dparr,
48  int *intarr);
49 
50 namespace Isis {
59  p_constantFrames.push_back(frameCode);
60  p_timeBias = 0.0;
61  p_source = Spice;
62  p_CJ.resize(9);
63  p_matrixSet = false;
64  p_et = -DBL_MAX;
65  p_degree = 2;
66  p_degreeApplied = false;
67  p_noOverride = true;
68  p_axis1 = 3;
69  p_axis2 = 1;
70  p_axis3 = 3;
72  p_hasAngularVelocity = false;
73  p_av.resize(3);
76  p_fullCacheSize = 0;
79  m_orientation = NULL;
80  }
81 
82 
93  SpiceRotation::SpiceRotation(int frameCode, int targetCode) {
95 
96  p_constantFrames.push_back(frameCode);
97  p_targetCode = targetCode;
98  p_timeBias = 0.0;
99  p_source = Nadir;
100  p_CJ.resize(9);
101  p_matrixSet = false;
102  p_et = -DBL_MAX;
103  p_axisP = 3;
104  p_degree = 2;
105  p_degreeApplied = false;
106  p_noOverride = true;
107  p_axis1 = 3;
108  p_axis2 = 1;
109  p_axis3 = 3;
111  p_hasAngularVelocity = false;
112  p_av.resize(3);
114  p_fullCacheEndTime = 0;
115 
116  p_fullCacheSize = 0;
117  m_frameType = DYN;
118  m_tOrientationAvailable = false;
119  m_orientation = NULL;
120 
121  // Determine the axis for the velocity vector
122  QString key = "INS" + toString(frameCode) + "_TRANSX";
123  SpiceDouble transX[2];
124  SpiceInt number;
125  SpiceBoolean found;
126  //Read starting at element 1 (skipping element 0)
127  gdpool_c(key.toLatin1().data(), 1, 2, &number, transX, &found);
128 
129  if (!found) {
130  QString msg = "Cannot find [" + key + "] in text kernels";
131  throw IException(IException::Io, msg, _FILEINFO_);
132  }
133 
134  p_axisV = 2;
135  if (transX[0] < transX[1]) p_axisV = 1;
136 
138  }
139 
140 
147  p_cacheTime = rotToCopy.p_cacheTime;
148  p_av = rotToCopy.p_av;
149  p_degree = rotToCopy.p_degree;
150  p_axis1 = rotToCopy.p_axis1;
151  p_axis2 = rotToCopy.p_axis2;
152  p_axis3 = rotToCopy.p_axis3;
153 
155  p_timeFrames = rotToCopy.p_timeFrames;
156  p_timeBias = rotToCopy.p_timeBias;
157 
158  p_et = rotToCopy.p_et;
159  p_quaternion = rotToCopy.p_quaternion;
160  p_matrixSet = rotToCopy.p_matrixSet;
161  p_source = rotToCopy.p_source;
162  p_axisP = rotToCopy.p_axisP;
163  p_axisV = rotToCopy.p_axisV;
164  p_targetCode = rotToCopy.p_targetCode;
165  p_baseTime = rotToCopy.p_baseTime;
166  p_timeScale = rotToCopy.p_timeScale;
167  p_degreeApplied = rotToCopy.p_degreeApplied;
168 
169 // for (std::vector<double>::size_type i = 0; i < rotToCopy.p_coefficients[0].size(); i++)
170  for (int i = 0; i < 3; i++)
171  p_coefficients[i] = rotToCopy.p_coefficients[i];
172 
173  p_noOverride = rotToCopy.p_noOverride;
176  p_minimizeCache = rotToCopy.p_minimizeCache;
179  p_fullCacheSize = rotToCopy.p_fullCacheSize;
180  p_TC = rotToCopy.p_TC;
181 
182  p_CJ = rotToCopy.p_CJ;
183  p_degree = rotToCopy.p_degree;
185  m_frameType = rotToCopy.m_frameType;
186 
187  if (rotToCopy.m_orientation) {
188  m_orientation = new ale::Orientations;
189  *m_orientation = *rotToCopy.m_orientation;
190  }
191  else {
192  m_orientation = NULL;
193  }
194  }
195 
196 
201  if (m_orientation) {
202  delete m_orientation;
203  m_orientation = NULL;
204  }
205  }
206 
207 
214  void SpiceRotation::SetFrame(int frameCode) {
215  p_constantFrames[0] = frameCode;
216  }
217 
218 
226  return p_constantFrames[0];
227  }
228 
229 
242  void SpiceRotation::SetTimeBias(double timeBias) {
243  p_timeBias = timeBias;
244  }
245 
246 
261 
262  // Save the time
263  if (p_et == et) return;
264  p_et = et;
265 
266  // Read from the cache
267  if (p_source == Memcache) {
269  }
270 
271  // Apply coefficients defining a function for each of the three camera angles and angular
272  // velocity if available
273  else if (p_source == PolyFunction) {
275  }
276  // Apply coefficients defining a function for each of the three camera angles and angular
277  // velocity if available
278  else if (p_source == PolyFunctionOverSpice) {
280  }
281  // Read from the kernel
282  else if (p_source == Spice) {
284  // Retrieve the J2000 (code=1) to reference rotation matrix
285  }
286  // Apply coefficients from PCK version of IAU solution for target body orientation and angular
287  // velocity???
288  else if (p_source == PckPolyFunction) {
290  }
291  // Compute from Nadir
292  else {
294  }
295 
296  // Set the quaternion for this rotation
297 // p_quaternion.Set ( p_CJ );
298  }
299 
300 
307  return p_et;
308  }
309 
310 
316  double SpiceRotation::TimeBias() const {
317  return p_timeBias;
318  }
319 
320 
326  bool SpiceRotation::IsCached() const {
327  return (m_orientation != NULL);
328  }
329 
330 
337  p_minimizeCache = status;
338  }
339 
340 
359  void SpiceRotation::LoadCache(double startTime, double endTime, int size) {
360 
361  // Check for valid arguments
362  if (size <= 0) {
363  QString msg = "Argument cacheSize must not be less or equal to zero";
364  throw IException(IException::Programmer, msg, _FILEINFO_);
365  }
366 
367  if (startTime > endTime) {
368  QString msg = "Argument startTime must be less than or equal to endTime";
369  throw IException(IException::Programmer, msg, _FILEINFO_);
370  }
371 
372  if ((startTime != endTime) && (size == 1)) {
373  QString msg = "Cache size must be more than 1 if startTime and endTime differ";
374  throw IException(IException::Programmer, msg, _FILEINFO_);
375  }
376 
377  // Make sure cache isn't already loaded
378  if (p_source == Memcache) {
379  QString msg = "A SpiceRotation cache has already been created";
380  throw IException(IException::Programmer, msg, _FILEINFO_);
381  }
382 
383  // Save full cache parameters
384  p_fullCacheStartTime = startTime;
385  p_fullCacheEndTime = endTime;
386  p_fullCacheSize = size;
387 
388  if (m_orientation != NULL) {
389  delete m_orientation;
390  m_orientation = NULL;
391  }
392 
393  // Make sure the constant frame is loaded. This method also does the frame trace.
394  if (p_timeFrames.size() == 0) InitConstantRotation(startTime);
395 
396  // Set the frame type. If the frame class is PCK, load the constants.
397  if (p_source == Spice) {
398  setFrameType();
399  }
400 
401  LoadTimeCache();
402  int cacheSize = p_cacheTime.size();
403 
404  // Loop and load the cache
405  std::vector<ale::Rotation> rotationCache;
406  std::vector< std::vector<double> > cache;
407  std::vector<ale::Vec3d> avCache;
408  for (int i = 0; i < cacheSize; i++) {
409  double et = p_cacheTime[i];
410  SetEphemerisTime(et);
411  rotationCache.push_back(ale::Rotation(p_CJ));
412  cache.push_back(p_CJ);
413 
414  if (p_hasAngularVelocity) {
415  avCache.push_back(ale::Vec3d(p_av));
416  }
417  }
418 
419  if (p_TC.size() > 1) {
420  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
421  ale::Rotation(p_TC), p_constantFrames, p_timeFrames);
422  }
423  else {
424  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
425  ale::Rotation(1,0,0,0), p_constantFrames, p_timeFrames);
426  }
427 
428  p_source = Memcache;
429 
430  // Downsize already loaded caches (both time and quats)
431  if (p_minimizeCache == Yes && cacheSize > 5) {
432  LoadTimeCache();
433  }
434  }
435 
436 
450  void SpiceRotation::LoadCache(double time) {
451  LoadCache(time, time, 1);
452  }
453 
454 
464  void SpiceRotation::LoadCache(json &isdRot){
465  if (p_source != Spice) {
466  throw IException(IException::Programmer, "SpiceRotation::LoadCache(json) only supports Spice source", _FILEINFO_);
467  }
468 
469  p_timeFrames.clear();
470  p_TC.clear();
471  p_cacheTime.clear();
472  p_hasAngularVelocity = false;
473  m_frameType = CK;
474 
475  if (m_orientation) {
476  delete m_orientation;
477  m_orientation = NULL;
478  }
479 
480  // Load the full cache time information from the label if available
481  p_fullCacheStartTime = isdRot["ck_table_start_time"].get<double>();
482  p_fullCacheEndTime = isdRot["ck_table_end_time"].get<double>();
483  p_fullCacheSize = isdRot["ck_table_original_size"].get<double>();
484  p_cacheTime = isdRot["ephemeris_times"].get<std::vector<double>>();
485  p_timeFrames = isdRot["time_dependent_frames"].get<std::vector<int>>();
486 
487  std::vector<ale::Rotation> rotationCache;
488  for (auto it = isdRot["quaternions"].begin(); it != isdRot["quaternions"].end(); it++) {
489  std::vector<double> quat = {it->at(0).get<double>(), it->at(1).get<double>(), it->at(2).get<double>(), it->at(3).get<double>()};
490  Quaternion q(quat);
491  std::vector<double> CJ = q.ToMatrix();
492  rotationCache.push_back(ale::Rotation(CJ));
493  }
494 
495  std::vector<ale::Vec3d> avCache;
496  if (isdRot["angular_velocities"].size() != 0) {
497  for (auto it = isdRot["angular_velocities"].begin(); it != isdRot["angular_velocities"].end(); it++) {
498  std::vector<double> av = {it->at(0).get<double>(), it->at(1).get<double>(), it->at(2).get<double>()};
499  avCache.push_back(ale::Vec3d(av));
500  }
501  p_hasAngularVelocity = true;
502  }
503 
504  bool hasConstantFrames = isdRot.find("constant_frames") != isdRot.end();
505 
506 
507  if (hasConstantFrames) {
508  p_constantFrames = isdRot["constant_frames"].get<std::vector<int>>();
509  p_TC = isdRot["constant_rotation"].get<std::vector<double>>();
510  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
511  ale::Rotation(p_TC), p_constantFrames, p_timeFrames);
512  }
513  else {
514  p_TC.resize(9);
515  ident_c((SpiceDouble( *)[3]) &p_TC[0]);
516  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
517  ale::Rotation(1,0,0,0), p_constantFrames, p_timeFrames);
518  }
519 
520 
521  p_source = Memcache;
523  }
524 
525 
551  // Clear any existing cached data to make it reentrant (KJB 2011-07-20).
552  p_timeFrames.clear();
553  p_TC.clear();
554  p_cacheTime.clear();
555 
556  p_hasAngularVelocity = false;
557 
558  if (m_orientation) {
559  delete m_orientation;
560  m_orientation = NULL;
561  }
562 
563  // Load the constant and time-based frame traces and the constant rotation
564  if (table.Label().hasKeyword("TimeDependentFrames")) {
565  PvlKeyword labelTimeFrames = table.Label()["TimeDependentFrames"];
566  for (int i = 0; i < labelTimeFrames.size(); i++) {
567  p_timeFrames.push_back(toInt(labelTimeFrames[i]));
568  }
569  }
570  else {
571  p_timeFrames.push_back(p_constantFrames[0]);
572  p_timeFrames.push_back(J2000Code);
573  }
574 
575  if (table.Label().hasKeyword("ConstantRotation")) {
576  PvlKeyword labelConstantFrames = table.Label()["ConstantFrames"];
577  p_constantFrames.clear();
578 
579  for (int i = 0; i < labelConstantFrames.size(); i++) {
580  p_constantFrames.push_back(toInt(labelConstantFrames[i]));
581  }
582  PvlKeyword labelConstantRotation = table.Label()["ConstantRotation"];
583 
584  for (int i = 0; i < labelConstantRotation.size(); i++) {
585  p_TC.push_back(toDouble(labelConstantRotation[i]));
586  }
587  }
588  else {
589  p_TC.resize(9);
590  ident_c((SpiceDouble( *)[3]) &p_TC[0]);
591  }
592 
593  // Load the full cache time information from the label if available
594  if (table.Label().hasKeyword("CkTableStartTime")) {
595  p_fullCacheStartTime = toDouble(table.Label().findKeyword("CkTableStartTime")[0]);
596  }
597  if (table.Label().hasKeyword("CkTableEndTime")) {
598  p_fullCacheEndTime = toDouble(table.Label().findKeyword("CkTableEndTime")[0]);
599  }
600  if (table.Label().hasKeyword("CkTableOriginalSize")) {
601  p_fullCacheSize = toInt(table.Label().findKeyword("CkTableOriginalSize")[0]);
602  }
603 
604  // Load FrameTypeCode from labels if available and the planetary constants keywords
605  if (table.Label().hasKeyword("FrameTypeCode")) {
606  m_frameType = (FrameType) toInt(table.Label().findKeyword("FrameTypeCode")[0]);
607  }
608  else {
610  }
611 
612  if (m_frameType == PCK) {
613  loadPCFromTable(table.Label());
614  }
615 
616  int recFields = table[0].Fields();
617 
618  // Loop through and move the table to the cache. Retrieve the first record to
619  // establish the type of cache and then use the appropriate loop.
620 
621  // list table of quaternion and time
622 
623  std::vector<ale::Rotation> rotationCache;
624  std::vector<ale::Vec3d> avCache;
625  if (recFields == 5) {
626  for (int r = 0; r < table.Records(); r++) {
627  TableRecord &rec = table[r];
628 
629  if (rec.Fields() != recFields) {
630  // throw and error
631  }
632 
633  std::vector<double> j2000Quat;
634  j2000Quat.push_back((double)rec[0]);
635  j2000Quat.push_back((double)rec[1]);
636  j2000Quat.push_back((double)rec[2]);
637  j2000Quat.push_back((double)rec[3]);
638 
639  Quaternion q(j2000Quat);
640  std::vector<double> CJ = q.ToMatrix();
641  rotationCache.push_back(ale::Rotation(CJ));
642 
643  p_cacheTime.push_back((double)rec[4]);
644  }
645  if (p_TC.size() > 1) {
646  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
647  ale::Rotation(p_TC), p_constantFrames, p_timeFrames);
648  }
649  else {
650  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
651  ale::Rotation(1,0,0,0), p_constantFrames, p_timeFrames);
652  }
653  p_source = Memcache;
654  }
655 
656  // list table of quaternion, angular velocity vector, and time
657  else if (recFields == 8) {
658  for (int r = 0; r < table.Records(); r++) {
659  TableRecord &rec = table[r];
660 
661  if (rec.Fields() != recFields) {
662  // throw and error
663  }
664 
665  std::vector<double> j2000Quat;
666  j2000Quat.push_back((double)rec[0]);
667  j2000Quat.push_back((double)rec[1]);
668  j2000Quat.push_back((double)rec[2]);
669  j2000Quat.push_back((double)rec[3]);
670 
671 
672  Quaternion q(j2000Quat);
673  std::vector<double> CJ = q.ToMatrix();
674  rotationCache.push_back(ale::Rotation(CJ));
675 
676  std::vector<double> av;
677  av.push_back((double)rec[4]);
678  av.push_back((double)rec[5]);
679  av.push_back((double)rec[6]);
680  avCache.push_back(ale::Vec3d(av));
681  p_cacheTime.push_back((double)rec[7]);
682  p_hasAngularVelocity = true;
683  }
684 
685  if (p_TC.size() > 1) {
686  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
687  ale::Rotation(p_TC), p_constantFrames, p_timeFrames);
688  }
689  else {
690  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
691  ale::Rotation(1,0,0,0), p_constantFrames, p_timeFrames);
692  }
693  p_source = Memcache;
694  }
695 
696  // coefficient table for angle1, angle2, and angle3
697  else if (recFields == 3) {
698  std::vector<double> coeffAng1, coeffAng2, coeffAng3;
699 
700  for (int r = 0; r < table.Records() - 1; r++) {
701  TableRecord &rec = table[r];
702 
703  if (rec.Fields() != recFields) {
704  // throw an error
705  }
706  coeffAng1.push_back((double)rec[0]);
707  coeffAng2.push_back((double)rec[1]);
708  coeffAng3.push_back((double)rec[2]);
709  }
710 
711  // Take care of time parameters
712  TableRecord &rec = table[table.Records()-1];
713  double baseTime = (double)rec[0];
714  double timeScale = (double)rec[1];
715  double degree = (double)rec[2];
716  SetPolynomialDegree((int) degree);
717  SetOverrideBaseTime(baseTime, timeScale);
718  SetPolynomial(coeffAng1, coeffAng2, coeffAng3);
720  if (degree > 0) p_hasAngularVelocity = true;
721  if (degree == 0 && m_orientation->getAngularVelocities().size() > 0) {
722  p_hasAngularVelocity = true;
723  }
724  }
725  else {
726  QString msg = "Expecting either three, five, or eight fields in the SpiceRotation table";
727  throw IException(IException::Programmer, msg, _FILEINFO_);
728  }
729  }
730 
731 
742  // Save current et
743  double et = p_et;
744  p_et = -DBL_MAX;
745 
746  std::vector<ale::Rotation> rotationCache;
747  std::vector<ale::Vec3d> avCache;
748  if (p_source == PolyFunction) {
749  // Clear existing matrices from cache
750  p_cacheTime.clear();
751 
752  // Load the time cache first
754  LoadTimeCache();
755 
756  if (p_fullCacheSize > 1) {
757  // Load the matrix and av caches
758  for (std::vector<double>::size_type pos = 0; pos < p_cacheTime.size(); pos++) {
759  SetEphemerisTime(p_cacheTime.at(pos));
760  rotationCache.push_back(ale::Rotation(p_CJ));
761  avCache.push_back(ale::Vec3d(p_av));
762  }
763  }
764  else {
765  // Load the matrix for the single updated time instance
767  rotationCache.push_back(ale::Rotation(p_CJ));
768  avCache.push_back(ale::Vec3d(p_av));
769  }
770  }
771  else if (p_source == PolyFunctionOverSpice) {
772  SpiceRotation tempRot(*this);
773  std::vector<double>::size_type maxSize = p_fullCacheSize;
774 
775  // Clear the existing caches
776  p_cacheTime.clear();
777 
778  // Reload the time cache first
780  LoadTimeCache();
781 
782  for (std::vector<double>::size_type pos = 0; pos < maxSize; pos++) {
783  tempRot.SetEphemerisTime(p_cacheTime.at(pos));
784  std::vector<double> CJ = tempRot.TimeBasedMatrix();
785  rotationCache.push_back(ale::Rotation(CJ));
787  avCache.push_back(ale::Vec3d(tempRot.AngularVelocity()));
788  }
789  }
790  }
791  else { //(p_source < PolyFunction)
792  QString msg = "The SpiceRotation has not yet been fit to a function";
793  throw IException(IException::Programmer, msg, _FILEINFO_);
794  }
795 
796  if (m_orientation) {
797  delete m_orientation;
798  m_orientation = NULL;
799  }
800 
801  if (p_TC.size() > 1) {
802  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
803  ale::Rotation(p_TC), p_constantFrames, p_timeFrames);
804  }
805  else {
806  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
807  ale::Rotation(1,0,0,0), p_constantFrames, p_timeFrames);
808  }
809 
810  // Set source to cache and reset current et
811  // Make sure source is Memcache now
812  p_source = Memcache;
813  p_et = -DBL_MAX;
814  SetEphemerisTime(et);
815  }
816 
817 
832  Table SpiceRotation::LineCache(const QString &tableName) {
833 
834  // Apply the function and fill the caches
836 
837  if (p_source != Memcache) {
838  QString msg = "Only cached rotations can be returned as a line cache of quaternions and time";
839  throw IException(IException::Programmer, msg, _FILEINFO_);
840  }
841  // Load the table and return it to caller
842  return Cache(tableName);
843  }
844 
845 
868  Table SpiceRotation::Cache(const QString &tableName) {
869  // First handle conversion of PolyFunctionOverSpiceConstant
870  // by converting it to the full Memcache and try to downsize it
872  LineCache(tableName);
873 
874  //std::cout << "Full cache size is " << p_cache.size() << endl;
876  LoadTimeCache();
877 
878  //std::cout << "Minimized cache size is " << p_cache.size() << endl;
879  }
880 
881  // Load the list of rotations and their corresponding times
882  if (p_source == Memcache) {
883  TableField q0("J2000Q0", TableField::Double);
884  TableField q1("J2000Q1", TableField::Double);
885  TableField q2("J2000Q2", TableField::Double);
886  TableField q3("J2000Q3", TableField::Double);
888 
889  TableRecord record;
890  record += q0;
891  record += q1;
892  record += q2;
893  record += q3;
894  int timePos = 4;
895 
896  if (p_hasAngularVelocity) {
897  TableField av1("AV1", TableField::Double);
898  TableField av2("AV2", TableField::Double);
899  TableField av3("AV3", TableField::Double);
900  record += av1;
901  record += av2;
902  record += av3;
903  timePos = 7;
904  }
905 
906  record += t;
907  Table table(tableName, record);
908 
909  std::vector<ale::Rotation> rots = m_orientation->getRotations();
910  std::vector<ale::Vec3d> angularVelocities = m_orientation->getAngularVelocities();
911  for (int i = 0; i < (int) p_cacheTime.size(); i++) {
912  std::vector<double> quat = rots[i].toQuaternion();
913 
914  // If the first component is less than zero, multiply the whole quaternion by -1. This
915  // matches NAIF.
916  if (quat[0] < 0) {
917  quat[0] = -1 * quat[0];
918  quat[1] = -1 * quat[1];
919  quat[2] = -1 * quat[2];
920  quat[3] = -1 * quat[3];
921  }
922 
923  record[0] = quat[0];
924  record[1] = quat[1];
925  record[2] = quat[2];
926  record[3] = quat[3];
927 
928  if (angularVelocities.size() > 0 && p_hasAngularVelocity ) {
929  ale::Vec3d angularVelocity = angularVelocities[i];
930  record[4] = angularVelocity.x;
931  record[5] = angularVelocity.y;
932  record[6] = angularVelocity.z;
933  }
934 
935  record[timePos] = p_cacheTime[i];
936  table += record;
937  }
938 
939  CacheLabel(table);
940  return table;
941  }
942  // Just load the position for the single epoch
943  else if (p_source == PolyFunction && p_degree == 0 && p_fullCacheSize == 1) {
944  return LineCache(tableName);
945  }
946  // Load the coefficients for the curves fit to the 3 camera angles
947  else if (p_source == PolyFunction) {
948  TableField angle1("J2000Ang1", TableField::Double);
949  TableField angle2("J2000Ang2", TableField::Double);
950  TableField angle3("J2000Ang3", TableField::Double);
951 
952  TableRecord record;
953  record += angle1;
954  record += angle2;
955  record += angle3;
956 
957  Table table(tableName, record);
958 
959  for (int cindex = 0; cindex < p_degree + 1; cindex++) {
960  record[0] = p_coefficients[0][cindex];
961  record[1] = p_coefficients[1][cindex];
962  record[2] = p_coefficients[2][cindex];
963  table += record;
964  }
965 
966  // Load one more table entry with the time adjustments for the fit equation
967  // t = (et - baseTime)/ timeScale
968  record[0] = p_baseTime;
969  record[1] = p_timeScale;
970  record[2] = (double) p_degree;
971 
972  table += record;
973  CacheLabel(table);
974  return table;
975  }
976  else {
977  // throw an error -- should not get here -- invalid Spice Source
978  QString msg = "To create table source of data must be either Memcache or PolyFunction";
979  throw IException(IException::Programmer, msg, _FILEINFO_);
980  }
981  }
982 
983 
991  void SpiceRotation::loadPCFromSpice(int centerBody) {
993  SpiceInt centerBodyCode = (SpiceInt) centerBody;
994 
995  // Retrieve the frame class from Naif. We distinguish PCK types into text PCK,
996  // binary PCK, and PCK not referenced to J2000. Isis binary PCK can
997  // not be used to solve for target body orientation because of the variety and
998  // complexity models used with binary PCK. Currently ISIS does not solve for
999  // target body orientation on bodies not referenced to J2000, but it could be
1000  // changed to handle that case.
1002 
1003  if (m_frameType == PCK) {
1004  // Make sure the reference frame is J2000. We will need to modify FrameTrace and
1005  // the pck methods in this class to handle this case. At the time this method was
1006  // added, this case is not being used in the pck file. It is mentioned in the Naif required
1007  // reading file, pck.req, as a possibility for future pck files.
1008  // Look for a reference frame keyword for the body. The default is J2000.
1009  QString naifKeyword = "BODY" + toString(centerBodyCode) + "_CONSTANTS_REF_FRAME" ;
1010  SpiceInt numExpected;
1011  SpiceInt numReturned;
1012  SpiceChar naifType;
1013  SpiceDouble relativeFrameCode = 0;
1014  SpiceBoolean found;
1015  dtpool_c(naifKeyword.toLatin1().data(), &found, &numExpected, &naifType);
1016 
1017  if (found) {
1018  // Go get the frame name if it is not the default J2000
1019  SpiceDouble relativeFrameCode;
1020  bodvcd_c(centerBodyCode, "CONSTANTS_REF_FRAME", 1,
1021  &numReturned, &relativeFrameCode);
1022  }
1023 
1024  if (!found || relativeFrameCode == 1) { // We only work with J2000 relative frames for now
1025 
1026  // Make sure the standard coefficients are available for the body code by
1027  // checking for ra
1028  naifKeyword = "BODY" + toString(centerBodyCode) + "_POLE_RA" ;
1029  dtpool_c(naifKeyword.toLatin1().data(), &found, &numExpected, &naifType);
1030 
1031  if (found) {
1032  std::vector<SpiceDouble> d(3);
1033  m_raPole.resize(numExpected);
1034  m_decPole.resize(numExpected);
1035  m_pm.resize(numExpected);
1036 
1037  bodvcd_c(centerBodyCode, "POLE_RA", numExpected, &numReturned, &d[0]);
1038  m_raPole[0].setDegrees(d[0]);
1039  m_raPole[1].setDegrees(d[1]);
1040  m_raPole[2].setDegrees(d[2]);
1041 
1042  bodvcd_c(centerBodyCode, "POLE_DEC", numExpected, &numReturned, &d[0]);
1043  m_decPole[0].setDegrees(d[0]);
1044  m_decPole[1].setDegrees(d[1]);
1045  m_decPole[2].setDegrees(d[2]);
1046 
1047  bodvcd_c(centerBodyCode, "PM", numExpected, &numReturned, &d[0]);
1048  m_pm[0].setDegrees(d[0]);
1049  m_pm[1].setDegrees(d[1]);
1050  m_pm[2].setDegrees(d[2]);
1051 
1052  // ***TODO*** Get long axis value
1053  m_tOrientationAvailable = true;
1054 
1055  // Now check for nutation/precession terms. Check for nut/prec ra values
1056  // first to see if the terms are even used for this body.
1057  naifKeyword = "BODY" + toString(centerBodyCode) + "_NUT_PREC_RA" ;
1058  dtpool_c(naifKeyword.toLatin1().data(), &found, &numReturned, &naifType);
1059  if (found) {
1060  // Get the barycenter (bc) linear coefficients first (2 for each period).
1061  // Then we can get the maximum expected coefficients.
1062  SpiceInt bcCode = centerBodyCode/100; // Ex: bc code for Jupiter (599) & its moons is 5
1063  naifKeyword = "BODY" + toString(bcCode) + "_NUT_PREC_ANGLES" ;
1064  dtpool_c(naifKeyword.toLatin1().data(), &found, &numExpected, &naifType);
1065  std::vector<double>npAngles(numExpected, 0.);
1066  bodvcd_c(bcCode, "NUT_PREC_ANGLES", numExpected, &numReturned, &npAngles[0]);
1067  numExpected /= 2.;
1068  m_raNutPrec.resize(numExpected, 0.);
1069  m_decNutPrec.resize(numExpected, 0.);
1070  m_pmNutPrec.resize(numExpected, 0.);
1071 
1072  std::vector<SpiceDouble> angles(numExpected);
1073  bodvcd_c(centerBodyCode, "NUT_PREC_RA", numExpected, &numReturned, &m_raNutPrec[0]);
1074  bodvcd_c(centerBodyCode, "NUT_PREC_DEC", numExpected, &numReturned, &m_decNutPrec[0]);
1075  bodvcd_c(centerBodyCode, "NUT_PREC_PM", numExpected, &numReturned, &m_pmNutPrec[0]);
1076 
1077  // Finally get the system linear terms separated into vectors of the constants and the
1078  // linear coefficients
1079 
1080  for (int i = 0; i < numExpected; i++) {
1081  m_sysNutPrec0.push_back(Angle(npAngles[i*2], Angle::Degrees));
1082  m_sysNutPrec1.push_back(Angle(npAngles[i*2+1], Angle::Degrees));
1083  }
1084  } // barycenter terms
1085  } // PCK constants available
1086  } // Relative to J2000
1087  else {
1089  }
1090  } // PCK
1091 
1093  }
1094 
1095 
1105 
1106  // First clear existing cached data
1107  m_raPole.clear();
1108  m_decPole.clear();
1109  m_pm.clear();
1110  m_raNutPrec.clear();
1111  m_decNutPrec.clear();
1112  m_sysNutPrec0.clear();
1113  m_sysNutPrec1.clear();
1114  int numLoaded = 0;
1115 
1116  // Load the PCK coeffcients if they are on the label
1117  if (label.hasKeyword("PoleRa")) {
1118  PvlKeyword labelCoeffs = label["PoleRa"];
1119  for (int i = 0; i < labelCoeffs.size(); i++){
1120  m_raPole.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees));
1121  }
1122  numLoaded += 1;
1123  }
1124  if (label.hasKeyword("PoleDec")) {
1125  PvlKeyword labelCoeffs = label["PoleDec"];
1126  for (int i = 0; i < labelCoeffs.size(); i++){
1127  m_decPole.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees));
1128  }
1129  numLoaded += 1;
1130  }
1131  if (label.hasKeyword("PrimeMeridian")) {
1132  PvlKeyword labelCoeffs = label["PrimeMeridian"];
1133  for (int i = 0; i < labelCoeffs.size(); i++){
1134  m_pm.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees));
1135  }
1136  numLoaded += 1;
1137  }
1138  if (numLoaded > 2) m_tOrientationAvailable = true;
1139 
1140  if (label.hasKeyword("PoleRaNutPrec")) {
1141  PvlKeyword labelCoeffs = label["PoleRaNutPrec"];
1142  for (int i = 0; i < labelCoeffs.size(); i++){
1143  m_raNutPrec.push_back(toDouble(labelCoeffs[i]));
1144  }
1145  }
1146  if (label.hasKeyword("PoleDecNutPrec")) {
1147  PvlKeyword labelCoeffs = label["PoleDecNutPrec"];
1148  for (int i = 0; i < labelCoeffs.size(); i++){
1149  m_decNutPrec.push_back(toDouble(labelCoeffs[i]));
1150  }
1151  }
1152  if (label.hasKeyword("PmNutPrec")) {
1153  PvlKeyword labelCoeffs = label["PmNutPrec"];
1154  for (int i = 0; i < labelCoeffs.size(); i++){
1155  m_pmNutPrec.push_back(toDouble(labelCoeffs[i]));
1156  }
1157  }
1158  if (label.hasKeyword("SysNutPrec0")) {
1159  PvlKeyword labelCoeffs = label["SysNutPrec0"];
1160  for (int i = 0; i < labelCoeffs.size(); i++){
1161  m_sysNutPrec0.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees));
1162  }
1163  }
1164  if (label.hasKeyword("SysNutPrec1")) {
1165  PvlKeyword labelCoeffs = label["SysNutPrec1"];
1166  for (int i = 0; i < labelCoeffs.size(); i++){
1167  m_sysNutPrec1.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees));
1168  }
1169  }
1170 
1172  }
1173 
1174 
1184  // Load the constant and time-based frame traces and the constant rotation
1185  // into the table as labels
1186  if (p_timeFrames.size() > 1) {
1187  table.Label() += PvlKeyword("TimeDependentFrames");
1188 
1189  for (int i = 0; i < (int) p_timeFrames.size(); i++) {
1190  table.Label()["TimeDependentFrames"].addValue(toString(p_timeFrames[i]));
1191  }
1192  }
1193 
1194  if (p_constantFrames.size() > 1) {
1195  table.Label() += PvlKeyword("ConstantFrames");
1196 
1197  for (int i = 0; i < (int) p_constantFrames.size(); i++) {
1198  table.Label()["ConstantFrames"].addValue(toString(p_constantFrames[i]));
1199  }
1200 
1201  table.Label() += PvlKeyword("ConstantRotation");
1202 
1203  for (int i = 0; i < (int) p_TC.size(); i++) {
1204  table.Label()["ConstantRotation"].addValue(toString(p_TC[i]));
1205  }
1206  }
1207 
1208  // Write original time coverage
1209  if (p_fullCacheStartTime != 0) {
1210  table.Label() += PvlKeyword("CkTableStartTime");
1211  table.Label()["CkTableStartTime"].addValue(toString(p_fullCacheStartTime));
1212  }
1213  if (p_fullCacheEndTime != 0) {
1214  table.Label() += PvlKeyword("CkTableEndTime");
1215  table.Label()["CkTableEndTime"].addValue(toString(p_fullCacheEndTime));
1216  }
1217  if (p_fullCacheSize != 0) {
1218  table.Label() += PvlKeyword("CkTableOriginalSize");
1219  table.Label()["CkTableOriginalSize"].addValue(toString(p_fullCacheSize));
1220  }
1221 
1222  // Begin section added 06-20-2015 DAC
1223  table.Label() += PvlKeyword("FrameTypeCode");
1224  table.Label()["FrameTypeCode"].addValue(toString(m_frameType));
1225 
1226  if (m_frameType == PCK) {
1227  // Write out all the body orientation constants
1228  // Pole right ascension coefficients for a quadratic equation
1229  table.Label() += PvlKeyword("PoleRa");
1230 
1231  for (int i = 0; i < (int) m_raPole.size(); i++) {
1232  table.Label()["PoleRa"].addValue(toString(m_raPole[i].degrees()));
1233  }
1234 
1235  // Pole right ascension, declination coefficients for a quadratic equation
1236  table.Label() += PvlKeyword("PoleDec");
1237  for (int i = 0; i < (int) m_decPole.size(); i++) {
1238  table.Label()["PoleDec"].addValue(toString(m_decPole[i].degrees()));
1239  }
1240 
1241  // Prime meridian coefficients for a quadratic equation
1242  table.Label() += PvlKeyword("PrimeMeridian");
1243  for (int i = 0; i < (int) m_pm.size(); i++) {
1244  table.Label()["PrimeMeridian"].addValue(toString(m_pm[i].degrees()));
1245  }
1246 
1247  if (m_raNutPrec.size() > 0) {
1248  // Pole right ascension nutation precision coefficients to the trig terms
1249  table.Label() += PvlKeyword("PoleRaNutPrec");
1250  for (int i = 0; i < (int) m_raNutPrec.size(); i++) {
1251  table.Label()["PoleRaNutPrec"].addValue(toString(m_raNutPrec[i]));
1252  }
1253 
1254  // Pole declination nutation precision coefficients to the trig terms
1255  table.Label() += PvlKeyword("PoleDecNutPrec");
1256  for (int i = 0; i < (int) m_decNutPrec.size(); i++) {
1257  table.Label()["PoleDecNutPrec"].addValue(toString(m_decNutPrec[i]));
1258  }
1259 
1260  // Prime meridian nutation precision coefficients to the trig terms
1261  table.Label() += PvlKeyword("PmNutPrec");
1262  for (int i = 0; i < (int) m_pmNutPrec.size(); i++) {
1263  table.Label()["PmNutPrec"].addValue(toString(m_pmNutPrec[i]));
1264  }
1265 
1266  // System nutation precision constant terms of linear model of periods
1267  table.Label() += PvlKeyword("SysNutPrec0");
1268  for (int i = 0; i < (int) m_sysNutPrec0.size(); i++) {
1269  table.Label()["SysNutPrec0"].addValue(toString(m_sysNutPrec0[i].degrees()));
1270  }
1271 
1272  // System nutation precision linear terms of linear model of periods
1273  table.Label() += PvlKeyword("SysNutPrec1");
1274  for (int i = 0; i < (int) m_sysNutPrec1.size(); i++) {
1275  table.Label()["SysNutPrec1"].addValue(toString(m_sysNutPrec1[i].degrees()));
1276  }
1277  }
1278  }
1279  // End section added 06-20-2015 DAC
1280 
1282  }
1283 
1284 
1290  std::vector<double> SpiceRotation::GetCenterAngles() {
1291  // Compute the center time
1292  double etCenter = (p_fullCacheEndTime + p_fullCacheStartTime) / 2.;
1293  SetEphemerisTime(etCenter);
1294 
1295  return Angles(p_axis3, p_axis2, p_axis1);
1296  }
1297 
1298 
1309  std::vector<double> SpiceRotation::Angles(int axis3, int axis2, int axis1) {
1311 
1312  SpiceDouble ang1, ang2, ang3;
1313  m2eul_c((SpiceDouble *) &p_CJ[0], axis3, axis2, axis1, &ang3, &ang2, &ang1);
1314 
1315  std::vector<double> angles;
1316  angles.push_back(ang1);
1317  angles.push_back(ang2);
1318  angles.push_back(ang3);
1319 
1321  return angles;
1322  }
1323 
1324 
1325 
1336  void SpiceRotation::SetAngles(std::vector<double> angles, int axis3, int axis2, int axis1) {
1337  eul2m_c(angles[2], angles[1], angles[0], axis3, axis2, axis1, (SpiceDouble (*)[3]) &(p_CJ[0]));
1338 
1339  if (m_orientation) {
1340  delete m_orientation;
1341  m_orientation = NULL;
1342  }
1343  std::vector<ale::Rotation> rotationCache;
1344  rotationCache.push_back(ale::Rotation(p_CJ));
1345  if (p_TC.size() > 1) {
1346  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, std::vector<ale::Vec3d>(),
1347  ale::Rotation(p_TC), p_constantFrames, p_timeFrames);
1348  }
1349  else {
1350  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, std::vector<ale::Vec3d>(),
1351  ale::Rotation(1,0,0,0), p_constantFrames, p_timeFrames);
1352  }
1353 
1354  // Reset to get the new values
1355  p_et = -DBL_MAX;
1357  }
1358 
1359 
1365  std::vector<double> SpiceRotation::AngularVelocity() {
1366  return p_av;
1367  }
1368 
1369 
1377  return p_constantFrames;
1378  }
1379 
1380 
1386  std::vector<int> SpiceRotation::TimeFrameChain() {
1387  return p_timeFrames;
1388  }
1389 
1390 
1397  return p_hasAngularVelocity;
1398  }
1399 
1400 
1408  std::vector<double> SpiceRotation::J2000Vector(const std::vector<double> &rVec) {
1410 
1411  std::vector<double> jVec;
1412  if (rVec.size() == 3) {
1413  double TJ[3][3];
1414  mxm_c((SpiceDouble *) &p_TC[0], (SpiceDouble *) &p_CJ[0], TJ);
1415  jVec.resize(3);
1416  mtxv_c(TJ, (SpiceDouble *) &rVec[0], (SpiceDouble *) &jVec[0]);
1417  }
1418 
1419  else if (rVec.size() == 6) {
1420  // See Naif routine frmchg for the format of the state matrix. The constant rotation, TC,
1421  // has a derivative with respect to time of I.
1422  if (!p_hasAngularVelocity) {
1423  // throw an error
1424  }
1425  std::vector<double> stateTJ(36);
1426  stateTJ = StateTJ();
1427 
1428  // Now invert (inverse of a state matrix is NOT simply the transpose)
1429  xpose6_c(&stateTJ[0], (SpiceDouble( *) [6]) &stateTJ[0]);
1430  double stateJT[6][6];
1431  invstm_((doublereal *) &stateTJ[0], (doublereal *) stateJT);
1432  xpose6_c(stateJT, stateJT);
1433  jVec.resize(6);
1434 
1435  mxvg_c(stateJT, (SpiceDouble *) &rVec[0], 6, 6, (SpiceDouble *) &jVec[0]);
1436  }
1438  return (jVec);
1439  }
1440 
1441 
1457  std::vector<Angle> SpiceRotation::poleRaCoefs() {
1458  return m_raPole;
1459  }
1460 
1461 
1477  std::vector<Angle> SpiceRotation::poleDecCoefs() {
1478  return m_decPole;
1479  }
1480 
1481 
1496  std::vector<Angle> SpiceRotation::pmCoefs() {
1497  return m_pm;
1498  }
1499 
1500 
1514  std::vector<double> SpiceRotation::poleRaNutPrecCoefs() {
1515  return m_raNutPrec;
1516  }
1517 
1518 
1531  std::vector<double> SpiceRotation::poleDecNutPrecCoefs() {
1532  return m_decNutPrec;
1533  }
1534 
1535 
1548  std::vector<double> SpiceRotation::pmNutPrecCoefs() {
1549  return m_pmNutPrec;
1550  }
1551 
1552 
1565  std::vector<Angle> SpiceRotation::sysNutPrecConstants() {
1566  return m_sysNutPrec0;
1567  }
1568 
1569 
1583  std::vector<Angle> SpiceRotation::sysNutPrecCoefs() {
1584  return m_sysNutPrec1;
1585  }
1586 
1587 
1607  std::vector<double> SpiceRotation::toJ2000Partial(const std::vector<double> &lookT,
1608  SpiceRotation::PartialType partialVar,
1609  int coeffIndex) {
1611 
1612  std::vector<double> jVec;
1613 
1614  // Get the rotation angles and form the derivative matrix for the partialVar
1615  std::vector<double> angles = Angles(p_axis3, p_axis2, p_axis1);
1616  int angleIndex = partialVar;
1617  int axes[3] = {p_axis1, p_axis2, p_axis3};
1618 
1619  double angle = angles.at(angleIndex);
1620 
1621  // Get TJ and apply the transpose to the input vector to get it to J2000
1622  double dmatrix[3][3];
1623  drotat_(&angle, (integer *) axes + angleIndex, (doublereal *) dmatrix);
1624  // Transpose to obtain row-major order
1625  xpose_c(dmatrix, dmatrix);
1626 
1627  // Get the derivative of the polynomial with respect to partialVar
1628  double dpoly = 0.;
1629  QString msg;
1630  switch (m_frameType) {
1631  case CK:
1632  case DYN:
1633  dpoly = DPolynomial(coeffIndex);
1634  break;
1635  case PCK:
1636  dpoly = DPckPolynomial(partialVar, coeffIndex);
1637  break;
1638  case BPC:
1639  msg = "Body rotation uses a binary PCK. Solutions for this model are not supported";
1640  throw IException(IException::User, msg, _FILEINFO_);
1641  break;
1642  case NOTJ2000PCK:
1643  msg = "Body rotation uses a PCK not referenced to J2000. "
1644  "Solutions for this model are not supported";
1645  throw IException(IException::User, msg, _FILEINFO_);
1646  break;
1647  default:
1648  msg = "Solutions are not supported for this frame type.";
1649  throw IException(IException::User, msg, _FILEINFO_);
1650  }
1651 
1652  // Multiply dpoly to complete dmatrix
1653  for (int row = 0; row < 3; row++) {
1654  for (int col = 0; col < 3; col++) {
1655  dmatrix[row][col] *= dpoly;
1656  }
1657  }
1658 
1659  // Apply the other 2 angles and chain them all together to get J2000 to constant frame
1660  double dCJ[3][3];
1661  switch (angleIndex) {
1662  case 0:
1663  rotmat_c(dmatrix, angles[1], axes[1], dCJ);
1664  rotmat_c(dCJ, angles[2], axes[2], dCJ);
1665  break;
1666  case 1:
1667  rotate_c(angles[0], axes[0], dCJ);
1668  mxm_c(dmatrix, dCJ, dCJ);
1669  rotmat_c(dCJ, angles[2], axes[2], dCJ);
1670  break;
1671  case 2:
1672  rotate_c(angles[0], axes[0], dCJ);
1673  rotmat_c(dCJ, angles[1], axes[1], dCJ);
1674  mxm_c(dmatrix, dCJ, dCJ);
1675  break;
1676  }
1677 
1678  // Multiply the constant matrix to rotate to target reference frame
1679  double dTJ[3][3];
1680  mxm_c((SpiceDouble *) &p_TC[0], dCJ[0], dTJ);
1681 
1682  // Finally rotate the target vector with the transpose of the
1683  // derivative matrix, dTJ to get a J2000 vector
1684  std::vector<double> lookdJ(3);
1685 
1686  mtxv_c(dTJ, (const SpiceDouble *) &lookT[0], (SpiceDouble *) &lookdJ[0]);
1687 
1689  return (lookdJ);
1690  }
1691 
1692 
1700  std::vector<double> SpiceRotation::ReferenceVector(const std::vector<double> &jVec) {
1702 
1703  std::vector<double> rVec(3);
1704 
1705  if (jVec.size() == 3) {
1706  double TJ[3][3];
1707  mxm_c((SpiceDouble *) &p_TC[0], (SpiceDouble *) &p_CJ[0], TJ);
1708  rVec.resize(3);
1709  mxv_c(TJ, (SpiceDouble *) &jVec[0], (SpiceDouble *) &rVec[0]);
1710  }
1711  else if (jVec.size() == 6) {
1712  // See Naif routine frmchg for the format of the state matrix. The constant rotation, TC,
1713  // has a derivative with respect to time of I.
1714  if (!p_hasAngularVelocity) {
1715  // throw an error
1716  }
1717  std::vector<double> stateTJ(36);
1718  stateTJ = StateTJ();
1719  rVec.resize(6);
1720  mxvg_c((SpiceDouble *) &stateTJ[0], (SpiceDouble *) &jVec[0], 6, 6, (SpiceDouble *) &rVec[0]);
1721  }
1722 
1724  return (rVec);
1725  }
1726 
1727 
1741  std::vector<double> coeffAng1, coeffAng2, coeffAng3;
1742 
1743  // Rotation is already stored as a polynomial -- throw an error
1744  if (p_source == PolyFunction) {
1745  // Nothing to do
1746  return;
1747 // QString msg = "Rotation already fit to a polynomial -- spiceint first to refit";
1748 // throw IException(IException::User,msg,_FILEINFO_);
1749  }
1750 
1751  // Adjust degree of polynomial on available data
1752  int size = m_orientation->getRotations().size();
1753  if (size == 1) {
1754  p_degree = 0;
1755  }
1756  else if (size == 2) {
1757  p_degree = 1;
1758  }
1759 
1760  //Check for polynomial over original pointing constant and initialize coefficients
1761  if (type == PolyFunctionOverSpice) {
1762  coeffAng1.assign(p_degree + 1, 0.);
1763  coeffAng2.assign(p_degree + 1, 0.);
1764  coeffAng3.assign(p_degree + 1, 0.);
1765  SetPolynomial(coeffAng1, coeffAng2, coeffAng3, type);
1766  return;
1767  }
1768 
1772 
1773  LeastSquares *fitAng1 = new LeastSquares(function1);
1774  LeastSquares *fitAng2 = new LeastSquares(function2);
1775  LeastSquares *fitAng3 = new LeastSquares(function3);
1776 
1777  // Compute the base time
1778  ComputeBaseTime();
1779  std::vector<double> time;
1780 
1781  if (size == 1) {
1782  double t = p_cacheTime.at(0);
1783  SetEphemerisTime(t);
1784  std::vector<double> angles = Angles(p_axis3, p_axis2, p_axis1);
1785  coeffAng1.push_back(angles[0]);
1786  coeffAng2.push_back(angles[1]);
1787  coeffAng3.push_back(angles[2]);
1788  }
1789  else if (size == 2) {
1790  // Load the times and get the corresponding rotation angles
1791  p_degree = 1;
1792  double t1 = p_cacheTime.at(0);
1793  SetEphemerisTime(t1);
1794  t1 -= p_baseTime;
1795  t1 = t1 / p_timeScale;
1796  std::vector<double> angles1 = Angles(p_axis3, p_axis2, p_axis1);
1797  double t2 = p_cacheTime.at(1);
1798  SetEphemerisTime(t2);
1799  t2 -= p_baseTime;
1800  t2 = t2 / p_timeScale;
1801  std::vector<double> angles2 = Angles(p_axis3, p_axis2, p_axis1);
1802  angles2[0] = WrapAngle(angles1[0], angles2[0]);
1803  angles2[2] = WrapAngle(angles1[2], angles2[2]);
1804  double slope[3];
1805  double intercept[3];
1806 
1807 // Compute the linear equation for each angle and save them
1808  for (int angleIndex = 0; angleIndex < 3; angleIndex++) {
1809  Isis::LineEquation angline(t1, angles1[angleIndex], t2, angles2[angleIndex]);
1810  slope[angleIndex] = angline.Slope();
1811  intercept[angleIndex] = angline.Intercept();
1812  }
1813  coeffAng1.push_back(intercept[0]);
1814  coeffAng1.push_back(slope[0]);
1815  coeffAng2.push_back(intercept[1]);
1816  coeffAng2.push_back(slope[1]);
1817  coeffAng3.push_back(intercept[2]);
1818  coeffAng3.push_back(slope[2]);
1819  }
1820  else {
1821  // Load the known values to compute the fit equation
1822  double start1 = 0.; // value of 1st angle1 in cache
1823  double start3 = 0.; // value of 1st angle1 in cache
1824 
1825  for (std::vector<double>::size_type pos = 0; pos < p_cacheTime.size(); pos++) {
1826  double t = p_cacheTime.at(pos);
1827  time.push_back((t - p_baseTime) / p_timeScale);
1828  SetEphemerisTime(t);
1829  std::vector<double> angles = Angles(p_axis3, p_axis2, p_axis1);
1830 
1831 // Fix 180/-180 crossovers on angles 1 and 3 before doing fit.
1832  if (pos == 0) {
1833  start1 = angles[0];
1834  start3 = angles[2];
1835  }
1836  else {
1837  angles[0] = WrapAngle(start1, angles[0]);
1838  angles[2] = WrapAngle(start3, angles[2]);
1839  }
1840 
1841  fitAng1->AddKnown(time, angles[0]);
1842  fitAng2->AddKnown(time, angles[1]);
1843  fitAng3->AddKnown(time, angles[2]);
1844  time.clear();
1845 
1846  }
1847  //Solve the equations for the coefficients
1848  fitAng1->Solve();
1849  fitAng2->Solve();
1850  fitAng3->Solve();
1851 
1852  // Delete the least squares objects now that we have all the coefficients
1853  delete fitAng1;
1854  delete fitAng2;
1855  delete fitAng3;
1856 
1857  // For now assume all three angles are fit to a polynomial. Later they may
1858  // each be fit to a unique basis function.
1859  // Fill the coefficient vectors
1860 
1861  for (int i = 0; i < function1.Coefficients(); i++) {
1862  coeffAng1.push_back(function1.Coefficient(i));
1863  coeffAng2.push_back(function2.Coefficient(i));
1864  coeffAng3.push_back(function3.Coefficient(i));
1865  }
1866 
1867  }
1868 
1869  // Now that the coefficients have been calculated set the polynomial with them
1870  SetPolynomial(coeffAng1, coeffAng2, coeffAng3);
1871 
1873  return;
1874  }
1875 
1876 
1891  void SpiceRotation::SetPolynomial(const std::vector<double> &coeffAng1,
1892  const std::vector<double> &coeffAng2,
1893  const std::vector<double> &coeffAng3,
1894  const Source type) {
1895 
1900 
1901  // Load the functions with the coefficients
1902  function1.SetCoefficients(coeffAng1);
1903  function2.SetCoefficients(coeffAng2);
1904  function3.SetCoefficients(coeffAng3);
1905 
1906  // Compute the base time
1907  ComputeBaseTime();
1908 
1909  // Save the current coefficients
1910  p_coefficients[0] = coeffAng1;
1911  p_coefficients[1] = coeffAng2;
1912  p_coefficients[2] = coeffAng3;
1913 
1914  // Set the flag indicating p_degree has been applied to the camera angles, the
1915  // coefficients of the polynomials have been saved, and the cache reloaded from
1916  // the polynomials
1917  p_degreeApplied = true;
1918  // p_source = PolyFunction;
1919  p_source = type;
1920 
1921  // Update the current rotation
1922  double et = p_et;
1923  p_et = -DBL_MAX;
1924  SetEphemerisTime(et);
1925 
1927  return;
1928  }
1929 
1930 
1949 
1950  // Check to see if rotation is already stored as a polynomial
1951  if (p_source == PckPolyFunction) {
1952  p_hasAngularVelocity = true;
1953  return;
1954  }
1955 
1956  // No target body orientation information available -- throw an error
1957  if (!m_tOrientationAvailable) {
1958  QString msg = "Target body orientation information not available. Rerun spiceinit.";
1959  throw IException(IException::User, msg, _FILEINFO_);
1960  }
1961 
1962  /* I think we have nothing to do, but check for available coefficients and set the Source
1963  // Set the scales
1964  p_dscale = 0.000011574074074; // seconds to days conversion
1965  p_tscale = 3.1688087814029D-10; // seconds to Julian centuries conversion
1966  //Set the quadratic part of the equations
1967  //TODO consider just hard coding this part in evaluate
1968  Isis::PolynomialUnivariate functionRa(p_degree); // Basis function fit to target body pole ra
1969  Isis::PolynomialUnivariate functionDec(p_degree); // Basis function fit to target body pole dec
1970  Isis::PolynomialUnivariate functionPm(p_degree); // Basis function fit to target body pm
1971 
1972  // Load the functions with the coefficients
1973  function1.SetCoefficients(p_raPole);
1974  function2.SetCoefficients(p_decPole);
1975  function3.SetCoefficients(p_pm);
1976 
1977  int numNutPrec = p_sysNutPrec0.size;
1978  if (numNutPrec > 0) {
1979  // Set the trigonometric part of the equation
1980  Isis::TrigBasis functionRaNutPrec("raNutPrec", Isis::TrigBasis::Sin, numNutPrec);
1981  Isis::TrigBasis functionRaNutPrec("decNutPrec", Isis::TrigBasis::Cos, numNutPrec);
1982  Isis::TrigBasis functionRaNutPrec("pmNutPrec", Isis::TrigBasis::Sin, numNutPrec);
1983  // Load the functions with the coefficients
1984  functionRaNutPrec.SetTCoefficients(p_raNutPrec);
1985  functionDecNutPrec.SetTCoefficients(p_decNutPrec);
1986  functionPmNutPrec.SetTCoefficients(p_pmNutPrec);
1987  functionRaNutPrec.SetConstants(p_sysNutPrec0);
1988  functionDecNutPrec.SetConstants(p_sysNutPrec0);
1989  functionPmNutPrec.SetConstants(p_sysNutPrec0);
1990  functionRaNutPrec.SetLCoefficients(p_sysNutPrec1);
1991  functionDecNutPrec.SetLCoefficients(p_sysNutPrec1);
1992  functionPmNutPrec.SetLCoefficients(p_sysNutPrec1);
1993  }
1994  */
1995 
1996  // Set the flag indicating p_degree has been applied to the planet angles, the
1997  // coefficients of the polynomials have been saved, and the cache reloaded from
1998  // TODO cache reloaded???
1999  // the polynomials.
2000  // ****At least for the planet angles, I don't think we want to reload the cache until just
2001  // before we write out the table
2002  p_degreeApplied = true;
2003  p_hasAngularVelocity = true;
2005  return;
2006  }
2007 
2008 
2028  void SpiceRotation::setPckPolynomial(const std::vector<Angle> &raCoeff,
2029  const std::vector<Angle> &decCoeff,
2030  const std::vector<Angle> &pmCoeff) {
2031  // Just set the constants and let usePckPolynomial() do the rest
2032  m_raPole = raCoeff;
2033  m_decPole = decCoeff;
2034  m_pm = pmCoeff;
2035  usePckPolynomial();
2036  // Apply new function parameters
2038  }
2039 
2040 
2051  void SpiceRotation::GetPolynomial(std::vector<double> &coeffAng1,
2052  std::vector<double> &coeffAng2,
2053  std::vector<double> &coeffAng3) {
2054  coeffAng1 = p_coefficients[0];
2055  coeffAng2 = p_coefficients[1];
2056  coeffAng3 = p_coefficients[2];
2057 
2058  return;
2059  }
2060 
2061 
2073  void SpiceRotation::getPckPolynomial(std::vector<Angle> &raCoeff,
2074  std::vector<Angle> &decCoeff,
2075  std::vector<Angle> &pmCoeff) {
2076  raCoeff = m_raPole;
2077  decCoeff = m_decPole;
2078  pmCoeff = m_pm;
2079 
2080  return;
2081  }
2082 
2083 
2088  if (p_noOverride) {
2089  p_baseTime = (p_cacheTime.at(0) + p_cacheTime.at(p_cacheTime.size() - 1)) / 2.;
2091  // Take care of case where 1st and last times are the same
2092  if (p_timeScale == 0) p_timeScale = 1.0;
2093  }
2094  else {
2097  }
2098 
2099  return;
2100  }
2101 
2102 
2110  void SpiceRotation::SetOverrideBaseTime(double baseTime, double timeScale) {
2111  p_overrideBaseTime = baseTime;
2112  p_overrideTimeScale = timeScale;
2113  p_noOverride = false;
2114  return;
2115  }
2116 
2117  void SpiceRotation::SetCacheTime(std::vector<double> cacheTime) {
2118  // Do not reset the cache times if they are already loaded.
2119  if (p_cacheTime.size() <= 0) {
2120  p_cacheTime = cacheTime;
2121  }
2122  }
2123 
2137  double SpiceRotation::DPolynomial(const int coeffIndex) {
2138  double derivative;
2139  double time = (p_et - p_baseTime) / p_timeScale;
2140 
2141  if (coeffIndex > 0 && coeffIndex <= p_degree) {
2142  derivative = pow(time, coeffIndex);
2143  }
2144  else if (coeffIndex == 0) {
2145  derivative = 1;
2146  }
2147  else {
2148  QString msg = "Unable to evaluate the derivative of the SPICE rotation fit polynomial for "
2149  "the given coefficient index [" + toString(coeffIndex) + "]. "
2150  "Index is negative or exceeds degree of polynomial ["
2151  + toString(p_degree) + "]";
2152  throw IException(IException::Programmer, msg, _FILEINFO_);
2153  }
2154  return derivative;
2155  }
2156 
2157 
2173  const int coeffIndex) {
2174  const double p_dayScale = 86400; // number of seconds in a day
2175  // Number of 24 hour days in a Julian century = 36525
2176  const double p_centScale = p_dayScale * 36525;
2177  double time = 0.;
2178 
2179  switch (partialVar) {
2180  case WRT_RightAscension:
2181  case WRT_Declination:
2182  time = p_et / p_centScale;
2183  break;
2184  case WRT_Twist:
2185  time = p_et / p_dayScale;
2186  break;
2187  }
2188 
2189  double derivative;
2190 
2191  switch (coeffIndex) {
2192  case 0:
2193  derivative = 1;
2194  break;
2195  case 1:
2196  case 2:
2197  derivative = pow(time, coeffIndex);
2198  break;
2199  default:
2200  QString msg = "Unable to evaluate the derivative of the target body rotation fit polynomial "
2201  "for the given coefficient index [" + toString(coeffIndex) + "]. "
2202  "Index is negative or exceeds degree of polynomial ["
2203  + toString(p_degree) + "]";
2204  throw IException(IException::Programmer, msg, _FILEINFO_);
2205  }
2206 
2207  // Now apply any difference to the partials due to building the rotation matrix on the angles
2208  // 90. + ra, 90. - dec, and pm. The only partial that changes is dec.
2209  if (partialVar == WRT_Declination) {
2210  derivative = -derivative;
2211  }
2212 
2213  return derivative;
2214  }
2215 
2216 
2232  std::vector<double> SpiceRotation::ToReferencePartial(std::vector<double> &lookJ,
2233  SpiceRotation::PartialType partialVar,
2234  int coeffIndex) {
2236  //TODO** To save time possibly save partial matrices
2237 
2238  // Get the rotation angles and form the derivative matrix for the partialVar
2239  std::vector<double> angles = Angles(p_axis3, p_axis2, p_axis1);
2240  int angleIndex = partialVar;
2241  int axes[3] = {p_axis1, p_axis2, p_axis3};
2242 
2243  double angle = angles.at(angleIndex);
2244 
2245  double dmatrix[3][3];
2246  drotat_(&angle, (integer *) axes + angleIndex, (doublereal *) dmatrix);
2247  // Transpose to obtain row-major order
2248  xpose_c(dmatrix, dmatrix);
2249 
2250  // Get the derivative of the polynomial with respect to partialVar
2251  double dpoly = 0.;
2252  switch (m_frameType) {
2253  case UNKNOWN: // For now let everything go through for backward compatability
2254  case CK:
2255  case DYN:
2256  dpoly = DPolynomial(coeffIndex);
2257  break;
2258  case PCK:
2259  dpoly = DPckPolynomial(partialVar, coeffIndex);
2260  break;
2261  default:
2262  QString msg = "Only CK, DYN, and PCK partials can be calculated";
2263  throw IException(IException::Programmer, msg, _FILEINFO_);
2264  }
2265 
2266  // Multiply dpoly to complete dmatrix
2267  for (int row = 0; row < 3; row++) {
2268  for (int col = 0; col < 3; col++) {
2269  dmatrix[row][col] *= dpoly;
2270  }
2271  }
2272 
2273  // Apply the other 2 angles and chain them all together
2274  double dCJ[3][3];
2275  switch (angleIndex) {
2276  case 0:
2277  rotmat_c(dmatrix, angles[1], axes[1], dCJ);
2278  rotmat_c(dCJ, angles[2], axes[2], dCJ);
2279  break;
2280  case 1:
2281  rotate_c(angles[0], axes[0], dCJ);
2282  mxm_c(dmatrix, dCJ, dCJ);
2283  rotmat_c(dCJ, angles[2], axes[2], dCJ);
2284  break;
2285  case 2:
2286  rotate_c(angles[0], axes[0], dCJ);
2287  rotmat_c(dCJ, angles[1], axes[1], dCJ);
2288  mxm_c(dmatrix, dCJ, dCJ);
2289  break;
2290  }
2291 
2292  // Multiply the constant matrix to rotate to the targeted reference frame
2293  double dTJ[3][3];
2294  mxm_c((SpiceDouble *) &p_TC[0], dCJ[0], dTJ);
2295 
2296  // Finally rotate the J2000 vector with the derivative matrix, dTJ to
2297  // get the vector in the targeted reference frame.
2298  std::vector<double> lookdT(3);
2299 
2300  mxv_c(dTJ, (const SpiceDouble *) &lookJ[0], (SpiceDouble *) &lookdT[0]);
2301 
2303  return lookdT;
2304  }
2305 
2306 
2315  double SpiceRotation::WrapAngle(double compareAngle, double angle) {
2317  double diff1 = compareAngle - angle;
2318 
2319  if (diff1 < -1 * pi_c()) {
2320  angle -= twopi_c();
2321  }
2322  else if (diff1 > pi_c()) {
2323  angle += twopi_c();
2324  }
2325 
2327  return angle;
2328  }
2329 
2330 
2344  // Adjust the degree for the data
2345  if (p_fullCacheSize == 1) {
2346  degree = 0;
2347  }
2348  else if (p_fullCacheSize == 2) {
2349  degree = 1;
2350  }
2351  // If polynomials have not been applied yet then simply set the degree and return
2352  if (!p_degreeApplied) {
2353  p_degree = degree;
2354  }
2355 
2356  // Otherwise the existing polynomials need to be either expanded ...
2357  else if (p_degree < degree) { // (increase the number of terms)
2358  std::vector<double> coefAngle1(p_coefficients[0]),
2359  coefAngle2(p_coefficients[1]),
2360  coefAngle3(p_coefficients[2]);
2361 
2362  for (int icoef = p_degree + 1; icoef <= degree; icoef++) {
2363  coefAngle1.push_back(0.);
2364  coefAngle2.push_back(0.);
2365  coefAngle3.push_back(0.);
2366  }
2367  p_degree = degree;
2368  SetPolynomial(coefAngle1, coefAngle2, coefAngle3, p_source);
2369  }
2370  // ... or reduced (decrease the number of terms)
2371  else if (p_degree > degree) {
2372  std::vector<double> coefAngle1(degree + 1),
2373  coefAngle2(degree + 1),
2374  coefAngle3(degree + 1);
2375 
2376  for (int icoef = 0; icoef <= degree; icoef++) {
2377  coefAngle1[icoef] = p_coefficients[0][icoef];
2378  coefAngle2[icoef] = p_coefficients[1][icoef];
2379  coefAngle3[icoef] = p_coefficients[2][icoef];
2380  }
2381  p_degree = degree;
2382  SetPolynomial(coefAngle1, coefAngle2, coefAngle3, p_source);
2383  }
2384  }
2385 
2386 
2393  return m_frameType;
2394  }
2395 
2396 
2403  return p_source;
2404  }
2405 
2406 
2413  p_source = source;
2414  return;
2415  }
2416 
2417 
2424  return p_baseTime;
2425  }
2426 
2427 
2434  return p_timeScale;
2435  }
2436 
2437 
2450  void SpiceRotation::SetAxes(int axis1, int axis2, int axis3) {
2451  if (axis1 < 1 || axis2 < 1 || axis3 < 1 || axis1 > 3 || axis2 > 3 || axis3 > 3) {
2452  QString msg = "A rotation axis is outside the valid range of 1 to 3";
2453  throw IException(IException::Programmer, msg, _FILEINFO_);
2454  }
2455  p_axis1 = axis1;
2456  p_axis2 = axis2;
2457  p_axis3 = axis3;
2458  }
2459 
2460 
2474  int count = 0;
2475 
2476  double observStart = p_fullCacheStartTime + p_timeBias;
2477  double observEnd = p_fullCacheEndTime + p_timeBias;
2478  // Next line added 12-03-2009 to allow observations to cross segment boundaries
2479  double currentTime = observStart;
2480  bool timeLoaded = false;
2481 
2482  // Get number of ck loaded for this rotation. This method assumes only one SpiceRotation
2483  // object is loaded.
2485  ktotal_c("ck", (SpiceInt *) &count);
2486 
2487  // Downsize the loaded cache
2488  if ((p_source == Memcache) && p_minimizeCache == Yes) {
2489  // Multiple ck case, type 5 ck case, or PolyFunctionOverSpice
2490  // final step -- downsize loaded cache and reload
2491 
2492  if (p_fullCacheSize != (int) p_cacheTime.size()) {
2493  QString msg =
2494  "Full cache size does NOT match cache size in LoadTimeCache -- should never happen";
2495  throw IException(IException::Programmer, msg, _FILEINFO_);
2496  }
2497 
2498  SpiceDouble timeSclkdp[p_fullCacheSize];
2499  SpiceDouble quats[p_fullCacheSize][4];
2500  double avvs[p_fullCacheSize][3]; // Angular velocity vector
2501 
2502  // We will treat et as the sclock time and avoid converting back and forth
2503  std::vector<ale::Rotation> fullRotationCache = m_orientation->getRotations();
2504  std::vector<ale::Vec3d> angularVelocities = m_orientation->getAngularVelocities();
2505  for (int r = 0; r < p_fullCacheSize; r++) {
2506  timeSclkdp[r] = p_cacheTime[r];
2507  std::vector<double> rotationMatrix = fullRotationCache[r].toRotationMatrix();
2508  SpiceDouble CJ[9] = { rotationMatrix[0], rotationMatrix[1], rotationMatrix[2],
2509  rotationMatrix[3], rotationMatrix[4], rotationMatrix[5],
2510  rotationMatrix[6], rotationMatrix[7], rotationMatrix[8]
2511  };
2512  m2q_c(CJ, quats[r]);
2513  if (p_hasAngularVelocity) {
2514  ale::Vec3d angularVelocity = angularVelocities[r];
2515  vequ_c((SpiceDouble *) &angularVelocity.x, avvs[r]);
2516  }
2517  }
2518 
2519  double cubeStarts = timeSclkdp[0]; //,timsSclkdp[ckBlob.Records()-1] };
2520  double radTol = 0.000000017453; //.000001 degrees Make this instrument dependent TODO
2521  SpiceInt avflag = 1; // Don't use angular velocity for now
2522  SpiceInt nints = 1; // Always make an observation a single interpolation interval
2523  double dparr[p_fullCacheSize]; // Double precision work array
2524  SpiceInt intarr[p_fullCacheSize]; // Integer work array
2525  SpiceInt sizOut = p_fullCacheSize; // Size of downsized cache
2526 
2527  ck3sdn(radTol, avflag, (int *) &sizOut, timeSclkdp, (doublereal *) quats,
2528  (SpiceDouble *) avvs, nints, &cubeStarts, dparr, (int *) intarr);
2529 
2530  // Clear full cache and load with downsized version
2531  p_cacheTime.clear();
2532  std::vector<double> av;
2533  av.resize(3);
2534 
2535  if (m_orientation) {
2536  delete m_orientation;
2537  m_orientation = NULL;
2538  }
2539 
2540  std::vector<ale::Rotation> rotationCache;
2541  std::vector<ale::Vec3d> avCache;
2542 
2543  for (int r = 0; r < sizOut; r++) {
2544  SpiceDouble et;
2545  // sct2e_c(spcode, timeSclkdp[r], &et);
2546  et = timeSclkdp[r];
2547  p_cacheTime.push_back(et);
2548  std::vector<double> CJ(9);
2549  q2m_c(quats[r], (SpiceDouble( *)[3]) &CJ[0]);
2550  rotationCache.push_back(CJ);
2551  vequ_c(avvs[r], (SpiceDouble *) &av[0]);
2552  avCache.push_back(av);
2553  }
2554 
2555  if (p_TC.size() > 1 ) {
2556  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, avCache,
2557  ale::Rotation(p_TC), p_constantFrames, p_timeFrames);
2558  }
2559  else {
2560  m_orientation = new ale::Orientations(rotationCache, p_cacheTime, std::vector<ale::Vec3d>(),
2561  ale::Rotation(1,0,0,0), p_constantFrames, p_timeFrames);
2562  }
2563  timeLoaded = true;
2565  }
2566  else if (count == 1 && p_minimizeCache == Yes) {
2567  // case of a single ck -- read instances and data straight from kernel for given time range
2568  SpiceInt handle;
2569 
2570  // Define some Naif constants
2571  int FILESIZ = 128;
2572  int TYPESIZ = 32;
2573  int SOURCESIZ = 128;
2574 // double DIRSIZ = 100;
2575 
2576  SpiceChar file[FILESIZ];
2577  SpiceChar filtyp[TYPESIZ]; // kernel type (ck, ek, etc.)
2578  SpiceChar source[SOURCESIZ];
2579 
2580  SpiceBoolean found;
2581  bool observationSpansToNextSegment = false;
2582 
2583  double segStartEt;
2584  double segStopEt;
2585 
2586  kdata_c(0, "ck", FILESIZ, TYPESIZ, SOURCESIZ, file, filtyp, source, &handle, &found);
2587  dafbfs_c(handle);
2588  daffna_c(&found);
2589  int spCode = ((int)(p_constantFrames[0] / 1000)) * 1000;
2590 
2591  while (found) {
2592  observationSpansToNextSegment = false;
2593  double sum[10]; // daf segment summary
2594  double dc[2]; // segment starting and ending times in tics
2595  SpiceInt ic[6]; // segment summary values:
2596  // instrument code for platform,
2597  // reference frame code,
2598  // data type,
2599  // velocity flag,
2600  // offset to quat 1,
2601  // offset to end.
2602  dafgs_c(sum);
2603  dafus_c(sum, (SpiceInt) 2, (SpiceInt) 6, dc, ic);
2604 
2605  // Don't read type 5 ck here
2606  if (ic[2] == 5) break;
2607 
2608  // Check times for type 3 ck segment if spacecraft matches
2609  if (ic[0] == spCode && ic[2] == 3) {
2610  sct2e_c((int) spCode / 1000, dc[0], &segStartEt);
2611  sct2e_c((int) spCode / 1000, dc[1], &segStopEt);
2613  double et;
2614 
2615  // Get times for this segment
2616  if (currentTime >= segStartEt && currentTime <= segStopEt) {
2617 
2618  // Check for a gap in the time coverage by making sure the time span of the observation
2619  // does not cross a segment unless the next segment starts where the current one ends
2620  if (observationSpansToNextSegment && currentTime > segStartEt) {
2621  QString msg = "Observation crosses segment boundary--unable to interpolate pointing";
2622  throw IException(IException::Programmer, msg, _FILEINFO_);
2623  }
2624  if (observEnd > segStopEt) {
2625  observationSpansToNextSegment = true;
2626  }
2627 
2628  // Extract necessary header parameters
2629  int dovelocity = ic[3];
2630  int end = ic[5];
2631  double val[2];
2632  dafgda_c(handle, end - 1, end, val);
2633 // int nints = (int) val[0];
2634  int ninstances = (int) val[1];
2635  int numvel = dovelocity * 3;
2636  int quatnoff = ic[4] + (4 + numvel) * ninstances - 1;
2637 // int nrdir = (int) (( ninstances - 1 ) / DIRSIZ); /* sclkdp directory records */
2638  int sclkdp1off = quatnoff + 1;
2639  int sclkdpnoff = sclkdp1off + ninstances - 1;
2640 // int start1off = sclkdpnoff + nrdir + 1;
2641 // int startnoff = start1off + nints - 1;
2642  int sclkSpCode = spCode / 1000;
2643 
2644  // Now get the times
2645  std::vector<double> sclkdp(ninstances);
2646  dafgda_c(handle, sclkdp1off, sclkdpnoff, (SpiceDouble *) &sclkdp[0]);
2647 
2648  int instance = 0;
2649  sct2e_c(sclkSpCode, sclkdp[0], &et);
2650 
2651  while (instance < (ninstances - 1) && et < currentTime) {
2652  instance++;
2653  sct2e_c(sclkSpCode, sclkdp[instance], &et);
2654  }
2655 
2656  if (instance > 0) instance--;
2657  sct2e_c(sclkSpCode, sclkdp[instance], &et);
2658 
2659  while (instance < (ninstances - 1) && et < observEnd) {
2660  p_cacheTime.push_back(et - p_timeBias);
2661  instance++;
2662  sct2e_c(sclkSpCode, sclkdp[instance], &et);
2663  }
2664  p_cacheTime.push_back(et - p_timeBias);
2665 
2666  if (!observationSpansToNextSegment) {
2667  timeLoaded = true;
2669  break;
2670  }
2671  else {
2672  currentTime = segStopEt;
2673  }
2674  }
2675  }
2676  dafcs_c(handle); // Continue search in daf last searched
2677  daffna_c(&found); // Find next forward array in current daf
2678  }
2679  }
2680  else if (count == 0 && p_source != Nadir && p_minimizeCache == Yes) {
2681  QString msg = "No camera kernels loaded...Unable to determine time cache to downsize";
2682  throw IException(IException::User, msg, _FILEINFO_);
2683  }
2684 
2685  // Load times according to cache size (body rotations) -- handle first round of type 5 ck case
2686  // and multiple ck case --Load a time for every line scan line and downsize later
2687  if (! (timeLoaded || (p_cacheTime.size() > 1))) {
2688  double cacheSlope = 0.0;
2689  if (p_fullCacheSize > 1)
2690  cacheSlope = (p_fullCacheEndTime - p_fullCacheStartTime) / (double)(p_fullCacheSize - 1);
2691  for (int i = 0; i < p_fullCacheSize; i++)
2692  p_cacheTime.push_back(p_fullCacheStartTime + (double) i * cacheSlope);
2693  if (p_source == Nadir) {
2694  p_minimizeCache = No;
2695  }
2696  }
2698  }
2699 
2700 
2708  std::vector<double> SpiceRotation::GetFullCacheTime() {
2709 
2710  // No time cache was initialized -- throw an error
2711  if (p_fullCacheSize < 1) {
2712  QString msg = "Time cache not available -- rerun spiceinit";
2713  throw IException(IException::User, msg, _FILEINFO_);
2714  }
2715 
2716  std::vector<double> fullCacheTime;
2717  double cacheSlope = 0.0;
2718  if (p_fullCacheSize > 1) {
2719  cacheSlope = (p_fullCacheEndTime - p_fullCacheStartTime) / (double)(p_fullCacheSize - 1);
2720  }
2721 
2722  for (int i = 0; i < p_fullCacheSize; i++)
2723  fullCacheTime.push_back(p_fullCacheStartTime + (double) i * cacheSlope);
2724 
2725  return fullCacheTime;
2726  }
2727 
2728 
2740  void SpiceRotation::FrameTrace(double et) {
2742  // The code for this method was extracted from the Naif routine rotget written by N.J. Bachman &
2743  // W.L. Taber (JPL)
2744  int center;
2745  FrameType type;
2746  int typid;
2747  SpiceBoolean found;
2748  int frmidx; // Frame chain index for current frame
2749  SpiceInt nextFrame; // Naif frame code of next frame
2751  std::vector<int> frameCodes;
2752  std::vector<int> frameTypes;
2753  frameCodes.push_back(p_constantFrames[0]);
2754 
2755  while (frameCodes[frameCodes.size()-1] != J2000Code) {
2756  frmidx = frameCodes.size() - 1;
2757  // First get the frame type (Note:: we may also need to save center if we use dynamic frames)
2758  // (Another note: the type returned is the Naif from type. This is not quite the same as the
2759  // SpiceRotation enumerated FrameType. The SpiceRotation FrameType differentiates between
2760  // pck types. FrameTypes of 2, 6, and 7 will all be considered to be Naif frame type 2. The
2761  // logic for FrameTypes in this method is correct for all types except type 7. Current pck
2762  // do not exercise this option. Should we ever use pck with a target body not referenced to
2763  // the J2000 frame and epoch, both this method and loadPCFromSpice will need to be modified.
2764  frinfo_c((SpiceInt) frameCodes[frmidx],
2765  (SpiceInt *) &center,
2766  (SpiceInt *) &type,
2767  (SpiceInt *) &typid, &found);
2768 
2769  if (!found) {
2770 
2771  if (p_source == Nadir) {
2772  frameTypes.push_back(0);
2773  break;
2774  }
2775 
2776  QString msg = "The frame" + toString((int) frameCodes[frmidx]) + " is not supported by Naif";
2777  throw IException(IException::Programmer, msg, _FILEINFO_);
2778  }
2779 
2780  double matrix[3][3];
2781 
2782  // To get the next link in the frame chain, use the frame type
2783  if (type == INERTL || type == PCK) {
2784  nextFrame = J2000Code;
2785  }
2786  else if (type == CK) {
2787  ckfrot_((SpiceInt *) &typid, &et, (double *) matrix, &nextFrame, (logical *) &found);
2788 
2789  if (!found) {
2790 
2791  if (p_source == Nadir) {
2792  frameTypes.push_back(0);
2793  break;
2794  }
2795 
2796  QString msg = "The ck rotation from frame " + toString(frameCodes[frmidx]) + " can not "
2797  + "be found due to no pointing available at requested time or a problem with the "
2798  + "frame";
2799  throw IException(IException::Programmer, msg, _FILEINFO_);
2800  }
2801  }
2802  else if (type == TK) {
2803  tkfram_((SpiceInt *) &typid, (double *) matrix, &nextFrame, (logical *) &found);
2804  if (!found) {
2805  QString msg = "The tk rotation from frame " + toString(frameCodes[frmidx]) +
2806  " can not be found";
2807  throw IException(IException::Programmer, msg, _FILEINFO_);
2808  }
2809  }
2810  else if (type == DYN) {
2811  //
2812  // Unlike the other frame classes, the dynamic frame evaluation
2813  // routine ZZDYNROT requires the input frame ID rather than the
2814  // dynamic frame class ID. ZZDYNROT also requires the center ID
2815  // we found via the FRINFO call.
2816 
2817  zzdynrot_((SpiceInt *) &typid, (SpiceInt *) &center, &et, (double *) matrix, &nextFrame);
2818  }
2819 
2820  else {
2821  QString msg = "The frame " + toString(frameCodes[frmidx]) +
2822  " has a type " + toString(type) + " not supported by your version of Naif Spicelib."
2823  + "You need to update.";
2824  throw IException(IException::Programmer, msg, _FILEINFO_);
2825 
2826  }
2827  frameCodes.push_back(nextFrame);
2828  frameTypes.push_back(type);
2829  }
2830 
2831  if ((int) frameCodes.size() == 1 && p_source != Nadir) { // Must be Sky
2832  p_constantFrames.push_back(frameCodes[0]);
2833  p_timeFrames.push_back(frameCodes[0]);
2834  return;
2835  }
2836 
2837  int nConstants = 0;
2838  p_constantFrames.clear();
2839  while (frameTypes[nConstants] == TK && nConstants < (int) frameTypes.size()) nConstants++;
2840 
2841 
2842  for (int i = 0; i <= nConstants; i++) {
2843  p_constantFrames.push_back(frameCodes[i]);
2844  }
2845 
2846  if (p_source != Nadir) {
2847  for (int i = nConstants; i < (int) frameCodes.size(); i++) {
2848  p_timeFrames.push_back(frameCodes[i]);
2849  }
2850  }
2851  else {
2852  // Nadir rotation is from spacecraft to J2000
2853  p_timeFrames.push_back(frameCodes[nConstants]);
2854  p_timeFrames.push_back(J2000Code);
2855  }
2857  }
2858 
2859 
2865  std::vector<double> SpiceRotation::Matrix() {
2867  std::vector<double> TJ;
2868  TJ.resize(9);
2869  mxm_c((SpiceDouble *) &p_TC[0], (SpiceDouble *) &p_CJ[0], (SpiceDouble( *) [3]) &TJ[0]);
2871  return TJ;
2872  }
2873 
2874 
2880  std::vector<double> SpiceRotation::ConstantRotation() {
2882  std::vector<double> q;
2883  q.resize(4);
2884  m2q_c((SpiceDouble( *)[3]) &p_TC[0], &q[0]);
2886  return q;
2887  }
2888 
2889 
2895  std::vector<double> &SpiceRotation::ConstantMatrix() {
2896  return p_TC;
2897  }
2898 
2899 
2905  void SpiceRotation::SetConstantMatrix(std::vector<double> constantMatrix) {
2906  p_TC = constantMatrix;
2907  return;
2908  }
2909 
2915  std::vector<double> SpiceRotation::TimeBasedRotation() {
2917  std::vector<double> q;
2918  q.resize(4);
2919  m2q_c((SpiceDouble( *)[3]) &p_CJ[0], &q[0]);
2921  return q;
2922  }
2923 
2924 
2930  std::vector<double> &SpiceRotation::TimeBasedMatrix() {
2931  return p_CJ;
2932  }
2933 
2934 
2940  void SpiceRotation::SetTimeBasedMatrix(std::vector<double> timeBasedMatrix) {
2941  p_CJ = timeBasedMatrix;
2942  return;
2943  }
2944 
2945 
2952  FrameTrace(et);
2953  // Get constant rotation which applies in all cases
2954  int targetFrame = p_constantFrames[0];
2955  int fromFrame = p_timeFrames[0];
2956  p_TC.resize(9);
2957  refchg_((SpiceInt *) &fromFrame, (SpiceInt *) &targetFrame, &et, (doublereal *) &p_TC[0]);
2958  // Transpose to obtain row-major order
2959  xpose_c((SpiceDouble( *)[3]) &p_TC[0], (SpiceDouble( *)[3]) &p_TC[0]);
2960  }
2961 
2962 
2984 
2985  // Make sure the angles have been fit to polynomials so we can calculate the derivative
2986  if (p_source < PolyFunction ) {
2987  QString msg = "The SpiceRotation pointing angles must be fit to polynomials in order to ";
2988  msg += "compute angular velocity.";
2989  throw IException(IException::Programmer, msg, _FILEINFO_);
2990  }
2991  if (p_source == PckPolyFunction) {
2992  QString msg = "Planetary angular velocity must be fit computed with PCK polynomials ";
2993  throw IException(IException::Programmer, msg, _FILEINFO_);
2994  }
2995  std::vector<double> dCJdt;
2996  dCJdt.resize(9);
2997 
2998  switch (m_frameType) {
2999  // Treat all cases the same except for target body rotations
3000  case UNKNOWN:
3001  case INERTL:
3002  case TK:
3003  case DYN:
3004  case CK:
3005  DCJdt(dCJdt);
3006  break;
3007  case PCK:
3008  case BPC:
3009  case NOTJ2000PCK:
3010  break;
3011  }
3012  double omega[3][3];
3013  mtxm_c((SpiceDouble( *)[3]) &dCJdt[0], (SpiceDouble( *)[3]) &p_CJ[0], omega);
3014  p_av[0] = omega[2][1];
3015  p_av[1] = omega[0][2];
3016  p_av[2] = omega[1][0];
3018  }
3019 
3020 
3027  void SpiceRotation::DCJdt(std::vector<double> &dCJ) {
3029 
3030  // Get the rotation angles and axes
3031  std::vector<double> angles = Angles(p_axis3, p_axis2, p_axis1);
3032  int axes[3] = {p_axis1, p_axis2, p_axis3};
3033 
3034  double dmatrix[3][3];
3035  double dangle;
3036  double wmatrix[3][3]; // work matrix
3037  dCJ.assign(9, 0.);
3038 
3039  for (int angleIndex = 0; angleIndex < 3; angleIndex++) {
3040  drotat_(&(angles[angleIndex]), (integer *) axes + angleIndex, (doublereal *) dmatrix);
3041  // Transpose to obtain row-major order
3042  xpose_c(dmatrix, dmatrix);
3043 
3044  // To get the derivative of the polynomial fit to the angle with respect to time
3045  // first create the function object for this angle and load its coefficients
3047  function.SetCoefficients(p_coefficients[angleIndex]);
3048 
3049  // Evaluate the derivative of function at p_et
3050  // dangle = function.DerivativeVar((p_et - p_baseTime) / p_timeScale);
3051  dangle = function.DerivativeVar((p_et - p_baseTime) / p_timeScale) / p_timeScale;
3052 
3053  // Multiply dangle to complete dmatrix
3054  for (int row = 0; row < 3; row++) {
3055  for (int col = 0; col < 3; col++) {
3056  dmatrix[row][col] *= dangle;
3057  }
3058  }
3059  // Apply the other 2 angles and chain them all together
3060  switch (angleIndex) {
3061  case 0:
3062  rotmat_c(dmatrix, angles[1], axes[1], dmatrix);
3063  rotmat_c(dmatrix, angles[2], axes[2], dmatrix);
3064  break;
3065  case 1:
3066  rotate_c(angles[0], axes[0], wmatrix);
3067  mxm_c(dmatrix, wmatrix, dmatrix);
3068  rotmat_c(dmatrix, angles[2], axes[2], dmatrix);
3069  break;
3070  case 2:
3071  rotate_c(angles[0], axes[0], wmatrix);
3072  rotmat_c(wmatrix, angles[1], axes[1], wmatrix);
3073  mxm_c(dmatrix, wmatrix, dmatrix);
3074  break;
3075  }
3076  int i, j;
3077  for (int index = 0; index < 9; index++) {
3078  i = index / 3;
3079  j = index % 3;
3080  dCJ[index] += dmatrix[i][j];
3081  }
3082  }
3083 
3085  }
3086 
3087 
3093  std::vector<double> SpiceRotation::StateTJ() {
3094  std::vector<double> stateTJ(36);
3095 
3096  // Build the state matrix for the time-based rotation from the matrix and angulary velocity
3097  double stateCJ[6][6];
3098  rav2xf_c(&p_CJ[0], &p_av[0], stateCJ);
3099 // (SpiceDouble (*) [3]) &p_CJ[0]
3100  int irow = 0;
3101  int jcol = 0;
3102  int vpos = 0;
3103 
3104  for (int row = 3; row < 6; row++) {
3105  irow = row - 3;
3106  vpos = irow * 3;
3107 
3108  for (int col = 0; col < 3; col++) {
3109  jcol = col + 3;
3110  // Fill the upper left corner
3111  stateTJ[irow*6 + col] = p_TC[vpos] * stateCJ[0][col] + p_TC[vpos+1] * stateCJ[1][col]
3112  + p_TC[vpos+2] * stateCJ[2][col];
3113  // Fill the lower left corner
3114  stateTJ[row*6 + col] = p_TC[vpos] * stateCJ[3][col] + p_TC[vpos+1] * stateCJ[4][col]
3115  + p_TC[vpos+2] * stateCJ[5][col];
3116  // Fill the upper right corner
3117  stateTJ[irow*6 + jcol] = 0;
3118  // Fill the lower right corner
3119  stateTJ[row*6 +jcol] = stateTJ[irow*6 + col];
3120  }
3121  }
3122  return stateTJ;
3123  }
3124 
3125 
3136  std::vector<double> SpiceRotation::Extrapolate(double timeEt) {
3138 
3139  if (!p_hasAngularVelocity){
3140  return p_CJ;
3141  }
3142 
3143  double diffTime = timeEt - p_et;
3144  std::vector<double> CJ(9, 0.0);
3145  double dmat[3][3];
3146 
3147  // Create a rotation matrix for the axis and magnitude of the angular velocity multiplied by
3148  // the time difference
3149  axisar_c((SpiceDouble *) &p_av[0], diffTime*vnorm_c((SpiceDouble *) &p_av[0]), dmat);
3150 
3151  // Rotate from the current time to the desired time assuming constant angular velocity
3152  mxm_c(dmat, (SpiceDouble *) &p_CJ[0], (SpiceDouble( *)[3]) &CJ[0]);
3154  return CJ;
3155  }
3156 
3157 
3165  void SpiceRotation::SetFullCacheParameters(double startTime, double endTime, int cacheSize) {
3166  // Save full cache parameters
3167  p_fullCacheStartTime = startTime;
3168  p_fullCacheEndTime = endTime;
3169  p_fullCacheSize = cacheSize;
3170  }
3171 
3172 
3181  // Get a count of all the loaded kernels
3182  SpiceInt count;
3183  ktotal_c("PCK", &count);
3184 
3185  // Define some Naif constants
3186  int FILESIZ = 128;
3187  int TYPESIZ = 32;
3188  int SOURCESIZ = 128;
3189  SpiceChar file[FILESIZ];
3190  SpiceChar filetype[TYPESIZ];
3191  SpiceChar source[SOURCESIZ];
3192  SpiceInt handle;
3193  SpiceBoolean found;
3194 
3195  // Get the name of each loaded kernel. The accuracy of this test depends on the use of the
3196  // "bpc" suffix to name a binary pck. If a binary bpc does not have the "bpc" suffix, it will not
3197  // be found by this test. This test was suggested by Boris Semenov at Naif.
3198  for (SpiceInt knum = 0; knum < count; knum++){
3199  kdata_c(knum, "PCK", FILESIZ, TYPESIZ, SOURCESIZ, file, filetype, source, &handle, &found);
3200 
3201  // search file for "bpc"
3202  if (strstr(file, "bpc") != NULL) {
3203  m_frameType = BPC;
3204  }
3205  }
3206  }
3207 
3208 
3217  SpiceInt frameCode = p_constantFrames[0];
3218  SpiceBoolean found;
3219  SpiceInt centerBodyCode;
3220  SpiceInt frameClass;
3221  SpiceInt classId;
3222  frinfo_c(frameCode, &centerBodyCode, &frameClass, &classId, &found);
3223 
3224  if (found) {
3225  if (frameClass == 2 || (centerBodyCode > 0 && frameClass != 3)) {
3226  m_frameType = PCK;
3227  // Load the PC information while it is available and set member values
3228  loadPCFromSpice(centerBodyCode);
3229  }
3230  else if (p_constantFrames.size() > 1) {
3231  for (std::vector<int>::size_type idx = 1; idx < p_constantFrames.size(); idx++) {
3232  frameCode = p_constantFrames[idx];
3233  frinfo_c(frameCode, &centerBodyCode, &frameClass, &classId, &found);
3234  if (frameClass == 3) m_frameType = CK;
3235  }
3236  }
3237  else {
3238  switch (frameClass) {
3239  case 1:
3240  m_frameType = INERTL;
3241  break;
3242  // case 2: handled in first if block
3243  case 3:
3244  m_frameType = CK;
3245  break;
3246  case 4:
3247  m_frameType = TK;
3248  break;
3249  case 5:
3250  m_frameType = DYN;
3251  break;
3252  default:
3253  m_frameType = UNKNOWN;
3254  }
3255  }
3256  }
3257  }
3258 
3259 
3269  // If the cache has only one rotation, set it
3271  if (p_cacheTime.size() == 1) {
3272  p_CJ = m_orientation->getRotations()[0].toRotationMatrix();
3273  if (p_hasAngularVelocity) {
3274  ale::Vec3d av = m_orientation->getAngularVelocities()[0];
3275  p_av[0] = av.x;
3276  p_av[1] = av.y;
3277  p_av[2] = av.z;
3278  }
3279  }
3280  // Otherwise determine the interval to interpolate
3281  else {
3282  p_CJ = m_orientation->interpolateTimeDep(p_et).toRotationMatrix();
3283 
3284  if (p_hasAngularVelocity) {
3285  ale::Vec3d av = m_orientation->interpolateAV(p_et);
3286  p_av[0] = av.x;
3287  p_av[1] = av.y;
3288  p_av[2] = av.z;
3289  }
3290  }
3292  }
3293 
3294 
3301  // TODO what about spk time bias and mission setting of light time corrections
3302  // That information has only been passed to the SpicePosition class and
3303  // is not available to this class, but probably should be applied to the
3304  // spkez call.
3305 
3306  // Make sure the constant frame is loaded. This method also does the frame trace.
3308  if (p_timeFrames.size() == 0) InitConstantRotation(p_et);
3309 
3310  SpiceDouble stateJ[6]; // Position and velocity vector in J2000
3311  SpiceDouble lt;
3312  SpiceInt spkCode = p_constantFrames[0] / 1000;
3313  spkez_c((SpiceInt) spkCode, p_et, "J2000", "LT+S",
3314  (SpiceInt) p_targetCode, stateJ, &lt);
3315  // reverse the position to be relative to the spacecraft. This may be
3316  // a mission dependent value and possibly the sense of the velocity as well.
3317  SpiceDouble sJ[3], svJ[3];
3318  vpack_c(-1 * stateJ[0], -1 * stateJ[1], -1 * stateJ[2], sJ);
3319  vpack_c(stateJ[3], stateJ[4], stateJ[5], svJ);
3320  twovec_c(sJ,
3321  p_axisP,
3322  svJ,
3323  p_axisV,
3324  (SpiceDouble( *)[3]) &p_CJ[0]);
3326  }
3327 
3328 
3341  SpiceInt j2000 = J2000Code;
3342 
3343  SpiceDouble time = p_et + p_timeBias;
3344  // Make sure the constant frame is loaded. This method also does the frame trace.
3345  if (p_timeFrames.size() == 0) InitConstantRotation(p_et);
3346  int toFrame = p_timeFrames[0];
3347 
3348  // First try getting the entire state matrix (6x6), which includes CJ and the angular velocity
3349  double stateCJ[6][6];
3350  frmchg_((integer *) &j2000, (integer *) &toFrame, &time, (doublereal *) stateCJ);
3351 
3352  // If Naif fails attempting to get the state matrix, assume the angular velocity vector is
3353  // not available and just get the rotation matrix. First turn off Naif error reporting and
3354  // return any error without printing them.
3355  SpiceBoolean ckfailure = failed_c();
3356  reset_c(); // Reset Naif error system to allow caller to recover
3357 
3358  if (!ckfailure) {
3359  xpose6_c(stateCJ, stateCJ);
3360  xf2rav_c(stateCJ, (SpiceDouble( *)[3]) &p_CJ[0], (SpiceDouble *) &p_av[0]);
3361  p_hasAngularVelocity = true;
3362  }
3363  else {
3364  refchg_((integer *) &j2000, (integer *) &toFrame, &time, (SpiceDouble *) &p_CJ[0]);
3365 
3366  if (failed_c()) {
3367  char naifstr[64];
3368  getmsg_c("SHORT", sizeof(naifstr), naifstr);
3369  reset_c(); // Reset Naif error system to allow caller to recover
3370 
3371  if (eqstr_c(naifstr, "SPICE(UNKNOWNFRAME)")) {
3372  Isis::IString msg = Isis::IString((int) p_constantFrames[0]) + " is an unrecognized " +
3373  "reference frame code. Has the mission frames kernel been loaded?";
3374  throw IException(IException::Io, msg, _FILEINFO_);
3375  }
3376  else {
3377  Isis::IString msg = "No pointing available at requested time [" +
3378  Isis::IString(p_et + p_timeBias) + "] for frame code [" +
3379  Isis::IString((int) p_constantFrames[0]) + "]";
3380  throw IException(IException::Io, msg, _FILEINFO_);
3381  }
3382  }
3383 
3384  // Transpose to obtain row-major order
3385  xpose_c((SpiceDouble( *)[3]) &p_CJ[0], (SpiceDouble( *)[3]) &p_CJ[0]);
3386  }
3387 
3389  }
3390 
3391 
3398  std::vector<double> SpiceRotation::EvaluatePolyFunction() {
3402 
3403  // Load the functions with the coefficients
3404  function1.SetCoefficients(p_coefficients[0]);
3405  function2.SetCoefficients(p_coefficients[1]);
3406  function3.SetCoefficients(p_coefficients[2]);
3407 
3408  std::vector<double> rtime;
3409  rtime.push_back((p_et - p_baseTime) / p_timeScale);
3410  std::vector<double> angles;
3411  angles.push_back(function1.Evaluate(rtime));
3412  angles.push_back(function2.Evaluate(rtime));
3413  angles.push_back(function3.Evaluate(rtime));
3414 
3415  // Get the first angle back into the range Naif expects [-180.,180.]
3416  if (angles[0] <= -1 * pi_c()) {
3417  angles[0] += twopi_c();
3418  }
3419  else if (angles[0] > pi_c()) {
3420  angles[0] -= twopi_c();
3421  }
3422  return angles;
3423  }
3424 
3425 
3437 
3438  // Load the functions with the coefficients
3439  function1.SetCoefficients(p_coefficients[0]);
3440  function2.SetCoefficients(p_coefficients[1]);
3441  function3.SetCoefficients(p_coefficients[2]);
3442 
3443  std::vector<double> rtime;
3444  rtime.push_back((p_et - p_baseTime) / p_timeScale);
3445  double angle1 = function1.Evaluate(rtime);
3446  double angle2 = function2.Evaluate(rtime);
3447  double angle3 = function3.Evaluate(rtime);
3448 
3449  // Get the first angle back into the range Naif expects [-180.,180.]
3450  if (angle1 < -1 * pi_c()) {
3451  angle1 += twopi_c();
3452  }
3453  else if (angle1 > pi_c()) {
3454  angle1 -= twopi_c();
3455  }
3456 
3457  eul2m_c((SpiceDouble) angle3, (SpiceDouble) angle2, (SpiceDouble) angle1,
3459  (SpiceDouble( *)[3]) &p_CJ[0]);
3460 
3461  if (p_hasAngularVelocity) {
3462  if ( p_degree == 0){
3463  ale::Vec3d av = m_orientation->getAngularVelocities()[0];
3464  p_av[0] = av.x;
3465  p_av[1] = av.y;
3466  p_av[2] = av.z;
3467  }
3468  else {
3469  ComputeAv();
3470  }
3471  }
3473  }
3474 
3475 
3485  std::vector<double> cacheAngles(3);
3486  std::vector<double> cacheVelocity(3);
3487  cacheAngles = Angles(p_axis3, p_axis2, p_axis1);
3488  cacheVelocity = p_av;
3490  std::vector<double> polyAngles(3);
3491  // The decomposition fails because the angles are outside the valid range for Naif
3492  // polyAngles = Angles(p_axis3, p_axis2, p_axis1);
3493  polyAngles = EvaluatePolyFunction();
3494  std::vector<double> polyVelocity(3);
3495  polyVelocity = p_av;
3496  std::vector<double> angles(3);
3497 
3498  for (int index = 0; index < 3; index++) {
3499  angles[index] = cacheAngles[index] + polyAngles[index];
3500  p_av[index] += cacheVelocity[index];
3501  }
3502 
3503  if (angles[0] <= -1 * pi_c()) {
3504  angles[0] += twopi_c();
3505  }
3506  else if (angles[0] > pi_c()) {
3507  angles[0] -= twopi_c();
3508  }
3509 
3510  if (angles[2] <= -1 * pi_c()) {
3511  angles[2] += twopi_c();
3512  }
3513  else if (angles[2] > pi_c()) {
3514  angles[2] -= twopi_c();
3515  }
3516 
3517  eul2m_c((SpiceDouble) angles[2], (SpiceDouble) angles[1], (SpiceDouble) angles[0],
3519  (SpiceDouble( *)[3]) &p_CJ[0]);
3520  }
3521 
3522 
3529  // Set the scales
3530  double dTime = p_et / 86400.; // seconds to days conversion
3531  double centTime = dTime / 36525; // seconds to Julian centuries conversion
3532  double secondsPerJulianCentury = 86400. * 36525.;
3533 
3534  // Calculate the quadratic part of the expression for the angles in degrees
3535  // Note: phi = ra + 90. and delta = 90 - dec for comparing results with older Isis 2 data
3536  Angle ra = m_raPole[0] + centTime*(m_raPole[1] + m_raPole[2]*centTime);
3537  Angle dec = m_decPole[0] + centTime*(m_decPole[1] + m_decPole[2]*centTime);
3538  Angle pm = m_pm[0] + dTime*(m_pm[1] + m_pm[2]*dTime);
3539  Angle dra = (m_raPole[1] + 2.*m_raPole[2]*centTime) / secondsPerJulianCentury;
3540  Angle ddec = (m_decPole[1] + 2.*m_decPole[2]*centTime) / secondsPerJulianCentury;
3541  Angle dpm = (m_pm[1] + 2.*m_pm[2]*dTime) / 86400;
3542 
3543  // Now add the nutation/precession (trig part) adjustment to the expression if any
3544  int numNutPrec = (int) m_raNutPrec.size();
3545  Angle theta;
3546  double dtheta;
3547  double costheta;
3548  double sintheta;
3549 
3550  for (int ia = 0; ia < numNutPrec; ia++) {
3551  theta = m_sysNutPrec0[ia] + m_sysNutPrec1[ia]*centTime;
3552  dtheta = m_sysNutPrec1[ia].degrees() * DEG2RAD;
3553  costheta = cos(theta.radians());
3554  sintheta = sin(theta.radians());
3555  ra += Angle(m_raNutPrec[ia] * sintheta, Angle::Degrees);
3556  dec += Angle(m_decNutPrec[ia] * costheta, Angle::Degrees);
3557  pm += Angle(m_pmNutPrec[ia] * sintheta, Angle::Degrees);
3558  dra += Angle(m_raNutPrec[ia] * dtheta / secondsPerJulianCentury * costheta, Angle::Degrees);
3559  ddec -= Angle(m_decNutPrec[ia] * dtheta / secondsPerJulianCentury * sintheta, Angle::Degrees);
3560  dpm += Angle(m_pmNutPrec[ia] * dtheta / secondsPerJulianCentury * costheta, Angle::Degrees);
3561  }
3562 
3563  // Get pm in correct range
3564  pm = Angle(fmod(pm.degrees(), 360), Angle::Degrees); // Get pm back into the domain range
3565 
3566  if (ra.radians() < -1 * pi_c()) {
3567  ra += Angle(twopi_c(), Angle::Radians);
3568  }
3569  else if (ra.radians() > pi_c()) {
3570  ra -= Angle(twopi_c(), Angle::Radians);
3571  }
3572 
3573  if (pm.radians() < -1 * pi_c()) {
3574  pm += Angle(twopi_c(), Angle::Radians);
3575  }
3576  else if (pm.radians() > pi_c()) {
3577  pm -= Angle(twopi_c(), Angle::Radians);
3578  }
3579 
3580  // Convert to Euler angles to get the matrix
3581  SpiceDouble phi = ra.radians() + HALFPI;
3582  SpiceDouble delta = HALFPI - dec.radians();
3583  SpiceDouble w = pm.radians();
3584  SpiceDouble dphi = dra.radians();
3585  SpiceDouble ddelta = -ddec.radians();
3586  SpiceDouble dw = dpm.radians();
3587 
3588  // Load the Euler angles and their derivatives into an array and create the state matrix
3589  SpiceDouble angsDangs[6];
3590  SpiceDouble BJs[6][6];
3591  vpack_c(w, delta, phi, angsDangs);
3592  vpack_c(dw, ddelta, dphi, &angsDangs[3]);
3593  eul2xf_c (angsDangs, p_axis3, p_axis2, p_axis1, BJs);
3594 
3595  // Decompose the state matrix to the rotation and its angular velocity
3596  xf2rav_c(BJs, (SpiceDouble( *)[3]) &p_CJ[0], (SpiceDouble *) &p_av[0]);
3597  }
3598 }
Isis::SpiceRotation::GetBaseTime
double GetBaseTime()
Accessor method to get the rotation base time.
Definition: SpiceRotation.cpp:2423
Isis::SpiceRotation::p_fullCacheSize
int p_fullCacheSize
Initial requested cache size.
Definition: SpiceRotation.h:474
Isis::Angle::Degrees
@ Degrees
Degrees are generally considered more human readable, 0-360 is one circle, however most math does not...
Definition: Angle.h:56
Isis::SpiceRotation::ComputeAv
void ComputeAv()
Compute the angular velocity from the time-based functions fit to the pointing angles This method com...
Definition: SpiceRotation.cpp:2982
Isis::SpiceRotation::EphemerisTime
double EphemerisTime() const
Accessor method to get current ephemeris time.
Definition: SpiceRotation.cpp:306
Isis::SpiceRotation::sysNutPrecConstants
std::vector< Angle > sysNutPrecConstants()
Return the constants used to calculate the target body system nut/prec angles.
Definition: SpiceRotation.cpp:1565
Isis::HALFPI
const double HALFPI
The mathematical constant PI/2.
Definition: Constants.h:41
Isis::SpiceRotation::BPC
@ BPC
Isis specific code for binary pck.
Definition: SpiceRotation.h:283
Isis::SpiceRotation::checkForBinaryPck
void checkForBinaryPck()
Check loaded pck to see if any are binary and set frame type to indicate binary pck.
Definition: SpiceRotation.cpp:3180
Isis::IException::Io
@ Io
A type of error that occurred when performing an actual I/O operation.
Definition: IException.h:155
Isis::LeastSquares::Solve
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...
Definition: LeastSquares.cpp:205
Isis::PvlObject
Contains Pvl Groups and Pvl Objects.
Definition: PvlObject.h:61
Isis::Quaternion::ToMatrix
std::vector< double > ToMatrix()
Converts quaternion to 3x3 rotational matrix.
Definition: Quaternion.cpp:75
Isis::SpiceRotation::SetTimeBias
void SetTimeBias(double timeBias)
Apply a time bias when invoking SetEphemerisTime method.
Definition: SpiceRotation.cpp:242
Isis::SpiceRotation::pmCoefs
std::vector< Angle > pmCoefs()
Return the coefficients used to calculate the target body prime meridian.
Definition: SpiceRotation.cpp:1496
Isis::SpiceRotation::p_axis3
int p_axis3
Axis of rotation for angle 3 of rotation.
Definition: SpiceRotation.h:431
Isis::SpiceRotation::CacheLabel
void CacheLabel(Table &table)
Add labels to a SpiceRotation table.
Definition: SpiceRotation.cpp:1182
Isis::SpiceRotation::GetFullCacheTime
std::vector< double > GetFullCacheTime()
Return full listing (cache) of original time coverage requested.
Definition: SpiceRotation.cpp:2708
Isis::SpiceRotation::EvaluatePolyFunction
std::vector< double > EvaluatePolyFunction()
Evaluate the polynomial fit function for the three pointing angles for the current ephemeris time.
Definition: SpiceRotation.cpp:3398
Isis::SpiceRotation::FrameType
FrameType
Enumeration for the frame type of the rotation.
Definition: SpiceRotation.h:276
Isis::SpiceRotation::p_quaternion
Quaternion p_quaternion
Quaternion for J2000 to reference rotation at et.
Definition: SpiceRotation.h:446
Isis::PvlKeyword
A single keyword-value pair.
Definition: PvlKeyword.h:82
Isis::SpiceRotation::p_axis1
int p_axis1
Axis of rotation for angle 1 of rotation.
Definition: SpiceRotation.h:429
Isis::SpiceRotation::m_frameType
FrameType m_frameType
The type of rotation frame.
Definition: SpiceRotation.h:453
Isis::SpiceRotation::p_coefficients
std::vector< double > p_coefficients[3]
Coefficients defining functions fit to 3 pointing angles.
Definition: SpiceRotation.h:466
Isis::SpiceRotation::p_overrideBaseTime
double p_overrideBaseTime
Value set by caller to override computed base time.
Definition: SpiceRotation.h:469
Isis::SpiceRotation::p_timeBias
double p_timeBias
iTime bias when reading kernels
Definition: SpiceRotation.h:443
Isis::SpiceRotation::p_cacheTime
std::vector< double > p_cacheTime
iTime for corresponding rotation
Definition: SpiceRotation.h:427
Isis::LineEquation::Intercept
double Intercept()
Compute the intercept of the line.
Definition: LineEquation.cpp:87
Isis::SpiceRotation::DownsizeStatus
DownsizeStatus
Status of downsizing the cache.
Definition: SpiceRotation.h:267
Isis::BasisFunction::SetCoefficients
void SetCoefficients(const std::vector< double > &coefs)
Set the coefficients for the equation.
Definition: BasisFunction.cpp:42
Isis::Table::Label
PvlObject & Label()
The Table's label.
Definition: Table.cpp:260
Isis::SpiceRotation::setFrameType
void setFrameType()
Cached orientation information.
Definition: SpiceRotation.cpp:3216
Isis::SpiceRotation::p_baseTime
double p_baseTime
Base time used in fit equations.
Definition: SpiceRotation.h:461
Isis::SpiceRotation::p_constantFrames
std::vector< int > p_constantFrames
Chain of Naif frame codes in constant rotation TC.
Definition: SpiceRotation.h:437
Isis::SpiceRotation::SetPolynomialDegree
void SetPolynomialDegree(int degree)
Set the degree of the polynomials to be fit to the three camera angles for the time period covered by...
Definition: SpiceRotation.cpp:2343
Isis::SpiceRotation::p_matrixSet
bool p_matrixSet
Flag indicating p_TJ has been set.
Definition: SpiceRotation.h:449
Isis::DEG2RAD
const double DEG2RAD
Multiplier for converting from degrees to radians.
Definition: Constants.h:43
Isis::SpiceRotation::Source
Source
The rotation can come from one of 3 places for an Isis cube.
Definition: SpiceRotation.h:245
Isis::SpiceRotation::loadPCFromTable
void loadPCFromTable(const PvlObject &Label)
Initialize planetary orientation constants from an cube body rotation label.
Definition: SpiceRotation.cpp:1103
Isis::SpiceRotation::GetCenterAngles
std::vector< double > GetCenterAngles()
Return the camera angles at the center time of the observation.
Definition: SpiceRotation.cpp:1290
Isis::SpiceRotation::poleRaCoefs
std::vector< Angle > poleRaCoefs()
Return the coefficients used to calculate the target body pole ra.
Definition: SpiceRotation.cpp:1457
Isis::PolynomialUnivariate
Nth degree Polynomial with one variable.
Definition: PolynomialUnivariate.h:37
Isis::SpiceRotation::SetPolynomial
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...
Definition: SpiceRotation.cpp:1739
Isis::TableRecord::Fields
int Fields() const
Returns the number of fields that are currently in the record.
Definition: TableRecord.cpp:78
Isis::SpiceRotation::TimeBasedRotation
std::vector< double > TimeBasedRotation()
Return time-based 3x3 rotation CJ matrix as a quaternion.
Definition: SpiceRotation.cpp:2915
Isis::SpiceRotation::m_raNutPrec
std::vector< double > m_raNutPrec
Coefficients of pole right ascension nut/prec terms.
Definition: SpiceRotation.h:572
Isis::SpiceRotation::GetSource
Source GetSource()
Accessor method to get the rotation source.
Definition: SpiceRotation.cpp:2402
Isis::SpiceRotation::poleDecCoefs
std::vector< Angle > poleDecCoefs()
Return the coefficients used to calculate the target body pole dec.
Definition: SpiceRotation.cpp:1477
Isis::SpiceRotation::p_TC
std::vector< double > p_TC
Rotation matrix from first constant rotation (after all time-based rotations in frame chain from J200...
Definition: SpiceRotation.h:475
Isis::LineEquation
Utility class for creating and using cartesean line equations.
Definition: LineEquation.h:29
Isis::SpiceRotation::FrameTrace
void FrameTrace(double et)
Compute frame trace chain from target frame to J2000.
Definition: SpiceRotation.cpp:2740
Isis::SpiceRotation::SetFullCacheParameters
void SetFullCacheParameters(double startTime, double endTime, int cacheSize)
Set the full cache time parameters.
Definition: SpiceRotation.cpp:3165
Isis::SpiceRotation::PckPolyFunction
@ PckPolyFunction
Quadratic polynomial function with linear trignometric terms.
Definition: SpiceRotation.h:251
Isis::NaifStatus::CheckErrors
static void CheckErrors(bool resetNaif=true)
This method looks for any naif errors that might have occurred.
Definition: NaifStatus.cpp:28
Isis::SpiceRotation::setEphemerisTimeMemcache
void setEphemerisTimeMemcache()
Updates rotation state based on the rotation cache.
Definition: SpiceRotation.cpp:3268
Isis::TableRecord
Definition: TableRecord.h:38
Isis::SpiceRotation::SetAngles
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.
Definition: SpiceRotation.cpp:1336
Isis::SpiceRotation::Yes
@ Yes
Downsize the cache.
Definition: SpiceRotation.h:268
Isis::SpiceRotation::J2000Vector
std::vector< double > J2000Vector(const std::vector< double > &rVec)
Given a direction vector in the reference frame, return a J2000 direction.
Definition: SpiceRotation.cpp:1408
Isis::toString
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
Definition: IString.cpp:211
Isis::SpiceRotation::MinimizeCache
void MinimizeCache(DownsizeStatus status)
Set the downsize status to minimize cache.
Definition: SpiceRotation.cpp:336
Isis::SpiceRotation::Angles
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.
Definition: SpiceRotation.cpp:1309
Isis::SpiceRotation::Cache
Table Cache(const QString &tableName)
Return a table with J2000 to reference rotations.
Definition: SpiceRotation.cpp:868
Isis::SpiceRotation::sysNutPrecCoefs
std::vector< Angle > sysNutPrecCoefs()
Return the coefficients used to calculate the target body system nut/prec angles.
Definition: SpiceRotation.cpp:1583
Isis::SpiceRotation::setEphemerisTimeSpice
void setEphemerisTimeSpice()
When setting the ephemeris time, updates the rotation state based on data read directly from NAIF ker...
Definition: SpiceRotation.cpp:3339
Isis::SpiceRotation::m_decNutPrec
std::vector< double > m_decNutPrec
Coefficients of pole decliniation nut/prec terms.
Definition: SpiceRotation.h:573
Isis::SpiceRotation::~SpiceRotation
virtual ~SpiceRotation()
Destructor for SpiceRotation object.
Definition: SpiceRotation.cpp:200
Isis::SpiceRotation::StateTJ
std::vector< double > StateTJ()
State matrix (6x6) for rotating state vectors from J2000 to target frame.
Definition: SpiceRotation.cpp:3093
Isis::SpiceRotation::p_axis2
int p_axis2
Axis of rotation for angle 2 of rotation.
Definition: SpiceRotation.h:430
Isis::SpiceRotation::p_fullCacheStartTime
double p_fullCacheStartTime
Initial requested starting time of cache.
Definition: SpiceRotation.h:472
Isis::SpiceRotation::LoadCache
void LoadCache(double startTime, double endTime, int size)
Cache J2000 rotation quaternion over a time range.
Definition: SpiceRotation.cpp:359
Isis::SpiceRotation::p_axisV
int p_axisV
The axis defined by the velocity vector for defining a nadir rotation.
Definition: SpiceRotation.h:457
Isis::SpiceRotation::p_av
std::vector< double > p_av
Angular velocity for rotation at time p_et.
Definition: SpiceRotation.h:480
Isis::SpiceRotation::HasAngularVelocity
bool HasAngularVelocity()
Checks whether the rotation has angular velocities.
Definition: SpiceRotation.cpp:1396
Isis::SpiceRotation::p_CJ
std::vector< double > p_CJ
Rotation matrix from J2000 to first constant rotation.
Definition: SpiceRotation.h:478
Isis::SpiceRotation::p_timeFrames
std::vector< int > p_timeFrames
Chain of Naif frame codes in time-based rotation CJ.
Definition: SpiceRotation.h:440
Isis::SpiceRotation::INERTL
@ INERTL
See Naif Frames.req document for.
Definition: SpiceRotation.h:278
Isis::SpiceRotation::setEphemerisTimePolyFunctionOverSpice
void setEphemerisTimePolyFunctionOverSpice()
When setting the ephemeris time, updates the rotation state based on a polynomial fit over spice kern...
Definition: SpiceRotation.cpp:3482
Isis::SpiceRotation::m_sysNutPrec1
std::vector< Angle > m_sysNutPrec1
Linear terms of planetary system nut/prec periods.
Definition: SpiceRotation.h:578
Isis::LeastSquares
Generic least square fitting class.
Definition: LeastSquares.h:99
Isis::SpiceRotation::p_degree
int p_degree
Degree of fit polynomial for angles.
Definition: SpiceRotation.h:428
Isis::SpiceRotation::Memcache
@ Memcache
From cached table.
Definition: SpiceRotation.h:248
Isis::SpiceRotation::No
@ No
Do not downsize the cache.
Definition: SpiceRotation.h:270
Isis::SpiceRotation::p_noOverride
bool p_noOverride
Flag to compute base time;.
Definition: SpiceRotation.h:468
Isis::SpiceRotation::IsCached
bool IsCached() const
Checks if the cache is empty.
Definition: SpiceRotation.cpp:326
Isis::SpiceRotation::SetConstantMatrix
void SetConstantMatrix(std::vector< double > constantMatrix)
Set the constant 3x3 rotation TC matrix from a vector of length 9.
Definition: SpiceRotation.cpp:2905
Isis::toInt
int toInt(const QString &string)
Global function to convert from a string to an integer.
Definition: IString.cpp:93
Isis::SpiceRotation::LoadTimeCache
void LoadTimeCache()
Load the time cache.
Definition: SpiceRotation.cpp:2472
Isis::SpiceRotation::PartialType
PartialType
This enumeration indicates whether the partial derivative is taken with respect to Right Ascension,...
Definition: SpiceRotation.h:258
Isis::SpiceRotation::p_axisP
int p_axisP
The axis defined by the spacecraft vector for defining a nadir rotation.
Definition: SpiceRotation.h:455
Isis::PvlObject::hasKeyword
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:236
Isis::SpiceRotation::ToReferencePartial
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...
Definition: SpiceRotation.cpp:2232
Isis::SpiceRotation::ConstantRotation
std::vector< double > ConstantRotation()
Return the constant 3x3 rotation TC matrix as a quaternion.
Definition: SpiceRotation.cpp:2880
Isis::SpiceRotation::m_raPole
std::vector< Angle > m_raPole
Coefficients of a quadratic polynomial fitting pole ra.
Definition: SpiceRotation.h:565
Isis::TableField::Double
@ Double
The values in the field are 8 byte doubles.
Definition: TableField.h:54
Isis::SpiceRotation::WRT_Declination
@ WRT_Declination
With respect to Declination.
Definition: SpiceRotation.h:260
Isis::Table
Class for storing Table blobs information.
Definition: Table.h:61
Isis::SpiceRotation::DPolynomial
double DPolynomial(const int coeffIndex)
Evaluate the derivative of the fit polynomial defined by the given coefficients with respect to the c...
Definition: SpiceRotation.cpp:2137
Isis::SpiceRotation::m_sysNutPrec0
std::vector< Angle > m_sysNutPrec0
Constants of planetary system nut/prec periods.
Definition: SpiceRotation.h:577
Isis::SpiceRotation::UNKNOWN
@ UNKNOWN
Isis specific code for unknown frame type.
Definition: SpiceRotation.h:277
Isis::SpiceRotation::AngularVelocity
std::vector< double > AngularVelocity()
Accessor method to get the angular velocity.
Definition: SpiceRotation.cpp:1365
Isis::SpiceRotation::WRT_Twist
@ WRT_Twist
With respect to Twist or Prime Meridian Rotation.
Definition: SpiceRotation.h:261
Isis::SpiceRotation::SetSource
void SetSource(Source source)
Resets the source of the rotation to the given value.
Definition: SpiceRotation.cpp:2412
Isis::SpiceRotation::PolyFunction
@ PolyFunction
From nth degree polynomial.
Definition: SpiceRotation.h:249
Isis::SpiceRotation::ConstantFrameChain
std::vector< int > ConstantFrameChain()
Accessor method to get the frame chain for the constant part of the rotation (ends in target)
Definition: SpiceRotation.cpp:1376
Isis::SpiceRotation::p_et
double p_et
Current ephemeris time.
Definition: SpiceRotation.h:445
Isis::SpiceRotation::InitConstantRotation
void InitConstantRotation(double et)
Initialize the constant rotation.
Definition: SpiceRotation.cpp:2951
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::SpiceRotation::Extrapolate
std::vector< double > Extrapolate(double timeEt)
Extrapolate pointing for a given time assuming a constant angular velocity.
Definition: SpiceRotation.cpp:3136
Isis::SpiceRotation::NOTJ2000PCK
@ NOTJ2000PCK
PCK frame not referenced to J2000.
Definition: SpiceRotation.h:284
Isis::Angle
Defines an angle and provides unit conversions.
Definition: Angle.h:45
Isis::SpiceRotation::WrapAngle
double WrapAngle(double compareAngle, double angle)
Wrap the input angle to keep it within 2pi radians of the angle to compare.
Definition: SpiceRotation.cpp:2315
Isis::SpiceRotation::Nadir
@ Nadir
Nadir pointing.
Definition: SpiceRotation.h:247
Isis::Spice
Obtain SPICE information for a spacecraft.
Definition: Spice.h:283
Isis::SpiceRotation::Frame
int Frame()
Accessor method that returns the frame code.
Definition: SpiceRotation.cpp:225
Isis::Quaternion
Provide operations for quaternion arithmetic.
Definition: Quaternion.h:36
Isis::SpiceRotation::DPckPolynomial
double DPckPolynomial(PartialType partialVar, const int coeffIndex)
Evaluate the derivative of the fit polynomial defined by the given coefficients with respect to the c...
Definition: SpiceRotation.cpp:2172
Isis::SpiceRotation::m_decPole
std::vector< Angle > m_decPole
Coefficients of a quadratic polynomial fitting pole dec.
Definition: SpiceRotation.h:566
Isis::SpiceRotation::LineCache
Table LineCache(const QString &tableName)
Return a table with J2000 to reference rotations.
Definition: SpiceRotation.cpp:832
Isis::SpiceRotation::usePckPolynomial
void usePckPolynomial()
Set the coefficients of a polynomial fit to each of the three planet angles for the time period cover...
Definition: SpiceRotation.cpp:1948
Isis::SpiceRotation::SetOverrideBaseTime
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...
Definition: SpiceRotation.cpp:2110
Isis::SpiceRotation::m_pm
std::vector< Angle > m_pm
Coefficients of a quadratic polynomial fitting pole pm.
Definition: SpiceRotation.h:567
Isis::SpiceRotation::getPckPolynomial
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.
Definition: SpiceRotation.cpp:2073
Isis::toDouble
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:149
Isis::IException::Programmer
@ Programmer
This error is for when a programmer made an API call that was illegal.
Definition: IException.h:146
Isis::SpiceRotation::p_targetCode
int p_targetCode
For computing Nadir rotation only.
Definition: SpiceRotation.h:459
Isis::SpiceRotation::Done
@ Done
Cache is downsized.
Definition: SpiceRotation.h:269
Isis::SpiceRotation::m_pmNutPrec
std::vector< double > m_pmNutPrec
Coefficients of prime meridian nut/prec terms.
Definition: SpiceRotation.h:574
Isis::SpiceRotation::GetPolynomial
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...
Definition: SpiceRotation.cpp:2051
Isis::SpiceRotation::ConstantMatrix
std::vector< double > & ConstantMatrix()
Return the constant 3x3 rotation TC matrix as a vector of length 9.
Definition: SpiceRotation.cpp:2895
Isis::SpiceRotation::p_degreeApplied
bool p_degreeApplied
Flag indicating whether or not a polynomial of degree p_degree has been created and used to fill the ...
Definition: SpiceRotation.h:463
Isis::SpiceRotation::toJ2000Partial
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...
Definition: SpiceRotation.cpp:1607
Isis::SpiceRotation::TimeFrameChain
std::vector< int > TimeFrameChain()
Accessor method to get the frame chain for the rotation (begins in J2000).
Definition: SpiceRotation.cpp:1386
Isis::SpiceRotation::m_tOrientationAvailable
bool m_tOrientationAvailable
Target orientation constants are available.
Definition: SpiceRotation.h:450
Isis::SpiceRotation::TimeBias
double TimeBias() const
Accessor method to get current time bias.
Definition: SpiceRotation.cpp:316
Isis::SpiceRotation::Matrix
std::vector< double > Matrix()
Return the full rotation TJ as a matrix.
Definition: SpiceRotation.cpp:2865
Isis::SpiceRotation::setEphemerisTimePolyFunction
void setEphemerisTimePolyFunction()
When setting the ephemeris time, updates the rotation according to a polynomial that defines the thre...
Definition: SpiceRotation.cpp:3432
Isis::SpiceRotation::ReloadCache
void ReloadCache()
Cache J2000 rotation over existing cached time range using polynomials.
Definition: SpiceRotation.cpp:741
Isis::PvlKeyword::size
int size() const
Returns the number of values stored in this keyword.
Definition: PvlKeyword.h:125
Isis::SpiceRotation::SetTimeBasedMatrix
void SetTimeBasedMatrix(std::vector< double > timeBasedMatrix)
Set the time-based 3x3 rotation CJ matrix from a vector of length 9.
Definition: SpiceRotation.cpp:2940
Isis::SpiceRotation::loadPCFromSpice
void loadPCFromSpice(int CenterBodyCode)
Initialize planetary orientation constants from Spice PCK.
Definition: SpiceRotation.cpp:991
Isis::SpiceRotation::p_hasAngularVelocity
bool p_hasAngularVelocity
Flag indicating whether the rotation includes angular velocity.
Definition: SpiceRotation.h:481
Isis::SpiceRotation::WRT_RightAscension
@ WRT_RightAscension
With respect to Right Ascension.
Definition: SpiceRotation.h:259
Isis::SpiceRotation::DCJdt
void DCJdt(std::vector< double > &dRJ)
Compute the derivative of the 3x3 rotation matrix CJ with respect to time.
Definition: SpiceRotation.cpp:3027
Isis::SpiceRotation::p_timeScale
double p_timeScale
Time scale used in fit equations.
Definition: SpiceRotation.h:462
Isis::SpiceRotation::GetTimeScale
double GetTimeScale()
Accessor method to get the rotation time scale.
Definition: SpiceRotation.cpp:2433
Isis::SpiceRotation::poleRaNutPrecCoefs
std::vector< double > poleRaNutPrecCoefs()
Return the coefficients used to calculate the target body pole ra nut/prec coefficients.
Definition: SpiceRotation.cpp:1514
Isis::SpiceRotation::SpiceRotation
SpiceRotation(int frameCode)
Construct an empty SpiceRotation class using a valid Naif frame code to set up for getting rotation f...
Definition: SpiceRotation.cpp:58
Isis::SpiceRotation::SetAxes
void SetAxes(int axis1, int axis2, int axis3)
Set the axes of rotation for decomposition of a rotation matrix into 3 angles.
Definition: SpiceRotation.cpp:2450
Isis::PvlObject::findKeyword
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:177
Isis::SpiceRotation::PolyFunctionOverSpice
@ PolyFunctionOverSpice
Kernels plus nth degree polynomial.
Definition: SpiceRotation.h:250
Isis::SpiceRotation::p_overrideTimeScale
double p_overrideTimeScale
Value set by caller to override computed time scale.
Definition: SpiceRotation.h:470
Isis::IString
Adds specific functionality to C++ strings.
Definition: IString.h:165
Isis::LineEquation::Slope
double Slope()
Compute the slope of the line.
Definition: LineEquation.cpp:66
Isis::LeastSquares::AddKnown
void AddKnown(const std::vector< double > &input, double expected, double weight=1.0)
Invoke this method for each set of knowns.
Definition: LeastSquares.cpp:96
Isis::SpiceRotation::ReferenceVector
std::vector< double > ReferenceVector(const std::vector< double > &jVec)
Given a direction vector in J2000, return a reference frame direction.
Definition: SpiceRotation.cpp:1700
Isis::Table::Records
int Records() const
Returns the number of records.
Definition: Table.cpp:313
Isis::SpiceRotation::poleDecNutPrecCoefs
std::vector< double > poleDecNutPrecCoefs()
Return the coefficients used to calculate the target body pole dec nut/prec coefficients.
Definition: SpiceRotation.cpp:1531
Isis::SpiceRotation::Spice
@ Spice
Directly from the kernels.
Definition: SpiceRotation.h:246
Isis::SpiceRotation::SetFrame
void SetFrame(int frameCode)
Change the frame to the given frame code.
Definition: SpiceRotation.cpp:214
Isis::BasisFunction::Evaluate
double Evaluate(const std::vector< double > &vars)
Compute the equation using the input variables.
Definition: BasisFunction.cpp:64
Isis::SpiceRotation::setPckPolynomial
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...
Definition: SpiceRotation.cpp:2028
Isis::SpiceRotation::TimeBasedMatrix
std::vector< double > & TimeBasedMatrix()
Return time-based 3x3 rotation CJ matrix as a vector of length 9.
Definition: SpiceRotation.cpp:2930
Isis::SpiceRotation::pmNutPrecCoefs
std::vector< double > pmNutPrecCoefs()
Return the coefficients used to calculate the target body pm nut/prec coefficients.
Definition: SpiceRotation.cpp:1548
Isis::SpiceRotation::p_fullCacheEndTime
double p_fullCacheEndTime
Initial requested ending time of cache.
Definition: SpiceRotation.h:473
Isis::SpiceRotation::setEphemerisTimeNadir
void setEphemerisTimeNadir()
When setting the ephemeris time, uses spacecraft nadir source to update the rotation state.
Definition: SpiceRotation.cpp:3300
Isis::SpiceRotation::getFrameType
FrameType getFrameType()
Accessor method to get the rotation frame type.
Definition: SpiceRotation.cpp:2392
Isis::SpiceRotation::p_minimizeCache
DownsizeStatus p_minimizeCache
Status of downsizing the cache (set to No to ignore)
Definition: SpiceRotation.h:471
Isis::Angle::Radians
@ Radians
Radians are generally used in mathematical equations, 0-2*PI is one circle, however these are more di...
Definition: Angle.h:63
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::BasisFunction::Coefficients
int Coefficients() const
Returns the number of coefficients for the equation.
Definition: BasisFunction.h:64
Isis::IException::User
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition: IException.h:126
Isis::SpiceRotation::SetEphemerisTime
void SetEphemerisTime(double et)
Return the J2000 to reference frame quaternion at given time.
Definition: SpiceRotation.cpp:260
Isis::SpiceRotation::PCK
@ PCK
definitions
Definition: SpiceRotation.h:279
Isis::SpiceRotation::p_source
Source p_source
The source of the rotation data.
Definition: SpiceRotation.h:454
Isis::BasisFunction::Coefficient
double Coefficient(int i) const
Returns the ith coefficient.
Definition: BasisFunction.h:107
Isis::SpiceRotation::setEphemerisTimePckPolyFunction
void setEphemerisTimePckPolyFunction()
When setting the ephemeris time, updates the rotation state based on the PcK polynomial.
Definition: SpiceRotation.cpp:3528
Isis::SpiceRotation
Obtain SPICE rotation information for a body.
Definition: SpiceRotation.h:209
Isis::TableField
Class for storing an Isis::Table's field information.
Definition: TableField.h:47
Isis::SpiceRotation::ComputeBaseTime
void ComputeBaseTime()
Compute the base time using cached times.
Definition: SpiceRotation.cpp:2087
Isis::Angle::radians
double radians() const
Convert an angle to a double.
Definition: Angle.h:226