Skip to content

Commit

Permalink
Lronac2pds App and Test Update (DOI-USGS#4135)
Browse files Browse the repository at this point in the history
* Converted lronac2pds to new application format

* Updated tests for lronac2pds to gtests

* Removed old lronac2pds test makefiles

* Removed local path

* Addressed PR comments
  • Loading branch information
acpaquette authored and Kelvin committed Dec 1, 2020
1 parent 939a59b commit 2eca723
Show file tree
Hide file tree
Showing 14 changed files with 542 additions and 440 deletions.
274 changes: 274 additions & 0 deletions isis/src/lro/apps/lronac2pds/lronac2pds.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,274 @@
#include "lronac2pds.h"

#include <sstream>

#include <QDebug>

#include "ProcessExport.h"
#include "ProcessByLine.h"
#include "Pvl.h"
#include "PvlToPvlTranslationManager.h"
#include "PvlFormatPds.h"
#include "OriginalLabel.h"
#include "iTime.h"
#include "md5.h"
#include "md5wrapper.h"

#define SCALING_FACTOR 32767

using namespace std;

namespace Isis {
void ResetGlobals ();
void ProcessImage ( Buffer &in, Buffer &out );
QString MD5Checksum ( QString filename );
void OutputLabel ( std::ofstream &fout, Cube* cube );
void CopyData ( std::ifstream &fin, std::ofstream &fout );

QString g_md5Checksum;

bool g_isIof;

QString g_productVersionId = "N/A";

void lronac2pds(UserInterface &ui) {
ResetGlobals();

g_productVersionId = ui.GetString("VERSIONIDSTRING");

// Set the processing object

ProcessByLine p;
CubeAttributeInput &att = ui.GetInputAttribute("FROM");
Cube *inCube = p.SetInputCube(ui.GetFileName("FROM"), att);

g_isIof = inCube->label()->findGroup("Radiometry", Pvl::Traverse).findKeyword("RadiometricType")[0].toUpper() == "IOF";

FileName scaledCube("$TEMPORARY/" + FileName(ui.GetFileName("FROM")).name());
scaledCube.addExtension("cub");

scaledCube = FileName::createTempFile(scaledCube);
p.SetOutputCube(
scaledCube.expanded(), CubeAttributeOutput(),
inCube->sampleCount(), inCube->lineCount(),
inCube->bandCount());

// Scale image and calculate max and min values
p.StartProcess(ProcessImage);
p.EndProcess();

ProcessExport pe;

// Setup the input cube
inCube = pe.SetInputCube(scaledCube.expanded(), CubeAttributeInput());

if (g_isIof) {
pe.SetOutputType(Isis::SignedWord);
pe.SetOutputEndian(Isis::Lsb);

pe.SetOutputRange(Isis::VALID_MIN2, Isis::VALID_MAX2);

pe.SetOutputNull(Isis::NULL2);
pe.SetOutputLrs(Isis::LOW_REPR_SAT2);
pe.SetOutputLis(Isis::LOW_INSTR_SAT2);
pe.SetOutputHis(Isis::HIGH_INSTR_SAT2);
pe.SetOutputHrs(Isis::HIGH_REPR_SAT2);
}
else {
pe.SetOutputType(Isis::Real);
pe.SetOutputEndian(Isis::Lsb);

pe.SetOutputRange(Isis::VALID_MIN4, Isis::VALID_MAX4);

pe.SetOutputNull(Isis::NULL4);
pe.SetOutputLrs(Isis::LOW_REPR_SAT4);
pe.SetOutputLis(Isis::LOW_INSTR_SAT4);
pe.SetOutputHis(Isis::HIGH_INSTR_SAT4);
pe.SetOutputHrs(Isis::HIGH_REPR_SAT4);
}

FileName tempFile;
tempFile = FileName::createTempFile("$TEMPORARY/" + FileName(ui.GetFileName("TO")).baseName() + ".temp");
QString tempFileName(tempFile.expanded());
ofstream temporaryFile(tempFileName.toLatin1().data());

pe.StartProcess(temporaryFile);
temporaryFile.close();

// Calculate MD5 Checksum
g_md5Checksum = MD5Checksum(tempFileName);

FileName outFile(ui.GetFileName("TO"));
QString outFileName(outFile.expanded());
ifstream inFile(tempFileName.toLatin1().data());
ofstream pdsFile(outFileName.toLatin1().data());

// Output the label
OutputLabel(pdsFile, inCube);

// Then copy the image data
CopyData(inFile, pdsFile);

pdsFile.close();

pe.EndProcess();

remove((scaledCube.expanded()).toLatin1().data());
remove(tempFileName.toLatin1().data());
return;
}

void ResetGlobals () {
g_md5Checksum = "";
g_isIof = false;
}

void ProcessImage ( Buffer &in, Buffer &out ) {
for (int i = 0; i < in.size(); i++) {
if (IsSpecial(in[i]))
out[i] = in[i];
else if (g_isIof)
out[i] = SCALING_FACTOR * in[i];
else
out[i] = in[i];
}
}

QString MD5Checksum ( QString filename ) {
md5wrapper md5;
QString checkSum = md5.getHashFromFile(filename);
return checkSum;
}

void OutputLabel ( std::ofstream &fout, Cube* cube ) {
OriginalLabel origLab(cube->fileName());
Pvl labelPvl = origLab.ReturnLabels();

//Pvl to store the labels
Pvl outLabel;
PvlFormatPds *p_formatter = new PvlFormatPds("$ISISROOT/appdata/translations/LroNacPdsExportRootGen.typ");
labelPvl.setFormat(p_formatter);
labelPvl.setTerminator("END");

stringstream stream;
QString pdsLabel = "";

//Translate the Original Pds Label
FileName transFile("$ISISROOT/appdata/translations/LroNacPdsLabelExport.trn");
PvlToPvlTranslationManager labelXlator(labelPvl, transFile.expanded());
labelXlator.Auto(outLabel);

// Copy any Translation changes over
for (int i = 0; i < outLabel.keywords(); i++) {
bool hasUnit = false;
QString unit = "";
if (labelPvl[outLabel[i].name()].unit() != "") {
hasUnit = true;
unit = labelPvl[outLabel[i].name()].unit();
}
bool hasComment = false;
QString comment = "";
if (labelPvl[outLabel[i].name()].comments() > 0) {
hasComment = true;
comment = labelPvl[outLabel[i].name()].comment(0);
}
labelPvl[outLabel[i].name()] = outLabel[i];

if (hasUnit)
labelPvl[outLabel[i].name()].setUnits(unit);
if (hasComment)
labelPvl[outLabel[i].name()].addComment(comment);
}

//Update the product ID
//we switch the last char in the id from edr->cdr
QString prod_id = labelPvl["PRODUCT_ID"][0];
labelPvl["PRODUCT_ID"][0].replace((prod_id.length()-1), 1, "C");

// Update the product creation time
labelPvl["PRODUCT_CREATION_TIME"].setValue(iTime::CurrentGMT());

labelPvl["PRODUCT_VERSION_ID"].setValue(g_productVersionId);

// Update the "IMAGE" Object
PvlObject &imageObject = labelPvl.findObject("IMAGE");
imageObject.clear();
imageObject += PvlKeyword("LINES", toString(cube->lineCount()));
imageObject += PvlKeyword("LINE_SAMPLES", toString(cube->sampleCount()));
if (g_isIof) {
imageObject += PvlKeyword("SAMPLE_BITS", toString(16));
imageObject += PvlKeyword("SAMPLE_TYPE", "LSB_INTEGER");
imageObject += PvlKeyword("SCALING_FACTOR", toString(1.0 / SCALING_FACTOR));
imageObject += PvlKeyword("VALID_MINIMUM", toString(Isis::VALID_MIN2));
imageObject += PvlKeyword("NULL", toString(Isis::NULL2));
imageObject += PvlKeyword("LOW_REPR_SATURATION", toString(Isis::LOW_REPR_SAT2));
imageObject += PvlKeyword("LOW_INSTR_SATURATION", toString(Isis::LOW_INSTR_SAT2));
imageObject += PvlKeyword("HIGH_INSTR_SATURATION", toString(Isis::HIGH_INSTR_SAT2));
imageObject += PvlKeyword("HIGH_REPR_SATURATION", toString(Isis::HIGH_REPR_SAT2));
imageObject += PvlKeyword("UNIT", "Scaled I/F");
}
else {
imageObject += PvlKeyword("SAMPLE_BITS", "32");
imageObject += PvlKeyword("SAMPLE_TYPE", "PC_REAL");
imageObject += PvlKeyword("VALID_MINIMUM", "16#FF7FFFFA#");
imageObject += PvlKeyword("NULL", "16#FF7FFFFB#");
imageObject += PvlKeyword("LOW_REPR_SATURATION", "16#FF7FFFFC#");
imageObject += PvlKeyword("LOW_INSTR_SATURATION", "16#FF7FFFFD#");
imageObject += PvlKeyword("HIGH_INSTR_SATURATION", "16#FF7FFFFE#");
imageObject += PvlKeyword("HIGH_REPR_SATURATION", "16#FF7FFFFF#");
imageObject += PvlKeyword("UNIT", "W / (m**2 micrometer sr)");
}
imageObject += PvlKeyword("MD5_CHECKSUM", g_md5Checksum);

stream << labelPvl;

int recordBytes = cube->sampleCount();
int labelRecords = (int) ((stream.str().length()) / recordBytes) + 1;

labelPvl["RECORD_BYTES"] = toString(recordBytes);
if (g_isIof)
labelPvl["FILE_RECORDS"] = toString((int) (cube->lineCount() * 2 + labelRecords));
else
labelPvl["FILE_RECORDS"] = toString((int) (cube->lineCount() * 4 + labelRecords));
labelPvl["LABEL_RECORDS"] = toString(labelRecords);
labelPvl["^IMAGE"] = toString((int) (labelRecords + 1));

stream.str(std::string());

stream << labelPvl;
pdsLabel += stream.str().c_str();
/* Ensure that we have enough room for the actual label content, plus at
* least two bytes for a carriage return and a linefeed, so the end of the
* label looks pretty */
while ((int)pdsLabel.length() + 2 > (int)(labelRecords * recordBytes)) {
labelRecords++;
// Refresh the label content
labelPvl["FILE_RECORDS"] = toString((int) (cube->lineCount() * 4 + labelRecords));
labelPvl["LABEL_RECORDS"] = toString(labelRecords);
labelPvl["^IMAGE"] = toString((int) (labelRecords + 1));
stream.str(std::string());
stream << labelPvl;
pdsLabel = stream.str().c_str();
}

/* Now, add a carriage return and linefeed, and then pad the label with
* spaces if necessary */
pdsLabel += "\r\n";


while ((int)pdsLabel.length() < (int) (labelRecords * recordBytes)) {
pdsLabel += " ";
}

fout << pdsLabel;
return;
}

void CopyData ( std::ifstream &fin, std::ofstream &fout ) {
char line[2532];
while (!fin.eof()) {
fin.read(line, 2532);
fout.write(line, fin.gcount());
}
}
}
11 changes: 11 additions & 0 deletions isis/src/lro/apps/lronac2pds/lronac2pds.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef lronac2pds_h
#define lronac2pds_h

#include "Pvl.h"
#include "UserInterface.h"

namespace Isis{
extern void lronac2pds(UserInterface &ui);
}

#endif
Loading

0 comments on commit 2eca723

Please sign in to comment.