diff --git a/isis/src/base/apps/camstats/camstats.cpp b/isis/src/base/apps/camstats/camstats.cpp new file mode 100644 index 0000000000000000000000000000000000000000..18d7635a8194c1652e9dcdafa0d81a2b9ceea24e --- /dev/null +++ b/isis/src/base/apps/camstats/camstats.cpp @@ -0,0 +1,227 @@ + +#include "camstats.h" +#include "Camera.h" +#include "CameraStatistics.h" +#include "Cube.h" +#include "Distance.h" +#include "IString.h" +#include "UserInterface.h" +#include "Process.h" +#include "Progress.h" +#include "Statistics.h" + + +using namespace std; +using namespace Isis; + +namespace Isis { + //function to build stats data + void buildStats(Camera *cam, int &sample, int &line); + void writeFlat(ofstream &os, const Statistics *s); + string valueToString(const double &value); + + /** + * Outputs camera statistics for a cube specified in ui parameters. + * + * @param ui UserInterface object containing camstats parameters + * @param(out) log the Pvl that camstat results log to + */ + void camstats(UserInterface &ui, Pvl *log) { + Process p; + + CubeAttributeInput cai; + Cube *icube = p.SetInputCube(ui.GetFileName("FROM"), cai, ReadWrite); + camstats(icube, ui, log); + + p.EndProcess(); + } + + + void camstats(Cube *icube, UserInterface &ui, Pvl *log) { + Process p; + p.SetInputCube(icube); + Camera *cam = icube->camera(); + + + QString from = icube->fileName(); + int sinc = ui.GetInteger("SINC"); + int linc = ui.GetInteger("LINC"); + CameraStatistics camStats(cam, sinc, linc, from); + + // Send the Output to the log area + Pvl statsPvl = camStats.toPvl(); + for (int i = 0; i < statsPvl.groups(); i++) { + log->addGroup(statsPvl.group(i)); + } + + if(ui.WasEntered("TO")) { + QString outfile = FileName(ui.GetFileName("TO")).expanded(); + bool exists = FileName(outfile).fileExists(); + bool append = ui.GetBoolean("APPEND"); + + // If the user chose a format of PVL, then write to the output file ("TO") + if(ui.GetString("FORMAT") == "PVL") { + (append) ? statsPvl.append(outfile) : statsPvl.write(outfile); + } + else { + // Create a flatfile of the data with columhn headings the flatfile is + // comma-delimited and can be imported in to spreadsheets + ofstream os; + bool writeHeader = true; + if(append) { + os.open(outfile.toLatin1().data(), ios::app); + if(exists) { + writeHeader = false; + } + } + else { + os.open(outfile.toLatin1().data(), ios::out); + } + + // if new file or append and no file exists then write header + if(writeHeader) { + os << "Filename," << + "LatitudeMinimum," << + "LatitudeMaximum," << + "LatitudeAverage," << + "LatitudeStandardDeviation," << + "LongitudeMinimum," << + "LongitudeMaximum," << + "LongitudeAverage," << + "LongitudeStandardDeviation," << + "SampleResolutionMinimum," << + "SampleResolutionMaximum," << + "SampleResolutionAverage," << + "SampleResolutionStandardDeviation," << + "LineResolutionMinimum," << + "LineResolutionMaximum," << + "LineResolutionAverage," << + "LineResolutionStandardDeviation," << + "ResolutionMinimum," << + "ResolutionMaximum," << + "ResolutionAverage," << + "ResolutionStandardDeviation," << + "AspectRatioMinimum," << + "AspectRatioMaximum," << + "AspectRatioAverage," << + "AspectRatioStandardDeviation," << + "PhaseMinimum," << + "PhaseMaximum," << + "PhaseAverage," << + "PhaseStandardDeviation," << + "EmissionMinimum," << + "EmissionMaximum," << + "EmissionAverage," << + "EmissionStandardDeviation," << + "IncidenceMinimum," << + "IncidenceMaximum," << + "IncidenceAverage," << + "IncidenceStandardDeviation," << + "LocalSolarTimeMinimum," << + "LocalSolarTimeMaximum," << + "LocalSolarTimeAverage," << + "LocalSolarTimeStandardDeviation," << + "LocalRadiusMaximum," << + "LocalRadiusMaximum," << + "LocalRadiusAverage," << + "LocalRadiusStandardDeviation," << + "NorthAzimuthMinimum," << + "NorthAzimuthMaximum," << + "NorthAzimuthAverage," << + "NorthAzimuthStandardDeviation," << + "ObliqueResolutionMinimum," << + "ObliqueResolutionMaximum," << + "ObliqueResolutionAverage," << + "ObliqueResolutionStandardDeviation," << + "ObliqueLineResolutionMinimum," << + "ObliqueLineResolutionMaximum," << + "ObliqueLineResolutionAverage," << + "ObliqueLineResolutionStandardDeviation," << + "ObliqueSampleResolutionMinimum," << + "ObliqueSampleResolutionMaximum," << + "ObliqueSampleResolutionAverage," << + "ObliqueSampleResolutionStandardDeviation," << endl; + + + } + os << FileName(from).expanded() << ","; + //call the function to write out the values for each group + writeFlat(os, camStats.getLatStat()); + writeFlat(os, camStats.getLonStat()); + writeFlat(os, camStats.getSampleResStat()); + writeFlat(os, camStats.getLineResStat()); + writeFlat(os, camStats.getResStat()); + writeFlat(os, camStats.getAspectRatioStat()); + writeFlat(os, camStats.getPhaseStat()); + writeFlat(os, camStats.getEmissionStat()); + writeFlat(os, camStats.getIncidenceStat()); + writeFlat(os, camStats.getLocalSolarTimeStat()); + writeFlat(os, camStats.getLocalRaduisStat()); + writeFlat(os, camStats.getNorthAzimuthStat()); + writeFlat(os,camStats.getObliqueResStat()); + writeFlat(os,camStats.getObliqueLineResStat()); + writeFlat(os,camStats.getObliqueSampleResStat()); + os << endl; + } + } + + if(ui.GetBoolean("ATTACH")) { + QString cam_name = "CameraStatistics"; + + //Creates new CameraStatistics Table + TableField fname("Name", Isis::TableField::Text, 45); + TableField fmin("Minimum", Isis::TableField::Double); + TableField fmax("Maximum", Isis::TableField::Double); + TableField favg("Average", Isis::TableField::Double); + TableField fstd("StandardDeviation", Isis::TableField::Double); + + TableRecord record; + record += fname; + record += fmin; + record += fmax; + record += favg; + record += fstd; + + Table table(cam_name, record); + + // Place all the gathered camera statistics in a table and attach it to the + // cube. Skip "User Parameters" group. + for (int i = 1; i < statsPvl.groups(); i++) { + PvlGroup &group = statsPvl.group(i); + + int entry = 0; + record[entry] = group.name(); + entry++; + for (int j = 0; j < group.keywords(); j++) { + record[entry] = toDouble(group[j][0]); + entry++; + } + table += record; + } + + icube->reopen("rw"); + icube->write(table); + p.WriteHistory(*icube); + icube->close(); + } + } + + + //function to write the stats values to flat file + void writeFlat(ofstream &os, const Statistics *s) { + os << valueToString(s->Minimum()) << "," << + valueToString(s->Maximum()) << "," << + valueToString(s->Average()) << "," << + valueToString(s->StandardDeviation()) << ","; + } + + + string valueToString(const double &value) { + if(IsSpecial(value)) { + return (string("NULL")); + } + else { + return ((string) IString(value)); + } + } +} diff --git a/isis/src/base/apps/camstats/camstats.h b/isis/src/base/apps/camstats/camstats.h new file mode 100644 index 0000000000000000000000000000000000000000..87c752bfa33bb8568acf210205340a786dbf0242 --- /dev/null +++ b/isis/src/base/apps/camstats/camstats.h @@ -0,0 +1,12 @@ +#ifndef camstats_h +#define camstats_h + +#include "Pvl.h" +#include "UserInterface.h" + +namespace Isis{ + extern void camstats(UserInterface &ui, Pvl *log); + extern void camstats(Cube *icube, UserInterface &ui, Pvl *log); +} + +#endif diff --git a/isis/src/base/apps/camstats/main.cpp b/isis/src/base/apps/camstats/main.cpp index dbdb39781b69c11630b81214389733705eeebf65..9dce94473924462ef805333f14afeaf33246bf76 100644 --- a/isis/src/base/apps/camstats/main.cpp +++ b/isis/src/base/apps/camstats/main.cpp @@ -1,211 +1,27 @@ #include "Isis.h" -#include "Camera.h" -#include "CameraStatistics.h" -#include "Cube.h" -#include "Distance.h" -#include "IString.h" -#include "UserInterface.h" -#include "Process.h" -#include "Progress.h" -#include "Statistics.h" +#include "camstats.h" +#include "Application.h" +#include "Pvl.h" using namespace std; using namespace Isis; -//function to build stats data -void buildStats(Camera *cam, int &sample, int &line); -void writeFlat(ofstream &os, const Statistics *s); -string valueToString(const double &value); - - void IsisMain() { - Process p; - Cube *icube = p.SetInputCube("FROM"); - Camera *cam = icube->camera(); - UserInterface &ui = Application::GetUserInterface(); - - QString from = ui.GetFileName("FROM"); - int sinc = ui.GetInteger("SINC"); - int linc = ui.GetInteger("LINC"); - CameraStatistics camStats(cam, sinc, linc, from); - - // Send the Output to the log area - Pvl statsPvl = camStats.toPvl(); - for (int i = 0; i < statsPvl.groups(); i++) { - Application::Log(statsPvl.group(i)); + Pvl appLog; + try { + camstats(ui, &appLog); } - - if(ui.WasEntered("TO")) { - QString outfile = FileName(ui.GetFileName("TO")).expanded(); - bool exists = FileName(outfile).fileExists(); - bool append = ui.GetBoolean("APPEND"); - - // If the user chose a format of PVL, then write to the output file ("TO") - if(ui.GetString("FORMAT") == "PVL") { - (append) ? statsPvl.append(outfile) : statsPvl.write(outfile); - } - else { - // Create a flatfile of the data with columhn headings the flatfile is - // comma-delimited and can be imported in to spreadsheets - ofstream os; - bool writeHeader = true; - if(append) { - os.open(outfile.toLatin1().data(), ios::app); - if(exists) { - writeHeader = false; - } - } - else { - os.open(outfile.toLatin1().data(), ios::out); - } - - // if new file or append and no file exists then write header - if(writeHeader) { - os << "Filename," << - "LatitudeMinimum," << - "LatitudeMaximum," << - "LatitudeAverage," << - "LatitudeStandardDeviation," << - "LongitudeMinimum," << - "LongitudeMaximum," << - "LongitudeAverage," << - "LongitudeStandardDeviation," << - "SampleResolutionMinimum," << - "SampleResolutionMaximum," << - "SampleResolutionAverage," << - "SampleResolutionStandardDeviation," << - "LineResolutionMinimum," << - "LineResolutionMaximum," << - "LineResolutionAverage," << - "LineResolutionStandardDeviation," << - "ResolutionMinimum," << - "ResolutionMaximum," << - "ResolutionAverage," << - "ResolutionStandardDeviation," << - "AspectRatioMinimum," << - "AspectRatioMaximum," << - "AspectRatioAverage," << - "AspectRatioStandardDeviation," << - "PhaseMinimum," << - "PhaseMaximum," << - "PhaseAverage," << - "PhaseStandardDeviation," << - "EmissionMinimum," << - "EmissionMaximum," << - "EmissionAverage," << - "EmissionStandardDeviation," << - "IncidenceMinimum," << - "IncidenceMaximum," << - "IncidenceAverage," << - "IncidenceStandardDeviation," << - "LocalSolarTimeMinimum," << - "LocalSolarTimeMaximum," << - "LocalSolarTimeAverage," << - "LocalSolarTimeStandardDeviation," << - "LocalRadiusMaximum," << - "LocalRadiusMaximum," << - "LocalRadiusAverage," << - "LocalRadiusStandardDeviation," << - "NorthAzimuthMinimum," << - "NorthAzimuthMaximum," << - "NorthAzimuthAverage," << - "NorthAzimuthStandardDeviation," << - "ObliqueResolutionMinimum," << - "ObliqueResolutionMaximum," << - "ObliqueResolutionAverage," << - "ObliqueResolutionStandardDeviation," << - "ObliqueLineResolutionMinimum," << - "ObliqueLineResolutionMaximum," << - "ObliqueLineResolutionAverage," << - "ObliqueLineResolutionStandardDeviation," << - "ObliqueSampleResolutionMinimum," << - "ObliqueSampleResolutionMaximum," << - "ObliqueSampleResolutionAverage," << - "ObliqueSampleResolutionStandardDeviation," << endl; - - - } - os << FileName(from).expanded() << ","; - //call the function to write out the values for each group - writeFlat(os, camStats.getLatStat()); - writeFlat(os, camStats.getLonStat()); - writeFlat(os, camStats.getSampleResStat()); - writeFlat(os, camStats.getLineResStat()); - writeFlat(os, camStats.getResStat()); - writeFlat(os, camStats.getAspectRatioStat()); - writeFlat(os, camStats.getPhaseStat()); - writeFlat(os, camStats.getEmissionStat()); - writeFlat(os, camStats.getIncidenceStat()); - writeFlat(os, camStats.getLocalSolarTimeStat()); - writeFlat(os, camStats.getLocalRaduisStat()); - writeFlat(os, camStats.getNorthAzimuthStat()); - writeFlat(os,camStats.getObliqueResStat()); - writeFlat(os,camStats.getObliqueLineResStat()); - writeFlat(os,camStats.getObliqueSampleResStat()); - os << endl; + catch (...) { + for (auto grpIt = appLog.beginGroup(); grpIt!= appLog.endGroup(); grpIt++) { + Application::Log(*grpIt); } + throw; } - if(ui.GetBoolean("ATTACH")) { - - QString cam_name = "CameraStatistics"; - - //Creates new CameraStatistics Table - TableField fname("Name", Isis::TableField::Text, 45); - TableField fmin("Minimum", Isis::TableField::Double); - TableField fmax("Maximum", Isis::TableField::Double); - TableField favg("Average", Isis::TableField::Double); - TableField fstd("StandardDeviation", Isis::TableField::Double); - - TableRecord record; - record += fname; - record += fmin; - record += fmax; - record += favg; - record += fstd; - - Table table(cam_name, record); - - // Place all the gathered camera statistics in a table and attach it to the - // cube. Skip "User Parameters" group. - for (int i = 1; i < statsPvl.groups(); i++) { - PvlGroup &group = statsPvl.group(i); - - int entry = 0; - record[entry] = group.name(); - entry++; - for (int j = 0; j < group.keywords(); j++) { - record[entry] = toDouble(group[j][0]); - entry++; - } - table += record; - } - - icube->reopen("rw"); - icube->write(table); - p.WriteHistory(*icube); - icube->close(); - } -} - - -//function to write the stats values to flat file -void writeFlat(ofstream &os, const Statistics *s) { - os << valueToString(s->Minimum()) << "," << - valueToString(s->Maximum()) << "," << - valueToString(s->Average()) << "," << - valueToString(s->StandardDeviation()) << ","; -} - - -string valueToString(const double &value) { - if(IsSpecial(value)) { - return (string("NULL")); - } - else { - return ((string) IString(value)); + for (auto grpIt = appLog.beginGroup(); grpIt!= appLog.endGroup(); grpIt++) { + Application::Log(*grpIt); } } diff --git a/isis/src/base/apps/camstats/tsts/default/Makefile b/isis/src/base/apps/camstats/tsts/default/Makefile deleted file mode 100644 index 2943d9690c7084b30684fb56768f495282d2188a..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/camstats/tsts/default/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -APPNAME = camstats - -include $(ISISROOT)/make/isismake.tsts - -commands: - $(APPNAME) FROM=$(INPUT)/input.cub TO=$(OUTPUT)/output.pvl > /dev/null; - $(CP) $(INPUT)/input.cub $(OUTPUT)/attached.cub; - $(APPNAME) FROM=$(OUTPUT)/attached.cub ATTACH=true > /dev/null; diff --git a/isis/src/base/objs/CameraStatistics/CameraStatistics.cpp b/isis/src/base/objs/CameraStatistics/CameraStatistics.cpp index a99a427cdea426fcc82fe3d55b2a745c2fa77326..a9f3f2fcb4c25752ce22b2269c0a88aca7e86952 100644 --- a/isis/src/base/objs/CameraStatistics/CameraStatistics.cpp +++ b/isis/src/base/objs/CameraStatistics/CameraStatistics.cpp @@ -441,6 +441,7 @@ namespace Isis { PvlGroup pAspectRatio("AspectRatio"); pAspectRatio += constructKeyword("AspectRatioMinimum", m_aspectRatioStat->Minimum()); + // Note: Maximum is spelled wrong here. pAspectRatio += constructKeyword("AspectRatioMaximun", m_aspectRatioStat->Maximum()); pAspectRatio += constructKeyword("AspectRatioAverage", m_aspectRatioStat->Average()); pAspectRatio += constructKeyword("AspectRatioStandardDeviation", @@ -513,4 +514,3 @@ namespace Isis { return returnPvl; } } - diff --git a/isis/tests/FunctionalTestsCamstats.cpp b/isis/tests/FunctionalTestsCamstats.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6794f654d018d2e351934b86ee6f308ea5d42c5f --- /dev/null +++ b/isis/tests/FunctionalTestsCamstats.cpp @@ -0,0 +1,154 @@ +#include +#include + +#include "camstats.h" +#include "Fixtures.h" +#include "Pvl.h" +#include "PvlGroup.h" +#include "TestUtilities.h" + + +using namespace Isis; + +static QString APP_XML = FileName("$ISISROOT/bin/xml/camstats.xml").expanded(); + +TEST_F(DefaultCube, FunctionalTestCamstatsDefaultParameters) { + QVector args = {}; + UserInterface options(APP_XML, args); + Pvl appLog; + + camstats(testCube, options, &appLog); + + PvlGroup group = appLog.findGroup("User Parameters"); + EXPECT_DOUBLE_EQ((double) group.findKeyword("Linc"), 1.0); + EXPECT_DOUBLE_EQ((double) group.findKeyword("Sinc"), 1.0); + + group = appLog.findGroup("Latitude"); + EXPECT_NEAR( (double) group.findKeyword("LatitudeMinimum"), 9.928647987, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LatitudeMaximum"), 10.434709753, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LatitudeAverage"), 10.181983206, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LatitudeStandardDeviation"), 0.110841027, 1e-8); + + group = appLog.findGroup("Longitude"); + EXPECT_NEAR( (double) group.findKeyword("LongitudeMinimum"), 255.645548718, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LongitudeMaximum"), 256.146069525, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LongitudeAverage"), 255.893904910, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LongitudeStandardDeviation"), 0.106583304, 1e-8); + + group = appLog.findGroup("SampleResolution"); + EXPECT_NEAR( (double) group.findKeyword("SampleResolutionMinimum"), 18.840683425, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("SampleResolutionMaximum"), 18.985953877, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("SampleResolutionAverage"), 18.908165593, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("SampleResolutionStandardDeviation"), 0.038060007, 1e-8); + + group = appLog.findGroup("LineResolution"); + EXPECT_NEAR( (double) group.findKeyword("LineResolutionMinimum"), 18.840683425, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LineResolutionMaximum"), 18.985953877, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LineResolutionAverage"), 18.908165593, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LineResolutionStandardDeviation"), 0.038060007, 1e-8); + + group = appLog.findGroup("Resolution"); + EXPECT_NEAR( (double) group.findKeyword("ResolutionMinimum"), 18.840683425, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ResolutionMaximum"), 18.985953877, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ResolutionAverage"), 18.908165593, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ResolutionStandardDeviation"), 0.038060007, 1e-8); + + group = appLog.findGroup("ObliqueSampleResolution"); + EXPECT_NEAR( (double) group.findKeyword("ObliqueSampleResolutionMinimum"), 19.180671135, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ObliqueSampleResolutionMaximum"), 19.525658668, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ObliqueSampleResolutionAverage"), 19.342626220, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ObliqueSampleResolutionStandardDeviation"), 0.078013435, 1e-8); + + group = appLog.findGroup("ObliqueLineResolution"); + EXPECT_NEAR( (double) group.findKeyword("ObliqueLineResolutionMinimum"), 19.180671135, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ObliqueLineResolutionMaximum"), 19.525658668, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ObliqueLineResolutionAverage"), 19.342626220, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ObliqueLineResolutionStandardDeviation"), 0.078013435, 1e-8); + + group = appLog.findGroup("ObliqueResolution"); + EXPECT_NEAR( (double) group.findKeyword("ObliqueResolutionMinimum"), 19.180671135, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ObliqueResolutionMaximum"), 19.525658668, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ObliqueResolutionAverage"), 19.342626220, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("ObliqueResolutionStandardDeviation"), 0.078013435, 1e-8); + + group = appLog.findGroup("AspectRatio"); + EXPECT_DOUBLE_EQ( (double) group.findKeyword("AspectRatioMinimum"), 1.0); + // Maximum spelled incorrectly to match misspelling in CameraStatistics.cpp + EXPECT_DOUBLE_EQ( (double) group.findKeyword("AspectRatioMaximun"), 1.0); + EXPECT_DOUBLE_EQ( (double) group.findKeyword("AspectRatioAverage"), 1.0); + EXPECT_DOUBLE_EQ( (double) group.findKeyword("AspectRatioStandardDeviation"), 0.0); + + group = appLog.findGroup("PhaseAngle"); + EXPECT_NEAR( (double) group.findKeyword("PhaseMinimum"), 79.756143590, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("PhaseMaximum"), 81.304900313, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("PhaseAverage"), 80.529097153, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("PhaseStandardDeviation"), 0.444208612, 1e-8); + + group = appLog.findGroup("EmissionAngle"); + EXPECT_NEAR( (double) group.findKeyword("EmissionMinimum"), 10.798462835, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("EmissionMaximum"), 13.502630463, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("EmissionAverage"), 12.15148695101, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("EmissionStandardDeviation"), 0.565437913, 1e-8); + + group = appLog.findGroup("IncidenceAngle"); + EXPECT_NEAR( (double) group.findKeyword("IncidenceMinimum"), 69.941096124, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("IncidenceMaximum"), 70.311944975, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("IncidenceAverage"), 70.127459134, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("IncidenceStandardDeviation"), 0.102490391, 1e-8); + + group = appLog.findGroup("LocalSolarTime"); + EXPECT_NEAR( (double) group.findKeyword("LocalSolarTimeMinimum"), 7.7698055422, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LocalSolarTimeMaximum"), 7.8031735959, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LocalSolarTimeAverage"), 7.7863626216, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LocalSolarTimeStandardDeviation"), 0.007105554, 1e-8); + + group = appLog.findGroup("LocalRadius"); + EXPECT_NEAR( (double) group.findKeyword("LocalRadiusMinimum"), 3410663.3374636001, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LocalRadiusMaximum"), 3413492.0662691998, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LocalRadiusAverage"), 3412205.8144924999, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("LocalRadiusStandardDeviation"), 648.5763070953, 1e-8); + + group = appLog.findGroup("NorthAzimuth"); + EXPECT_NEAR( (double) group.findKeyword("NorthAzimuthMinimum"), 312.299406589, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("NorthAzimuthMaximum"), 350.597812506, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("NorthAzimuthAverage"), 332.967661510, 1e-8); + EXPECT_NEAR( (double) group.findKeyword("NorthAzimuthStandardDeviation"), 0.673831891, 1e-8); +} + +TEST_F(DefaultCube, FunctionalTestCamstatsAttach) { + QVector args = {"attach=true", "linc=100", "sinc=100"}; + UserInterface options(APP_XML, args); + Pvl appLog; + + camstats(testCube, options, &appLog); + + testCube->open(testCube->fileName(), "r"); + EXPECT_TRUE(testCube->hasTable("CameraStatistics")); +} + +TEST_F(DefaultCube, FunctionalTestCamstatsFlat) { + QTemporaryFile flatFile; + flatFile.open(); + QVector args = {"to=" + flatFile.fileName(), "format=flat", "linc=100", "sinc=100"}; + UserInterface options(APP_XML, args); + Pvl appLog; + + camstats(testCube, options, &appLog); + + int lineNumber = 0; + QTextStream flatStream(&flatFile); + while(!flatStream.atEnd()) { + QString line = flatStream.readLine(); + QStringList fields = line.split(","); + + if(lineNumber == 0) { + EXPECT_PRED_FORMAT2(AssertQStringsEqual, fields.value(1), "LatitudeMinimum"); + EXPECT_PRED_FORMAT2(AssertQStringsEqual, fields.value(2), "LatitudeMaximum"); + } + else if(lineNumber == 1) { + EXPECT_NEAR(fields.value(2).toDouble(), 10.434709753, 1e-8); + EXPECT_NEAR(fields.value(1).toDouble(), 9.928647987, 1e-8); + } + lineNumber++; + } +}