Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jigsaw Output CSMState String #5675

Draft
wants to merge 2 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 6 additions & 83 deletions isis/src/base/apps/csminit/csminit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,95 +70,18 @@ namespace Isis {
else if (ui.WasEntered("ISD")) {
QString isdFilePath = ui.GetFileName("ISD");

QList<QStringList> possibleModels;
for (const csm::Plugin * plugin : csm::Plugin::getList()) {
QString currentPluginName = QString::fromStdString(plugin->getPluginName());
if (ui.WasEntered("PLUGINNAME") && currentPluginName != ui.GetString("PLUGINNAME")) {
continue;
}

for (size_t modelIndex = 0; modelIndex < plugin->getNumModels(); modelIndex++) {
QString currentModelName = QString::fromStdString(plugin->getModelName(modelIndex));
if (ui.WasEntered("MODELNAME") && currentModelName != ui.GetString("MODELNAME")) {
continue;
}

csm::Isd fileIsd(isdFilePath.toStdString());
if (plugin->canModelBeConstructedFromISD(fileIsd, currentModelName.toStdString())) {
QStringList modelSpec = {
currentPluginName,
currentModelName,
QString::fromStdString(fileIsd.format())};
possibleModels.append(modelSpec);
continue; // If the file ISD works, don't check the other ISD formats
}

csm::Nitf21Isd nitf21Isd(isdFilePath.toStdString());
if (plugin->canModelBeConstructedFromISD(nitf21Isd, currentModelName.toStdString())) {
QStringList modelSpec = {
currentPluginName,
currentModelName,
QString::fromStdString(nitf21Isd.format())};
possibleModels.append(modelSpec);
continue; // If the NITF 2.1 ISD works, don't check the other ISD formats
}
}
}

if (possibleModels.size() > 1) {
QString message = "Multiple models can be created from the ISD [" + isdFilePath + "]. "
"Re-run with the PLUGINNAME and MODELNAME parameters. "
"Possible plugin & model names:\n";
for (const QStringList &modelSpec : possibleModels) {
message += "Plugin [" + modelSpec[0] + "], Model [" + modelSpec[1] + "]\n";
}
throw IException(IException::User, message, _FILEINFO_);
if (ui.WasEntered("PLUGINNAME")) {
pluginName = ui.GetString("PLUGINNAME");
}

if (possibleModels.empty()) {
QString message = "No loaded model could be created from the ISD [" + isdFilePath + "]."
"Loaded plugin & model names:\n";
for (const csm::Plugin * plugin : csm::Plugin::getList()) {
QString currentPluginName = QString::fromStdString(plugin->getPluginName());
for (size_t modelIndex = 0; modelIndex < plugin->getNumModels(); modelIndex++) {
QString modelName = QString::fromStdString(plugin->getModelName(modelIndex));
message += "Plugin [" + currentPluginName + "], Model [" + modelName + "]\n";
}
}
throw IException(IException::User, message, _FILEINFO_);
}

// If we are here, then we have exactly 1 model
QStringList modelSpec = possibleModels.front();

if (modelSpec.size() != 3) {
QString message = "Model specification [" + modelSpec.join(" ") + "] has [" + modelSpec.size() + "] elements "
"when it should have 3 elements.";
throw IException(IException::Programmer, message, _FILEINFO_);
if (ui.WasEntered("MODELNAME")) {
modelName = ui.GetString("MODELNAME");
}

QStringList modelSpec = CameraFactory::getModelSpecFromIsd(isdFilePath, pluginName, modelName);
model = CameraFactory::constructModelFromIsd(isdFilePath, modelSpec[0], modelSpec[1], modelSpec[2]);
pluginName = modelSpec[0];
modelName = modelSpec[1];
QString isdFormat = modelSpec[2];

const csm::Plugin *plugin = csm::Plugin::findPlugin(pluginName.toStdString());
if (plugin == NULL) {
QString message = "Cannot find requested Plugin: [" + pluginName + "].";
throw IException(IException::User, message, _FILEINFO_);
}

csm::Isd fileIsd(isdFilePath.toStdString());
csm::Nitf21Isd nitf21Isd(isdFilePath.toStdString());
if (isdFormat == QString::fromStdString(fileIsd.format())) {
model = plugin->constructModelFromISD(fileIsd, modelName.toStdString());
}
else if (isdFormat == QString::fromStdString(nitf21Isd.format())) {
model = plugin->constructModelFromISD(nitf21Isd, modelName.toStdString());
}
else {
QString message = "Invalid ISD format specifications [" + isdFormat + "].";
throw IException(IException::Programmer, message, _FILEINFO_);
}
} // end of ISD if statement

else if (ui.WasEntered("STATE")) {
Expand Down
126 changes: 126 additions & 0 deletions isis/src/base/objs/CameraFactory/CameraFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ find files of those names at the top level of this repository. **/
#include "Preference.h"

#include "csm/csm.h"
#include "csm/GeometricModel.h"
#include "csm/Isd.h"
#include "csm/Model.h"
#include "csm/NitfIsd.h"
#include "csm/Plugin.h"

using namespace csm;
Expand Down Expand Up @@ -220,4 +223,127 @@ namespace Isis {
throw IException(e, IException::Unknown, msg, _FILEINFO_);
}
}

/**
* Constructs CSM Model from ISD.
*
* @param isdFilePath Path to ISD file
* @param pluginName Plugin name
* @param modelName Model name
* @param isdFormat ISD format type (e.g., NITF)
*
*/
csm::Model *CameraFactory::constructModelFromIsd(QString isdFilePath, QString pluginName, QString modelName, QString isdFormat) {

// Get model spec if any of these params are not passed in
if (pluginName.isEmpty() || modelName.isEmpty() || isdFormat.isEmpty()) {
QStringList modelSpec = getModelSpecFromIsd(isdFilePath);
pluginName = modelSpec[0];
modelName = modelSpec[1];
isdFormat = modelSpec[2];
}

csm::Model *model = nullptr;

const csm::Plugin *plugin = csm::Plugin::findPlugin(pluginName.toStdString());
if (plugin == NULL) {
QString message = "Cannot find requested Plugin: [" + pluginName + "].";
throw IException(IException::User, message, _FILEINFO_);
}

csm::Isd fileIsd(isdFilePath.toStdString());
csm::Nitf21Isd nitf21Isd(isdFilePath.toStdString());
if (isdFormat == QString::fromStdString(fileIsd.format())) {
model = plugin->constructModelFromISD(fileIsd, modelName.toStdString());
}
else if (isdFormat == QString::fromStdString(nitf21Isd.format())) {
model = plugin->constructModelFromISD(nitf21Isd, modelName.toStdString());
}
else {
QString message = "Invalid ISD format specifications [" + isdFormat + "].";
throw IException(IException::Programmer, message, _FILEINFO_);
}

return model;
}

/**
* Generate CSM Model specs from ISD.
*
* @param isdFilePath Path to ISD file
* @param pluginName Plugin name
* @param modelName Model name
*/
QStringList CameraFactory::getModelSpecFromIsd(QString isdFilePath, QString pluginName, QString modelName) {
QList<QStringList> possibleModels;
for (const csm::Plugin * plugin : csm::Plugin::getList()) {
QString currentPluginName = QString::fromStdString(plugin->getPluginName());

if (!pluginName.isEmpty() && pluginName != pluginName) {
continue;
}

for (size_t modelIndex = 0; modelIndex < plugin->getNumModels(); modelIndex++) {
QString currentModelName = QString::fromStdString(plugin->getModelName(modelIndex));

if (!modelName.isEmpty() && currentModelName != modelName) {
continue;
}

csm::Isd fileIsd(isdFilePath.toStdString());
if (plugin->canModelBeConstructedFromISD(fileIsd, currentModelName.toStdString())) {
QStringList modelSpec = {
currentPluginName,
currentModelName,
QString::fromStdString(fileIsd.format())};
possibleModels.append(modelSpec);
continue; // If the file ISD works, don't check the other ISD formats
}

csm::Nitf21Isd nitf21Isd(isdFilePath.toStdString());
if (plugin->canModelBeConstructedFromISD(nitf21Isd, currentModelName.toStdString())) {
QStringList modelSpec = {
currentPluginName,
currentModelName,
QString::fromStdString(nitf21Isd.format())};
possibleModels.append(modelSpec);
continue; // If the NITF 2.1 ISD works, don't check the other ISD formats
}
}
}

if (possibleModels.size() > 1) {
QString message = "Multiple models can be created from the ISD [" + isdFilePath + "]. "
"Re-run with the PLUGINNAME and MODELNAME parameters. "
"Possible plugin & model names:\n";
for (const QStringList &modelSpec : possibleModels) {
message += "Plugin [" + modelSpec[0] + "], Model [" + modelSpec[1] + "]\n";
}
throw IException(IException::User, message, _FILEINFO_);
}

if (possibleModels.empty()) {
QString message = "No loaded model could be created from the ISD [" + isdFilePath + "]."
"Loaded plugin & model names:\n";
for (const csm::Plugin * plugin : csm::Plugin::getList()) {
QString currentPluginName = QString::fromStdString(plugin->getPluginName());
for (size_t modelIndex = 0; modelIndex < plugin->getNumModels(); modelIndex++) {
QString modelName = QString::fromStdString(plugin->getModelName(modelIndex));
message += "Plugin [" + currentPluginName + "], Model [" + modelName + "]\n";
}
}
throw IException(IException::User, message, _FILEINFO_);
}

// If we are here, then we have exactly 1 model
QStringList modelSpec = possibleModels.front();

if (modelSpec.size() != 3) {
QString message = "Model specification [" + modelSpec.join(" ") + "] has [" + modelSpec.size() + "] elements "
"when it should have 3 elements.";
throw IException(IException::Programmer, message, _FILEINFO_);
}

return modelSpec;
}
} // end namespace isis
3 changes: 3 additions & 0 deletions isis/src/base/objs/CameraFactory/CameraFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ find files of those names at the top level of this repository. **/

/* SPDX-License-Identifier: CC0-1.0 */
#include "Plugin.h"
#include "csm/Model.h"

namespace Isis {
class Camera;
Expand Down Expand Up @@ -55,6 +56,8 @@ namespace Isis {
static int CameraVersion(Cube &cube);
static int CameraVersion(Pvl &lab);
static void initPlugin();
static csm::Model *constructModelFromIsd(QString isdFilePath, QString pluginName = "", QString modelName = "", QString isdFormat = "");
static QStringList getModelSpecFromIsd(QString isdFilePath, QString pluginName = "", QString modelName = "");

private:
/**
Expand Down
55 changes: 55 additions & 0 deletions isis/src/control/apps/jigsaw/jigsaw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ find files of those names at the top level of this repository. **/
#include <highfive/H5DataSet.hpp>
#include <highfive/H5Group.hpp>
#include <vector>
#include <cstdio>

#include <QDir>
#include <QList>
Expand All @@ -37,6 +38,12 @@ find files of those names at the top level of this repository. **/
#include "SerialNumber.h"
#include "SerialNumberList.h"
#include "Table.h"
#include "CameraFactory.h"

#include <ale/Load.h>
#include <nlohmann/json.hpp>
#include <boost/filesystem.hpp>
using json = nlohmann::json;

#include "jigsaw.h"

Expand Down Expand Up @@ -70,6 +77,7 @@ namespace Isis {
ui.PutBoolean("RESIDUALS_CSV", false);
ui.PutBoolean("LIDAR_CSV", false);
ui.PutBoolean("OUTADJUSTMENTH5", false);
ui.PutBoolean("OUTPUT_ADJUSTED_CSMSTATE", false);

File fileRead(ui.GetFileName("ADJUSTMENT_INPUT").toStdString(), File::ReadOnly);
SerialNumberList *snList = new SerialNumberList(cubeList);
Expand Down Expand Up @@ -339,6 +347,53 @@ namespace Isis {
throw IException(e, IException::User, msg, _FILEINFO_);
}

if (ui.GetBoolean("OUTPUT_ADJUSTED_CSMSTATE")) {

// Go thru each file in cubelist
SerialNumberList *snList = new SerialNumberList(cubeList);
for (int i = 0; i < snList->size(); i++) {
QString filename = snList->fileName(i);

// Generate ISD from cube
json props;
json isd = ale::load(filename.toStdString(), props.dump(), "ale", false, true, false);

// Load plugin list
CameraFactory::initPlugin();

// Write ISD to temp file
boost::filesystem::path tempIsdFilePath = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
tempIsdFilePath = tempIsdFilePath.replace_extension(".json");
std::ofstream tempIsdFile(tempIsdFilePath.c_str());
if (tempIsdFile.is_open()) {
tempIsdFile << isd.dump() << std::endl;
tempIsdFile.close();
} else {
std::cerr << "Error creating temporary file [" << tempIsdFilePath << "]." << std::endl;
boost::filesystem::remove(tempIsdFilePath);
}

// Generate CSMState string
QString tempIsdFilePathStr = QString::fromStdString(tempIsdFilePath.string());
csm::Model *csmModel = CameraFactory::constructModelFromIsd(tempIsdFilePathStr);
std::string csmStateString = csmModel->getModelState();

// Remove temp file
boost::filesystem::remove(tempIsdFilePath);

// Write CSMState string to file
boost::filesystem::path filenamePath(filename.toStdString());
boost::filesystem::path csmStateFilename = filenamePath.replace_extension(".state.json");
ofstream csmStateFile(csmStateFilename.c_str());
if (csmStateFile.is_open()) {
csmStateFile << csmStateString << std::endl;
csmStateFile.close();
} else {
std::cerr << "Error creating CSMState file [" << csmStateFilename << "]." << std::endl;
}
}
}

//TODO - WHY DOES THIS MAKE VALGRIND ANGRY???
delete bundleAdjustment;
}
Expand Down
13 changes: 13 additions & 0 deletions isis/src/control/apps/jigsaw/jigsaw.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1871,6 +1871,19 @@
</default>
</parameter>

<parameter name="OUTPUT_ADJUSTED_CSMSTATE">
<brief> Outputs CSMState string to file after adjustment</brief>
<description>
Selection of this parameter flags output of CSMState string
to a JSON file. A CSMState string is generated for each cube
in the cube list and outputted to where the cubes are located.
</description>
<type>boolean</type>
<default>
<item>no</item>
</default>
</parameter>

<parameter name="OUTADJUSTMENTH5">
<brief> Outputs bundle adjustment values to HDF5 file - adjustment_out.h5</brief>
<description>
Expand Down