diff --git a/CHANGELOG.md b/CHANGELOG.md
index b6934a7fe0..0fd2d78adc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -39,6 +39,7 @@ release.
- Added backplane options for SunIllumination and SurfaceObliqueDetectorResolution to phocube [#5467](https://github.com/DOI-USGS/ISIS3/issues/5467)
### Changed
+- Photrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5581](https://github.com/USGS-Astrogeology/ISIS3/issues/5581)
- Bandtrim has been refactored to be callable; old Makefile tests have been removed and replaced by gtests. Issue: [#5571](https://github.com/USGS-Astrogeology/ISIS3/issues/5571)
- Modified kaguyasp2isis to work with new (detached) data [#5436](https://github.com/DOI-USGS/ISIS3/issues/5436)
- Added jigsaw error message for csminit'd images without csm parameters[#5486](https://github.com/DOI-USGS/ISIS3/issues/5486)
diff --git a/isis/src/base/apps/photrim/main.cpp b/isis/src/base/apps/photrim/main.cpp
index 12f38766d5..86dcae99a8 100644
--- a/isis/src/base/apps/photrim/main.cpp
+++ b/isis/src/base/apps/photrim/main.cpp
@@ -1,93 +1,20 @@
-#include "Isis.h"
-#include "Camera.h"
-#include "ProcessByLine.h"
-#include "SpecialPixel.h"
+/** This is free and unencumbered software released into the public domain.
-using namespace std;
-using namespace Isis;
+The authors of ISIS do not claim copyright on the contents of this file.
+For more details about the LICENSE terms and the AUTHORS, you will
+find files of those names at the top level of this repository. **/
-// Global variables
-Camera *cam;
-Cube *icube;
-bool usedem;
-double minPhase;
-double maxPhase;
-double minEmission;
-double maxEmission;
-double minIncidence;
-double maxIncidence;
-int lastBand;
+/* SPDX-License-Identifier: CC0-1.0 */
-void photrim(Buffer &in, Buffer &out);
+#include "Isis.h"
-void IsisMain() {
- // We will be processing by line
- ProcessByLine p;
+#include "photrim.h"
- // Setup the input and get the camera model
- icube = p.SetInputCube("FROM");
- cam = icube->camera();
+#include "Application.h"
- // Create the output cube
- p.SetOutputCube("TO");
+using namespace Isis;
- // Get the trim angles
+void IsisMain() {
UserInterface &ui = Application::GetUserInterface();
-
- minPhase = ui.GetDouble("MINPHASE");
- maxPhase = ui.GetDouble("MAXPHASE");
- minEmission = ui.GetDouble("MINEMISSION");
- maxEmission = ui.GetDouble("MAXEMISSION");
- minIncidence = ui.GetDouble("MININCIDENCE");
- maxIncidence = ui.GetDouble("MAXINCIDENCE");
-
- usedem = ui.GetBoolean("USEDEM");
-
- if (!usedem) {
- cam->IgnoreElevationModel(true);
-
- }
-
- // Start the processing
- lastBand = 0;
- p.StartProcess(photrim);
- p.EndProcess();
-}
-
-
-// Line processing routine
-void photrim(Buffer &in, Buffer &out) {
- // See if there is a change in band which would change the camera model
- if (in.Band() != lastBand) {
- lastBand = in.Band();
- cam->SetBand(icube->physicalBand(lastBand));
- }
-
- // Loop for each pixel in the line.
- double samp, phase, emission, incidence;
- double line = in.Line();
- for (int i = 0; i < in.size(); i++) {
- samp = in.Sample(i);
- cam->SetImage(samp, line);
- if (cam->HasSurfaceIntersection()) {
- if (((phase = cam->PhaseAngle()) < minPhase) || (phase > maxPhase)) {
- out[i] = Isis::NULL8;
- }
- else if (((emission = cam->EmissionAngle()) < minEmission) ||
- (emission > maxEmission)) {
- out[i] = Isis::NULL8;
- }
- else if (((incidence = cam->IncidenceAngle()) < minIncidence) ||
- (incidence > maxIncidence)) {
- out[i] = Isis::NULL8;
- }
- else {
- out[i] = in[i];
- }
- }
- // Trim outerspace
- else {
- out[i] = Isis::NULL8;
- }
- }
+ photrim(ui);
}
diff --git a/isis/src/base/apps/photrim/photrim.cpp b/isis/src/base/apps/photrim/photrim.cpp
new file mode 100644
index 0000000000..ff95d54ef4
--- /dev/null
+++ b/isis/src/base/apps/photrim/photrim.cpp
@@ -0,0 +1,115 @@
+/** This is free and unencumbered software released into the public domain.
+
+The authors of ISIS do not claim copyright on the contents of this file.
+For more details about the LICENSE terms and the AUTHORS, you will
+find files of those names at the top level of this repository. **/
+
+/* SPDX-License-Identifier: CC0-1.0 */
+
+#include "photrim.h"
+
+#include "Camera.h"
+#include "ProcessByLine.h"
+#include "SpecialPixel.h"
+
+namespace Isis {
+
+ /*
+ * The photrim program trims pixels outside of the phase, incidence,
+ * and emission angles by setting them to "null" within all bands of
+ * the cube. A user can either trim using the program's default method
+ * or the USEDEM method.
+ *
+ * @param ui UserInterface object containing parameters
+ */
+ void photrim(UserInterface &ui) {
+
+ // open input cube
+ Cube icube;
+ icube.open(ui.GetCubeName("FROM"));
+
+ photrim(&icube, ui);
+ }
+
+
+ /*
+ * The photrim program trims pixels outside of the phase, incidence,
+ * and emission angles by setting them to "null" within all bands of
+ * the cube. A user can either trim using the program's default method
+ * or the USEDEM method.
+ *
+ * @param iCube Input cube
+ * @param ui UserInterface object containing parameters
+ */
+ void photrim(Cube *icube, UserInterface &ui) {
+ // processing by line
+ ProcessByLine p;
+
+ // Setup input cube and get the camera model
+ p.SetInputCube(icube);
+
+ Camera* cam = icube->camera();
+
+ // Create the output cube
+ QString fname = ui.GetCubeName("TO");
+ CubeAttributeOutput &atts = ui.GetOutputAttribute("TO");
+ p.SetOutputCube(fname, atts);
+
+ // Get the trim angles
+ double minPhase = ui.GetDouble("MINPHASE");
+ double maxPhase = ui.GetDouble("MAXPHASE");
+ double minEmission = ui.GetDouble("MINEMISSION");
+ double maxEmission = ui.GetDouble("MAXEMISSION");
+ double minIncidence = ui.GetDouble("MININCIDENCE");
+ double maxIncidence = ui.GetDouble("MAXINCIDENCE");
+
+ bool usedem = ui.GetBoolean("USEDEM");
+
+ if (!usedem) {
+ cam->IgnoreElevationModel(true);
+ }
+
+ // Start the processing
+ int lastBand = 0;
+
+ // lambda function with captures to process by line
+ auto photrimLineProcess = [&](Buffer &in, Buffer &out)->void {
+ // See if there is a change in band which would change the camera model
+ if (in.Band() != lastBand) {
+ lastBand = in.Band();
+ cam->SetBand(icube->physicalBand(lastBand));
+ }
+
+ // Loop for each pixel in the line.
+ double samp, phase, emission, incidence;
+ double line = in.Line();
+ for (int i = 0; i < in.size(); i++) {
+ samp = in.Sample(i);
+ cam->SetImage(samp, line);
+ if (cam->HasSurfaceIntersection()) {
+ if (((phase = cam->PhaseAngle()) < minPhase) || (phase > maxPhase)) {
+ out[i] = Isis::NULL8;
+ }
+ else if (((emission = cam->EmissionAngle()) < minEmission) ||
+ (emission > maxEmission)) {
+ out[i] = Isis::NULL8;
+ }
+ else if (((incidence = cam->IncidenceAngle()) < minIncidence) ||
+ (incidence > maxIncidence)) {
+ out[i] = Isis::NULL8;
+ }
+ else {
+ out[i] = in[i];
+ }
+ }
+ // Trim outerspace
+ else {
+ out[i] = Isis::NULL8;
+ }
+ }
+ };
+
+ p.StartProcess(photrimLineProcess);
+ p.EndProcess();
+ }
+}
diff --git a/isis/src/base/apps/photrim/photrim.h b/isis/src/base/apps/photrim/photrim.h
new file mode 100644
index 0000000000..8b03e06dbc
--- /dev/null
+++ b/isis/src/base/apps/photrim/photrim.h
@@ -0,0 +1,19 @@
+/** This is free and unencumbered software released into the public domain.
+
+The authors of ISIS do not claim copyright on the contents of this file.
+For more details about the LICENSE terms and the AUTHORS, you will
+find files of those names at the top level of this repository. **/
+
+/* SPDX-License-Identifier: CC0-1.0 */
+
+#ifndef photrim_h
+#define photrim_h
+
+#include "UserInterface.h"
+
+namespace Isis{
+ extern void photrim(UserInterface &ui);
+ extern void photrim(Cube *icube, UserInterface &ui);
+}
+
+#endif
diff --git a/isis/src/base/apps/photrim/photrim.xml b/isis/src/base/apps/photrim/photrim.xml
index 33ea366f50..98d44dab50 100644
--- a/isis/src/base/apps/photrim/photrim.xml
+++ b/isis/src/base/apps/photrim/photrim.xml
@@ -70,6 +70,9 @@
Added the option to use the digital elevation model when trimming the image.
Created examples for using the DEM and not using the DEM. Fixes #4181.
+
+ Converted to callable app and converted Makefile tests to gtests.
+
diff --git a/isis/src/base/apps/photrim/tsts/Makefile b/isis/src/base/apps/photrim/tsts/Makefile
deleted file mode 100644
index 46d84c74c2..0000000000
--- a/isis/src/base/apps/photrim/tsts/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-BLANKS = "%-6s"
-LENGTH = "%-40s"
-
-include $(ISISROOT)/make/isismake.tststree
diff --git a/isis/src/base/apps/photrim/tsts/base/Makefile b/isis/src/base/apps/photrim/tsts/base/Makefile
deleted file mode 100644
index fb2ea8e09a..0000000000
--- a/isis/src/base/apps/photrim/tsts/base/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-APPNAME = photrim
-
-include $(ISISROOT)/make/isismake.tsts
-
-commands:
- $(APPNAME) from= $(INPUT)/ab102401.cub \
- to= $(OUTPUT)/PhotrimTruth1.cub \
- minphase=0.0 \
- maxphase=180.0 \
- minemission=0.0 \
- maxemission=90.0 \
- minincidence=0.0 \
- maxincidence=90.0 > /dev/null;
diff --git a/isis/src/base/apps/photrim/tsts/emission/Makefile b/isis/src/base/apps/photrim/tsts/emission/Makefile
deleted file mode 100644
index 07533bd341..0000000000
--- a/isis/src/base/apps/photrim/tsts/emission/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-APPNAME = photrim
-
-include $(ISISROOT)/make/isismake.tsts
-
-commands:
- $(APPNAME) from= $(INPUT)/ab102401.cub \
- to= $(OUTPUT)/PhotrimTruth3.cub \
- minphase=0.0 \
- maxphase=180.0 \
- minemission=22.5 \
- maxemission=67.5 \
- minincidence=0.0 \
- maxincidence=90.0 > /dev/null;
diff --git a/isis/src/base/apps/photrim/tsts/incidence/Makefile b/isis/src/base/apps/photrim/tsts/incidence/Makefile
deleted file mode 100644
index 1a8d13fc15..0000000000
--- a/isis/src/base/apps/photrim/tsts/incidence/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-APPNAME = photrim
-
-include $(ISISROOT)/make/isismake.tsts
-
-commands:
- $(APPNAME) from= $(INPUT)/ab102401.cub \
- to= $(OUTPUT)/PhotrimTruth4.cub \
- minphase=0.0 \
- maxphase=180.0 \
- minemission=0.0 \
- maxemission=90.0 \
- minincidence=22.5 \
- maxincidence=67.5 > /dev/null;
diff --git a/isis/src/base/apps/photrim/tsts/phase/Makefile b/isis/src/base/apps/photrim/tsts/phase/Makefile
deleted file mode 100644
index f7a1c9a913..0000000000
--- a/isis/src/base/apps/photrim/tsts/phase/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-APPNAME = photrim
-
-include $(ISISROOT)/make/isismake.tsts
-
-commands:
- $(APPNAME) from= $(INPUT)/ab102401.cub \
- to= $(OUTPUT)/PhotrimTruth2.cub \
- minphase=45.0 \
- maxphase=135.0 \
- minemission=0.0 \
- maxemission=90.0 \
- minincidence=0.0 \
- maxincidence=90.0 > /dev/null;
diff --git a/isis/src/base/apps/photrim/tsts/usedem/Makefile b/isis/src/base/apps/photrim/tsts/usedem/Makefile
deleted file mode 100644
index 20a6b9d663..0000000000
--- a/isis/src/base/apps/photrim/tsts/usedem/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-APPNAME = photrim
-
-include $(ISISROOT)/make/isismake.tsts
-
-commands:
- $(APPNAME) from= $(INPUT)/AS15-M-1499_msk-L2_1250mpp.cub \
- to= $(OUTPUT)/PhotrimTruth5.cub \
- usedem=true \
- minphase=0.0 \
- maxphase=180.0 \
- minemission=0.0 \
- maxemission=85.0 \
- minincidence=0.0 \
- maxincidence=90.0 > /dev/null;
\ No newline at end of file
diff --git a/isis/tests/FunctionalTestsPhotrim.cpp b/isis/tests/FunctionalTestsPhotrim.cpp
new file mode 100644
index 0000000000..57fa2d58ad
--- /dev/null
+++ b/isis/tests/FunctionalTestsPhotrim.cpp
@@ -0,0 +1,314 @@
+
+#include
+#include
+
+#include "CameraFixtures.h"
+#include "Histogram.h"
+
+#include "photrim.h"
+
+#include "gtest/gtest.h"
+
+using namespace Isis;
+
+static QString APP_XML = FileName("$ISISROOT/bin/xml/photrim.xml").expanded();
+
+/**
+ * FunctionalTestsPhotrimBase
+ *
+ * PhotrimEmission test given a single 5x5 input cube with 1 band.
+ * Default values for all parameters are used, resulting in no Null
+ * pixels.
+ *
+ * | 1| 2| 3| 4| 5| Valid Pixels: 25
+ * | 6| 7| 8| 9|10| Histogram Sum: 325
+ * |11|12|13|14|15| Histogram Avg: 13
+ * |16|17|18|19|20|
+ * |21|22|23|24|25|
+ *
+ * The output cube is verified by checking histogram statistics.
+ *
+ * INPUT: testCube from DefaultCube fixture resized to 5x5 pixels
+ * with one band.
+ minemission=10.852
+ maxemission=10.857
+ *
+ * DEFAULTS: usedem=false
+ * minphase=0.0
+ * maxphase=180.0
+ * minemission=0.0
+ * maxemission=90.0
+ * minincidence=0.0
+ * maxincidence=90.0
+ *
+ * OUTPUT: photrimEmission.cub
+ */
+ TEST_F(DefaultCube, FunctionalTestsPhotrimBase) {
+ resizeCube(5,5,1);
+
+ QVector args = {"to=" + tempDir.path() + "/PhotrimBase.cub"};
+
+ UserInterface ui(APP_XML, args);
+
+ try {
+ photrim(testCube, ui);
+ }
+ catch(IException &e) {
+ FAIL() << e.toString().toStdString().c_str() << std::endl;
+ }
+
+ // validate output cube
+ Cube outCube(tempDir.path() + "/PhotrimBase.cub");
+
+ // validate histogram statistics for output cube
+ std::unique_ptr hist (outCube.histogram(1));
+ EXPECT_EQ(hist->ValidPixels(), 25);
+ EXPECT_EQ(hist->Average(), 13);
+ EXPECT_EQ(hist->Sum(), 325);
+
+ outCube.close();
+}
+
+
+/**
+ * FunctionalTestsPhotrimEmission
+ *
+ * PhotrimEmission test given a single 5x5 input cube with 1 band.
+ * All pixels outside the range as defined by minemission and
+ * maxemission are set to Null. Resulting pixel values are as
+ * shown below.
+ *
+ * | N| N| 3| 4| 5| Valid Pixels: 14
+ * | 6| 7| 8| 9|10| Histogram Sum: 135
+ * |11|12|13|14| N| Histogram Avg: 9.6428571428571423
+ * |16|17| N| N| N|
+ * | N| N| N| N| N|
+ *
+ * The output cube is verified by checking histogram statistics.
+ *
+ * INPUT: testCube from DefaultCube fixture resized to 5x5 pixels
+ * with one band.
+ minemission=10.852
+ maxemission=10.857
+ *
+ * DEFAULTS: usedem=false
+ * minphase=0.0
+ * maxphase=180.0
+ * minemission=0.0
+ * maxemission=90.0
+ * minincidence=0.0
+ * maxincidence=90.0
+ *
+ * OUTPUT: photrimEmission.cub
+ */
+TEST_F(DefaultCube, FunctionalTestsPhotrimEmission) {
+ resizeCube(5,5,1);
+
+ QVector args = {"to=" + tempDir.path() + "/photrimEmission.cub",
+ "minemission=10.852",
+ "maxemission=10.857"
+ };
+
+ UserInterface ui(APP_XML, args);
+
+ try {
+ photrim(testCube, ui);
+ }
+ catch(IException &e) {
+ FAIL() << e.toString().toStdString().c_str() << std::endl;
+ }
+
+ // validate output cube
+ Cube outCube(tempDir.path() + "/photrimEmission.cub");
+
+ // validate histogram statistics for output cube
+ std::unique_ptr hist (outCube.histogram(1));
+ EXPECT_EQ(hist->ValidPixels(), 14);
+ EXPECT_NEAR(hist->Average(), 9.642857, 0.000001);
+ EXPECT_EQ(hist->Sum(), 135);
+
+ outCube.close();
+}
+
+
+/**
+ * FunctionalTestsPhotrimPhase
+ *
+ * PhotrimPhase test given a single 5x5 input cube with 1 band.
+ * All pixels outside the range as defined by minphase and
+ * maxphase are set to Null. Resulting pixel values are as
+ * shown below.
+ *
+ * | N| N| N| N| N| Valid Pixels: 8
+ * | N| N| N| N| N| Histogram Sum: 122
+ * |11|12|13|14|15| Histogram Avg: 15.25
+ * | N| N|18|19|20|
+ * | N| N| N| N| N|
+ *
+ * The output cube is verified by checking histogram statistics.
+ *
+ * INPUT: testCube from DefaultCube fixture resized to 5x5 pixels
+ * with one band.
+ * minphase=79.77
+ * maxphase=79.772
+ *
+ * DEFAULTS: usedem=false
+ * minphase=0.0
+ * maxphase=180.0
+ * minemission=0.0
+ * maxemission=90.0
+ * minincidence=0.0
+ * maxincidence=90.0
+ *
+ * OUTPUT: photrimPhase.cub
+ */
+TEST_F(DefaultCube, FunctionalTestsPhotrimPhase) {
+ resizeCube(5,5,1);
+
+ QVector args = {"to=" + tempDir.path() + "/photrimPhase.cub",
+ "minphase=79.77",
+ "maxphase=79.772"
+ };
+
+ UserInterface ui(APP_XML, args);
+
+ try {
+ photrim(testCube, ui);
+ }
+ catch(IException &e) {
+ FAIL() << e.toString().toStdString().c_str() << std::endl;
+ }
+
+ // validate output cube
+ Cube outCube(tempDir.path() + "/photrimPhase.cub");
+
+ // validate histogram statistics for output cube
+ std::unique_ptr hist (outCube.histogram(1));
+ EXPECT_EQ(hist->ValidPixels(), 8);
+ EXPECT_EQ(hist->Average(), 15.25);
+ EXPECT_EQ(hist->Sum(), 122);
+
+ outCube.close();
+}
+
+
+/**
+ * FunctionalTestsPhotrimIncidence
+ *
+ * PhotrimIncidence test given a single 5x5 input cube with 1 band.
+ * All pixels outside the range as defined by minincidence and
+ * maxincidence are set to Null. Resulting pixel values are as
+ * shown below.
+ *
+ * | N| N| N| N| N| Valid Pixels: 5
+ * | N| N| N| N| N| Histogram Sum: 65
+ * |11|12|13|14|15| Histogram Avg: 13
+ * | N| N| N| N| N|
+ * | N| N| N| N| N|
+ *
+ * The output cube is verified by checking histogram statistics.
+ *
+ * INPUT: testCube from DefaultCube fixture resized to 5x5 pixels
+ * with one band.
+ * minincidence=70.248
+ * maxincidence=70.2485
+ *
+ * DEFAULTS: usedem=false
+ * minphase=0.0
+ * maxphase=180.0
+ * minemission=0.0
+ * maxemission=90.0
+ * minincidence=0.0
+ * maxincidence=90.0
+ *
+ * OUTPUT: photrimIncidence.cub
+ */
+TEST_F(DefaultCube, FunctionalTestsPhotrimIncidence) {
+ resizeCube(5,5,1);
+
+ QVector args = {"to=" + tempDir.path() + "/photrimIncidence.cub",
+ "minincidence=70.248",
+ "maxincidence=70.2485"
+ };
+
+ UserInterface ui(APP_XML, args);
+
+ try {
+ photrim(testCube, ui);
+ }
+ catch(IException &e) {
+ FAIL() << e.toString().toStdString().c_str() << std::endl;
+ }
+
+ // validate output cube
+ Cube outCube(tempDir.path() + "/photrimIncidence.cub");
+
+ // validate histogram statistics for output cube
+ std::unique_ptr hist (outCube.histogram(1));
+ EXPECT_EQ(hist->ValidPixels(), 5);
+ EXPECT_EQ(hist->Average(), 13);
+ EXPECT_EQ(hist->Sum(), 65);
+}
+
+
+/**
+ * FunctionalTestsPhotrimUseDEM
+ *
+ * PhotrimIncidence test given a single 5x5 input cube with 1 band.
+ * The shapemodel set in cube is utilized. All pixels outside the
+ * range as defined by minemission and maxemission are set to Null.
+ * Resulting pixel values are as shown below.
+ *
+ * | N| N| 3| 4| 5| Valid Pixels: 17
+ * | 6| 7| 8| 9|10| Histogram Sum: 189
+ * |11|12|13|14|15| Histogram Avg: 11.117647058823529
+ * |16|17|18| N| N|
+ * |21| N| N| N| N|
+ *
+ * The output cube is verified by checking histogram statistics.
+ *
+ * INPUT: testCube from DefaultCube fixture resized to 5x5 pixels
+ * with one band.
+ * usedem=true
+ * minemission=10.8
+ * maxemission=10.805
+ *
+ * DEFAULTS: usedem=false
+ * minphase=0.0
+ * maxphase=180.0
+ * minemission=0.0
+ * maxemission=90.0
+ * minincidence=0.0
+ * maxincidence=90.0
+ *
+ * OUTPUT: photrimIncidence.cub
+ */
+TEST_F(DefaultCube, FunctionalTestsPhotrimUseDEM) {
+ resizeCube(5,5,1);
+
+ QVector args = {"to=" + tempDir.path() + "/photrimUseDEM.cub",
+ "usedem=true",
+ "minemission=10.8",
+ "maxemission=10.805",
+ };
+
+ UserInterface ui(APP_XML, args);
+
+ try {
+ photrim(testCube, ui);
+ }
+ catch(IException &e) {
+ FAIL() << e.toString().toStdString().c_str() << std::endl;
+ }
+
+ // validate output cube
+ Cube outCube(tempDir.path() + "/photrimUseDEM.cub");
+
+ // validate histogram statistics for output cube
+ std::unique_ptr hist (outCube.histogram(1));
+ EXPECT_EQ(hist->ValidPixels(),17);
+ EXPECT_NEAR(hist->Average(), 11.117647, 0.000001);
+ EXPECT_EQ(hist->Sum(), 189);
+
+ outCube.close();
+}