diff --git a/CHANGELOG.md b/CHANGELOG.md index 71e3cb372f154920e2959e05cb8ce32484c14265..296ae88776e4bcda8e706a7c142cd2927f39950c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ release. - Added an optional cubename parameter to tgocassisstitch which lets the user override the timestamp style naming convention of the output cube with their own name; if not specified retains existing behavior [#5125](https://github.com/USGS-Astrogeology/ISIS3/issues/5162) +- Added new parameters ONERROR, ERRORLOG, and ERRORLIST to mosrange to provide better control over error behavior and provide diagnostics when problems are encountered processing the input file list.[#3606](https://github.com/DOI-USGS/ISIS3/issues/3606) ### Deprecated diff --git a/isis/src/base/apps/mosrange/main.cpp b/isis/src/base/apps/mosrange/main.cpp index 773237ee357e3943284f2e7e08bf4988e0f2a288..3d947d6b3dde57694f5951a2cf313931d14f409b 100644 --- a/isis/src/base/apps/mosrange/main.cpp +++ b/isis/src/base/apps/mosrange/main.cpp @@ -9,12 +9,16 @@ find files of those names at the top level of this repository. **/ #include "Application.h" #include "Pvl.h" +#include "UserInterface.h" #include "mosrange.h" using namespace Isis; void IsisMain() { UserInterface &ui = Application::GetUserInterface(); - Pvl appLog; - mosrange(ui, &appLog); + Pvl results = mosrange(ui); + + for (int resultIndex = 0; resultIndex < results.groups(); resultIndex++) { + Application::Log(results.group(resultIndex)); + } } diff --git a/isis/src/base/apps/mosrange/mosrange.cpp b/isis/src/base/apps/mosrange/mosrange.cpp index b76e6692dc23bf4499878e57b16cfaff790eef8b..df876e85b1f40279c0ccf824b03239d844d372aa 100644 --- a/isis/src/base/apps/mosrange/mosrange.cpp +++ b/isis/src/base/apps/mosrange/mosrange.cpp @@ -9,10 +9,12 @@ find files of those names at the top level of this repository. **/ #include +#include +#include + #include "Camera.h" #include "Cube.h" #include "Distance.h" -#include "FileList.h" #include "Process.h" #include "Pvl.h" #include "Statistics.h" @@ -67,18 +69,42 @@ namespace Isis { return (localRadius / pixres * pi_c() / 180.0); } - void mosrange(UserInterface &ui, Pvl *log) { - Process p; + /** + * Compute lat/lon range of a set of camera images for mosaicking + * + * @param ui UserInterface object containing parameters + * @return Pvl results log file + */ + Pvl mosrange(UserInterface &ui) { - // Get the list of names of input CCD cubes to stitch together - FileList flist; - flist.read(ui.GetFileName("FROMLIST")); - if(flist.size() < 1) { + // Get the list of names of input cubes to stitch together + FileList cubeFileList; + cubeFileList.read(ui.GetFileName("FROMLIST")); + + return mosrange(cubeFileList, ui); + } + + + /** + * Compute lat/lon range of a set of camera images for mosaicking + * + * @param FileList List of cube filenames + * @return Pvl results log file + * + * @throws IException::User "The list file [FILENAME] does not contain any filenames" + * @throws IException::User "--> Fatal Errors Encountered <___ [FILENAMES]" + * @throws IException::User "Unable to open/create error list file [FILENAME]" + */ + Pvl mosrange(FileList &cubeFileList, UserInterface &ui) { + if ( cubeFileList.size() < 1) { QString msg = "The list file[" + ui.GetFileName("FROMLIST") + " does not contain any filenames"; throw IException(IException::User, msg, _FILEINFO_); } + Pvl log; + Process p; + QString projection("Equirectangular"); if(ui.WasEntered("MAP")) { Pvl mapfile(ui.GetFileName("MAP")); @@ -100,149 +126,156 @@ namespace Isis { londir = (londir == "POSITIVEEAST") ? "PositiveEast" : "PositiveWest"; Progress prog; - prog.SetMaximumSteps(flist.size()); + prog.SetMaximumSteps(cubeFileList.size()); prog.CheckStatus(); Statistics scaleStat; - - Statistics obliqueScaleStat; - Statistics longitudeStat; Statistics latitudeStat; Statistics equiRadStat; Statistics poleRadStat; PvlObject fileset("FileSet"); + PvlObject errorset("ErrorSet"); - // Save major equitorial and polar radii for last occuring + // Save major equitorial and polar radii for last occurring double eqRad; double poleRad; QString target("Unknown"); - for(int i = 0 ; i < flist.size() ; i++) { - try { - // Set the input image, get the camera model, and a basic mapping - // group - Cube cube; - cube.open(flist[i].toString()); - - int lines = cube.lineCount(); - int samples = cube.sampleCount(); - + QList > badfiles; + for(int i = 0 ; i < cubeFileList.size() ; i++) { PvlObject fmap("File"); - fmap += PvlKeyword("Name", flist[i].toString()); - fmap += PvlKeyword("Lines", toString(lines)); - fmap += PvlKeyword("Samples", toString(samples)); - - Camera *cam = cube.camera(); - Pvl mapping; - cam->BasicMapping(mapping); - PvlGroup &mapgrp = mapping.findGroup("Mapping"); - mapgrp.addKeyword(PvlKeyword("ProjectionName", projection), Pvl::Replace); - mapgrp.addKeyword(PvlKeyword("LatitudeType", lattype), Pvl::Replace); - mapgrp.addKeyword(PvlKeyword("LongitudeDirection", londir), Pvl::Replace); - mapgrp.addKeyword(PvlKeyword("LongitudeDomain", londom), Pvl::Replace); - - // Get the radii - Distance radii[3]; - cam->radii(radii); - - eqRad = radii[0].meters(); - poleRad = radii[2].meters(); - - target = cam->target()->name(); - equiRadStat.AddData(&eqRad, 1); - poleRadStat.AddData(&poleRad, 1); - - // Get resolution - double lowres = cam->LowestImageResolution(); - double hires = cam->HighestImageResolution(); - - - double lowObliqueRes = cam->LowestObliqueImageResolution(); - - - - double hiObliqueRes= cam->HighestObliqueImageResolution(); - - - scaleStat.AddData(&hires, 1); - scaleStat.AddData(&lowres, 1); - - - obliqueScaleStat.AddData(&hiObliqueRes,1); - obliqueScaleStat.AddData(&lowObliqueRes,1); - - - double pixres = (lowres + hires) / 2.0; - - - //double obliquePixRes = (lowObliqueRes+hiObliqueRes)/2.0; - - double scale = Scale(pixres, poleRad, eqRad); - - - //double obliqueScale = Scale(obliquePixRes,poleRad,eqRad); - - - mapgrp.addKeyword(PvlKeyword("PixelResolution", toString(pixres)), Pvl::Replace); - - - //mapgrp.addKeyword(PvlKeyword("ObliquePixelResolution", toString(obliquePixRes)), - // Pvl::Replace); - - mapgrp.addKeyword(PvlKeyword("Scale", toString(scale), "pixels/degree"), Pvl::Replace); - - - //mapgrp.addKeyword(PvlKeyword("ObliqueScale", toString(obliqueScale), "pixels/degree"), - // Pvl::Replace); - mapgrp += PvlKeyword("MinPixelResolution", toString(lowres), "meters/pixel"); - mapgrp += PvlKeyword("MaxPixelResolution", toString(hires), "meters/pixel"); - - - mapgrp += PvlKeyword("MinObliquePixelResolution", toString(lowObliqueRes), "meters/pixel"); - mapgrp += PvlKeyword("MaxObliquePixelResolution", toString(hiObliqueRes), "meters/pixel"); - - // Get the universal ground range - double minlat, maxlat, minlon, maxlon; - cam->GroundRange(minlat, maxlat, minlon, maxlon, mapping); - mapgrp.addKeyword(PvlKeyword("MinimumLatitude", toString(minlat)), Pvl::Replace); - mapgrp.addKeyword(PvlKeyword("MaximumLatitude", toString(maxlat)), Pvl::Replace); - mapgrp.addKeyword(PvlKeyword("MinimumLongitude", toString(minlon)), Pvl::Replace); - mapgrp.addKeyword(PvlKeyword("MaximumLongitude", toString(maxlon)), Pvl::Replace); - - fmap.addGroup(mapgrp); - fileset.addObject(fmap); - - longitudeStat.AddData(&minlon, 1); - longitudeStat.AddData(&maxlon, 1); - latitudeStat.AddData(&minlat, 1); - latitudeStat.AddData(&maxlat, 1); - } - catch(IException &ie) { - QString mess = "Problems with file " + flist[i].toString() + "\n" + - ie.what(); - throw IException(IException::User, mess, _FILEINFO_); - } + fmap += PvlKeyword("Name", cubeFileList[i].toString()); + + try { + // Set input image, get camera model, and a basic mapping group + Cube cube; + cube.open(cubeFileList[i].toString()); + + int lines = cube.lineCount(); + int samples = cube.sampleCount(); + + PvlObject fmap("File"); + fmap += PvlKeyword("Name", cubeFileList[i].toString()); + fmap += PvlKeyword("Lines", toString(lines)); + fmap += PvlKeyword("Samples", toString(samples)); + + Camera *cam = cube.camera(); + Pvl mapping; + cam->BasicMapping(mapping); + PvlGroup &mapgrp = mapping.findGroup("Mapping"); + mapgrp.addKeyword(PvlKeyword("ProjectionName", projection), Pvl::Replace); + mapgrp.addKeyword(PvlKeyword("LatitudeType", lattype), Pvl::Replace); + mapgrp.addKeyword(PvlKeyword("LongitudeDirection", londir), Pvl::Replace); + mapgrp.addKeyword(PvlKeyword("LongitudeDomain", londom), Pvl::Replace); + + // Get the radii + Distance radii[3]; + cam->radii(radii); + + eqRad = radii[0].meters(); + poleRad = radii[2].meters(); + + target = cam->target()->name(); + equiRadStat.AddData(&eqRad, 1); + poleRadStat.AddData(&poleRad, 1); + + // Get resolution + double lowres = cam->LowestImageResolution(); + double hires = cam->HighestImageResolution(); + + double lowObliqueRes = cam->LowestObliqueImageResolution(); + double hiObliqueRes= cam->HighestObliqueImageResolution(); + + scaleStat.AddData(&hires, 1); + scaleStat.AddData(&lowres, 1); + + obliqueScaleStat.AddData(&hiObliqueRes,1); + obliqueScaleStat.AddData(&lowObliqueRes,1); + + double pixres = (lowres + hires) / 2.0; + double scale = Scale(pixres, poleRad, eqRad); + + mapgrp.addKeyword(PvlKeyword("PixelResolution", toString(pixres)), Pvl::Replace); + mapgrp.addKeyword(PvlKeyword("Scale", toString(scale), "pixels/degree"), Pvl::Replace); + mapgrp += PvlKeyword("MinPixelResolution", toString(lowres), "meters/pixel"); + mapgrp += PvlKeyword("MaxPixelResolution", toString(hires), "meters/pixel"); + mapgrp += PvlKeyword("MinObliquePixelResolution", toString(lowObliqueRes), "meters/pixel"); + mapgrp += PvlKeyword("MaxObliquePixelResolution", toString(hiObliqueRes), "meters/pixel"); + + // Get the universal ground range + double minlat, maxlat, minlon, maxlon; + cam->GroundRange(minlat, maxlat, minlon, maxlon, mapping); + mapgrp.addKeyword(PvlKeyword("MinimumLatitude", toString(minlat)), Pvl::Replace); + mapgrp.addKeyword(PvlKeyword("MaximumLatitude", toString(maxlat)), Pvl::Replace); + mapgrp.addKeyword(PvlKeyword("MinimumLongitude", toString(minlon)), Pvl::Replace); + mapgrp.addKeyword(PvlKeyword("MaximumLongitude", toString(maxlon)), Pvl::Replace); + + fmap.addGroup(mapgrp); + fileset.addObject(fmap); + + longitudeStat.AddData(&minlon, 1); + longitudeStat.AddData(&maxlon, 1); + latitudeStat.AddData(&minlat, 1); + latitudeStat.AddData(&maxlat, 1); + } + catch(IException &ie) { + QString mess = cubeFileList[i].toString() + " - " + ie.what(); + fmap += PvlKeyword("Error", mess); + errorset.addObject(fmap); + + badfiles.append(qMakePair(cubeFileList[i].toString(), ie.what())); + } + + p.ClearInputCubes(); + prog.CheckStatus(); + } - p.ClearInputCubes(); - prog.CheckStatus(); + // Now check for error behavior if a problem was encountered + if ( badfiles.size() > 0 ) { + + if ( ui.WasEntered("ERRORLOG") ) { + Pvl temp; + temp.addObject(errorset); + temp.write(ui.GetFileName("ERRORLOG", "log")); + } + + if ( ui.WasEntered("ERRORLIST") ) { + FileName filename( ui.GetFileName("ERRORLIST") ); + QFile logfile(filename.expanded()); + if ( !logfile.open(QIODevice::WriteOnly | QIODevice::Truncate | + QIODevice::Text | QIODevice::Unbuffered) ) { + QString mess = "Unable to open/create error list file " + filename.name(); + throw IException(IException::User, mess, _FILEINFO_); + } + + QTextStream lout(&logfile); + for ( int f = 0 ; f < badfiles.size() ; f++) { + lout << badfiles[f].first << "\n"; + } + } + + // Now check onerror status + if ( ("FAIL" == ui.GetString("ONERROR").toUpper()) || + (badfiles.size() == cubeFileList.size()) ) { + QString errors("--> Fatal Errors Encountered <___\n"); + for (int i = 0 ; i < badfiles.size() ; i++) { + errors += badfiles[i].first + " - " + badfiles[i].second + "\n"; + } + throw IException(IException::User, errors, _FILEINFO_); + } } - // Construct the output mapping group with statistics + // Construct the output mapping group with statistics PvlGroup mapping("Mapping"); double avgPixRes( (scaleStat.Minimum() + scaleStat.Maximum() ) / 2.0); - - - //double avgObliquePixRes( (obliqueScaleStat.Minimum() + obliqueScaleStat.Maximum() ) / 2.0); - double avgLat((latitudeStat.Minimum() + latitudeStat.Maximum()) / 2.0); double avgLon((longitudeStat.Minimum() + longitudeStat.Maximum()) / 2.0); double avgEqRad((equiRadStat.Minimum() + equiRadStat.Maximum()) / 2.0); double avgPoleRad((poleRadStat.Minimum() + poleRadStat.Maximum()) / 2.0); double scale = Scale(avgPixRes, avgPoleRad, avgEqRad); - //double obliqueScale = Scale(avgObliquePixRes,avgPoleRad,avgEqRad); mapping += PvlKeyword("ProjectionName", projection); mapping += PvlKeyword("TargetName", target); @@ -252,27 +285,13 @@ namespace Isis { mapping += PvlKeyword("LongitudeDirection", londir); mapping += PvlKeyword("LongitudeDomain", londom); mapping += PvlKeyword("PixelResolution", toString(SetRound(avgPixRes, digits)), "meters/pixel"); - - - //mapping += PvlKeyword("ObliquePixelResolution", toString(SetRound(avgObliquePixRes, digits)), - // "meters/pixel"); - - mapping += PvlKeyword("Scale", toString(SetRound(scale, digits)), "pixels/degree"); - - - //mapping += PvlKeyword("ObliqueScale", toString(SetRound(obliqueScale, digits)), "pixels/degree"); - - mapping += PvlKeyword("MinPixelResolution", toString(scaleStat.Minimum()), "meters/pixel"); mapping += PvlKeyword("MaxPixelResolution", toString(scaleStat.Maximum()), "meters/pixel"); - - mapping += PvlKeyword("MinObliquePixelResolution", toString(obliqueScaleStat.Minimum()), "meters/pixel"); mapping += PvlKeyword("MaxObliquePixelResolution", toString(obliqueScaleStat.Maximum()), "meters/pixel"); - mapping += PvlKeyword("CenterLongitude", toString(SetRound(avgLon, digits))); mapping += PvlKeyword("CenterLatitude", toString(SetRound(avgLat, digits))); mapping += PvlKeyword("MinimumLatitude", toString(MAX(SetFloor(latitudeStat.Minimum(), @@ -293,10 +312,8 @@ namespace Isis { mapping += PvlKeyword("PreciseMinimumLongitude", toString(longitudeStat.Minimum())); mapping += PvlKeyword("PreciseMaximumLongitude", toString(longitudeStat.Maximum())); - if (log){ - log->addLogGroup(mapping); - } - + log.addGroup(mapping); + // Write the output file if requested if(ui.WasEntered("TO")) { Pvl temp; @@ -311,6 +328,8 @@ namespace Isis { } p.EndProcess(); + + return log; } } diff --git a/isis/src/base/apps/mosrange/mosrange.h b/isis/src/base/apps/mosrange/mosrange.h index 05b73353fc32cde36a0e7d4023303c29159690fb..3e8de928cc7aec5def0a831be9f936117106ad26 100644 --- a/isis/src/base/apps/mosrange/mosrange.h +++ b/isis/src/base/apps/mosrange/mosrange.h @@ -8,10 +8,12 @@ find files of those names at the top level of this repository. **/ #ifndef mosrange_h #define mosrange_h +#include "FileList.h" #include "UserInterface.h" namespace Isis{ - extern void mosrange(UserInterface &ui, Pvl *log=nullptr); + extern Pvl mosrange(UserInterface &ui); + extern Pvl mosrange(FileList &cubeList, UserInterface &ui); } #endif diff --git a/isis/src/base/apps/mosrange/mosrange.xml b/isis/src/base/apps/mosrange/mosrange.xml index 6828eb93f80a3caaa413f9e3df6c1f8c1813e1c4..56b102483293b1fd428d4893889eb56346aec94e 100644 --- a/isis/src/base/apps/mosrange/mosrange.xml +++ b/isis/src/base/apps/mosrange/mosrange.xml @@ -4,36 +4,48 @@ xsi:noNamespaceSchemaLocation= "http://isis.astrogeology.usgs.gov/Schemas/Application/application.xsd"> - Compute the lat/lon range of a set camera images for mosaicking + Compute the lat/lon range of a set of camera images for mosaicking

- This program computes and outputs the - latitude/longitude - range of a set of images in camera space, as well as the - pixel resolution and the - oblique pixel resolution.. It creates a cam2map ready map file with - the extents of the latitude/longitude ranges of the image set. + mosrange computes and outputs the latitude + and longitude ranges of a set of Level1 + images (i.e. non-projected), as well as the pixel + resolution and the oblique pixel resolution. + It creates a cam2map ready map file + with the extents of the latitude/longitude ranges of the image set.

The user can select the type of map projection - preferred by two different means. The PROJECTION parameter allows direct + preferred by two different ways. The PROJECTION parameter allows direct specification of an ISIS supported projection. Or, the user can select a map file from the ISIS map template system that contains the projection name. If none of these options are used, then Equirectangular is the default.

- mosrange provides better control over the values of the latitude/longitude + mosrange provides better control over the values of the latitude/longitude ranges by providing a PRECISION parameter. This parameter specifies the - maximum nuber of digits precision for many of the Mapping group parameters + maximum number of digits of precision for many of the Mapping group parameters used to project images.

- + +

+ ONERROR, ERRORLOG, and ERRORLIST parameters offer better error handling and + diagnostics when problems are encountered processing the input file list. + ONERROR dictates whether mosrange will abort or continue when an error + occurs. If ONERROR=FAIL (default behavior), mosrange aborts upon error + without generating a map file. If ONERROR=CONTINUE, mosrange produces + an output map file with data collected from all successfully processed images. + A detailed list of files that fail and their associated errors are written to + the ERRORLOG file if provided. A simple list of failed files is written to the + ERRORLIST file if provided. +

+

- Its primary use is to provide a quick, simple and batchable means of + The primary use of mosrange is to provide a quick, simple and batchable means of creating map files for projections.

@@ -111,12 +123,20 @@ End Updated to use new Target class. References Mantis tickets #775 and #1114. - Updated to use upated Camera/CameraPointInfo classes which include improved approximations + Updated to use updated Camera/CameraPointInfo classes which include improved approximations to Pixel/Detector/Line/Sample resolutions, as well as providing the ability for developers - to order the fields in CSV/Pvl output. References #476" + to order the fields in CSV/Pvl output. References #476. - - + + Added ERRORLOG, ERRORLIST and ONERROR flags to provide better control + error behavior and provide diagnostics when problems are encountered + processing input file list. + + + Moved Kris Becker's 2019-03-11 changes from UofA code base to USGS. Updated documentation. + Cleaned up unnecessary blank lines and commented code in mosrange.cpp. References #3606. + + @@ -367,5 +387,83 @@ End
+ + + + string + + Define behavior when a file error occurs + + + This flag is provided to specify what action is to be + taken should an error occur processing the input file + list. A detailed list of errors for each file will be + recorded to ERRORLOG if a file name is provided. A list + containing the file names that failed will be written + to ERRORLIST if provided. If ONERROR=FAIL, a single + error will result in an abort. FAIL is the default + (to preserve existing behavior). + + + FAIL + + + + + + + + filename + output + None + + Writes detailed information for each failed file to a PVL file + + + Each file that encounters an error will produce the issue + that cased the error. The ERRORLOG file can be specified to + get a detailed account of why each file failed to successfully + complete. Data collected from this process will be written + to the specified ERRORLOG in the form of a PVL object. + + + + + filename + output + None + + Record filename of each cube that failed to this file + + + The filename of each cube that encountered an error will be + written to this file if provided. The ERRORLIST file can be + used to difference against the input list to determine all + the successful files included in the mapping statistics. + + + diff --git a/isis/src/base/apps/mosrange/tsts/Makefile b/isis/src/base/apps/mosrange/tsts/Makefile deleted file mode 100644 index 46d84c74c297304e943452a44e06b111f179a92b..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/mosrange/tsts/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -BLANKS = "%-6s" -LENGTH = "%-40s" - -include $(ISISROOT)/make/isismake.tststree diff --git a/isis/src/base/apps/mosrange/tsts/default/Makefile b/isis/src/base/apps/mosrange/tsts/default/Makefile deleted file mode 100644 index fd4016ca302142848f31352192959413d28a0421..0000000000000000000000000000000000000000 --- a/isis/src/base/apps/mosrange/tsts/default/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -APPNAME = mosrange - -mosrange_equi.txt.IGNORELINES = MinPixelResolution MaxPixelResolution \ - PreciseCenterLongitude PreciseCenterLatitude \ - PreciseMinimumLatitude PreciseMaximumLatitude \ - PreciseMinimumLongitude PreciseMaximumLongitude - - -include $(ISISROOT)/make/isismake.tsts - -commands: - $(LS) $(INPUT)/*.cub > $(OUTPUT)/files.lis; - $(APPNAME) FROMLIST=$(OUTPUT)/files.lis \ - MAP=$(ISISROOT)/appdata/templates/maps/equirectangular.map \ - TO=$(OUTPUT)/mosrange_equi.map PRECISION=4 > /dev/null; - /bin/mv $(OUTPUT)/mosrange_equi.map $(OUTPUT)/mosrange_equi.txt - $(RM) $(OUTPUT)/files.lis; diff --git a/isis/tests/FunctionalTestsMosrange.cpp b/isis/tests/FunctionalTestsMosrange.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3fdfad82f361a6138e5a2f7f09fb9837b0219bd9 --- /dev/null +++ b/isis/tests/FunctionalTestsMosrange.cpp @@ -0,0 +1,177 @@ + +#include +#include +#include +#include + +#include "Pvl.h" +#include "PvlGroup.h" +#include "mosrange.h" + +#include "gtest/gtest.h" + +using namespace Isis; + +static QString APP_XML = FileName("$ISISROOT/bin/xml/mosrange.xml").expanded(); + +/** + * MosrangeDefault + * + * Mosrange test given a list of four cubes and a map file. + */ +TEST(Mosrange, MosrangeDefault) { + + QVector args = {"fromlist=data/mosrange/mosrangeCubes.lis", + "map=data/mosrange/equi.map", + "precision=4" + }; + + UserInterface options(APP_XML, args); + + Pvl results; + + try { + results = mosrange(options); + } + catch(IException &e) { + FAIL() << e.toString().toStdString().c_str() << std::endl; + } + + PvlGroup &mapping = results.findGroup("Mapping", Pvl::Traverse); + + EXPECT_EQ(mapping["ProjectionName"][0].toStdString(), "Equirectangular"); + EXPECT_EQ(mapping["TargetName"][0].toStdString(), "Mercury"); + EXPECT_DOUBLE_EQ(double(mapping["EquatorialRadius"]), 2440000.0); + EXPECT_DOUBLE_EQ(double(mapping["PolarRadius"]), 2440000.0); + EXPECT_EQ(mapping["LatitudeType"][0].toStdString(), "Planetocentric"); + EXPECT_EQ(mapping["LongitudeDirection"][0].toStdString(), "PositiveEast"); + EXPECT_EQ(int(mapping["LongitudeDomain"]), 360); + EXPECT_DOUBLE_EQ(double(mapping["PixelResolution"]), 506.7143); + EXPECT_DOUBLE_EQ(double(mapping["Scale"]), 84.0435); + EXPECT_DOUBLE_EQ(double(mapping["MinObliquePixelResolution"]), 490.32027782048); + EXPECT_DOUBLE_EQ(double(mapping["MaxObliquePixelResolution"]), 2265.4589309332); + EXPECT_DOUBLE_EQ(double(mapping["CenterLongitude"]), 167.2285); + EXPECT_DOUBLE_EQ(double(mapping["CenterLatitude"]), -13.6504); + EXPECT_DOUBLE_EQ(double(mapping["MinimumLatitude"]), -21.5392); + EXPECT_DOUBLE_EQ(double(mapping["MaximumLatitude"]), -5.7616); + EXPECT_DOUBLE_EQ(double(mapping["MinimumLongitude"]), 134.2321); + EXPECT_DOUBLE_EQ(double(mapping["MaximumLongitude"]), 200.2249); +} + +/** + * MosrangeOnErrorContinue + * + * Mosrange test given a list of four cubes and a map file. Three have been + * processed with spiceinit and one has not. Mosrange should continue to + * produce a result with the three good cubes. + */ +TEST(Mosrange, MosrangeOnErrorContinue) { + + QVector args = {"fromlist=data/mosrange/mosrangeBadCube.lis", + "map=data/mosrange/equi.map", + "precision=4", + "onerror=continue" + }; + + UserInterface options(APP_XML, args); + + Pvl results; + + try { + results = mosrange(options); + } + catch(IException &e) { + FAIL() << e.toString().toStdString().c_str() << std::endl; + } + + PvlGroup &mapping = results.findGroup("Mapping", Pvl::Traverse); + + EXPECT_EQ(mapping["ProjectionName"][0].toStdString(), "Equirectangular"); + EXPECT_EQ(mapping["TargetName"][0].toStdString(), "Mercury"); + EXPECT_DOUBLE_EQ(double(mapping["EquatorialRadius"]), 2440000.0); + EXPECT_DOUBLE_EQ(double(mapping["PolarRadius"]), 2440000.0); + EXPECT_EQ(mapping["LatitudeType"][0].toStdString(), "Planetocentric"); + EXPECT_EQ(mapping["LongitudeDirection"][0].toStdString(), "PositiveEast"); + EXPECT_EQ(int(mapping["LongitudeDomain"]), 360); + EXPECT_DOUBLE_EQ(double(mapping["PixelResolution"]), 495.0249); + EXPECT_DOUBLE_EQ(double(mapping["Scale"]), 86.0281); + EXPECT_DOUBLE_EQ(double(mapping["MinObliquePixelResolution"]), 490.32027782048); + EXPECT_DOUBLE_EQ(double(mapping["MaxObliquePixelResolution"]), 821.88316879416); + EXPECT_DOUBLE_EQ(double(mapping["CenterLongitude"]), 154.5774); + EXPECT_DOUBLE_EQ(double(mapping["CenterLatitude"]), -14.3546); + EXPECT_DOUBLE_EQ(double(mapping["MinimumLatitude"]), -21.5392); + EXPECT_DOUBLE_EQ(double(mapping["MaximumLatitude"]), -7.17); + EXPECT_DOUBLE_EQ(double(mapping["MinimumLongitude"]), 134.2321); + EXPECT_DOUBLE_EQ(double(mapping["MaximumLongitude"]), 174.9228); +} + +/** + * MosrangeOnErrorFail + * + * Mosrange test given a list of four cubes and a map file. Three have been + * processed with spiceinit and one has not. The unspiced cube should throw + * the Exception "Unable to initialize camera model". Tests contents of output + * errorlog and errorlist files. + */ +TEST(Mosrange, MosrangeOnErrorFail) { + QTemporaryDir tempDir; + + QVector args = {"fromlist=data/mosrange/mosrangeBadCube.lis", + "map=data/mosrange/equi.map", + "precision=4", + "onerror=fail", + "errorlog=" + tempDir.path() + "/errorLog", + "errorlist=" + tempDir.path() + "/errorList.txt" + }; + + UserInterface options(APP_XML, args); + + Pvl results; + + try { + results = mosrange(options); + FAIL() << "Expected Exception for a cube that hasn't been spiceinited"; + } + catch(IException &e) { + EXPECT_TRUE(e.toString().toLatin1().contains("Unable to initialize camera model")) + << e.toString().toStdString(); + } + + // try to read back error log pvl output file + Pvl errorLogPvl; + try { + errorLogPvl.read(tempDir.path()+ "/errorLog.log"); + } + catch (IException &e) { + FAIL() << "Unable to open error log pvl file: " << e.what() << std::endl; + } + + ASSERT_TRUE(errorLogPvl.hasObject("ErrorSet")); + PvlObject errorSet = errorLogPvl.findObject("ErrorSet"); + ASSERT_TRUE(errorSet.hasObject("File")); + PvlObject errorFile = errorSet.findObject("File"); + ASSERT_TRUE(errorFile.hasKeyword("Name")); + ASSERT_TRUE(errorFile.hasKeyword("Error")); + + // confirm name of cube with no spice error + QFileInfo errorFileFullPath = (QFileInfo)(errorFile.findKeyword("Name")); + ASSERT_EQ(errorFileFullPath.fileName(), "EN0108828337M_noSPICE.cub"); + + // confirm bad cube needs to be re-spiceinited + QString errorType = (QString)(errorFile.findKeyword("Error")); + ASSERT_TRUE(errorType.contains("re-run spiceinit")); + + // try to read back errorList output file + QFile errorListFile(tempDir.path() + "/errorList.txt"); + try { + errorListFile.open(QIODevice::ReadOnly | QIODevice::Text); + } + catch (IException &e) { + FAIL() << "Unable to open error list text file: " << e.what() << std::endl; + } + + // confirm name of cube with no spice error is in this file as well + QTextStream in (&errorListFile); + const QString content = in.readAll(); + ASSERT_TRUE(content.contains("EN0108828337M_noSPICE.cub")); +} diff --git a/isis/tests/data/mosrange/equi.map b/isis/tests/data/mosrange/equi.map new file mode 100644 index 0000000000000000000000000000000000000000..c6f4a0230c493524b488a33eece68d1d83e70a9e --- /dev/null +++ b/isis/tests/data/mosrange/equi.map @@ -0,0 +1,30 @@ +Group = Mapping + ProjectionName = Equirectangular + TargetName = Mars + EquatorialRadius = 3396190.0 + PolarRadius = 3376200.0 + LatitudeType = Planetocentric + LongitudeDirection = PositiveEast + LongitudeDomain = 360 + PixelResolution = 4.434456285329 + Scale = 13366.846735961 + MinPixelResolution = 4.4319183304641 + MaxPixelResolution = 4.4369942401935 + MinObliquePixelResolution = 4.5174230281992 + MaxObliquePixelResolution = 4.5255899788918 + CenterLongitude = 176.64264073103 + CenterLatitude = -29.845670941671 + MinimumLatitude = -30.153087961753 + MaximumLatitude = -29.538253921589 + MinimumLongitude = 176.52709102356 + MaximumLongitude = 176.7581904385 + + # Actual Parameters without precision applied + PreciseCenterLongitude = 176.64264073103 + PreciseCenterLatitude = -29.845670941671 + PreciseMinimumLatitude = -30.153087961752 + PreciseMaximumLatitude = -29.538253921589 + PreciseMinimumLongitude = 176.52709102356 + PreciseMaximumLongitude = 176.7581904385 +End_Group +End diff --git a/isis/tests/data/mosrange/mosrangeBadCube.lis b/isis/tests/data/mosrange/mosrangeBadCube.lis new file mode 100644 index 0000000000000000000000000000000000000000..14b69e565062d083233789a0100c7a784ff54813 --- /dev/null +++ b/isis/tests/data/mosrange/mosrangeBadCube.lis @@ -0,0 +1,4 @@ +data/mosrange/EN0108828322M_iof.cub +data/mosrange/EN0108828327M_iof.cub +data/mosrange/EN0108828332M_iof.cub +data/mosrange/EN0108828337M_noSPICE.cub diff --git a/isis/tests/data/mosrange/mosrangeCubes.lis b/isis/tests/data/mosrange/mosrangeCubes.lis new file mode 100644 index 0000000000000000000000000000000000000000..a49cd652e6d7424ea99b88d13208d690bb6d537f --- /dev/null +++ b/isis/tests/data/mosrange/mosrangeCubes.lis @@ -0,0 +1,4 @@ +data/mosrange/EN0108828322M_iof.cub +data/mosrange/EN0108828327M_iof.cub +data/mosrange/EN0108828332M_iof.cub +data/mosrange/EN0108828337M_iof.cub