diff --git a/isis/src/base/apps/csminit/csminit.cpp b/isis/src/base/apps/csminit/csminit.cpp index ca58e98334..b788201233 100644 --- a/isis/src/base/apps/csminit/csminit.cpp +++ b/isis/src/base/apps/csminit/csminit.cpp @@ -70,95 +70,18 @@ namespace Isis { else if (ui.WasEntered("ISD")) { QString isdFilePath = ui.GetFileName("ISD"); - QList 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")) { diff --git a/isis/src/base/objs/CameraFactory/CameraFactory.cpp b/isis/src/base/objs/CameraFactory/CameraFactory.cpp index e32b7a1d48..5aaa846f3b 100644 --- a/isis/src/base/objs/CameraFactory/CameraFactory.cpp +++ b/isis/src/base/objs/CameraFactory/CameraFactory.cpp @@ -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; @@ -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 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 diff --git a/isis/src/base/objs/CameraFactory/CameraFactory.h b/isis/src/base/objs/CameraFactory/CameraFactory.h index 5739bc56db..09a3ff7945 100644 --- a/isis/src/base/objs/CameraFactory/CameraFactory.h +++ b/isis/src/base/objs/CameraFactory/CameraFactory.h @@ -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; @@ -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: /** diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index 9dc7bac4ce..5f41a1b5db 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -12,6 +12,7 @@ find files of those names at the top level of this repository. **/ #include #include #include +#include #include #include @@ -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 +#include +#include +using json = nlohmann::json; #include "jigsaw.h" @@ -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); @@ -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; } diff --git a/isis/src/control/apps/jigsaw/jigsaw.xml b/isis/src/control/apps/jigsaw/jigsaw.xml index 1dc590d335..a58bdd779d 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.xml +++ b/isis/src/control/apps/jigsaw/jigsaw.xml @@ -1871,6 +1871,19 @@ + + Outputs CSMState string to file after adjustment + + 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. + + boolean + + no + + + Outputs bundle adjustment values to HDF5 file - adjustment_out.h5