diff --git a/CHANGELOG.md b/CHANGELOG.md index d01d817f1a..490f3f7f14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ release. - Added Vectorize to ProcessGroundPolygon library - Added gtest files for the app and unit test - Added Chandrayaan2 template for isisimport +- Added HRSC support in socetlinescankeywords [#5465](https://github.com/DOI-USGS/ISIS3/issues/5465) ### Changed - Refactored the pixel2map app diff --git a/isis/src/socet/apps/socetlinescankeywords/socetlinescankeywords.cpp b/isis/src/socet/apps/socetlinescankeywords/socetlinescankeywords.cpp index ba36a12cf1..560fc0e16d 100644 --- a/isis/src/socet/apps/socetlinescankeywords/socetlinescankeywords.cpp +++ b/isis/src/socet/apps/socetlinescankeywords/socetlinescankeywords.cpp @@ -1,11 +1,15 @@ +#include "socetlinescankeywords.h" + +#include +#include +#include + #include #include #include -#include +#include #include -#include #include -#include #include "Camera.h" #include "CameraDetectorMap.h" @@ -17,45 +21,42 @@ #include "FileName.h" #include "IException.h" #include "IString.h" -#include "iTime.h" #include "LineScanCameraDetectorMap.h" #include "NaifStatus.h" #include "Process.h" #include "Pvl.h" #include "Spice.h" -#include "Table.h" #include "TProjection.h" +#include "Table.h" #include "VariableLineScanCameraDetectorMap.h" - -#include "socetlinescankeywords.h" +#include "iTime.h" using namespace std; namespace Isis { -//TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS -//int GetHRSCLineRates(Cube *cube, vector &lineRates, int &totalLines, -// double &HRSCNadirCenterTime); -// -//double GetHRSCScanDuration(vector &lineRates, int &totalLines); + int GetHRSCLineRates(Cube *cube, vector &lineRates, + int &totalLines, double &HRSCNadirCenterTime); + + double GetHRSCScanDuration(vector &lineRates, int &totalLines); -void socetlinescankeywords (UserInterface &ui) { + void socetlinescankeywords(UserInterface &ui) { // Get user parameters and error check Cube input(ui.GetCubeName("FROM"), "rw"); socetlinescankeywords(&input, ui); } - void socetlinescankeywords(Cube *input, UserInterface &ui) { // Use a regular Process Process p; QString to = FileName(ui.GetFileName("TO")).expanded(); - //TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS - // double HRSCNadirCenterTime = ui.GetDouble("HRSC_NADIRCENTERTIME"); + + double HRSCNadirCenterTime = ui.GetDouble("HRSC_NADIRCENTERTIME"); if (input->isProjected()) { - QString msg = "Input images is a map projected cube ... not a level 1 image"; + QString msg = + "Input images is a map projected cube ... not a level 1 image"; throw IException(IException::User, msg, _FILEINFO_); } @@ -137,8 +138,9 @@ void socetlinescankeywords(Cube *input, UserInterface &ui) { else if (instrumentId == "NACR") { isLroNACR = true; } -//TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS -// else if (instrumentId == "HRSC") isHRSC = true; + else if (instrumentId == "HRSC") { + isHRSC = true; + } else { QString msg = "Unsupported instrument: " + instrumentId; throw IException(IException::User, msg, _FILEINFO_); @@ -162,43 +164,42 @@ void socetlinescankeywords(Cube *input, UserInterface &ui) { double focal = cam->FocalLength(); // focal length returned in mm -//TO DO: UNCOMMENT THESE LINES ONCE HRSC and MOC IS WORKING IN SS -// if (isMocWARed) -// focal = focal * 0.007; // pixel to mm conversion -// else if (isHRSC) -// { -// switch (ikCode) { -// case -41219: //S1: fwd stereo -// focal = 184.88; -// break; -// case -41218: //IR: infra-red -// focal = 181.57; -// break; -// case -41217: //P1: fwd photo -// focal = 179.16; -// break; -// case -41216: // GREEN -// focal = 175.31; -// break; -// case -41215: // NADIR -// focal = 175.01; -// break; -// case -41214: // BLUE -// focal = 175.53; -// break; -// case -41213: // P2: aft photo -// focal = 179.19; -// break; -// case -41212: // RED -// focal = 181.77; -// break; -// case -41211: // S2: aft stereo -// focal = 184.88; -// break; -// default: -// break; -// } -// } + // TO DO: UNCOMMENT THESE LINES ONCE MOC IS WORKING IN SS + // if (isMocWARed) + // focal = focal * 0.007; // pixel to mm conversion + if (isHRSC) { + switch (ikCode) { + case -41219: // S1: fwd stereo + focal = 184.88; + break; + case -41218: // IR: infra-red + focal = 181.57; + break; + case -41217: // P1: fwd photo + focal = 179.16; + break; + case -41216: // GREEN + focal = 175.31; + break; + case -41215: // NADIR + focal = 175.01; + break; + case -41214: // BLUE + focal = 175.53; + break; + case -41213: // P2: aft photo + focal = 179.19; + break; + case -41212: // RED + focal = 181.77; + break; + case -41211: // S2: aft stereo + focal = 184.88; + break; + default: + break; + } + } // Get instrument summing modes int csum = (int) detectorMap->SampleScaleFactor(); @@ -236,29 +237,23 @@ void socetlinescankeywords(Cube *input, UserInterface &ui) { double scanDuration = 0.0; double intTime = 0.0; -//TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS -// int numIntTimes = 0.0; -// vector lineRates; -// if (isHRSC) { -// numIntTimes = GetHRSCLineRates(&cube, lineRates, totalLines, HRSCNadirCenterTime); -// if (numIntTimes == 1) { -// LineRateChange lrc = lineRates.at(0); -// intTime = lrc.GetLineScanRate(); -// } -// if (numIntTimes <= 0) { -// QString msg = "HRSC: Invalid number of scan times"; -// throw IException(IException::Programmer, msg, _FILEINFO_); -// } -// else -// scanDuration = GetHRSCScanDuration(lineRates, totalLines); -// } -// else { -// -// TO DO: indent the following two lines when HRSC is working in SS - intTime = detectorMap->LineRate(); //LineRate is in seconds + int numIntTimes = 0.0; + vector lineRates; + if (isHRSC) { + numIntTimes = GetHRSCLineRates(input, lineRates, totalLines, HRSCNadirCenterTime); + if (numIntTimes == 1) { + LineRateChange lrc = lineRates.at(0); + intTime = lrc.GetLineScanRate(); + } + if (numIntTimes <= 0) { + QString msg = "HRSC: Invalid number of scan times"; + throw IException(IException::Programmer, msg, _FILEINFO_); + } else + scanDuration = GetHRSCScanDuration(lineRates, totalLines); + } else { + intTime = detectorMap->LineRate(); // LineRate is in seconds scanDuration = intTime * totalLines; -//TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS -// } + } // For reference, this is the code if calculating interval time // via LineExposureDuration keyword off image labels: @@ -275,14 +270,13 @@ void socetlinescankeywords(Cube *input, UserInterface &ui) { // 2) For others, cam->PixelPitch() returns the pixel pitch (size) in mm. double alongScanPxSize = 0.0; double crossScanPxSize = 0.0; -//TO DO: UNCOMMENT THESE LINES ONCE MOC IS WORKING IN SS -// if (isMocWARed || isHRSC) { -// alongScanPxSize = csum * 0.007; -// crossScanPxSize = dsum * 0.007; -// } -// else { -// -// TO DO: indent the following 24 lines when HRSC is working in SS + // TO DO: UNCOMMENT THESE LINES ONCE MOC IS WORKING IN SS + // if (isMocWARed || isHRSC) { + if (isHRSC) { + alongScanPxSize = csum * 0.007; + crossScanPxSize = dsum * 0.007; + } + else { crossScanPxSize = dsum * cam->PixelPitch(); // Get the ephemeris time, ground position and undistorted focal plane X @@ -307,9 +301,7 @@ void socetlinescankeywords(Cube *input, UserInterface &ui) { // the along scan pixel size is the difference in focal plane X coordinates alongScanPxSize = abs(uXCenter - uX); - -//TO DO: UNCOMMENT THIS LINE ONCE MOC and HRSC IS WORKING IN SS -// } + } // Now that we have totalLines, totalSamples, alongScanPxSize and // crossScanPxSize, fill the Interior Orientation Coefficient arrays @@ -747,25 +739,25 @@ void socetlinescankeywords(Cube *input, UserInterface &ui) { toStrm << setprecision(25) << "T_CENTER "; double tCenter = 0.0; -//TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS -// if (isHRSC) { -// tCenter = etCenter - HRSCNadirCenterTime; -// toStrm << tCenter << endl; -// } -// else - toStrm << tCenter << endl; + if (isHRSC) { + tCenter = etCenter - HRSCNadirCenterTime; + toStrm << tCenter << endl; + } + else { + toStrm << tCenter << endl; + } toStrm << "DT_EPHEM " << dtEphem << endl; toStrm << "T0_EPHEM "; -//TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS -// if (isHRSC) { -// double t = tCenter + t0Ephem; -// toStrm << t << endl; -// } -// else - toStrm << t0Ephem << endl; + if (isHRSC) { + double t = tCenter + t0Ephem; + toStrm << t << endl; + } + else { + toStrm << t0Ephem << endl; + } toStrm << "NUMBER_OF_EPHEM " << numEphem << endl; toStrm << "EPHEM_PTS" << endl; @@ -798,19 +790,18 @@ void socetlinescankeywords(Cube *input, UserInterface &ui) { toStrm << "\n\nSCAN_DURATION " << scanDuration << endl; - // UNCOMMENT toStrm << "\nNUMBER_OF_INT_TIMES " << numIntTimes << endl; - // - // if (isHRSC) { - // toStrm << "INT_TIMES" << endl; - // for (int i = 0; i < numIntTimes; i++) { - // LineRateChange lr = lineRates.at(i); - // toStrm << " " << lr.GetStartEt(); - // toStrm << " " << lr.GetLineScanRate(); - // toStrm << " " << lr.GetStartLine() << endl; - // } - // } - // else + if (isHRSC) { + toStrm << "INT_TIMES" << endl; + for (int i = 0; i < numIntTimes; i++) { + LineRateChange lr = lineRates.at(i); + toStrm << " " << lr.GetStartEt(); + toStrm << " " << lr.GetLineScanRate(); + toStrm << " " << lr.GetStartLine() << endl; + } + } + else { toStrm << "INT_TIME " << intTime << endl; + } toStrm << "\nALONG_SCAN_PIXEL_SIZE " << alongScanPxSize << endl; toStrm << "CROSS_SCAN_PIXEL_SIZE " << crossScanPxSize << endl; @@ -859,142 +850,137 @@ void socetlinescankeywords(Cube *input, UserInterface &ui) { } // end main -//TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS -//int GetHRSCLineRates(Cube *cube, vector &lineRates, -// int &dtotalLines, double &HRSCNadirCenterTime) { -// -// FileName cubefname = cube->fileName(); -// FileName tablefname = FileName(cubefname.path() + "/tabledump.txt"); -// -// // system call to ISIS function tabledump to dump LineScanTimes -// char syscmd[1056]; -// sprintf(syscmd, "tabledump from=%s to=%s name=LineScanTimes", -// cubefname.expanded().toLatin1().data(), tablefname.expanded().toAscii().data()); -// -// int n = system(syscmd); -// if (n != 0) -// return -1; -// -// // read table back in. This whole mess is necessary since -// // HrscCamera::ReadLineRates(IString filename) is private -// -// // open tabledump.txt for reading -// ifstream fpIn(tablefname.expanded().toLatin1().data(), ifstream::in); -// if (!fpIn) -// return -1; -// -// Camera *cam = cube->camera(); -// -// char buf[512]; -// -// // read and discard header line -// if (!fpIn.getline(buf, 512)) -// return -1; -// -// double ephemerisTime, exposureTime; -// int lineStart; -// -// // read and store all line rate data -// while (fpIn.getline(buf, 512)) { -// sscanf(buf, "%lf,%lf,%d", &ephemerisTime, &exposureTime, &lineStart); -// lineRates.push_back(LineRateChange(lineStart, ephemerisTime, exposureTime)); -// } -// -// // close file pointer -// fpIn.close(); -// -// // if cube has not been cropped, we're done (if AlphaCube group is -// // present, cube has been cropped) -// bool bIsCropped = cube->hasGroup("AlphaCube"); -// -// if (!bIsCropped) -// return lineRates.size(); -// -// // if cube is cropped, we need to trim the lineRates and map the line -// // numbers to match the cropped image. This is because the lineRates table -// // stores data for the original (alpha) image -// -// // get alpha cube start line -// PvlGroup alphacube = cube->group("AlphaCube"); -// QString str = (QString) alphacube["AlphaStartingLine"]; -// double dAlphaStartLine = atof(str.toLatin1().data()); -// double dAlphaLastLine = dAlphaStartLine + dtotalLines; -// cam->SetImage(1, 0.5); -// double dStartETime = cam->time().Et(); -// double dFirstLineTime = dStartETime - HRSCNadirCenterTime; -// -// if (lineRates.size() == 1) { -// LineRateChange lrc = lineRates.at(0); -// double lsr = lrc.GetLineScanRate(); -// lineRates.erase(lineRates.begin()); -// lineRates.push_back(LineRateChange(1, dFirstLineTime, lsr)); -// return lineRates.size(); -// } -// -// LineRateChange firstlrc(0, 0, 0); -// for (int i = 0; i < int(lineRates.size()); i++) { -// LineRateChange lrc = lineRates.at(i); -// -// int nRateStartLine = lrc.GetStartLine(); -// -// // Line rate is within cropped boundaries, keep it and set the line -// // number to match the cropped image -// if (nRateStartLine >= dAlphaStartLine && nRateStartLine <= dAlphaLastLine) { -// double et = lrc.GetStartEt(); -// double lsr = lrc.GetLineScanRate(); -// int rsl = nRateStartLine - dAlphaStartLine + 1; -// lineRates.erase(lineRates.begin() + i); -// -// lineRates.insert(lineRates.begin() + i, LineRateChange(rsl, et - HRSCNadirCenterTime, lsr)); -// continue; -// } -// -// if (nRateStartLine < dAlphaStartLine) -// firstlrc = lrc; -// -// lineRates.erase(lineRates.begin() + i); -// i--; -// } -// -// // insert first line -// double secondtime = lineRates.at(0).GetStartEt(); -// int secondstartline = lineRates.at(0).GetStartLine(); -// double lsr = firstlrc.GetLineScanRate(); -// double et = secondtime - (secondstartline - 1) * lsr; -// lineRates.insert(lineRates.begin(), LineRateChange(1, et, lsr)); -// -// return lineRates.size(); -// -//} // end GetHRSCLineRates -// -//double GetHRSCScanDuration(vector &lineRates, int &ntotalLines) { -// -// int nLineRates = lineRates.size(); -// if (nLineRates == 1) -// return lineRates.at(0).GetLineScanRate() * ntotalLines; -// -// int nLines; -// double scanTime = 0.0; -// int i = 0; -// int nLastLine = lineRates.at(0).GetStartLine() + ntotalLines - 1; -// do { -// LineRateChange lrc1 = lineRates.at(i); -// LineRateChange lrc2 = lineRates.at(i + 1); -// -// nLines = lrc2.GetStartLine() - lrc1.GetStartLine(); -// scanTime += lrc1.GetLineScanRate() * (double)nLines; -// -// i++; -// -// } while (int i < (nLineRates - 1)); -// -// // add in last interval -// LineRateChange lrc = lineRates.at(nLineRates - 1); -// nLines = nLastLine - lrc.GetStartLine() + 1; -// -// scanTime += lrc.GetLineScanRate() * (double)nLines; -// -// return scanTime; -// -//} // end GetHRSCScanDuration -} + int GetHRSCLineRates(Cube *cube, vector &lineRates, + int &dtotalLines, double &HRSCNadirCenterTime) { + FileName cubefname = cube->fileName(); + QTemporaryDir prefix; + FileName tablefname = FileName(prefix.path() + "/tabledump.txt"); + + // system call to ISIS function tabledump to dump LineScanTimes + char syscmd[1056]; + snprintf(syscmd, sizeof(syscmd), "tabledump from=%s to=%s name=LineScanTimes", + cubefname.expanded().toLatin1().data(), tablefname.expanded().toLatin1().data()); + + + int n = system(syscmd); + if (n != 0) return -1; + + // read table back in. This whole mess is necessary since + // HrscCamera::ReadLineRates(IString filename) is private + + // open tabledump.txt for reading + ifstream fpIn(tablefname.expanded().toLatin1().data(), ifstream::in); + if (!fpIn) return -1; + + Camera *cam = cube->camera(); + + char buf[512]; + + // read and discard header line + if (!fpIn.getline(buf, 512)) return -1; + + double ephemerisTime, exposureTime; + int lineStart; + + // read and store all line rate data + while (fpIn.getline(buf, 512)) { + sscanf(buf, "%lf,%lf,%d", &ephemerisTime, &exposureTime, &lineStart); + lineRates.push_back(LineRateChange(lineStart, ephemerisTime, exposureTime)); + } + + // close file pointer + fpIn.close(); + + // if cube has not been cropped, we're done (if AlphaCube group is + // present, cube has been cropped) + bool bIsCropped = cube->hasGroup("AlphaCube"); + + if (!bIsCropped) return lineRates.size(); + + // if cube is cropped, we need to trim the lineRates and map the line + // numbers to match the cropped image. This is because the lineRates table + // stores data for the original (alpha) image + + // get alpha cube start line + PvlGroup alphacube = cube->group("AlphaCube"); + QString str = (QString)alphacube["AlphaStartingLine"]; + double dAlphaStartLine = atof(str.toLatin1().data()); + double dAlphaLastLine = dAlphaStartLine + dtotalLines; + cam->SetImage(1, 0.5); + double dStartETime = cam->time().Et(); + double dFirstLineTime = dStartETime - HRSCNadirCenterTime; + + if (lineRates.size() == 1) { + LineRateChange lrc = lineRates.at(0); + double lsr = lrc.GetLineScanRate(); + lineRates.erase(lineRates.begin()); + lineRates.push_back(LineRateChange(1, dFirstLineTime, lsr)); + return lineRates.size(); + } + + LineRateChange firstlrc(0, 0, 0); + for (int i = 0; i < int(lineRates.size()); i++) { + LineRateChange lrc = lineRates.at(i); + + int nRateStartLine = lrc.GetStartLine(); + + // Line rate is within cropped boundaries, keep it and set the line + // number to match the cropped image + if (nRateStartLine >= dAlphaStartLine && nRateStartLine <= dAlphaLastLine) { + double et = lrc.GetStartEt(); + double lsr = lrc.GetLineScanRate(); + int rsl = nRateStartLine - dAlphaStartLine + 1; + lineRates.erase(lineRates.begin() + i); + + lineRates.insert(lineRates.begin() + i, + LineRateChange(rsl, et - HRSCNadirCenterTime, lsr)); + continue; + } + + if (nRateStartLine < dAlphaStartLine) firstlrc = lrc; + + lineRates.erase(lineRates.begin() + i); + i--; + } + + // insert first line + double secondtime = lineRates.at(0).GetStartEt(); + int secondstartline = lineRates.at(0).GetStartLine(); + double lsr = firstlrc.GetLineScanRate(); + double et = secondtime - (secondstartline - 1) * lsr; + lineRates.insert(lineRates.begin(), LineRateChange(1, et, lsr)); + + return lineRates.size(); + + } // end GetHRSCLineRates + + double GetHRSCScanDuration(vector &lineRates, + int &ntotalLines) { + int nLineRates = lineRates.size(); + if (nLineRates == 1) return lineRates.at(0).GetLineScanRate() * ntotalLines; + + int nLines; + double scanTime = 0.0; + int i = 0; + int nLastLine = lineRates.at(0).GetStartLine() + ntotalLines - 1; + do { + LineRateChange lrc1 = lineRates.at(i); + LineRateChange lrc2 = lineRates.at(i + 1); + + nLines = lrc2.GetStartLine() - lrc1.GetStartLine(); + scanTime += lrc1.GetLineScanRate() * (double)nLines; + + i++; + + } while (i < (nLineRates - 1)); + + // add in last interval + LineRateChange lrc = lineRates.at(nLineRates - 1); + nLines = nLastLine - lrc.GetStartLine() + 1; + + scanTime += lrc.GetLineScanRate() * (double)nLines; + + return scanTime; + + } // end GetHRSCScanDuration +} // namespace Isis diff --git a/isis/src/socet/apps/socetlinescankeywords/socetlinescankeywords.xml b/isis/src/socet/apps/socetlinescankeywords/socetlinescankeywords.xml index 6c563fdc76..2b296e5108 100644 --- a/isis/src/socet/apps/socetlinescankeywords/socetlinescankeywords.xml +++ b/isis/src/socet/apps/socetlinescankeywords/socetlinescankeywords.xml @@ -24,9 +24,9 @@ MRO-CTX LRO-NACL LRO-NACR - @@ -110,8 +110,6 @@ - + diff --git a/isis/tests/FunctionalTestsSocetlinescankeywords.cpp b/isis/tests/FunctionalTestsSocetlinescankeywords.cpp index 0caa2c81bc..8974ebc8a8 100644 --- a/isis/tests/FunctionalTestsSocetlinescankeywords.cpp +++ b/isis/tests/FunctionalTestsSocetlinescankeywords.cpp @@ -36,7 +36,7 @@ TEST_F(MroHiriseCube, FunctionalTestSocetlinescankeywordsHirise) { contents = bo.read(bo.size()); } else { - FAIL() << "Failed to open bundleout.txt" << std::endl; + FAIL() << "Failed to open SOCET Set support file" << std::endl; } QStringList lines = contents.split("\n"); @@ -146,3 +146,96 @@ TEST_F(DefaultCube, FunctionalTestSocetlinescankeywordsNoBlob) { EXPECT_THAT(e.what(), HasSubstr("Input image does not contain needed SPICE blobs...run spiceinit with attach=yes"));; } } + + +TEST(Socetlinescankeywords, FunctionalTestSocetlinescankeywordsHRSC) { + QTemporaryDir prefix; + QString outFileName = prefix.path() + "/outTEMP.txt"; + QVector args = {"from=data/socet/h2254_0000_s12-cropped.cub", "to="+outFileName}; + + UserInterface options(APP_XML, args); + + try { + socetlinescankeywords(options); + } + catch (IException &e) { + FAIL() << "Call failed, Unable to process cube: " << e.what() << std::endl; + } + + QFile bo(outFileName); + QString contents; + + if (bo.open(QIODevice::ReadOnly)) { + contents = bo.read(bo.size()); + } + else { + FAIL() << "Failed to open SOCET Set support file" << std::endl; + } + + QStringList lines = contents.split("\n"); + + QStringList line = lines[3].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "GROUND_ZERO"); + EXPECT_NEAR(line[1].toDouble(), -1.23270191076522, 0.0001); + EXPECT_NEAR(line[2].toDouble(), 0.866560982464329, 0.0001); + EXPECT_NEAR(line[3].toDouble(), 0, 0.0001); + + line = lines[7].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "SENSOR_TYPE"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[1], "USGSAstroLineScanner"); + + line = lines[23].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "DT_EPHEM"); + EXPECT_NEAR(line[1].toDouble(), 2.2755849626328889662163490e-02, 0.0001); + + line = lines[24].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "T0_EPHEM"); + EXPECT_NEAR(line[1].toDouble(), 1.8268123272588416934013367e+08, 0.0001); + line = lines[25].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "NUMBER_OF_EPHEM"); + EXPECT_EQ(line[1].toInt(), 65); + + line = lines[162].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "DT_QUAT"); + EXPECT_NEAR(line[1].toDouble(), 5.3392420521653889090452766e-05, 0.0001); + + line = lines[163].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "T0_QUAT"); + EXPECT_NEAR(line[1].toDouble(), -5.1251384615898132324218750e-01, 0.0001); + + line = lines[164].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "NUMBER_OF_QUATERNIONS"); + EXPECT_EQ(line[1].toInt(), 19199); + + line = lines[19375].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "CENTER_GP"); + EXPECT_NEAR(line[1].toDouble(), -1.2327019107652188445456432, 0.0001); + EXPECT_NEAR(line[2].toDouble(), 8.6656098246432888831947139e-01, 0.0001); + EXPECT_NEAR(line[3].toDouble(), 0, 0.0001); + + // check some interior orientation stuff + line = lines[19385].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "IKCODE"); + EXPECT_EQ(line[1].toInt(), -41219); + + line = lines[19386].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "ISIS_Z_DIRECTION"); + EXPECT_NEAR(line[1].toDouble(), 1, 0.0001); + + line = lines[19388].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "ITRANSS"); + EXPECT_NEAR(line[1].toDouble(), -6.8139200054785997728856728e-01, 0.001); + EXPECT_NEAR(line[2].toDouble(), -1.4285712640235999515425647e+02, 0.001); + EXPECT_NEAR(line[3].toDouble(), 6.8566503695772995641277703e-02, 0.001); + + line = lines[19389].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "ITRANSL"); + EXPECT_NEAR(line[1].toDouble(), -8.5695561557859000458847731e+03, 0.001); + EXPECT_NEAR(line[2].toDouble(), 6.8566503695772995641277703e-02, 0.001); + EXPECT_NEAR(line[3].toDouble(), 1.4285712640235999515425647e+02, 0.001); + + line = lines[19396].split(QRegExp("\\s+"), Qt::SkipEmptyParts); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, line[0], "STARTING_EPHEMERIS_TIME"); + EXPECT_NEAR(line[1].toDouble(), 1.8268123294718480110168457e+08, 0.0001); +} diff --git a/isis/tests/data/socet/h2254_0000_s12-cropped.cub b/isis/tests/data/socet/h2254_0000_s12-cropped.cub new file mode 100644 index 0000000000..489a833443 Binary files /dev/null and b/isis/tests/data/socet/h2254_0000_s12-cropped.cub differ