diff --git a/isis/src/base/objs/Application/Application.cpp b/isis/src/base/objs/Application/Application.cpp index 1e32f38704b48ee16bec4c6827898ffd2a6add48..b4b26ff8ab3a5d41330a3de74e287e943c45eff9 100644 --- a/isis/src/base/objs/Application/Application.cpp +++ b/isis/src/base/objs/Application/Application.cpp @@ -102,14 +102,6 @@ namespace Isis { strncpy(env, "LANG=en_US", 1023); putenv(env); - // Verify ISISROOT was set - if (getenv("ISISROOT") == NULL || QString(getenv("ISISROOT")) == "") { - QString message = "Please set ISISROOT before running any Isis " - "applications"; - cerr << message << endl; - abort(); - } - // Get the starting cpu time, direct I/Os, page faults, and swaps //p_startClock = clock(); p_startDirectIO = DirectIO(); diff --git a/isis/src/base/objs/EmbreeShapeModel/EmbreeShapeModel.cpp b/isis/src/base/objs/EmbreeShapeModel/EmbreeShapeModel.cpp index 273a98178d190508edb8e9bfc05081b34c56eb95..ca78a550ed5cc83cee8ac067c5853fdcc15540ed 100644 --- a/isis/src/base/objs/EmbreeShapeModel/EmbreeShapeModel.cpp +++ b/isis/src/base/objs/EmbreeShapeModel/EmbreeShapeModel.cpp @@ -593,50 +593,6 @@ namespace Isis { } - /** - * Computes and returns emission angle, in degrees, given the observer - * position. The surface normal vector is calculated using an ellipsoid, not - * the local normal of the actual target shape. - * - * Emission Angle: The angle between the surface normal vector at the - * intersection point and the vector from the intersection point to the - * observer (usually the spacecraft). The emission angle varies from 0 degrees - * when the observer is viewing the sub-spacecraft point (nadir viewing) to 90 - * degrees when the intercept is tangent to the surface of the target body. - * Thus, higher values of emission angle indicate more oblique viewing of the - * target. - * - * @param observerBodyFixedPosition Three dimensional position of the observer, - * in the coordinate system of the target body. - * - * @return The emission angle, in decimal degrees. - * - */ - double EmbreeShapeModel::emissionAngle(const std::vector<double> &observerBodyFixedPosition) { - - // If there is already a normal save it, because it's probably the local normal - std::vector<double> localNormal; - bool hadNormal = hasNormal(); - if ( hadNormal ) { - localNormal = normal(); - } - - // Calculate the ellipsoid surface normal - calculateDefaultNormal(); - - // Use ShapeModel to calculate the ellipsoid emission angle - double ellipsoidEmission = ShapeModel::emissionAngle(observerBodyFixedPosition); - - // If there's a saved normal, reset it - if ( hadNormal ) { - setNormal(localNormal); - } - - // Return the ellipsoid emission angle - return ellipsoidEmission; - } - - /** * Computes and returns incidence angle, in degrees, given the illuminator position. * The surface normal vector is calculated using an ellipsoid, not the local diff --git a/isis/src/base/objs/EmbreeShapeModel/EmbreeShapeModel.h b/isis/src/base/objs/EmbreeShapeModel/EmbreeShapeModel.h index 1d0d66320c14c3b6685724096b9006fa9cd9e7ab..e11f615b77ff036d862da99ded9c26900e4469e2 100644 --- a/isis/src/base/objs/EmbreeShapeModel/EmbreeShapeModel.h +++ b/isis/src/base/objs/EmbreeShapeModel/EmbreeShapeModel.h @@ -47,6 +47,8 @@ namespace Isis { * * @internal * @history 2017-04-22 Jesse Mapel and Jeannie Backer - Original Version + * @history 2018-05-01 Christopher Combs - Removed emissionAngle function to + * fix issues with using ellipsoids to find normals. Fixes #5387. */ class EmbreeShapeModel : public ShapeModel { public: @@ -84,10 +86,8 @@ namespace Isis { virtual void calculateSurfaceNormal(); QVector<double> ellipsoidNormal(); - virtual double emissionAngle(const std::vector<double> &sB); virtual double incidenceAngle(const std::vector<double> &uB); - virtual Distance localRadius(const Latitude &lat, const Longitude &lon); // Determine if the internal intercept is occluded from the observer/lookdir diff --git a/isis/src/base/objs/Isis/Isis.h b/isis/src/base/objs/Isis/Isis.h index df6889d3e23bc4f64fde2b2f67a5cfaf2bf9cce3..2e6e8d87e2fc3d96758bf22d3b87ffb7d079811f 100644 --- a/isis/src/base/objs/Isis/Isis.h +++ b/isis/src/base/objs/Isis/Isis.h @@ -107,6 +107,14 @@ void InterruptSignal(int); * @return int */ int main(int argc, char *argv[]) { + // Verify ISISROOT was set + // Note: as printing and logging IExceptions requires ISISROOT to be set (for preferences), + // The case below cannot be handled with IExceptions + if (getenv("ISISROOT") == NULL || QString(getenv("ISISROOT")) == "") { + std::cerr << "Please set ISISROOT before running any Isis applications" << std::endl; + exit(1); + } + #ifdef CWDEBUG startMonitoringMemory(); signal(SIGSEGV, SegmentationFault); @@ -119,7 +127,7 @@ int main(int argc, char *argv[]) { #ifdef USE_GUI_QAPP Isis::Application::p_applicationForceGuiApp = true; #endif - + // Add the plugin directory so QT looks at the Isis plugin dir Isis::FileName qtpluginpath("$ISISROOT/3rdParty/plugins"); QCoreApplication::addLibraryPath(qtpluginpath.expanded()); diff --git a/isis/src/base/objs/ProcessImport/ProcessImport.cpp b/isis/src/base/objs/ProcessImport/ProcessImport.cpp index c6ccd306bdc488d40e98b29101ba3214d9fb2a4f..7ae955ad9b51b02baf71d25ade870600ae7d7456 100644 --- a/isis/src/base/objs/ProcessImport/ProcessImport.cpp +++ b/isis/src/base/objs/ProcessImport/ProcessImport.cpp @@ -725,7 +725,7 @@ namespace Isis { * This method returns the number of data trailer bytes */ int ProcessImport::DataTrailerBytes() const { - return p_dataTrailerBytes; + return p_dataTrailerBytes; } @@ -1847,11 +1847,6 @@ namespace Isis { */ void ProcessImport::ProcessBip(void funct(Isis::Buffer &out)) { - // Figure out the number of bytes to read for a single line - int readBytes = Isis::SizeOf(p_pixelType); - readBytes = readBytes * p_ns * p_nb; - char *in = new char [readBytes]; - // Set up an Isis::EndianSwapper object QString tok(Isis::ByteOrderName(p_byteOrder)); tok = tok.toUpper(); @@ -1902,6 +1897,11 @@ namespace Isis { p_progress->SetMaximumSteps(p_nl); p_progress->CheckStatus(); + // Figure out the number of bytes to read for a single line + int sampleBytes = Isis::SizeOf(p_pixelType) * p_nb + p_dataPreBytes + p_dataPostBytes; + int readBytes = p_ns * sampleBytes; + char *in = new char [readBytes]; + // Loop for each line for(int line = 0; line < p_nl; line++) { // Check the last io @@ -1915,16 +1915,6 @@ namespace Isis { // Space for storing prefix and suffix data pointers vector<char *> tempPre, tempPost; - // Handle any line prefix bytes - pos = fin.tellg(); - if (p_saveDataPre) { - tempPre.push_back(new char[p_dataPreBytes]); - fin.read(tempPre.back(), p_dataPreBytes); - } - else { - fin.seekg(p_dataPreBytes, ios_base::cur); - } - // Check the last io if (!fin.good()) { QString msg = "Cannot read file [" + p_inFile + "]. Position [" + @@ -1960,31 +1950,32 @@ namespace Isis { // to special pixels int osamp = 0; - for(int samp = band; samp < p_ns * p_nb; samp += p_nb) { + for(int samp = 0; samp < p_ns; samp++) { + int bufferIndex = p_dataPreBytes + Isis::SizeOf(p_pixelType)*band + samp*sampleBytes; switch(p_pixelType) { case Isis::UnsignedByte: - (*out)[osamp] = (double)((unsigned char *)in)[samp]; + (*out)[osamp] = (double)((unsigned char *)in)[bufferIndex]; break; case Isis::UnsignedWord: (*out)[osamp] = - (double)swapper.UnsignedShortInt((unsigned short int *)in+samp); + (double)swapper.UnsignedShortInt(&in[bufferIndex]); break; case Isis::SignedWord: - (*out)[osamp] = (double)swapper.ShortInt((short int *)in+samp); + (*out)[osamp] = (double)swapper.ShortInt(&in[bufferIndex]); break; case Isis::SignedInteger: - (*out)[samp] = (double)swapper.Int((int *)in+samp); + (*out)[samp] = (double)swapper.Int(&in[bufferIndex]); break; case Isis::Real: if(p_vax_convert) { - (*out)[osamp]= VAXConversion( (float *)in+samp ); + (*out)[osamp]= VAXConversion(&in[bufferIndex]); } else { - (*out)[osamp] = (double)swapper.Float((float *)in+samp); + (*out)[osamp] = (double)swapper.Float(&in[bufferIndex]); } break; case Isis::Double: - (*out)[osamp] = (double)swapper.Double((double *)in+samp); + (*out)[osamp] = (double)swapper.Double(&in[bufferIndex]); break; default: break; @@ -2008,47 +1999,38 @@ namespace Isis { funct(*out); } - // Handle any line suffix bytes - pos = fin.tellg(); - if (p_saveDataPost) { - tempPost.push_back(new char[p_dataPostBytes]); - fin.read(tempPost.back(), p_dataPostBytes); - } - else { - fin.seekg(p_dataPostBytes, ios_base::cur); - } - - // Check the last io - if (!fin.good()) { - QString msg = "Cannot read file [" + p_inFile + "]. Position [" + - toString((int)pos) + "]. Byte count [" + - toString(p_dataPreBytes) + "]" ; - throw IException(IException::Io, msg, _FILEINFO_); - } - - - // Save off the prefix bytes vector - if (p_saveDataPre) { - p_dataPre.push_back(tempPre); - tempPre.clear(); - } + } // End band loop - // Save off the suffix bytes vector - if (p_saveDataPost) { - p_dataPost.push_back(tempPost); - tempPost.clear(); + // Handle record prefix and suffix + if (p_saveDataPre) { + for(int samp = 0; samp < p_ns; samp++) { + char *samplePrefix = new char[p_dataPreBytes]; + memcpy(samplePrefix, &in[samp*sampleBytes], p_dataPreBytes); + tempPre.push_back(samplePrefix); } - - // Check the last io - if (!fin.good()) { - QString msg = "Cannot read file [" + p_inFile + "]. Position [" + - toString((int)pos) + "]. Byte count [" + - toString(p_fileHeaderBytes) + "]" ; - throw IException(IException::Io, msg, _FILEINFO_); + p_dataPre.push_back(tempPre); + tempPre.clear(); + } + if (p_saveDataPost) { + for(int samp = 0; samp < p_ns; samp++) { + char *sampleSuffix = new char[p_dataPostBytes]; + int suffixIndex = p_dataPreBytes + Isis::SizeOf(p_pixelType)*p_nb + samp*sampleBytes; + memcpy(sampleSuffix, &in[suffixIndex], p_dataPostBytes); + tempPost.push_back(sampleSuffix); } + p_dataPost.push_back(tempPost); + tempPost.clear(); + } - } // End band loop + // Check the last io + if (!fin.good()) { + QString msg = "Cannot read file [" + p_inFile + "]. Position [" + + toString((int)pos) + "]. Byte count [" + + toString(p_dataPreBytes) + "]" ; + throw IException(IException::Io, msg, _FILEINFO_); + } + // Handle the data trailer pos = fin.tellg(); if (p_saveDataTrailer) { p_dataTrailer.push_back(new char[p_dataTrailerBytes]); diff --git a/isis/src/base/objs/ProcessImport/ProcessImport.h b/isis/src/base/objs/ProcessImport/ProcessImport.h index 1e47db453f8d68ae86fcfc2da5a27114102f6043..33a3cd3fa5818b194f325f0b1f16a556698f53fb 100644 --- a/isis/src/base/objs/ProcessImport/ProcessImport.h +++ b/isis/src/base/objs/ProcessImport/ProcessImport.h @@ -150,8 +150,19 @@ namespace Isis { * imports. Brought code closer to coding standards. * @history 2016-04-21 Makayla Shepherd - Added UnsignedWord pixel type handling. * @history 2017-05-29 Kristin Berry - Added support for data trailers in BIP files and fixed - * a typo so that DataTrailerBytes() will return the correct value. - * References #3888. + * a typo so that DataTrailerBytes() will return the correct value. + * References #3888. + * @history 2018-05-01 Jesse Mapel - Changed data suffix and prefix in BIP files. Previously, + * data suffixes and prefixes were for each band before/after each line. + * Now, data suffixes and prefixes are before/after each sample. For a + * RGB, 3-band image with n samples a line of data was previously + * | Header | R prefix | G prefix | B prefix | R 1 | G 1 | B 1| ... + * | R n | G n | B n| R suffix | G suffix | B suffix | Trailer |. Now + * it is | Header | Prefix 1 | R 1 | G 1 | B 1 | Suffix 1 | ... + * | Prefix n | R n | G n | B n | Suffix n | Trailer |. This change + * was made to accomodate Rosetta VIRTIS-m calibrated data files and + * has no impact on other supported BIP files. + * Fixes #5398. * */ class ProcessImport : public Isis::Process { diff --git a/isis/src/base/objs/PushFrameCameraCcdLayout/PushFrameCameraCcdLayout.truth b/isis/src/base/objs/PushFrameCameraCcdLayout/PushFrameCameraCcdLayout.truth index f36198413ae088b2edefa59d47bc2ce4d430c34f..d54562e565205f3c9b2224bc8e6e3ca24c196527 100644 --- a/isis/src/base/objs/PushFrameCameraCcdLayout/PushFrameCameraCcdLayout.truth +++ b/isis/src/base/objs/PushFrameCameraCcdLayout/PushFrameCameraCcdLayout.truth @@ -31,7 +31,7 @@ Get the METHANE filter layout METHANE filter ID: -61504 METHANE filter name: "METHANE" METHANE filter start sample: 1 -METHANE filter start line: 291 +METHANE filter start line: 285 METHANE filter samples: 1648 METHANE filter lines: 128 @@ -39,7 +39,7 @@ Get the METHANE filter layout but give it a different name METHANE filter ID: -61504 METHANE filter name: "methane" METHANE filter start sample: 1 -METHANE filter start line: 291 +METHANE filter start line: 285 METHANE filter samples: 1648 METHANE filter lines: 128 diff --git a/isis/src/base/objs/PvlToPvlTranslationManager/PvlToPvlTranslationManager.cpp b/isis/src/base/objs/PvlToPvlTranslationManager/PvlToPvlTranslationManager.cpp index 2db7ad7c4d3c1a823f9d5680147d8fd6b6887276..95ee570ca43ebdaeeedf12c5c14bcf2a38922a56 100644 --- a/isis/src/base/objs/PvlToPvlTranslationManager/PvlToPvlTranslationManager.cpp +++ b/isis/src/base/objs/PvlToPvlTranslationManager/PvlToPvlTranslationManager.cpp @@ -40,7 +40,7 @@ namespace Isis { * set the input label before translating. This may be done by using * SetLabel(Pvl inputLabel) or Auto(Pvl inputLabel, Pvl outputLabel). * - * @param transFile The translation file to be used to tranlate keywords in + * @param transFile The translation file to be used to translate keywords in * the input label. */ PvlToPvlTranslationManager::PvlToPvlTranslationManager(const QString &transFile) @@ -53,8 +53,8 @@ namespace Isis { * input label before translating. This may be done by using SetLabel(Pvl * inputLabel) or Auto(Pvl inputLabel, Pvl outputLabel). * - * @param transStrm A stream containing the tranlation table to be used to - * tranlate keywords in the input label. + * @param transStrm A stream containing the translation table to be used to + * translate keywords in the input label. */ PvlToPvlTranslationManager::PvlToPvlTranslationManager(std::istream &transStrm) : LabelTranslationManager(transStrm) { @@ -66,7 +66,7 @@ namespace Isis { * * @param inputLabel The Pvl holding the input label. * - * @param transFile The translation file to be used to tranlate keywords in + * @param transFile The translation file to be used to translate keywords in * the input label. */ PvlToPvlTranslationManager::PvlToPvlTranslationManager(Pvl &inputLabel, @@ -81,8 +81,8 @@ namespace Isis { * * @param inputLabel The Pvl holding the input label. * - * @param transStrm A stream containing the tranlation table to be used to - * tranlate keywords in the input label. + * @param transStrm A stream containing the translation table to be used to + * translate keywords in the input label. */ PvlToPvlTranslationManager::PvlToPvlTranslationManager(Pvl &inputLabel, std::istream &transStrm) @@ -103,34 +103,37 @@ namespace Isis { /** * Returns a translated value. The output name is used to find the input - * group, keyword, default and tranlations in the translation table. If the + * group, keyword, default and translations in the translation table. If the * keyword does not exist in the input label and an input default is available, * then this default will be used as the input value. This input value is * then used to search all of the translations. If a match is found the * translated value is returned. * - * @param nName The output name used to identify the input keyword to be - * translated. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @param findex The index into the input keyword array. Defaults to 0 * * @return string */ - QString PvlToPvlTranslationManager::Translate(QString nName, int findex) { + QString PvlToPvlTranslationManager::Translate(QString translationGroupName, int findex) { const PvlContainer *con; int inst = 0; PvlKeyword grp; - while((grp = InputGroup(nName, inst++)).name() != "") { + while((grp = InputGroup(translationGroupName, inst++)).name() != "") { if((con = GetContainer(grp)) != NULL) { - if(con->hasKeyword(InputKeywordName(nName))) { - return PvlTranslationTable::Translate(nName, - (*con)[InputKeywordName(nName)][findex]); + if(con->hasKeyword(InputKeywordName(translationGroupName))) { + return PvlTranslationTable::Translate(translationGroupName, + (*con)[InputKeywordName(translationGroupName)][findex]); } } } - return PvlTranslationTable::Translate(nName); + return PvlTranslationTable::Translate(translationGroupName); } @@ -143,12 +146,15 @@ namespace Isis { * * @see Auto(). * - * @param nName The output name used to identify the input keyword to be - * translated. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @return PvlKeyword */ - PvlKeyword PvlToPvlTranslationManager::DoTranslation(const QString nName) { + PvlKeyword PvlToPvlTranslationManager::DoTranslation(const QString translationGroupName) { const PvlContainer *con = NULL; PvlKeyword key; @@ -156,9 +162,9 @@ namespace Isis { PvlGroup transGroup; PvlKeyword grp; - while((grp = InputGroup(nName, inst++)).name() != "") { + while((grp = InputGroup(translationGroupName, inst++)).name() != "") { if((con = GetContainer(grp)) != NULL) { - transGroup = TranslationTable().findGroup(nName); + transGroup = TranslationTable().findGroup(translationGroupName); Pvl::ConstPvlKeywordIterator it = transGroup.findKeyword("InputKey", transGroup.begin(), transGroup.end()); @@ -167,10 +173,10 @@ namespace Isis { while(it != transGroup.end()) { const PvlKeyword &result = *it; if(con->hasKeyword(result[0])) { - key.setName(OutputName(nName)); + key.setName(OutputName(translationGroupName)); for(int v = 0; v < (*con)[(result[0])].size(); v++) { - key.addValue(PvlTranslationTable::Translate(nName, + key.addValue(PvlTranslationTable::Translate(translationGroupName, (*con)[result[0]][v]), (*con)[result[0]].unit(v)); } @@ -182,8 +188,8 @@ namespace Isis { } } - return PvlKeyword(OutputName(nName), - PvlTranslationTable::Translate(nName, "")); + return PvlKeyword(OutputName(translationGroupName), + PvlTranslationTable::Translate(translationGroupName, "")); } @@ -227,16 +233,20 @@ namespace Isis { /** * Returns the ith input value associated with the output name argument. * - * @param nName The output name used to identify the input keyword. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @param findex The index into the input keyword array. Defaults to 0 * * @throws IException::Programmer */ - const PvlKeyword &PvlToPvlTranslationManager::InputKeyword(const QString nName) const { + const PvlKeyword &PvlToPvlTranslationManager::InputKeyword(const QString translationGroupName) const { int instanceNumber = 0; - PvlKeyword inputGroupKeyword = InputGroup(nName, instanceNumber); + PvlKeyword inputGroupKeyword = InputGroup(translationGroupName, instanceNumber); bool anInputGroupFound = false; while(inputGroupKeyword.name() != "") { @@ -244,31 +254,31 @@ namespace Isis { if(containingGroup != NULL) { anInputGroupFound = true; - if(containingGroup->hasKeyword(InputKeywordName(nName))) { - return containingGroup->findKeyword(InputKeywordName(nName)); + if(containingGroup->hasKeyword(InputKeywordName(translationGroupName))) { + return containingGroup->findKeyword(InputKeywordName(translationGroupName)); } } instanceNumber ++; - inputGroupKeyword = InputGroup(nName, instanceNumber); + inputGroupKeyword = InputGroup(translationGroupName, instanceNumber); } if(anInputGroupFound) { - QString msg = "Unable to find input keyword [" + InputKeywordName(nName) + - "] for output name [" + nName + "] in file [" + TranslationTable().fileName() + "]"; + QString msg = "Unable to find input keyword [" + InputKeywordName(translationGroupName) + + "] for output name [" + translationGroupName + "] in file [" + TranslationTable().fileName() + "]"; throw IException(IException::Programmer, msg, _FILEINFO_); } else { QString container = ""; - for(int i = 0; i < InputGroup(nName).size(); i++) { + for(int i = 0; i < InputGroup(translationGroupName).size(); i++) { if(i > 0) container += ","; - container += InputGroup(nName)[i]; + container += InputGroup(translationGroupName)[i]; } QString msg = "Unable to find input group [" + container + - "] for output name [" + nName + "] in file [" + TranslationTable().fileName() + "]"; + "] for output name [" + translationGroupName + "] in file [" + TranslationTable().fileName() + "]"; throw IException(IException::Programmer, msg, _FILEINFO_); } } @@ -278,21 +288,25 @@ namespace Isis { * Indicates if the input keyword corresponding to the output name exists in * the label * - * @param nName The output name used to identify the input keyword. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. */ - bool PvlToPvlTranslationManager::InputHasKeyword(const QString nName) { + bool PvlToPvlTranslationManager::InputHasKeyword(const QString translationGroupName) { // Set the current position in the input label pvl // by finding the input group corresponding to the output group const PvlContainer *con; int inst = 0; - //while ((con = GetContainer(InputGroup(nName, inst++))) != NULL) { - //if ((con = GetContainer (InputGroup(nName))) != NULL) { + //while ((con = GetContainer(InputGroup(translationGroupName, inst++))) != NULL) { + //if ((con = GetContainer (InputGroup(translationGroupName))) != NULL) { PvlKeyword grp; - while((grp = InputGroup(nName, inst++)).name() != "") { + while((grp = InputGroup(translationGroupName, inst++)).name() != "") { if((con = GetContainer(grp)) != NULL) { - if(con->hasKeyword(InputKeywordName(nName))) return true; + if(con->hasKeyword(InputKeywordName(translationGroupName))) return true; } } @@ -340,10 +354,17 @@ namespace Isis { /** * Create the requsted container and any containers above it and - * return a reference to the container - * list is an PvlKeyword with an array of container types an their names + * return a reference to the container. List is a PvlKeyword + * with an array of container types and their names. + * + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. + * @param pvl Pvl */ - PvlContainer *PvlToPvlTranslationManager::CreateContainer(const QString nName, Pvl &pvl) { - return LabelTranslationManager::CreateContainer(nName, pvl); + PvlContainer *PvlToPvlTranslationManager::CreateContainer(const QString translationGroupName, Pvl &pvl) { + return LabelTranslationManager::CreateContainer(translationGroupName, pvl); } } // end namespace isis diff --git a/isis/src/base/objs/PvlToPvlTranslationManager/PvlToPvlTranslationManager.h b/isis/src/base/objs/PvlToPvlTranslationManager/PvlToPvlTranslationManager.h index 842d475e87f11846fb43da1f16a6e6d99f3716ff..fcc4c70d5434272ea809f4400dfa36a6a42fccea 100644 --- a/isis/src/base/objs/PvlToPvlTranslationManager/PvlToPvlTranslationManager.h +++ b/isis/src/base/objs/PvlToPvlTranslationManager/PvlToPvlTranslationManager.h @@ -71,7 +71,8 @@ namespace Isis { * PvlToPvlTranslationManager. Fixes #4901. * @history 2018-01-10 Christopher Combs - Changed ProcessDataFilePointer call to reflect * changes made to voy2isis. Fixes #4345, #4421. - * @history 2018-04-16 Jeannie Backer - Fixed indentation of history comments. + * @history 2018-04-16 Jeannie Backer - Fixed indentation of history comments and + * brought code closer to coding standards. * @todo 2005-02-15 Stuart Sides - add coded example and implementation example * to class documentation, and finish * documentation. @@ -92,24 +93,24 @@ namespace Isis { // Attempt to translate the requested output name to output value // using the input name and value/default value - virtual QString Translate(QString nName, int findex = 0); + virtual QString Translate(QString translationGroupName, int findex = 0); // Translate all translation table groups which contain "Auto" void Auto(Pvl &outputLabel); void Auto(Pvl &inputLabel, Pvl &outputLabel); // Return the ith input value associated with a output name - virtual const PvlKeyword &InputKeyword(const QString nName) const; + virtual const PvlKeyword &InputKeyword(const QString translationGroupName) const; // Return true if the input lable contains the translated group and key names - virtual bool InputHasKeyword(const QString nName); + virtual bool InputHasKeyword(const QString translationGroupName); void SetLabel(Pvl &inputLabel); protected: - virtual PvlKeyword DoTranslation(const QString nName); + virtual PvlKeyword DoTranslation(const QString translationGroupName); virtual const PvlContainer *GetContainer(const PvlKeyword &inputGroup) const; - virtual PvlContainer *CreateContainer(const QString nName, Pvl &pvl); + virtual PvlContainer *CreateContainer(const QString translationGroupName, Pvl &pvl); private: Pvl p_fLabel; //!< A Pvl object for the input label file }; diff --git a/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.cpp b/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.cpp index 80d9b7379101a94c817de085cd56b565b1c5254a..06882220e51ba8ba07c7fc4337b15cad6ce53883 100644 --- a/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.cpp +++ b/isis/src/base/objs/PvlTranslationTable/PvlTranslationTable.cpp @@ -214,9 +214,11 @@ namespace Isis { * Translates a single output value from the given translation * group name and input value. * - * @param translationGroupName The name of the pvl translation - * group. Often, this is the same - * as the output keyword name. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * @param inputKeyValue The value to be translated, from the * input keyword. * @@ -283,7 +285,11 @@ namespace Isis { * Returns the input group name from the translation table corresponding to * the output name argument. * - * @param translationGroupName The output name to be used to search the translation table. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * @param inst The occurence number of the "InputGroup" keyword * (first one is zero) * @@ -357,9 +363,15 @@ namespace Isis { * Returns the input keyword name from the translation table corresponding to * the output name argument. * - * @param translationGroupName The output name to be used to search the translation table. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. + * + * @return QString The input keyword name * - * @return QString The input keyword name. + * @throws IException::Programmer */ QString PvlTranslationTable::InputKeywordName(const QString translationGroupName) const { @@ -375,7 +387,11 @@ namespace Isis { * Returns the input default value from the translation table corresponding * to the output name argument. * - * @param translationGroupName The output name to be used to search the translation table. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @return QString The input default value. */ @@ -395,7 +411,11 @@ namespace Isis { * PvlKeyword with the name "InputDefault". Note: no value needs * to be assigned to this keyword. * - * @param translationGroupName The name of the PVL translation group. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @return bool Indicates whether the given group has an * InputDefault keyword. @@ -416,7 +436,11 @@ namespace Isis { * group contains a PvlKeyword with the name "Auto". Note: * no value is assigned to this keyword. * - * @param translationGroupName The name of the PVL translation group. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @return bool Indicates whether the given group has an Auto * keyword. @@ -437,7 +461,11 @@ namespace Isis { * PvlKeyword with the name "Optional". Note: no value is * assigned to this keyword. * - * @param translationGroupName The name of the PVL translation group. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @return bool Indicates whether the given group has an * Optional keyword. @@ -456,7 +484,11 @@ namespace Isis { * Retrieves the OutputPosition PvlKeyword for the translation * group with the given name. * - * @param translationGroupName The name of the PVL translation group. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @return PvlKeyword The OutputPosition keyword from the given * translation group. @@ -483,7 +515,11 @@ namespace Isis { * Retrieves a string containing the value of the OutputName * keyword for the translation group with the given name. * - * @param translationGroupName The name of the PVL translation group. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @return @b QString The value of the OutputName keyword from * the given translation group. @@ -504,7 +540,11 @@ namespace Isis { * * @see PvlObject::findGroup() * - * @param translationGroupName Name of the PVL group to search for. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @return const PvlGroup& The first PVL group with the given name. * diff --git a/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp b/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp index ceb4e7cd1095eeaf2249baea31a7782b1df1ea9a..a7cebd130f3cf70bcea0fde53eb82015c6923e3a 100644 --- a/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp +++ b/isis/src/base/objs/SpiceRotation/SpiceRotation.cpp @@ -149,7 +149,7 @@ namespace Isis { p_timeBias = rotToCopy.p_timeBias; p_et = rotToCopy.p_et; - p_quaternion = rotToCopy.p_quaternion; + p_quaternion = rotToCopy.p_quaternion; p_matrixSet = rotToCopy.p_matrixSet; p_source = rotToCopy.p_source; p_axisP = rotToCopy.p_axisP; @@ -159,8 +159,8 @@ namespace Isis { p_timeScale = rotToCopy.p_timeScale; p_degreeApplied = rotToCopy.p_degreeApplied; -// for (std::vector<double>::size_type i = 0; i < rotToCopy.p_coefficients[0].size(); i++) - for (int i = 0; i < 3; i++) +// for (std::vector<double>::size_type i = 0; i < rotToCopy.p_coefficients[0].size(); i++) + for (int i = 0; i < 3; i++) p_coefficients[i] = rotToCopy.p_coefficients[i]; p_noOverride = rotToCopy.p_noOverride; @@ -180,43 +180,43 @@ namespace Isis { } - /** + /** * Destructor for SpiceRotation object. - */ - SpiceRotation::~SpiceRotation() { + */ + SpiceRotation::~SpiceRotation() { } - /** + /** * Change the frame to the given frame code. This method has no effect if - * spice is cached. + * spice is cached. * - * @param frameCode The integer-valued frame code - */ + * @param frameCode The integer-valued frame code + */ void SpiceRotation::SetFrame(int frameCode) { p_constantFrames[0] = frameCode; } - /** - * Accessor method that returns the frame code. This is the first value of the - * constant frames member variable. - * - * @return @b int An integer value indicating the frame code. - */ + /** + * Accessor method that returns the frame code. This is the first value of the + * constant frames member variable. + * + * @return @b int An integer value indicating the frame code. + */ int SpiceRotation::Frame() { return p_constantFrames[0]; } - /** + /** * Apply a time bias when invoking SetEphemerisTime method. * * The bias is used only when reading from NAIF kernels. It is added to the * ephermeris time passed into SetEphemerisTime and then the body * position is read from the NAIF kernels and returned. When the cache - * is loaded from a table the bias is ignored as it is assumed to have - * already been applied. If this method is never called the default bias is + * is loaded from a table the bias is ignored as it is assumed to have + * already been applied. If this method is never called the default bias is * 0.0 seconds. * * @param timeBias time bias in seconds @@ -226,7 +226,7 @@ namespace Isis { } - /** + /** * Return the J2000 to reference frame quaternion at given time. * * This method returns the J2000 to reference frame rotational matrix at a @@ -280,11 +280,11 @@ namespace Isis { } - /** + /** * Accessor method to get current ephemeris time. * * @return @b double The current ephemeris time. - */ + */ double SpiceRotation::EphemerisTime() const { return p_et; } @@ -301,16 +301,16 @@ namespace Isis { /** - * Set the downsize status to minimize cache. + * Set the downsize status to minimize cache. * - * @param status The DownsizeStatus enumeration value. - */ + * @param status The DownsizeStatus enumeration value. + */ void SpiceRotation::MinimizeCache(DownsizeStatus status) { p_minimizeCache = status; } - /** + /** * Cache J2000 rotation quaternion over a time range. * * This method will load an internal cache with frames over a time @@ -384,7 +384,7 @@ namespace Isis { } - /** + /** * Cache J2000 to frame rotation for a time. * * This method will load an internal cache with a rotation for a single @@ -402,7 +402,7 @@ namespace Isis { } - /** + /** * Cache J2000 rotations using a table file. * * This method will load either an internal cache with rotations (quaternions) @@ -423,7 +423,7 @@ namespace Isis { * @param table An ISIS table blob containing valid J2000 to reference * quaternion/time values * - * @throws IException::Programmer "Expecting either three, five, or eight fields in the + * @throws IException::Programmer "Expecting either three, five, or eight fields in the * SpiceRotation table" */ void SpiceRotation::LoadCache(Table &table) { @@ -476,7 +476,7 @@ namespace Isis { p_fullCacheSize = toInt(table.Label().findKeyword("CkTableOriginalSize")[0]); } - // Load FrameTypeCode from labels if available and the planetary constants keywords + // Load FrameTypeCode from labels if available and the planetary constants keywords if (table.Label().hasKeyword("FrameTypeCode")) { m_frameType = (FrameType) toInt(table.Label().findKeyword("FrameTypeCode")[0]); } @@ -582,7 +582,7 @@ namespace Isis { } - /** + /** * Cache J2000 rotation over existing cached time range using polynomials * * This method will reload an internal cache with matrices @@ -601,7 +601,7 @@ namespace Isis { p_cacheTime.clear(); p_cache.clear(); - // Clear the angular velocity cache if we can calculate it instead. It can't be calculated + // Clear the angular velocity cache if we can calculate it instead. It can't be calculated // for functions of degree 0 (framing cameras), so keep the original av. It is better than // nothing. if (p_degree > 0 && p_cacheAv.size() > 1) p_cacheAv.clear(); @@ -644,7 +644,7 @@ namespace Isis { if (p_hasAngularVelocity) p_cacheAv.push_back(tempRot.AngularVelocity()); } } - else { //(p_source < PolyFunction) + else { //(p_source < PolyFunction) QString msg = "The SpiceRotation has not yet been fit to a function"; throw IException(IException::Programmer, msg, _FILEINFO_); } @@ -657,7 +657,7 @@ namespace Isis { } - /** + /** * Return a table with J2000 to reference rotations. * * Return a table containing the cached pointing with the given @@ -668,7 +668,7 @@ namespace Isis { * * @throws IException::Programmer "Only cached rotations can be returned as a line cache of * quaternions and time" - * + * * @return @b Table Table with given name that contains the cached pointing */ Table SpiceRotation::LineCache(const QString &tableName) { @@ -685,7 +685,7 @@ namespace Isis { } - /** + /** * Return a table with J2000 to reference rotations. * * Return a table containing the cached pointing with the given @@ -703,7 +703,7 @@ namespace Isis { * @param tableName Name of the table to create and return * * @throws IException::Programmer "To create table source of data must be either Memcache or - * PolyFunction" + * PolyFunction" * * @return @b Table Table with given name that contains the cached pointing */ @@ -812,8 +812,8 @@ namespace Isis { } - /** - * Initialize planetary orientation constants from Spice PCK + /** + * Initialize planetary orientation constants from Spice PCK * * Retrieve planetary orientation constants from a Spice PCK and store them in the class. * @@ -825,12 +825,12 @@ namespace Isis { // Retrieve the frame class from Naif. We distinguish PCK types into text PCK, // binary PCK, and PCK not referenced to J2000. Isis binary PCK can - // not be used to solve for target body orientation because of the variety and + // not be used to solve for target body orientation because of the variety and // complexity models used with binary PCK. Currently ISIS does not solve for // target body orientation on bodies not referenced to J2000, but it could be // changed to handle that case. checkForBinaryPck(); - + if (m_frameType == PCK) { // Make sure the reference frame is J2000. We will need to modify FrameTrace and // the pck methods in this class to handle this case. At the time this method was @@ -848,13 +848,13 @@ namespace Isis { if (found) { // Go get the frame name if it is not the default J2000 SpiceDouble relativeFrameCode; - bodvcd_c(centerBodyCode, "CONSTANTS_REF_FRAME", 1, + bodvcd_c(centerBodyCode, "CONSTANTS_REF_FRAME", 1, &numReturned, &relativeFrameCode); - } + } if (!found || relativeFrameCode == 1) { // We only work with J2000 relative frames for now - // Make sure the standard coefficients are available for the body code by + // Make sure the standard coefficients are available for the body code by // checking for ra naifKeyword = "BODY" + toString(centerBodyCode) + "_POLE_RA" ; dtpool_c(naifKeyword.toLatin1().data(), &found, &numExpected, &naifType); @@ -899,7 +899,7 @@ namespace Isis { m_raNutPrec.resize(numExpected, 0.); m_decNutPrec.resize(numExpected, 0.); m_pmNutPrec.resize(numExpected, 0.); - + std::vector<SpiceDouble> angles(numExpected); bodvcd_c(centerBodyCode, "NUT_PREC_RA", numExpected, &numReturned, &m_raNutPrec[0]); bodvcd_c(centerBodyCode, "NUT_PREC_DEC", numExpected, &numReturned, &m_decNutPrec[0]); @@ -924,7 +924,7 @@ namespace Isis { } - /** + /** * Initialize planetary orientation constants from an cube body rotation label * * Retrieve planetary orientation constants from a cube body rotation label if they are present. @@ -998,12 +998,12 @@ namespace Isis { m_sysNutPrec1.push_back(Angle(toDouble(labelCoeffs[i]), Angle::Degrees)); } } - + NaifStatus::CheckErrors(); } - /** + /** * Add labels to a SpiceRotation table. * * Return a table containing the labels defining the rotation. @@ -1052,7 +1052,7 @@ namespace Isis { // Begin section added 06-20-2015 DAC table.Label() += PvlKeyword("FrameTypeCode"); - table.Label()["FrameTypeCode"].addValue(toString(m_frameType)); + table.Label()["FrameTypeCode"].addValue(toString(m_frameType)); if (m_frameType == PCK) { // Write out all the body orientation constants @@ -1113,7 +1113,7 @@ namespace Isis { } - /** + /** * Return the camera angles at the center time of the observation * * @return @b vector<double> Camera angles at center time @@ -1127,9 +1127,9 @@ namespace Isis { } - /** - * Return the camera angles (right ascension, declination, and twist) for the - * time-based matrix CJ + /** + * Return the camera angles (right ascension, declination, and twist) for the + * time-based matrix CJ * * @param axis3 The rotation axis for the third angle * @param axis2 The rotation axis for the second angle @@ -1154,8 +1154,8 @@ namespace Isis { - /** - * Set the rotation angles (phi, delta, and w) for the current time to define the + /** + * Set the rotation angles (phi, delta, and w) for the current time to define the * time-based matrix CJ. This method was created for unitTests and should not * be used otherwise. It only works for cached data with a cache size of 1. * @@ -1167,54 +1167,54 @@ namespace Isis { void SpiceRotation::SetAngles(std::vector<double> angles, int axis3, int axis2, int axis1) { eul2m_c(angles[2], angles[1], angles[0], axis3, axis2, axis1, (SpiceDouble (*)[3]) &(p_CJ[0])); p_cache[0] = p_CJ; - // Reset to get the new values + // Reset to get the new values p_et = -DBL_MAX; SetEphemerisTime(p_et); } - /** - * Accessor method to get the angular velocity + /** + * Accessor method to get the angular velocity * * @return @b vector<double> Angular velocity - */ + */ std::vector<double> SpiceRotation::AngularVelocity() { return p_av; } - /** - * Accessor method to get the frame chain for the constant part of the - * rotation (ends in target) + /** + * Accessor method to get the frame chain for the constant part of the + * rotation (ends in target) * - * @return @b vector<int> The frame chain for the constant part of the rotation. - */ + * @return @b vector<int> The frame chain for the constant part of the rotation. + */ std::vector<int> SpiceRotation::ConstantFrameChain() { return p_constantFrames; } - /** + /** * Accessor method to get the frame chain for the rotation (begins in J2000). - * + * * @return @b vector<int> The frame chain for the rotation. - */ + */ std::vector<int> SpiceRotation::TimeFrameChain() { return p_timeFrames; } - /** - * Checks whether the rotation has angular velocities. + /** + * Checks whether the rotation has angular velocities. * * @return @b bool Indicates whether the rotation has angular velocities. - */ + */ bool SpiceRotation::HasAngularVelocity() { return p_hasAngularVelocity; } - /** + /** * Given a direction vector in the reference frame, return a J2000 direction. * * @param[in] rVec A direction vector in the reference frame @@ -1223,7 +1223,7 @@ namespace Isis { */ std::vector<double> SpiceRotation::J2000Vector(const std::vector<double> &rVec) { NaifStatus::CheckErrors(); - + std::vector<double> jVec; if (rVec.size() == 3) { @@ -1232,7 +1232,7 @@ namespace Isis { jVec.resize(3); mtxv_c(TJ, (SpiceDouble *) &rVec[0], (SpiceDouble *) &jVec[0]); } - + else if (rVec.size() == 6) { // See Naif routine frmchg for the format of the state matrix. The constant rotation, TC, // has a derivative with respect to time of I. @@ -1257,7 +1257,7 @@ namespace Isis { } - /** + /** * Return the coefficients used to calculate the target body pole ra * * Return the coefficients used to calculate the target body right @@ -1267,7 +1267,7 @@ namespace Isis { * right ascension (usually the same as the most recent IAU Report) * the trignometric terms to account for nutation/precession need to * be added. - * + * * pole ra = ra0 + ra1*T + ra2*T**2 + sum(racoef[i]i*sin(angle[i])) * * @return @b vector<double> A vector of length 3 containing the pole ra coefficients @@ -1277,7 +1277,7 @@ namespace Isis { } - /** + /** * Return the coefficients used to calculate the target body pole dec * * Return the coefficients used to calculate the target body declination @@ -1287,7 +1287,7 @@ namespace Isis { * declination (usually the same as the most recent IAU Report) * the trignometric terms to account for nutation/precession need to * be added. - * + * * pole dec = dec0 + dec1*T + dec2*T**2 + sum(racoef[i]i*sin(angle[i])) * * @return @b vector<double> A vector of length 3 containing the pole declination coefficients. @@ -1297,16 +1297,16 @@ namespace Isis { } - /** + /** * Return the coefficients used to calculate the target body prime meridian * * Return the coefficients used to calculate the target body prime * meridian without nutation/precession. The model is a standard - * quadratic polynomial in time in days from the standard epoch + * quadratic polynomial in time in days from the standard epoch * (usually J2000). To match the Naif PCK prime meridian, (usually * the same as the most recent IAU Report) the trignometric terms * to account for nutation/precession need to be added. - * + * * pm = pm0 + pm1*d + pm2*d**2 + sum(pmcoef[i]i*sin(angle[i])) * * @return @b vector<double> A vector of length 3 containing the prime meridian coefficients. @@ -1316,7 +1316,7 @@ namespace Isis { } - /** + /** * Return the coefficients used to calculate the target body pole ra nut/prec coefficients * * Return the coefficients used to calculate the target body right @@ -1324,7 +1324,7 @@ namespace Isis { * sum of the products of the coefficients returned by this method * with the sin of the corresponding angles associated with the * barycenter related to the target body. - * + * * pole ra = ra0 + ra1*T + ra2*T**2 + sum(raCoef[i]i*sin(angle[i])) * * @return @b vector<double> A vector containing the pole ra nut/prec coefficients. @@ -1334,14 +1334,14 @@ namespace Isis { } - /** + /** * Return the coefficients used to calculate the target body pole dec nut/prec coefficients * * Return the coefficients used to calculate the target body declination - * nutation/precession contribution. The model is the sum of the products - * of the coefficients returned by this method with the sin of the corresponding + * nutation/precession contribution. The model is the sum of the products + * of the coefficients returned by this method with the sin of the corresponding * angles associated with the barycenter related to the target body. - * + * * pole dec = dec0 + dec1*T + dec2*T**2 + sum(decCoef[i]i*sin(angle[i])) * * @return @b vector<double> A vector containing the pole dec nut/prec coeffcients. @@ -1351,14 +1351,14 @@ namespace Isis { } - /** + /** * Return the coefficients used to calculate the target body pm nut/prec coefficients * * Return the coefficients used to calculate the target body prime meridian - * nutation/precession contribution. The model is the sum of the products - * of the coefficients returned by this method with the sin of the corresponding + * nutation/precession contribution. The model is the sum of the products + * of the coefficients returned by this method with the sin of the corresponding * angles associated with the barycenter related to the target body. - * + * * prime meridian = pm0 + pm1*T + pm2*d**2 + sum(pmCoef[i]i*sin(angle[i])) * * @return @b vector<double> A vector containing the pm nut/prec coeffcients. @@ -1368,14 +1368,14 @@ namespace Isis { } - /** + /** * Return the constants used to calculate the target body system nut/prec angles * * Return the constant terms used to calculate the target body system (barycenter) * nutation/precession angles (periods). The model for the angles is linear in - * time in Julian centuries since the standard epoch (usually J2000). + * time in Julian centuries since the standard epoch (usually J2000). * angles associated with the barycenter related to the target body. - * + * * angle[i] = constant[i] + coef[i]*T * * @return @b vector<Angle> A vector containing the system nut/prec constant terms. @@ -1385,15 +1385,15 @@ namespace Isis { } - /** + /** * Return the coefficients used to calculate the target body system nut/prec angles * - * Return the linear coefficients used to calculate the target body system - * (barycenter) nutation/precession angles (periods). The model for the - * angles is linear in time in Julian centuries since the standard epoch - * (usually J2000). angles associated with the barycenter related to the + * Return the linear coefficients used to calculate the target body system + * (barycenter) nutation/precession angles (periods). The model for the + * angles is linear in time in Julian centuries since the standard epoch + * (usually J2000). angles associated with the barycenter related to the * target body. - * + * * angle[i] = constant[i] + coef[i]*T * * @return @b vector<Angle> A vector containing the system nut/prec linear coefficients. @@ -1403,9 +1403,9 @@ namespace Isis { } - /** + /** * Given a direction vector in the reference frame, compute the derivative - * with respect to one of the coefficients in the angle polynomial fit + * with respect to one of the coefficients in the angle polynomial fit * equation of a vector rotated from the reference frame to J2000. * TODO - merge this method with ToReferencePartial * @@ -1416,14 +1416,14 @@ namespace Isis { * @throws IException::User "Body rotation uses a binary PCK. Solutions for this model are not * supported" * @throws IException::User "Body rotation uses a PCK not referenced to J2000. Solutions for this - * model are not supported" + * model are not supported" * @throws IException::User "Solutions are not supported for this frame type." * - * @return @b vector<double> A direction vector rotated by derivative + * @return @b vector<double> A direction vector rotated by derivative * of reference to J2000 rotation. */ - std::vector<double> SpiceRotation::toJ2000Partial(const std::vector<double> &lookT, - SpiceRotation::PartialType partialVar, + std::vector<double> SpiceRotation::toJ2000Partial(const std::vector<double> &lookT, + SpiceRotation::PartialType partialVar, int coeffIndex) { NaifStatus::CheckErrors(); @@ -1459,7 +1459,7 @@ namespace Isis { break; case NOTJ2000PCK: msg = "Body rotation uses a PCK not referenced to J2000. " - "Solutions for this model are not supported"; + "Solutions for this model are not supported"; throw IException(IException::User, msg, _FILEINFO_); break; default: @@ -1497,7 +1497,7 @@ namespace Isis { double dTJ[3][3]; mxm_c((SpiceDouble *) &p_TC[0], dCJ[0], dTJ); - // Finally rotate the target vector with the transpose of the + // Finally rotate the target vector with the transpose of the // derivative matrix, dTJ to get a J2000 vector std::vector<double> lookdJ(3); @@ -1508,7 +1508,7 @@ namespace Isis { } - /** + /** * Given a direction vector in J2000, return a reference frame direction. * * @param[in] jVec A direction vector in J2000 @@ -1543,7 +1543,7 @@ namespace Isis { } - /** + /** * Set the coefficients of a polynomial fit to each * of the three camera angles for the time period covered by the * cache, angle = a + bt + ct**2, where t = (time - p_baseTime)/ p_timeScale. @@ -1691,7 +1691,7 @@ namespace Isis { } - /** + /** * Set the coefficients of a polynomial fit to each of the * three camera angles for the time period covered by the * cache, angle = c0 + c1*t + c2*t**2 + ... + cn*t**n, @@ -1745,10 +1745,10 @@ namespace Isis { } - /** + /** * Set the coefficients of a polynomial fit to each * of the three planet angles for the time period covered by the - * cache, ra = ra0 + ra1*t + ra2*t**2 + raTrig, + * cache, ra = ra0 + ra1*t + ra2*t**2 + raTrig, * dec = dec0 + dec1*t + dec2*t**2 + decTrig, * pm = pm0 + pm1*d + pm2*t**2 + pmTrig, * where t = time / (seconds per day). for time = et @@ -1764,7 +1764,7 @@ namespace Isis { */ void SpiceRotation::usePckPolynomial() { - // Check to see if rotation is already stored as a polynomial + // Check to see if rotation is already stored as a polynomial if (p_source == PckPolyFunction) { p_hasAngularVelocity = true; return; @@ -1780,7 +1780,7 @@ namespace Isis { // Set the scales p_dscale = 0.000011574074074; // seconds to days conversion p_tscale = 3.1688087814029D-10; // seconds to Julian centuries conversion - //Set the quadratic part of the equations + //Set the quadratic part of the equations //TODO consider just hard coding this part in evaluate Isis::PolynomialUnivariate functionRa(p_degree); // Basis function fit to target body pole ra Isis::PolynomialUnivariate functionDec(p_degree); // Basis function fit to target body pole dec @@ -1793,7 +1793,7 @@ namespace Isis { int numNutPrec = p_sysNutPrec0.size; if (numNutPrec > 0) { - // Set the trigonometric part of the equation + // Set the trigonometric part of the equation Isis::TrigBasis functionRaNutPrec("raNutPrec", Isis::TrigBasis::Sin, numNutPrec); Isis::TrigBasis functionRaNutPrec("decNutPrec", Isis::TrigBasis::Cos, numNutPrec); Isis::TrigBasis functionRaNutPrec("pmNutPrec", Isis::TrigBasis::Sin, numNutPrec); @@ -1811,9 +1811,9 @@ namespace Isis { */ // Set the flag indicating p_degree has been applied to the planet angles, the - // coefficients of the polynomials have been saved, and the cache reloaded from + // coefficients of the polynomials have been saved, and the cache reloaded from // TODO cache reloaded??? - // the polynomials. + // the polynomials. // ****At least for the planet angles, I don't think we want to reload the cache until just // before we write out the table p_degreeApplied = true; @@ -1823,10 +1823,10 @@ namespace Isis { } - /** + /** * Set the coefficients of a polynomial fit to each * of the three planet angles for the time period covered by the - * cache, ra = ra0 + ra1*t + ra2*t**2 + raTrig, + * cache, ra = ra0 + ra1*t + ra2*t**2 + raTrig, * dec = dec0 + dec1*t + dec2*t**2 + decTrig, * pm = pm0 + pm1*d + pm2*t**2 + pmTrig, * where t = time / (seconds per day). for time = et @@ -1853,7 +1853,7 @@ namespace Isis { // Apply new function parameters setEphemerisTimePckPolyFunction(); } - + /** * Return the coefficients of a polynomial fit to each of the @@ -1939,7 +1939,7 @@ namespace Isis { * * @param coeffIndex The index of the coefficient to differentiate * - * @throws IException::Programmer "Unable to evaluate the derivative of the SPICE rotation fit + * @throws IException::Programmer "Unable to evaluate the derivative of the SPICE rotation fit * polynomial for the given coefficient index. Index is negative * or exceeds degree of polynomial" * @@ -1974,7 +1974,7 @@ namespace Isis { * @param partialVar Variable derivative is to be with respect to * @param coeffIndex The index of the coefficient to differentiate * - * @throws IException::Programmer "Unable to evaluate the derivative of the SPICE rotation fit + * @throws IException::Programmer "Unable to evaluate the derivative of the SPICE rotation fit * polynomial for the given coefficient index. Index is negative * or exceeds degree of polynomial" * @@ -1983,7 +1983,7 @@ namespace Isis { double SpiceRotation::DPckPolynomial(SpiceRotation::PartialType partialVar, const int coeffIndex) { const double p_dayScale = 86400; // number of seconds in a day - // Number of 24 hour days in a Julian century = 36525 + // Number of 24 hour days in a Julian century = 36525 const double p_centScale = p_dayScale * 36525; double time = 0.; @@ -2104,7 +2104,7 @@ namespace Isis { double dTJ[3][3]; mxm_c((SpiceDouble *) &p_TC[0], dCJ[0], dTJ); - // Finally rotate the J2000 vector with the derivative matrix, dTJ to + // Finally rotate the J2000 vector with the derivative matrix, dTJ to // get the vector in the targeted reference frame. std::vector<double> lookdT(3); @@ -2115,7 +2115,7 @@ namespace Isis { } - /** + /** * Wrap the input angle to keep it within 2pi radians of the angle to compare. * * @param[in] compareAngle Look vector in J2000 frame @@ -2139,7 +2139,7 @@ namespace Isis { } - /** + /** * Set the degree of the polynomials to be fit to the * three camera angles for the time period covered by the * cache, angle = c0 + c1*t + c2*t**2 + ... + cn*t**n, @@ -2195,8 +2195,8 @@ namespace Isis { } - /** - * Accessor method to get the rotation frame type. + /** + * Accessor method to get the rotation frame type. * * @return @b SpiceRotation::FrameType The frame type of the rotation. */ @@ -2205,8 +2205,8 @@ namespace Isis { } - /** - * Accessor method to get the rotation source. + /** + * Accessor method to get the rotation source. * * @return @b SpiceRotation::Source The source of the rotation. */ @@ -2216,9 +2216,9 @@ namespace Isis { /** - * Resets the source of the rotation to the given value. + * Resets the source of the rotation to the given value. * - * @param source The rotation source to be set. + * @param source The rotation source to be set. */ void SpiceRotation::SetSource(Source source) { p_source = source; @@ -2227,7 +2227,7 @@ namespace Isis { /** - * Accessor method to get the rotation base time. + * Accessor method to get the rotation base time. * * @return @b double The base time for the rotation. */ @@ -2237,7 +2237,7 @@ namespace Isis { /** - * Accessor method to get the rotation time scale. + * Accessor method to get the rotation time scale. * * @return @b double The time scale for the rotation. */ @@ -2246,7 +2246,7 @@ namespace Isis { } - /** + /** * Set the axes of rotation for decomposition of a rotation * matrix into 3 angles. * @@ -2269,15 +2269,15 @@ namespace Isis { } - /** - * Load the time cache. This method should works with the LoadCache(startTime, endTime, size) + /** + * Load the time cache. This method should works with the LoadCache(startTime, endTime, size) * method to load the time cache. * * @throws IException::Programmer "Full cache size does NOT match cache size in LoadTimeCache -- * should never happen" - * @throws IException::Programmer "Observation crosses segment boundary--unable to interpolate + * @throws IException::Programmer "Observation crosses segment boundary--unable to interpolate * pointing" - * @throws IException::User "No camera kernels loaded...Unable to determine time cache to + * @throws IException::User "No camera kernels loaded...Unable to determine time cache to * downsize" */ void SpiceRotation::LoadTimeCache() { @@ -2311,7 +2311,7 @@ namespace Isis { SpiceDouble quats[p_fullCacheSize][4]; double avvs[p_fullCacheSize][3];// Angular velocity vector - // We will treat et as the sclock time and avoid converting back and forth + // We will treat et as the sclock time and avoid converting back and forth for (int r = 0; r < p_fullCacheSize; r++) { timeSclkdp[r] = p_cacheTime[r]; SpiceDouble CJ[9] = { p_cache[r][0], p_cache[r][1], p_cache[r][2], @@ -2332,7 +2332,7 @@ namespace Isis { SpiceInt intarr[p_fullCacheSize]; // Integer work array SpiceInt sizOut = p_fullCacheSize; // Size of downsized cache - ck3sdn(radTol, avflag, (int *) &sizOut, timeSclkdp, (doublereal *) quats, + ck3sdn(radTol, avflag, (int *) &sizOut, timeSclkdp, (doublereal *) quats, (SpiceDouble *) avvs, nints, &cubeStarts, dparr, (int *) intarr); // Clear full cache and load with downsized version @@ -2398,7 +2398,7 @@ namespace Isis { // Don't read type 5 ck here if (ic[2] == 5) break; -// +// // Check times for type 3 ck segment if spacecraft matches if (ic[0] == spCode && ic[2] == 3) { sct2e_c((int) spCode / 1000, dc[0], &segStartEt); @@ -2409,7 +2409,7 @@ namespace Isis { // Get times for this segment if (currentTime >= segStartEt && currentTime <= segStopEt) { - // Check for a gap in the time coverage by making sure the time span of the observation + // Check for a gap in the time coverage by making sure the time span of the observation // does not cross a segment unless the next segment starts where the current one ends if (observationSpansToNextSegment && currentTime > segStartEt) { QString msg = "Observation crosses segment boundary--unable to interpolate pointing"; @@ -2476,7 +2476,7 @@ namespace Isis { throw IException(IException::User, msg, _FILEINFO_); } - // Load times according to cache size (body rotations) -- handle first round of type 5 ck case + // Load times according to cache size (body rotations) -- handle first round of type 5 ck case // and multiple ck case --Load a time for every line scan line and downsize later if (!timeLoaded) { double cacheSlope = 0.0; @@ -2490,7 +2490,7 @@ namespace Isis { } - /** + /** * Return full listing (cache) of original time coverage requested. * * @throws IException::User "Time cache not availabe -- rerun spiceinit" @@ -2518,7 +2518,7 @@ namespace Isis { } - /** + /** * Compute frame trace chain from target frame to J2000 * * @param et Ephemeris time @@ -2611,7 +2611,7 @@ namespace Isis { else { QString msg = "The frame " + toString(frameCodes[frmidx]) + - " has a type " + toString(type) + " not supported by your version of Naif Spicelib." + " has a type " + toString(type) + " not supported by your version of Naif Spicelib." + "You need to update."; throw IException(IException::Programmer, msg, _FILEINFO_); @@ -2649,7 +2649,7 @@ namespace Isis { } - /** + /** * Return the full rotation TJ as a matrix * * @return @b vector<double> Returned matrix. @@ -2664,9 +2664,9 @@ namespace Isis { } - /** + /** * Return the constant 3x3 rotation TC matrix as a quaternion. - * + * * @return @b vector<double> Constant rotation quaternion, TC. */ std::vector<double> SpiceRotation::ConstantRotation() { @@ -2679,9 +2679,9 @@ namespace Isis { } - /** + /** * Return the constant 3x3 rotation TC matrix as a vector of length 9. - * + * * @return @b vector<double> Constant rotation matrix, TC. */ std::vector<double> &SpiceRotation::ConstantMatrix() { @@ -2689,9 +2689,9 @@ namespace Isis { } - /** + /** * Set the constant 3x3 rotation TC matrix from a vector of length 9. - * + * * @param constantMatrix Constant rotation matrix, TC. */ void SpiceRotation::SetConstantMatrix(std::vector<double> constantMatrix) { @@ -2699,9 +2699,9 @@ namespace Isis { return; } - /** + /** * Return time-based 3x3 rotation CJ matrix as a quaternion. - * + * * @return @b vector<double> Time-based rotation quaternion, CJ. */ std::vector<double> SpiceRotation::TimeBasedRotation() { @@ -2714,9 +2714,9 @@ namespace Isis { } - /** + /** * Return time-based 3x3 rotation CJ matrix as a vector of length 9. - * + * * @return @b vector<double> Time-based rotation matrix, CJ. */ std::vector<double> &SpiceRotation::TimeBasedMatrix() { @@ -2724,9 +2724,9 @@ namespace Isis { } - /** + /** * Set the time-based 3x3 rotation CJ matrix from a vector of length 9. - * + * * @param timeBasedMatrix Time-based rotation matrix, TC. */ void SpiceRotation::SetTimeBasedMatrix(std::vector<double> timeBasedMatrix) { @@ -2735,7 +2735,7 @@ namespace Isis { } - /** + /** * Initialize the constant rotation * * @param et Ephemeris time. @@ -2752,7 +2752,7 @@ namespace Isis { } - /** + /** * Compute the angular velocity from the time-based functions fit to the pointing angles * This method computes omega = angular velocity matrix, and extracts the angular velocity. * See comments in the Naif Spicelib routine xf2rav_c.c. @@ -2810,7 +2810,7 @@ namespace Isis { } - /** + /** * Compute the derivative of the 3x3 rotation matrix CJ with respect to time. * The derivative is computed based on p_CJ (J2000 to first constant frame). * @@ -2877,7 +2877,7 @@ namespace Isis { } - /** + /** * Compute & return the rotation matrix that rotates vectors from J2000 to the targeted frame. * * @return @b vector<double> Returned rotation matrix. @@ -2900,7 +2900,7 @@ namespace Isis { for (int col = 0; col < 3; col++) { jcol = col + 3; // Fill the upper left corner - stateTJ[irow*6 + col] = p_TC[vpos] * stateCJ[0][col] + p_TC[vpos+1] * stateCJ[1][col] + stateTJ[irow*6 + col] = p_TC[vpos] * stateCJ[0][col] + p_TC[vpos+1] * stateCJ[1][col] + p_TC[vpos+2] * stateCJ[2][col]; // Fill the lower left corner stateTJ[row*6 + col] = p_TC[vpos] * stateCJ[3][col] + p_TC[vpos+1] * stateCJ[4][col] @@ -2915,7 +2915,7 @@ namespace Isis { } - /** + /** * Extrapolate pointing for a given time assuming a constant angular velocity. * The pointing and angular velocity at the current time will be used to * extrapolate pointing at the input time. If angular velocity does not @@ -2934,7 +2934,7 @@ namespace Isis { std::vector<double> CJ(9, 0.0); double dmat[3][3]; - // Create a rotation matrix for the axis and magnitude of the angular velocity multiplied by + // Create a rotation matrix for the axis and magnitude of the angular velocity multiplied by // the time difference axisar_c((SpiceDouble *) &p_av[0], diffTime*vnorm_c((SpiceDouble *) &p_av[0]), dmat); @@ -2945,7 +2945,7 @@ namespace Isis { } - /** + /** * Set the full cache time parameters. * * @param[in] startTime The earliest time of the full cache coverage @@ -2960,7 +2960,7 @@ namespace Isis { } - /** + /** * Check loaded pck to see if any are binary and set frame type to indicate binary pck. * * This is strictly a local method to be called only when the source is Spice. Its purpose is @@ -2971,7 +2971,7 @@ namespace Isis { // Get a count of all the loaded kernels SpiceInt count; ktotal_c("PCK", &count); - + // Define some Naif constants int FILESIZ = 128; int TYPESIZ = 32; @@ -2981,7 +2981,7 @@ namespace Isis { SpiceChar source[SOURCESIZ]; SpiceInt handle; SpiceBoolean found; - + // Get the name of each loaded kernel. The accuracy of this test depends on the use of the // "bpc" suffix to name a binary pck. If a binary bpc does not have the "bpc" suffix, it will not // be found by this test. This test was suggested by Boris Semenov at Naif. @@ -2994,9 +2994,9 @@ namespace Isis { } } } - - /** + + /** * Set the frame type (m_frameType). * * This is strictly a local method to be called only when the source is Spice. Its purpose is @@ -3012,7 +3012,7 @@ namespace Isis { frinfo_c(frameCode, ¢erBodyCode, &frameClass, &classId, &found); if (found) { - if (frameClass == 2 || centerBodyCode > 0) { + if (frameClass == 2 || (centerBodyCode > 0 && frameClass != 3)) { m_frameType = PCK; // Load the PC information while it is available and set member values loadPCFromSpice(centerBodyCode); @@ -3043,7 +3043,7 @@ namespace Isis { m_frameType = UNKNOWN; } } - } + } } @@ -3102,7 +3102,7 @@ namespace Isis { SpiceDouble delta[3][3]; axisar_c(axis, angle * (SpiceDouble)mult, delta); mxmt_c((SpiceDouble *) &CJ1[0], delta, (SpiceDouble( *) [3]) &p_CJ[0]); - + if (p_hasAngularVelocity) { double v1[3], v2[3]; // Vectors surrounding desired time vequ_c((SpiceDouble *) &p_cacheAv[cacheIndex][0], v1); @@ -3154,7 +3154,7 @@ namespace Isis { * When setting the ephemeris time, updates the rotation state based on data read directly * from NAIF kernels using NAIF Spice routines * - * @throws IException::Io "[framecode] is an unrecognized reference frame code. Has the mission + * @throws IException::Io "[framecode] is an unrecognized reference frame code. Has the mission * frames kernel been loaded?" * @throws IException::Io "No pointing is availabe at request time for frame code" * @@ -3294,7 +3294,7 @@ namespace Isis { /** * When setting the ephemeris time, updates the rotation state based on a polynomial fit - * over spice kernel data. + * over spice kernel data. * * @see SpiceRotation::SetEphemerisTime */ @@ -3308,7 +3308,7 @@ namespace Isis { setEphemerisTimePolyFunction(); std::vector<double> polyAngles(3); // The decomposition fails because the angles are outside the valid range for Naif - // polyAngles = Angles(p_axis3, p_axis2, p_axis1); + // polyAngles = Angles(p_axis3, p_axis2, p_axis1); polyAngles = EvaluatePolyFunction(); std::vector<double> polyVelocity(3); polyVelocity = p_av; @@ -3358,14 +3358,14 @@ namespace Isis { Angle dra = (m_raPole[1] + 2.*m_raPole[2]*centTime) / secondsPerJulianCentury; Angle ddec = (m_decPole[1] + 2.*m_decPole[2]*centTime) / secondsPerJulianCentury; Angle dpm = (m_pm[1] + 2.*m_pm[2]*dTime) / 86400; - + // Now add the nutation/precession (trig part) adjustment to the expression if any int numNutPrec = (int) m_raNutPrec.size(); Angle theta; double dtheta; double costheta; double sintheta; - + for (int ia = 0; ia < numNutPrec; ia++) { theta = m_sysNutPrec0[ia] + m_sysNutPrec1[ia]*centTime; dtheta = m_sysNutPrec1[ia].degrees() * DEG2RAD; @@ -3408,7 +3408,7 @@ namespace Isis { SpiceDouble angsDangs[6]; SpiceDouble BJs[6][6]; vpack_c(w, delta, phi, angsDangs); - vpack_c(dw, ddelta, dphi, &angsDangs[3]); + vpack_c(dw, ddelta, dphi, &angsDangs[3]); eul2xf_c (angsDangs, p_axis3, p_axis2, p_axis1, BJs); // Decompose the state matrix to the rotation and its angular velocity diff --git a/isis/src/base/objs/SpiceRotation/SpiceRotation.h b/isis/src/base/objs/SpiceRotation/SpiceRotation.h index 74b842f046b383e2652822decea6b2970c8f11a2..9523b64c1f1a72305a746092e9a1c66ae53a72da 100644 --- a/isis/src/base/objs/SpiceRotation/SpiceRotation.h +++ b/isis/src/base/objs/SpiceRotation/SpiceRotation.h @@ -187,31 +187,37 @@ namespace Isis { * @history 2015-02-20 Jeannie Backer - Improved error messages. * @history 2015-07-21 Kristin Berry - Added additional NaifStatus::CheckErrors() calls to see if * any NAIF errors were signaled. References #2248. - * @history 2015-08-05 Debbie A. Cook - Programmer notes - Modified LoadCache, + * @history 2015-08-05 Debbie A. Cook - Programmer notes - Modified LoadCache, * and ComputeAv. - * Added new methods + * Added new methods * loadPCFromSpice, loadPCFromTable, toJ2000Partial, poleRaCoefs, - * poleDecCoefs, pmCoefs, poleRaNutPrecCoefs, poleDecNutPrecCoefs, + * poleDecCoefs, pmCoefs, poleRaNutPrecCoefs, poleDecNutPrecCoefs, * pmNutPrecCoefs, sysNutPrecConstants, sysNutPrecCoefs, * usePckPolynomial, setPckPolynomial(raCoef, decCoef, pmCoef), * getPckPolynomial, setEphemerisTimePckPolyFunction, getFrameType - * and members m_frameType, m_tOrientationAvailable, + * and members m_frameType, m_tOrientationAvailable, * m_raPole, m_decPole, m_pm, m_raNutPrec, m_decNutPrec, m_pmNutPrec, - * m_sysNutPrec0, m_sysNutPrec1, m_dscale, m_Tscale to support request for + * m_sysNutPrec0, m_sysNutPrec1, m_dscale, m_Tscale to support request for * solving for target body parameters. - * Also added a new enumerated value for Source, PckPolyFunction, + * Also added a new enumerated value for Source, PckPolyFunction, * and PartialType, WRT_RotationRate. * @history 2016-02-15 Debbie A. Cook - Programmer notes - Added private method - * setFrameType to set the frame type. It also loads the planetary - * constants for a PCK type. + * setFrameType to set the frame type. It also loads the planetary + * constants for a PCK type. * @history 2016-06-28 Ian Humphrey - Updated documentation and coding standards. Added new * tests to unit test. Fixes #3972. * @history 2017-12-13 Ken Edmundson - Added "case DYN:" to methods ToReferencePartial and toJ2000Partial. Fixes #5251. * This problem was found when trying to bundle M3 images that had been spiceinited with nadir * pointing. The nadir frame is defined as a Dynamic Frame by Naif. + * @history 2018-04-21 Jesse Mapel - Modified frametype resolution to check if a body centered + * frame uses a CK or PCK definition. This only occurs for bodies + * where a pck cannot accurately define for the duration of a mission. + * The current example is the comet 67P/CHURYUMOV-GERASIMENKO + * imaged by Rosetta. Some future comet/astroid missions are expected + * to use a CK defined body fixed reference frame. Fixes #5408. * * @todo Downsize using Hermite cubic spline and allow Nadir tables to be downsized again. - * @todo Consider making this a base class with child classes based on frame type or + * @todo Consider making this a base class with child classes based on frame type or * storage type (polynomial, polynomial over cache, cache, etc.) */ class SpiceRotation { @@ -236,66 +242,66 @@ namespace Isis { /** * The rotation can come from one of 3 places for an Isis cube. The class * expects function to be after Memcache. - * Spice - the rotation is calculated by Naif Spice routines with data + * Spice - the rotation is calculated by Naif Spice routines with data * read directly from Naif kernels. - * Nadir - the rotation is calculated using the Naif routine twovec with + * Nadir - the rotation is calculated using the Naif routine twovec with * the position and velocity vectors of the spacecraft. - * Memcache - the rotation is linearly interpolated from time-based + * Memcache - the rotation is linearly interpolated from time-based * values in a table. - * PolyFunction - the rotation is calculated from an nth degree + * PolyFunction - the rotation is calculated from an nth degree * polynomial in one variable (time in scaled seconds) * PolyFunctionOverSpice - the rotation is calculated from an nth * degree polynomial fit over the Naif Spice results. - * PckPolyFunction - The rotation is calculated using the IAU fit + * PckPolyFunction - The rotation is calculated using the IAU fit * polynomials in one variable (time in Julian centuries and days). */ - enum Source { - Spice, //!< Directly from the kernels + enum Source { + Spice, //!< Directly from the kernels Nadir, //!< Nadir pointing Memcache, //!< From cached table PolyFunction, //!< From nth degree polynomial - PolyFunctionOverSpice , //!< Kernels plus nth degree polynomial + PolyFunctionOverSpice , //!< Kernels plus nth degree polynomial PckPolyFunction //!< Quadratic polynomial function with linear trignometric terms - }; + }; - /** - * This enumeration indicates whether the partial derivative is taken with - * respect to Right Ascension, Declination, or Twist (or Rotation). - */ - enum PartialType { + /** + * This enumeration indicates whether the partial derivative is taken with + * respect to Right Ascension, Declination, or Twist (or Rotation). + */ + enum PartialType { WRT_RightAscension, //!< With respect to Right Ascension WRT_Declination, //!< With respect to Declination WRT_Twist //!< With respect to Twist or Prime Meridian Rotation }; - /** + /** * Status of downsizing the cache - */ - enum DownsizeStatus { - Yes, //!< Downsize the cache + */ + enum DownsizeStatus { + Yes, //!< Downsize the cache Done, //!< Cache is downsized - No //!< Do not downsize the cache + No //!< Do not downsize the cache }; - /** - * Enumeration for the frame type of the rotation - */ + /** + * Enumeration for the frame type of the rotation + */ enum FrameType { UNKNOWN = 0, //!< Isis specific code for unknown frame type - INERTL = 1, //!< See Naif Frames.req document for + INERTL = 1, //!< See Naif Frames.req document for PCK = 2, //!< definitions - CK = 3, //!< - TK = 4, //!< + CK = 3, //!< + TK = 4, //!< DYN = 5, //!< BPC = 6, //!< Isis specific code for binary pck NOTJ2000PCK = 7 //!< PCK frame not referenced to J2000 - }; + }; void SetEphemerisTime(double et); double EphemerisTime() const; std::vector<double> GetCenterAngles(); - + std::vector<double> Matrix(); std::vector<double> AngularVelocity(); @@ -422,9 +428,9 @@ namespace Isis { void setEphemerisTimePolyFunctionOverSpice(); void setEphemerisTimePckPolyFunction(); std::vector<double> p_cacheTime; //!< iTime for corresponding rotation - std::vector<std::vector<double> > p_cache; /**< Cached rotations, stored as - rotation matrix from J2000 - to 1st constant frame (CJ) or + std::vector<std::vector<double> > p_cache; /**< Cached rotations, stored as + rotation matrix from J2000 + to 1st constant frame (CJ) or coefficients of polynomial fit to rotation angles.*/ int p_degree; //!< Degree of fit polynomial for angles @@ -435,11 +441,11 @@ namespace Isis { private: // method void setFrameType(); - std::vector<int> p_constantFrames; /**< Chain of Naif frame codes in constant - rotation TC. The first entry will always + std::vector<int> p_constantFrames; /**< Chain of Naif frame codes in constant + rotation TC. The first entry will always be the target frame code*/ - std::vector<int> p_timeFrames; /**< Chain of Naif frame codes in time-based - rotation CJ. The last entry will always + std::vector<int> p_timeFrames; /**< Chain of Naif frame codes in time-based + rotation CJ. The last entry will always be 1 (J2000 code)*/ double p_timeBias; //!< iTime bias when reading kernels @@ -449,7 +455,7 @@ namespace Isis { bool p_matrixSet; //!< Flag indicating p_TJ has been set bool m_tOrientationAvailable; //!< Target orientation constants are available - + FrameType m_frameType; //!< The type of rotation frame Source p_source; //!< The source of the rotation data @@ -464,7 +470,7 @@ namespace Isis { bool p_degreeApplied; /**< Flag indicating whether or not a polynomial of degree p_degree has been created and used to fill the cache*/ - std::vector<double> p_coefficients[3]; /**< Coefficients defining functions fit + std::vector<double> p_coefficients[3]; /**< Coefficients defining functions fit to 3 pointing angles*/ bool p_noOverride; //!< Flag to compute base time; double p_overrideBaseTime; //!< Value set by caller to override computed base time @@ -473,34 +479,34 @@ namespace Isis { double p_fullCacheStartTime; //!< Initial requested starting time of cache double p_fullCacheEndTime; //!< Initial requested ending time of cache int p_fullCacheSize; //!< Initial requested cache size - std::vector<double> p_TC; /**< Rotation matrix from first constant rotation + std::vector<double> p_TC; /**< Rotation matrix from first constant rotation (after all time-based rotations in frame chain from J2000 to target) to the target frame*/ - std::vector<double> p_CJ; /**< Rotation matrix from J2000 to first constant + std::vector<double> p_CJ; /**< Rotation matrix from J2000 to first constant rotation*/ std::vector<std::vector<double> > p_cacheAv; //!< Cached angular velocities for corresponding rotactions in p_cache std::vector<double> p_av; //!< Angular velocity for rotation at time p_et - bool p_hasAngularVelocity; /**< Flag indicating whether the rotation + bool p_hasAngularVelocity; /**< Flag indicating whether the rotation includes angular velocity*/ - std::vector<double> StateTJ(); /**< State matrix (6x6) for rotating state + std::vector<double> StateTJ(); /**< State matrix (6x6) for rotating state vectors from J2000 to target frame*/ - // The remaining items are only used for PCK frame types. In this case the + // The remaining items are only used for PCK frame types. In this case the // rotation is stored as a cache, but the coefficients are available for display - // or comparison, and the first three coefficient sets can be solved for and + // or comparison, and the first three coefficient sets can be solved for and // updated in jigsaw. The initial coefficient values are read from a Naif PCK. // // The general equation for the right ascension of the pole is // // raPole = raPole[0] + raPole[1]*Time + raPole[2]*Time**2 + raNutPrec, - // where - // raNutPrec = raNutPrec1[0]*sin(sysNutPrec[0][0] + sysNutPrec[0][1]*Time) + + // where + // raNutPrec = raNutPrec1[0]*sin(sysNutPrec[0][0] + sysNutPrec[0][1]*Time) + // raNutPrec1[1]*sin(sysNutPrec[1][0] + sysNutPrec[1][1]*Time) + ... // raNutPrec1[N-1]*sin(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time) + // (optional for multiples of nutation precession angles) // raNutPrec2[0]*sin(2*(sysNutPrec[0][0] + sysNutPrec[0][1]*Time)) + // raNutPrec2[1]*sin(2*(sysNutPrec[1][0] + sysNutPrec[1][1]*Time)) + ... - // raNutPrec2[N-1]*sin(2*(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time)) + + // raNutPrec2[N-1]*sin(2*(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time)) + // raNutPrecM[0]*sin(M*(sysNutPrec[0][0] + sysNutPrec[0][1]*Time)) + // raNutPrecM[1]*sin(M*(sysNutPrec[1][0] + sysNutPrec[1][1]*Time)) + ... // raNutPrecM[N-1]*sin(M*(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time)) + @@ -508,8 +514,8 @@ namespace Isis { // The general equation for the declination of the pole is // // decPole = p_decPole[0] + p_decPole[1]*Time + p_decPole[2]*Time**2 + decNutPrec, - // where - // decNutPrec = decNutPrec1[0]*cos(sysNutPrec[0][0] + sysNutPrec[0][1]*Time) + + // where + // decNutPrec = decNutPrec1[0]*cos(sysNutPrec[0][0] + sysNutPrec[0][1]*Time) + // decNutPrec1[1]*cos(sysNutPrec[1][0] + sysNutPrec[1][1]*Time) + ... // decNutPrec1[N-1]*cos(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time) + // decNutPrec2[0]*cos(2*(sysNutPrec[0][0] + sysNutPrec[0][1]*Time)) + @@ -518,15 +524,15 @@ namespace Isis { // (optional for multiples of nutation precession angles) // decNutPrecM[0]*sin(M*(sysNutPrec[0][0] + sysNutPrec[0][1]*Time)) + // decNutPrecM[1]*sin(M*(sysNutPrec[1][0] + sysNutPrec[1][1]*Time)) + ... - // decNutPrecM[N-1]*sin(M*(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time)) + // decNutPrecM[N-1]*sin(M*(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time)) // // and Time is julian centuries since J2000. // // The general equation for the prime meridian rotation is // // pm = p_pm[0] + p_pm[1]*Dtime + p_pm[2]*Dtime**2 + pmNutPrec, - // where - // pmNutPrec = pmNutPrec1[0]*sin(sysNutPrec[0][0] + sysNutPrec[0][1]*Time) + + // where + // pmNutPrec = pmNutPrec1[0]*sin(sysNutPrec[0][0] + sysNutPrec[0][1]*Time) + // pmNutPrec1[1]*sin(sysNutPrec[1][0] + sysNutPrec[1][1]*Time) + ... // pmNutPrec1[N-1]*sin(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time) + // (optional for multiples of nutation precession angles) @@ -535,24 +541,24 @@ namespace Isis { // pmNutPrec2[N-1]*sin(2*(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time)) + // pmNutPrecM[0]*sin(M*(sysNutPrec[0][0] + sysNutPrec[0][1]*Time)) + // pmNutPrecM[1]*sin(M*(sysNutPrec[1][0] + sysNutPrec[1][1]*Time)) + ... - // pmNutPrecM[N-1]*sin(M*(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time)) + // pmNutPrecM[N-1]*sin(M*(sysNutPrec[N-1][0] + sysNutPrec[N-1][1]*Time)) // - // Time is interval in Julian centuries since the standard epoch, + // Time is interval in Julian centuries since the standard epoch, // dTime is interval in days from the standard epoch (J2000), // - // N is the number of nutation/precession terms for the planetary system of the target - // body, (possibly including multiple angles as unique terms, + // N is the number of nutation/precession terms for the planetary system of the target + // body, (possibly including multiple angles as unique terms, // ie. 2*sysNutPrec[0][0] + sysNutPrec[][1]*Time). // // Many of the constants in this equation are 0. for a given body. // - // M is included as an option for future improvements. M = highest multiple (period) + // M is included as an option for future improvements. M = highest multiple (period) // of any of the nutation/precession angles included in the equations. // - // ***NOTE*** Currently Naif stores multiples (amplitudes) as if they were additional - // nutation/precession terms (periods) in the equation. This method works as - // long as jigsaw does not solve for those values. In order to solve for - // those values, the multiples will need to be known so that the partial + // ***NOTE*** Currently Naif stores multiples (amplitudes) as if they were additional + // nutation/precession terms (periods) in the equation. This method works as + // long as jigsaw does not solve for those values. In order to solve for + // those values, the multiples will need to be known so that the partial // derivatives can be correctly calculated. Some possible ways of doing this // are 1) Convince Naif to change their data format indicating the relation // 2) Make an Isis version of the PCK data and have Isis software to @@ -561,7 +567,7 @@ namespace Isis { // and software to apply them when calculating the rotation and partials. // // For now this software will handle any terms with the same period and different - // amplitudes as unique terms in the equation (raNutPrec, decNutPrec, + // amplitudes as unique terms in the equation (raNutPrec, decNutPrec, // and pmNutPrec). // // The next three vectors will have length 3 (for a quadratic polynomial) if used. @@ -569,19 +575,19 @@ namespace Isis { std::vector<Angle>m_decPole; //!< Coefficients of a quadratic polynomial fitting pole dec. std::vector<Angle>m_pm ; //!< Coefficients of a quadratic polynomial fitting pole pm. // - // Currently multiples (terms with periods matching other terms but varying amplitudes) - // are handled as additional terms added to the end of the vector as Naif does (see - // comments in any of the standard Naif PCK. - std::vector<double>m_raNutPrec; //!< Coefficients of pole right ascension nut/prec terms. - std::vector<double>m_decNutPrec; //!< Coefficients of pole decliniation nut/prec terms. - std::vector<double>m_pmNutPrec; //!< Coefficients of prime meridian nut/prec terms. + // Currently multiples (terms with periods matching other terms but varying amplitudes) + // are handled as additional terms added to the end of the vector as Naif does (see + // comments in any of the standard Naif PCK. + std::vector<double>m_raNutPrec; //!< Coefficients of pole right ascension nut/prec terms. + std::vector<double>m_decNutPrec; //!< Coefficients of pole decliniation nut/prec terms. + std::vector<double>m_pmNutPrec; //!< Coefficients of prime meridian nut/prec terms. // The periods of bodies in the same system are modeled with a linear equation std::vector<Angle>m_sysNutPrec0; //!< Constants of planetary system nut/prec periods std::vector<Angle>m_sysNutPrec1; //!< Linear terms of planetary system nut/prec periods // The following scalars are used in the IAU equations to convert p_et to the appropriate time - // units for calculating target body ra, dec, and w. These need to be initialized in every + // units for calculating target body ra, dec, and w. These need to be initialized in every // constructor. //! Seconds per Julian century for scaling time in seconds static const double m_centScale; @@ -591,4 +597,3 @@ namespace Isis { }; #endif - diff --git a/isis/src/base/objs/SpiceRotation/SpiceRotation.truth b/isis/src/base/objs/SpiceRotation/SpiceRotation.truth index fa867d10df9e9f90a297d3df714a2da810503d26..695c9a31d7a0c46a531ff901237940c442da5114 100644 --- a/isis/src/base/objs/SpiceRotation/SpiceRotation.truth +++ b/isis/src/base/objs/SpiceRotation/SpiceRotation.truth @@ -624,6 +624,13 @@ Frame type is binary PCK and cannot be updated End of PCK testing +Testing CK based body rotation with 67P/Churyumov–Gerasimenko data ... +Time = 4.6285471e+08 +CJ = 0.93816333 -0.34618155 -0.002810256 + 0.30996014 0.84356223 -0.43855157 + 0.15418909 0.41056193 0.89870163 + + Testing exceptions... **I/O ERROR** Cannot find [INS-99999_TRANSX] in text kernels. diff --git a/isis/src/base/objs/SpiceRotation/unitTest.cpp b/isis/src/base/objs/SpiceRotation/unitTest.cpp index 95f0c9749fa0f00555a56cc73518bf29acb33f7f..673da7149b2c927ac76bb8a1d50b292e7de66010 100644 --- a/isis/src/base/objs/SpiceRotation/unitTest.cpp +++ b/isis/src/base/objs/SpiceRotation/unitTest.cpp @@ -37,6 +37,8 @@ int main(int argc, char *argv[]) { QString mocbsp(dir + "moc.bsp"); QString de(dir + "de405.bsp"); QString pck("/usgs/cpkgs/isis3/data/base/kernels/pck/pck00009.tpc"); + QString cgFK(dir + "ROS_V29.TF"); + QString cgCK(dir + "CATT_DV_145_02_______00216.BC"); //QString mocadd(dir+"mocAddendum.ti"); QString mocspice(dir + "mocSpiceRotationUnitTest.ti"); furnsh_c(naif.toLatin1().data()); @@ -47,6 +49,8 @@ int main(int argc, char *argv[]) { furnsh_c(de.toLatin1().data()); furnsh_c(pck.toLatin1().data()); furnsh_c(mocspice.toLatin1().data()); + furnsh_c(cgFK.toLatin1().data()); + furnsh_c(cgCK.toLatin1().data()); double startTime = -69382819.0; double endTime = -69382512.0; @@ -202,7 +206,7 @@ int main(int argc, char *argv[]) { lookC.push_back(1.); vector<double> lookJ = rot.J2000Vector(lookC); // Save a J2000 vector for testing target body partial methods later. - vector<double> testLookJ(lookJ); + vector<double> testLookJ(lookJ); cout << " For lookJ = " << lookJ[0] << " " << lookJ[1] << " " << lookJ[2] << endl; vector<double> dAraLookC(3); dAraLookC = rot.ToReferencePartial(lookJ, SpiceRotation::WRT_RightAscension, 0); @@ -385,11 +389,11 @@ int main(int argc, char *argv[]) { // Use Galileo Io image with product id = 21I0165 for testing nutation/precession terms. Mars has none. // tet = -15839262.24291 // body frame code for Io = 10023 - // Use Europa for exercising the code using nutation/precession terms. Mars has none. + // Use Europa for exercising the code using nutation/precession terms. Mars has none. SpiceRotation targrot1(10014); //Frame code for Mars // SpiceRotation targrotV1(10024); //Frame code for Europa // targrotV1.LoadCache(-646009153.46723, -646009153.46723, 1); // This calls LoadPcFromSpice for Europa - SpiceRotation targrotV1(10023); //Frame code for Io + SpiceRotation targrotV1(10023); //Frame code for Io targrotV1.LoadCache(-15839262.24291, -15839262.24291, 1); // This calls LoadPcFromSpice for Io targrot1.LoadCache(startTime, endTime, 2); // This calls LoadPcFromSpice for Mars cout << "Test CacheLabel for PCK data..." << endl; @@ -397,8 +401,8 @@ int main(int argc, char *argv[]) { Table pcktabV = targrotV1.Cache("Planetary constants test table"); // This calls CacheLabel SpiceRotation targrot(10014); // Mars // SpiceRotation targrotV(10024); // Europa -- The results for pm will differ slightly from TrigBasis because of the older PCK - SpiceRotation targrotV(10023); // Io -- - cout << "Test LoadPCFromTable..." << endl; + SpiceRotation targrotV(10023); // Io -- + cout << "Test LoadPCFromTable..." << endl; targrot.LoadCache(pcktab); // This calls LoadPcFromTable targrotV.LoadCache(pcktabV); // This calls LoadPcFromTable // Now get the values @@ -460,7 +464,7 @@ int main(int argc, char *argv[]) { // cout << " Angles = " << pckanglesV[0]*dpr_c() <<","<< pckanglesV[1]*dpr_c() <<"," // << pckanglesV[2]*dpr_c() <<endl <<endl; // end Europa test - + // For testing Io with the nutation/precession terms and a cache size of 1 tet = -15839262.24291; // time et for Io ibod = 501; // Io @@ -471,8 +475,8 @@ int main(int argc, char *argv[]) { << pckanglesV[2]*dpr_c() <<endl <<endl; // end Io test - // For testing Mars with more than one value in the cache - cout << endl << " Mars original SPICE values for target body orientation unadjusted" + // For testing Mars with more than one value in the cache + cout << endl << " Mars original SPICE values for target body orientation unadjusted" << endl; cout << " Source = " << targrot.GetSource() << endl; for (int i = 0; i < 10; i++) { @@ -520,18 +524,18 @@ int main(int argc, char *argv[]) { cout << " " << CJ[6] << " " << CJ[7] << " " << CJ[8] << endl; } - // Test angular velocities + // Test angular velocities cout << endl << endl << "Testing angular velocity with Io data ..." << endl; if (targrotV.HasAngularVelocity()) { vector<double> av = targrotV.AngularVelocity(); cout << "SpiceRotation av = " << av[0] << " " << av[1] << " " << av[2] << endl; SpiceDouble tsipm[6][6]; - sxform_c ( "J2000", "IAU_IO", -15839262.24291, tsipm); - // sxform_c ( "J2000", "IAU_EUROPA", -646009153.46723, tsipm); + sxform_c ( "J2000", "IAU_IO", -15839262.24291, tsipm); + // sxform_c ( "J2000", "IAU_EUROPA", -646009153.46723, tsipm); SpiceDouble tipm[3][3]; vector<SpiceDouble> nav(3,0.); xf2rav_c (tsipm, tipm, &(nav[0]) ); - cout << "J2000 to body-fixed Naif av = " << nav[0] << " " << nav[1] << " " << nav[2] << endl; + cout << "J2000 to body-fixed Naif av = " << nav[0] << " " << nav[1] << " " << nav[2] << endl; } cout << endl; @@ -559,7 +563,7 @@ int main(int argc, char *argv[]) { << matchLookJ[1] << " " << matchLookJ[2] << endl; dLookB = targrot.ToReferencePartial(testLookJ, SpiceRotation::WRT_Twist, 1); - cout << endl << " dLookB with respect to rotation rate = " << dLookB[0] << " " << + cout << endl << " dLookB with respect to rotation rate = " << dLookB[0] << " " << dLookB[1] << " " << dLookB[2] << endl; //If I apply toJ2000Partial to dLookB, I get back lookJ(x,y,0) with roundoff -- 05-12-2015 DAC matchLookJ = targrot.toJ2000Partial(dLookB, SpiceRotation::WRT_Twist, 1); @@ -567,7 +571,7 @@ int main(int argc, char *argv[]) { << matchLookJ[1] << " " << matchLookJ[2] << endl; dLookB = targrot.ToReferencePartial(testLookJ, SpiceRotation::WRT_Twist, 0); - cout << endl << " dLookB with respect to rotation = " << dLookB[0] << " " << + cout << endl << " dLookB with respect to rotation = " << dLookB[0] << " " << dLookB[1] << " " << dLookB[2] << endl; //If I apply toJ2000Partial to dLookB, I get back lookJ(x,y,0) with roundoff -- 05-12-2015 DAC matchLookJ = targrot.toJ2000Partial(dLookB, SpiceRotation::WRT_Twist, 0); @@ -589,15 +593,28 @@ int main(int argc, char *argv[]) { if (frameType == SpiceRotation::BPC) cout << "Frame type is binary PCK and cannot be updated" << endl; - + cout << "End of PCK testing" << endl; - + // Test CK based body rotation + cout << endl << endl << "Testing CK based body rotation with 67P/Churyumov–Gerasimenko data ..." << endl; + + SpiceRotation cgRotation(-1000012000); + // Test time from Rosetta OSIRIS NAC image n20140901t144253568id30f22 + double cgTestTime = 462854709.88606; + cgRotation.SetEphemerisTime(cgTestTime); + vector<double> cgCJ = cgRotation.Matrix(); + cout << "Time = " << cgRotation.EphemerisTime() << endl; + cout << "CJ = " << cgCJ[0] << " " << cgCJ[1] << " " << cgCJ[2] << endl; + cout << " " << cgCJ[3] << " " << cgCJ[4] << " " << cgCJ[5] << endl; + cout << " " << cgCJ[6] << " " << cgCJ[7] << " " << cgCJ[8] << endl; + + //Test exceptions cout << endl << endl << "Testing exceptions..." << endl; SpiceRotation testRot(-94031); // MGS_MOC - // SpiceRotation(frameCode, targetCode) + // SpiceRotation(frameCode, targetCode) // "Cannot find [key] in text kernels try { cout << endl; @@ -611,13 +628,13 @@ int main(int argc, char *argv[]) { // "Argument cacheSize must not be less or equal to zero" try { cout << endl; - testRot.LoadCache(10, 20, -1); + testRot.LoadCache(10, 20, -1); } catch (IException &e) { e.print(); } - // "Argument startTime must be less than or equal to endTime" + // "Argument startTime must be less than or equal to endTime" try { cout << endl; testRot.LoadCache(20, 10, 1); @@ -639,7 +656,7 @@ int main(int argc, char *argv[]) { try { cout << endl; testRot.LoadCache(startTime, endTime, 2); - testRot.LoadCache(startTime, endTime - 1, 2); + testRot.LoadCache(startTime, endTime - 1, 2); } catch (IException &e) { e.print(); @@ -656,7 +673,7 @@ int main(int argc, char *argv[]) { } // LineCache(tableName) - // "Only cached rotations can be returned as a line cache of quaternions and time" + // "Only cached rotations can be returned as a line cache of quaternions and time" try { cout << endl; SpiceRotation sr(-94031); @@ -665,7 +682,7 @@ int main(int argc, char *argv[]) { catch (IException &e) { e.print(); } - + // Cache(tableName) // "To create table source of data must be either Memcache or PolyFunction" try { @@ -690,10 +707,10 @@ int main(int argc, char *argv[]) { e.print(); } - // DPolynomial(coeffIndex) - // "Unable to evaluate the derivative of the SPCIE rotation fit + // DPolynomial(coeffIndex) + // "Unable to evaluate the derivative of the SPCIE rotation fit // polynomial for the given coefficient index. Index is negative - // or exceeds degree of polynomial" + // or exceeds degree of polynomial" try { cout << endl; testRot.DPolynomial(-1); @@ -703,7 +720,7 @@ int main(int argc, char *argv[]) { } // DPckPolynomial(partialVar, coeffIndex) - // "Unable to evaluate the derivative of the SPCIE rotation fit + // "Unable to evaluate the derivative of the SPCIE rotation fit // polynomial for the given coefficient index. Index is negative // or exceeds degree of polynomial" try { @@ -731,9 +748,9 @@ int main(int argc, char *argv[]) { // LoadTimeCache() //TODO test its 3 exceptions - + // GetFullCacheTime() - // "Time cache not availabe -- rerun spiceinit" + // "Time cache not availabe -- rerun spiceinit" try { cout << endl; SpiceRotation sr(-94031); @@ -745,7 +762,7 @@ int main(int argc, char *argv[]) { // FrameTrace() //TODO test its 3 exceptions - + // ComputeAv() // "The SpiceRotation pointing angles must be fit to polynomials in order to // compute angular velocity." diff --git a/isis/src/base/objs/XmlToPvlTranslationManager/XmlToPvlTranslationManager.cpp b/isis/src/base/objs/XmlToPvlTranslationManager/XmlToPvlTranslationManager.cpp index f4c5bee799abe90e7659985498f1066521ba8bc4..052ccc2c14581f4f47f6bb56c71101acb88f4b5b 100644 --- a/isis/src/base/objs/XmlToPvlTranslationManager/XmlToPvlTranslationManager.cpp +++ b/isis/src/base/objs/XmlToPvlTranslationManager/XmlToPvlTranslationManager.cpp @@ -142,19 +142,24 @@ namespace Isis { /** - * Returns a translated value. The output name is used to find the input - * group, keyword, default and tranlations in the translation table. If the - * keyword does not exist in the input label, the input default if - * available will be used as the input value. This input value - * is then used to search all of the translations. If a match is - * found the translated value is returned. + * Returns a translated value. The translation group name is + * used to find the input group, keyword, default and + * tranlations in the translation table. If the keyword does not + * exist in the input label, the input default if available will + * be used as the input value. This input value is then used to + * search all of the translations. If a match is found the + * translated value is returned. * - * @param outputName The output name used to identify the input keyword to - * be translated. + * @param translationGroupName The name of the PVL translation + * group used to identify the + * input/output keywords to be + * translated. Often, this is the + * same as the output keyword name. * * @param index The index into the input keyword array. Defaults to 0 * - * @return string The ISIS cube label value for the outputName. + * @return @b QString The translated output value to be + * placed in the ISIS3 cube label. * * @throws IException::Unknown "Failed to translate output value." * @throws IException::Unknown "Cannot translate value. Xml files can only @@ -170,7 +175,7 @@ namespace Isis { * @throws IException::Unknown "Could not find an input value or default value." * @throws IException::Unknown "Input element does not have the named attribute." */ - QString XmlToPvlTranslationManager::Translate(QString outputName, + QString XmlToPvlTranslationManager::Translate(QString translationGroupName, int index) { try { if (index != 0) { @@ -182,7 +187,7 @@ namespace Isis { const Pvl &transTable = TranslationTable(); PvlGroup transGroup; try { - transGroup = transTable.findGroup(outputName); + transGroup = transTable.findGroup(translationGroupName); } catch (IException &e){ QString msg = "Unable to retrieve translation group from translation table."; @@ -228,7 +233,7 @@ namespace Isis { // Notify what we are translating and what the translating group is. if (isDebug) { cout << endl << " ==================== " << endl; - cout << endl << "Translating output keyword: " << outputName << endl; + cout << endl << "Translating output keyword: " << translationGroupName << endl; cout << endl << "Translation group:" << endl; cout << transGroup << endl << endl; } @@ -269,13 +274,13 @@ namespace Isis { } if (inputParentElement.isNull()) { - if (hasInputDefault(outputName)) { + if (hasInputDefault(translationGroupName)) { if (isDebug) { cout << endl << "Could not traverse input position, " << "using default value: " << - InputDefault(outputName) << endl; + InputDefault(translationGroupName) << endl; } - return PvlTranslationTable::Translate( outputName ); + return PvlTranslationTable::Translate( translationGroupName ); } else { QString msg = "Failed traversing input position. [" + @@ -312,12 +317,12 @@ namespace Isis { // If the parent element is NULL at this point then we traversed every // potential input element and none of them satisfied the dependencies. if ( inputParentElement.isNull() ) { - if ( hasInputDefault(outputName) ) { + if ( hasInputDefault(translationGroupName) ) { if (isDebug) { cout << endl << "No input value found, using default value: " << - InputDefault(outputName) << endl; + InputDefault(translationGroupName) << endl; } - return PvlTranslationTable::Translate( outputName ); + return PvlTranslationTable::Translate( translationGroupName ); } else { QString msg = "Could not find an input or default value that fits the given input " @@ -333,12 +338,12 @@ namespace Isis { if ( inputKeyElement.hasAttribute(attributeName) ) { inputValue = inputKeyElement.attribute(attributeName); } - else if (hasInputDefault(outputName) ) { + else if (hasInputDefault(translationGroupName) ) { if (isDebug) { cout << endl << "No input value found, using default value: " << - InputDefault(outputName) << endl; + InputDefault(translationGroupName) << endl; } - return PvlTranslationTable::Translate( outputName ); + return PvlTranslationTable::Translate( translationGroupName ); } else { QString msg = "Input element [" + inputKeyElement.tagName() + @@ -350,10 +355,10 @@ namespace Isis { if (isDebug) { cout << endl << "Translating input value: " << inputValue << endl; } - return PvlTranslationTable::Translate( outputName, inputValue.trimmed() ); + return PvlTranslationTable::Translate( translationGroupName, inputValue.trimmed() ); } catch (IException &e){ - QString msg = "Failed to translate output value for [" + outputName + "]."; + QString msg = "Failed to translate output value for [" + translationGroupName + "]."; throw IException(e, IException::Unknown, msg, _FILEINFO_); } } diff --git a/isis/src/base/objs/XmlToPvlTranslationManager/XmlToPvlTranslationManager.h b/isis/src/base/objs/XmlToPvlTranslationManager/XmlToPvlTranslationManager.h index 8f726fa2f82dde60f59a3d049fd8f2275402ca3d..1a7a6fa9a1908cae03a2339751bf59e69d512914 100644 --- a/isis/src/base/objs/XmlToPvlTranslationManager/XmlToPvlTranslationManager.h +++ b/isis/src/base/objs/XmlToPvlTranslationManager/XmlToPvlTranslationManager.h @@ -143,7 +143,7 @@ namespace Isis { // Attempt to translate the requested output name to output value // using the input name and value/default value - virtual QString Translate(QString nName, int findex = 0); + virtual QString Translate(QString translationGroupName, int findex = 0); // Translate all translation table groups which contain "Auto" using LabelTranslationManager::Auto; diff --git a/isis/src/control/apps/deltack/deltack.cpp b/isis/src/control/apps/deltack/deltack.cpp index 0b88d4aa5b7032df44603038281b07eb99e88f73..529c84a9a53adf2a90692890cec9820a5bf26868 100644 --- a/isis/src/control/apps/deltack/deltack.cpp +++ b/isis/src/control/apps/deltack/deltack.cpp @@ -267,12 +267,12 @@ void IsisMain() { QObject::connect( bundleAdjust, SIGNAL( statusUpdate(QString) ), bundleAdjust, SLOT( outputBundleStatus(QString) ) ); - BundleSolutionInfo bundleSolution = bundleAdjust->solveCholeskyBR(); + BundleSolutionInfo *bundleSolution = bundleAdjust->solveCholeskyBR(); // Output bundle adjust files - bundleSolution.outputText(); - bundleSolution.outputResiduals(); + bundleSolution->outputText(); + bundleSolution->outputResiduals(); Table cmatrix = bundleAdjust->cMatrix(0); @@ -285,6 +285,9 @@ void IsisMain() { //cmatrix.Label().findObject("Table",Pvl::Traverse).addKeyword(description); c.write(cmatrix); + + delete bundleAdjust; + delete bundleSolution; } // Now do final clean up as the update was successful if we reach here... diff --git a/isis/src/control/apps/deltack/deltack.xml b/isis/src/control/apps/deltack/deltack.xml index 76122f369e7b9f61a4e0ad38d8c4cf269ebf9428..25f78dd1d424c2f6e2cb0e5e2d23f5750ca9122e 100644 --- a/isis/src/control/apps/deltack/deltack.xml +++ b/isis/src/control/apps/deltack/deltack.xml @@ -190,7 +190,11 @@ method to apply. The default is METHOD=BUNDLE which chooses pre-existing behavor. Updated documentation to reflect these new changes. Fixes #4868. </change> - + <change name="Ken Edmundson" date="2018-05-23"> + Modifed call to bundleAdjustment->solveCholeskyBR() to return a raw pointer to a + BundleSolutionInfo object. Am also deleting this pointer because jigsaw.cpp takes + ownership from BundleAdjust. + </change> </history> <groups> diff --git a/isis/src/control/apps/jigsaw/jigsaw.cpp b/isis/src/control/apps/jigsaw/jigsaw.cpp index 66a0d84bfd9df5817486c2017d4c6e8eedcca348..daf0f46865a90dbff1cd075903daf5b540d1befc 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.cpp +++ b/isis/src/control/apps/jigsaw/jigsaw.cpp @@ -80,24 +80,24 @@ void IsisMain() { QObject::connect( bundleAdjustment, SIGNAL( statusUpdate(QString) ), bundleAdjustment, SLOT( outputBundleStatus(QString) ) ); - BundleSolutionInfo bundleSolution = bundleAdjustment->solveCholeskyBR(); + BundleSolutionInfo *bundleSolution = bundleAdjustment->solveCholeskyBR(); cout << "\nGenerating report files\n" << endl; // write output files if (ui.GetBoolean("BUNDLEOUT_TXT")) { - bundleSolution.outputText(); + bundleSolution->outputText(); } if (ui.GetBoolean("IMAGESCSV")) { - bundleSolution.outputImagesCSV(); + bundleSolution->outputImagesCSV(); } if (ui.GetBoolean("OUTPUT_CSV")) { - bundleSolution.outputPointsCSV(); + bundleSolution->outputPointsCSV(); } if (ui.GetBoolean("RESIDUALS_CSV")) { - bundleSolution.outputResiduals(); + bundleSolution->outputResiduals(); } // write updated control net @@ -147,6 +147,7 @@ void IsisMain() { gp += PvlKeyword("Status", "Camera pointing NOT updated"); } Application::Log(gp); + delete bundleSolution; } catch(IException &e) { bundleAdjustment->controlNet()->Write(ui.GetFileName("ONET")); diff --git a/isis/src/control/apps/jigsaw/jigsaw.xml b/isis/src/control/apps/jigsaw/jigsaw.xml index ec0f2bb3d5907baa1d156ee3365c3b771ebe7d36..460aaad7a001949cea65154fcc46aa906ba45c45 100644 --- a/isis/src/control/apps/jigsaw/jigsaw.xml +++ b/isis/src/control/apps/jigsaw/jigsaw.xml @@ -252,6 +252,11 @@ <change name="Summer Stapleton" date="2017-08-09"> Fixed bug where an invalid control net was not throwing exception. Fixes #5068. </change> + <change name="Ken Edmundson" date="2018-05-23"> + Modifed call to bundleAdjustment->solveCholeskyBR() to return a raw pointer to a + BundleSolutionInfo object. Am also deleting this pointer because jigsaw.cpp takes + ownership from BundleAdjust. + </change> </history> <groups> diff --git a/isis/src/control/objs/BundleAdjust/BundleAdjust.cpp b/isis/src/control/objs/BundleAdjust/BundleAdjust.cpp index 8c892e114cb8e5d137778a1f66c279b860f366db..2e3ef8cd5d06f392f5fc275da5cabe24b6af7c52 100644 --- a/isis/src/control/objs/BundleAdjust/BundleAdjust.cpp +++ b/isis/src/control/objs/BundleAdjust/BundleAdjust.cpp @@ -680,7 +680,7 @@ namespace Isis { * * @TODO make solveCholesky return a BundleSolutionInfo object and delete this placeholder ??? */ - BundleSolutionInfo BundleAdjust::solveCholeskyBR() { + BundleSolutionInfo* BundleAdjust::solveCholeskyBR() { solveCholesky(); return bundleSolveInformation(); } @@ -976,8 +976,7 @@ namespace Isis { m_bundleResults.setObservations(m_bundleObservations); m_bundleResults.setBundleControlPoints(m_bundleControlPoints); - BundleSolutionInfo *results = new BundleSolutionInfo(bundleSolveInformation()); - emit resultsReady(results); + emit resultsReady(bundleSolveInformation()); emit statusUpdate("\nBundle Complete"); @@ -999,12 +998,18 @@ namespace Isis { /** * Create a BundleSolutionInfo containing the settings and results from the bundle adjustment. * - * @return @b BundleSolutionInfo A container with solve information from the adjustment. + * @return @b BundleSolutionInfo A container with solve information from the adjustment. NOTE: + * Caller takes ownership and is responsible for memory management of returned + * BundleSolutionInfo raw pointer. + * */ - BundleSolutionInfo BundleAdjust::bundleSolveInformation() { - BundleSolutionInfo results(m_bundleSettings, FileName(m_cnetFileName), m_bundleResults, imageLists()); - results.setRunTime(""); - return results; + BundleSolutionInfo *BundleAdjust::bundleSolveInformation() { + BundleSolutionInfo *bundleSolutionInfo = new BundleSolutionInfo(m_bundleSettings, + FileName(m_cnetFileName), + m_bundleResults, + imageLists()); + bundleSolutionInfo->setRunTime(""); + return bundleSolutionInfo; } diff --git a/isis/src/control/objs/BundleAdjust/BundleAdjust.h b/isis/src/control/objs/BundleAdjust/BundleAdjust.h index 8c30664b4536254a1c923c6c670205ffb37efe57..428973b9b2a337af237e5ff3eeda156866b7022f 100644 --- a/isis/src/control/objs/BundleAdjust/BundleAdjust.h +++ b/isis/src/control/objs/BundleAdjust/BundleAdjust.h @@ -285,6 +285,13 @@ namespace Isis { * @history 2017-08-09 Summer Stapleton - Added a try/catch around the m_controlNet assignment * in each of the constructors to verify valid control net input. * Fixes #5068. + * @history 2018-05-22 Ken Edmundson - Modified methods bundleSolveInformation() and + * solveCholeskyBR() to return raw pointers to a BundleSolutionInfo object. + * Also modified resultsReady signal to take a raw pointer to a + * BundleSolutionInfo object. This was done to avoid using a copy + * constructor in the BundleSolutionInfo class because it is derived + * from QObject. Note that we ultimately want to return a QSharedPointer + * instead of a raw pointer. */ class BundleAdjust : public QObject { Q_OBJECT @@ -314,7 +321,7 @@ namespace Isis { QList<ImageList *> imgList, bool printSummary); ~BundleAdjust(); - BundleSolutionInfo solveCholeskyBR(); + BundleSolutionInfo* solveCholeskyBR(); QList<ImageList *> imageLists(); @@ -350,7 +357,7 @@ namespace Isis { bool validateNetwork(); bool solveSystem(); void iterationSummary(); - BundleSolutionInfo bundleSolveInformation(); + BundleSolutionInfo* bundleSolveInformation(); bool computeBundleStatistics(); void applyParameterCorrections(); bool errorPropagation(); diff --git a/isis/src/control/objs/BundleSettings/BundleSettings.cpp b/isis/src/control/objs/BundleSettings/BundleSettings.cpp index 7434226a2a8acaf6a549dbb911ff4b3826e1a7da..b2e9d2ab97f9b97a847b3f8771e00be9cab765ea 100644 --- a/isis/src/control/objs/BundleSettings/BundleSettings.cpp +++ b/isis/src/control/objs/BundleSettings/BundleSettings.cpp @@ -10,10 +10,6 @@ #include <QXmlStreamWriter> #include <QXmlInputSource> -#include <H5Cpp.h> -#include <hdf5_hl.h> -#include <hdf5.h> - #include "BundleObservationSolveSettings.h" //#include "FileName.h"currently only used in commented code #include "IException.h" @@ -52,7 +48,7 @@ namespace Isis { m_solveRadius = false; m_updateCubeLabel = false; m_errorPropagation = false; - m_createInverseMatrix = true; + m_createInverseMatrix = false; m_outlierRejection = false; m_outlierRejectionMultiplier = 1.0; diff --git a/isis/src/control/objs/BundleSettings/BundleSettings.h b/isis/src/control/objs/BundleSettings/BundleSettings.h index 3475474b7f40e779fc0247de3bc46206a3ebd750..88db2ff4c71f2a978f9e1e8129ae2b717b7345d9 100644 --- a/isis/src/control/objs/BundleSettings/BundleSettings.h +++ b/isis/src/control/objs/BundleSettings/BundleSettings.h @@ -101,6 +101,11 @@ namespace Isis { * @history 2016-10-17 Jesse Mapel - Removed m_SCPVLFilename parameter in accordance with * USEPVL being removed from jigsaw. References #4316. * @history 2017-04-24 Ian Humphrey - Removed pvlObject(). Fixes #4797. + * @history 2018-03-20 Ken Edmundson + * 1) Temporarily set default for m_createInverseMatrix to false. This + * is for creating and displaying the correlation matrix, which is + * currently not working. + * 2) commented out hdf5 header includes in cpp * * @todo Determine which XmlStackedHandlerReader constructor is preferred * @todo Determine which XmlStackedHandler needs a Project pointer (see constructors) diff --git a/isis/src/control/objs/BundleSettings/BundleSettings.truth b/isis/src/control/objs/BundleSettings/BundleSettings.truth index 29abea63bdc5a8b29e789e0b127615d58d8b4688..853a4c351862bae73b2d739f7dac4dcd08c98de0 100644 --- a/isis/src/control/objs/BundleSettings/BundleSettings.truth +++ b/isis/src/control/objs/BundleSettings/BundleSettings.truth @@ -120,7 +120,7 @@ Testing mutator methods... <bundleSettings> <globalSettings> <validateNetwork>Yes</validateNetwork> - <solveOptions solveObservationMode="Yes" solveRadius="Yes" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="Yes"/> + <solveOptions solveObservationMode="Yes" solveRadius="Yes" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="No"/> <aprioriSigmas latitude="1000.0" longitude="2000.0" radius="3000.0"/> <outlierRejectionOptions rejection="Yes" multiplier="4.0"/> <convergenceCriteriaOptions convergenceCriteria="ParameterCorrections" threshold="0.25" maximumIterations="26"/> @@ -170,7 +170,7 @@ Testing mutator methods... <bundleSettings> <globalSettings> <validateNetwork>Yes</validateNetwork> - <solveOptions solveObservationMode="Yes" solveRadius="No" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="Yes"/> + <solveOptions solveObservationMode="Yes" solveRadius="No" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="No"/> <aprioriSigmas latitude="N/A" longitude="N/A" radius="N/A"/> <outlierRejectionOptions rejection="No" multiplier="N/A"/> <convergenceCriteriaOptions convergenceCriteria="Sigma0" threshold="1.0e-10" maximumIterations="50"/> @@ -198,7 +198,7 @@ Testing mutator methods... <bundleSettings> <globalSettings> <validateNetwork>Yes</validateNetwork> - <solveOptions solveObservationMode="Yes" solveRadius="No" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="Yes"/> + <solveOptions solveObservationMode="Yes" solveRadius="No" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="No"/> <aprioriSigmas latitude="N/A" longitude="N/A" radius="N/A"/> <outlierRejectionOptions rejection="No" multiplier="N/A"/> <convergenceCriteriaOptions convergenceCriteria="Sigma0" threshold="1.0e-10" maximumIterations="50"/> @@ -275,7 +275,7 @@ Serializing test XML object to file: <bundleSettings> <globalSettings> <validateNetwork>Yes</validateNetwork> - <solveOptions solveObservationMode="Yes" solveRadius="No" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="Yes"/> + <solveOptions solveObservationMode="Yes" solveRadius="No" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="No"/> <aprioriSigmas latitude="N/A" longitude="N/A" radius="N/A"/> <outlierRejectionOptions rejection="No" multiplier="N/A"/> <convergenceCriteriaOptions convergenceCriteria="Sigma0" threshold="1.0e-10" maximumIterations="50"/> @@ -304,7 +304,7 @@ Testing XML: Object deserialized as (should match object above): <bundleSettings> <globalSettings> <validateNetwork>Yes</validateNetwork> - <solveOptions solveObservationMode="Yes" solveRadius="No" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="Yes"/> + <solveOptions solveObservationMode="Yes" solveRadius="No" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="No"/> <aprioriSigmas latitude="N/A" longitude="N/A" radius="N/A"/> <outlierRejectionOptions rejection="No" multiplier="N/A"/> <convergenceCriteriaOptions convergenceCriteria="Sigma0" threshold="1.0e-10" maximumIterations="50"/> @@ -334,7 +334,7 @@ Serializing test XML object to file: <bundleSettings> <globalSettings> <validateNetwork>Yes</validateNetwork> - <solveOptions solveObservationMode="Yes" solveRadius="Yes" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="Yes"/> + <solveOptions solveObservationMode="Yes" solveRadius="Yes" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="No"/> <aprioriSigmas latitude="1000.0" longitude="2000.0" radius="3000.0"/> <outlierRejectionOptions rejection="Yes" multiplier="4.0"/> <convergenceCriteriaOptions convergenceCriteria="ParameterCorrections" threshold="0.25" maximumIterations="26"/> @@ -385,7 +385,7 @@ Testing XML: Object deserialized as (should match object above): <bundleSettings> <globalSettings> <validateNetwork>Yes</validateNetwork> - <solveOptions solveObservationMode="Yes" solveRadius="Yes" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="Yes"/> + <solveOptions solveObservationMode="Yes" solveRadius="Yes" updateCubeLabel="Yes" errorPropagation="Yes" createInverseMatrix="No"/> <aprioriSigmas latitude="1000.0" longitude="2000.0" radius="3000.0"/> <outlierRejectionOptions rejection="Yes" multiplier="4.0"/> <convergenceCriteriaOptions convergenceCriteria="ParameterCorrections" threshold="0.25" maximumIterations="26"/> diff --git a/isis/src/control/objs/BundleSettings/unitTest.cpp b/isis/src/control/objs/BundleSettings/unitTest.cpp index b8811df68fc3d583be0cfde31d8b88512443165a..54d3e40663e41d5d657980454c2bd5c0243682c4 100755 --- a/isis/src/control/objs/BundleSettings/unitTest.cpp +++ b/isis/src/control/objs/BundleSettings/unitTest.cpp @@ -47,6 +47,8 @@ void printXml(const T &); * most likely going to move to HDF5. Fixes #4327. * @history 2017-04-24 Ian Humphrey - Removed pvlObject() and replaced with the XML save(). * Fixes #4797. + * @history 2018-05-24 Ken Edmundson - Updated truth data to indicate default value for + * m_createInverseMatrix was changed from true to false. * * @todo Truth updated so that the name of the BundleObservationSolveSettings object is Null, * this should be fixed as part of #4292. diff --git a/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.cpp b/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.cpp index a0a83357b193c837c607ce07dfa73a99b155afd6..d9c53bd6cb466e3acea682128ccb73ccd22f7535 100755 --- a/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.cpp +++ b/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.cpp @@ -10,6 +10,7 @@ #include <QXmlStreamWriter> #include "BundleResults.h" +#include "ControlList.h" #include "ControlMeasure.h" #include "ControlNet.h" #include "ControlPoint.h" @@ -39,25 +40,19 @@ namespace Isis { QList<ImageList *> imgList, QObject *parent) : QObject(parent) { m_id = new QUuid(QUuid::createUuid()); - m_runTime = ""; - m_name = m_runTime; - - m_controlNetworkFileName = new FileName(controlNetworkFileName); - + m_inputControlNetFileName = new FileName(controlNetworkFileName); + m_outputControl = NULL; m_settings = inputSettings; - m_statisticsResults = new BundleResults(outputStatistics); - m_images = new QList<ImageList *>(imgList); - m_adjustedImages = new QList<ImageList *>; } /** - * Constructor. Creates a BundleSolutionInfo. + * Constructor. Creates a BundleSolutionInfo from disk. * * @param project The current project * @param xmlReader An XML reader that's up to an <bundleSettings/> tag. @@ -70,7 +65,8 @@ namespace Isis { m_id = new QUuid(QUuid::createUuid()); m_runTime = ""; m_name = m_runTime; - m_controlNetworkFileName = NULL; + m_inputControlNetFileName = NULL; + m_outputControl = NULL; m_statisticsResults = NULL; // what about the rest of the member data ? should we set defaults ??? CREATE INITIALIZE METHOD m_images = new QList<ImageList *>; @@ -81,34 +77,17 @@ namespace Isis { } - /** - * Constructor. Creates a BundleSolutionInfo. - * - * @param src BundleSolutionInfo where the settings and BundleResults are read from. - */ - BundleSolutionInfo::BundleSolutionInfo(const BundleSolutionInfo &src) - : m_id(new QUuid(QUuid::createUuid())), - m_name(src.m_name), - m_runTime(src.m_runTime), - m_controlNetworkFileName(new FileName(src.m_controlNetworkFileName->expanded())), - m_settings(new BundleSettings(*src.m_settings)), - m_statisticsResults(new BundleResults(*src.m_statisticsResults)), - m_images(new QList<ImageList *>(*src.m_images)), - m_adjustedImages(new QList<ImageList *>(*src.m_adjustedImages)), - m_csvSavedImagesFilename(src.m_csvSavedImagesFilename), - m_csvSavedPointsFilename(src.m_csvSavedPointsFilename), - m_csvSavedResidualsFilename(src.m_csvSavedResidualsFilename) { - } - - /** * Destructor */ BundleSolutionInfo::~BundleSolutionInfo() { delete m_id; - delete m_controlNetworkFileName; - m_controlNetworkFileName = NULL; + delete m_inputControlNetFileName; + m_inputControlNetFileName = NULL; + + delete m_outputControl; + m_outputControl = NULL; delete m_statisticsResults; m_statisticsResults = NULL; @@ -128,53 +107,40 @@ namespace Isis { /** - * Creates an equal operator for BundleSolutionInfos. - * - * @param src the BundleSolutionInfo that we are comparing the current BundleSolutionInfo to. + * Returns bundleout text filename. * - * @return @b BundleSolutionInfo Reference to the current BundleSolutionInfo + * @return QString Bundleout text filename. */ - BundleSolutionInfo &BundleSolutionInfo::operator=(const BundleSolutionInfo &src) { - - if (&src != this) { - - delete m_id; - m_id = new QUuid(QUuid::createUuid()); - - m_runTime = src.m_runTime; - - if (src.m_name == "" || src.m_name == src.m_runTime) { - m_name = m_runTime; - } - else { - m_name = src.m_name; - } - - delete m_controlNetworkFileName; - m_controlNetworkFileName = new FileName(src.m_controlNetworkFileName->expanded()); - - m_settings = src.m_settings; - - delete m_statisticsResults; - m_statisticsResults = new BundleResults(*src.m_statisticsResults); - - delete m_images; - m_images = new QList<ImageList *>(*src.m_images); - - delete m_adjustedImages; - m_adjustedImages = new QList<ImageList *>(*src.m_adjustedImages); - } - return *this; + QString BundleSolutionInfo::savedBundleOutputFilename() { + return m_txtBundleOutputFilename; } + + /** + * Returns filename of output bundle images csv file. + * + * @return QString filename of output bundle images csv file. + */ QString BundleSolutionInfo::savedImagesFilename() { return m_csvSavedImagesFilename; } + + /** + * Returns filename of output bundle points csv file. + * + * @return QString filename of output bundle points csv file. + */ QString BundleSolutionInfo::savedPointsFilename() { return m_csvSavedPointsFilename; } + + /** + * Returns filename of output bundle residuals csv file. + * + * @return QString filename of output bundle residuals csv file. + */ QString BundleSolutionInfo::savedResidualsFilename() { return m_csvSavedResidualsFilename; } @@ -203,6 +169,8 @@ namespace Isis { /** + * TODO: change description below to something more like english. + * * Change the on-disk file name for the control network used to be where the control network * ought to be in the given project. * @@ -216,10 +184,19 @@ namespace Isis { //TODO do we need to close anything here? - FileName oldFileName(*m_controlNetworkFileName); - FileName newName(project->cnetRoot() + "/" + - oldFileName.dir().dirName() + "/" + oldFileName.name()); - *m_controlNetworkFileName = newName.expanded(); + FileName oldInputFileName(*m_inputControlNetFileName); + FileName newInputFileName(project->cnetRoot() + "/" + + oldInputFileName.dir().dirName() + "/" + oldInputFileName.name()); + *m_inputControlNetFileName = newInputFileName.expanded(); + + FileName oldOutputFileName(m_outputControl->fileName()); + FileName newOutputFileName(project->cnetRoot() + "/" + + oldOutputFileName.dir().dirName() + "/" + oldOutputFileName.name()); + + if (m_outputControl) { + delete m_outputControl; + } + m_outputControl = new Control(newOutputFileName.expanded()); } @@ -277,19 +254,49 @@ namespace Isis { /** - * Returns the name of the control network. + * Returns the name of the input control network. + * + * @return @b QString The name of the input control network. + */ + QString BundleSolutionInfo::inputControlNetFileName() const { + return m_inputControlNetFileName->expanded(); + } + + + /** + * Returns the name of the output control network. + * + * @return @b QString The name of the output control network. + */ + QString BundleSolutionInfo::outputControlNetFileName() const { + return m_outputControl->fileName(); + } + + + /** + * Returns the name of the output control network. + * + * @return @b QString The name of the output control network. + */ + void BundleSolutionInfo::setOutputControl(Control *outputControl) { + m_outputControl = outputControl; + } + + + /** + * Returns bundle output Control object. * - * @return @b QString The name of the control network. + * @return Control* Pointer to bundle output Control object. */ - QString BundleSolutionInfo::controlNetworkFileName() const { - return m_controlNetworkFileName->expanded(); + Control *BundleSolutionInfo::control() const { + return m_outputControl; } /** - * Returns the bundle settings. + * Returns bundle settings. * - * @return @b BundleSettingsQsp The bundle settings. + * @return BundleSettingsQsp Bundle settings. */ BundleSettingsQsp BundleSolutionInfo::bundleSettings() { return m_settings; @@ -538,7 +545,7 @@ namespace Isis { Isis::iTime::CurrentLocalTime().toLatin1().data()); fpOut << buf; sprintf(buf, "\n Network Filename: %s", - m_controlNetworkFileName->expanded().toLatin1().data()); + m_inputControlNetFileName->expanded().toLatin1().data()); fpOut << buf; sprintf(buf, "\n Network Id: %s", m_statisticsResults->outputControlNet()->GetNetworkId().toLatin1().data()); @@ -1116,6 +1123,8 @@ namespace Isis { return false; } + m_txtBundleOutputFilename = ofname; + char buf[1056]; BundleObservationQsp observation; @@ -1311,19 +1320,16 @@ namespace Isis { // print column headers if (m_settings->errorPropagation()) { - sprintf(buf, "Point,Point,Accepted,Rejected,Residual,3-d,3-d,3-d,Sigma," - "Sigma,Sigma,Correction,Correction,Correction,Coordinate," - "Coordinate,Coordinate\nID,,,,,Latitude,Longitude,Radius," - "Latitude,Longitude,Radius,Latitude,Longitude,Radius,X,Y,Z\n" - "Label,Status,Measures,Measures,RMS,(dd),(dd),(km),(m),(m),(m)," - "(m),(m),(m),(km),(km),(km)\n"); + sprintf(buf, ",,,,,3-d,3-d,3-d,Sigma,Sigma,Sigma,Correction,Correction,Correction,Coordinate," + "Coordinate,Coordinate\nPoint,Point,Accepted,Rejected,Residual,Latitude,Longitude," + "Radius,Latitude,Longitude,Radius,Latitude,Longitude,Radius,X,Y,Z\nLabel,Status," + "Measures,Measures,RMS,(dd),(dd),(km),(m),(m),(m),(m),(m),(m),(km),(km),(km)\n"); } else { - sprintf(buf, "Point,Point,Accepted,Rejected,Residual,3-d,3-d,3-d," - "Correction,Correction,Correction,Coordinate,Coordinate," - "Coordinate\n,,,,,Latitude,Longitude,Radius,Latitude," - "Longitude,Radius,X,Y,Z\nLabel,Status,Measures,Measures," - "RMS,(dd),(dd),(km),(m),(m),(m),(km),(km),(km)\n"); + sprintf(buf, ",,,,,3-d,3-d,3-d,Correction,Correction,Correction,Coordinate,Coordinate," + "Coordinate\nPoint,Point,Accepted,Rejected,Residual,Latitude,Longitude,Radius," + "Latitude,Longitude,Radius,X,Y,Z\nLabel,Status,Measures,Measures,RMS,(dd),(dd),(km)," + "(m),(m),(m),(km),(km),(km)\n"); } fpOut << buf; @@ -1502,7 +1508,10 @@ namespace Isis { void BundleSolutionInfo::save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot) const { + // TODO: comment below not clear, why is this done? // This is done for unitTest which has no Project + // SHOULD WE BE CREATING A SERIALIZED PROJECT AS INPUT TO THIS UNIT TEST? + QString relativePath; QString relativeBundlePath; FileName bundleSolutionInfoRoot; @@ -1521,14 +1530,20 @@ namespace Isis { .arg(bundleSolutionInfoRoot.path()), _FILEINFO_); } - QString oldFile = oldPath + "/" + m_controlNetworkFileName->name(); - QString newFile = newPath + "/" + m_controlNetworkFileName->name(); - //QString outputControlFile = m_statisticsResults->outputControlNet()-> + QString oldFile = oldPath + "/" + FileName(m_outputControl->fileName()).name(); + QString newFile = newPath + "/" + FileName(m_outputControl->fileName()).name(); if (!QFile::copy(oldFile, newFile)) { throw IException(IException::Io, QString("Failed to copy file [%1] to new file [%2]") - .arg(m_controlNetworkFileName->name()).arg(newFile), - _FILEINFO_); + .arg(m_outputControl->fileName()).arg(newFile), + _FILEINFO_); + } + newFile = newPath + "/" + FileName(m_txtBundleOutputFilename).name(); + if (!QFile::copy(m_txtBundleOutputFilename, newFile)) { + throw IException(IException::Io, + QString("Failed to copy file [%1] to new file [%2]") + .arg(m_txtBundleOutputFilename).arg(newFile), + _FILEINFO_); } newFile = newPath + "/" + FileName(m_csvSavedImagesFilename).name(); if (!QFile::copy(m_csvSavedImagesFilename, newFile)) { @@ -1553,7 +1568,14 @@ namespace Isis { } } - // Create relative path for bundleSolutionInfo + // Create relativePath + relativePath = m_inputControlNetFileName->expanded().remove(project->newProjectRoot()); + // Get rid of any preceding "/" , but add on ending "/" + if (relativePath.startsWith("/")) { + relativePath.remove(0,1); + } + + // Create relativeBundlePath for bundleSolutionInfo relativeBundlePath = newPath.remove(project->newProjectRoot()); // Get rid of any preceding "/" , but add on ending "/" if (relativeBundlePath.startsWith("/")) { @@ -1562,14 +1584,19 @@ namespace Isis { relativeBundlePath += "/"; } + // TODO: so, we can do the stuff below if project is NULL? + stream.writeStartElement("bundleSolutionInfo"); // save ID, cnet file name, and run time to stream stream.writeStartElement("generalAttributes"); stream.writeTextElement("id", m_id->toString()); stream.writeTextElement("name", m_name); stream.writeTextElement("runTime", runTime()); - stream.writeTextElement("fileName", - relativeBundlePath + m_controlNetworkFileName->name()); + + stream.writeTextElement("inputFileName", + relativePath); + stream.writeTextElement("bundleOutTXT", + relativeBundlePath + FileName(m_txtBundleOutputFilename).name()); stream.writeTextElement("imagesCSV", relativeBundlePath + FileName(m_csvSavedImagesFilename).name()); stream.writeTextElement("pointsCSV", @@ -1593,7 +1620,13 @@ namespace Isis { } stream.writeEndElement(); } + + // save output control + stream.writeStartElement("outputControl"); + m_outputControl->save(stream, project, relativeBundlePath); + stream.writeEndElement(); } + stream.writeEndElement(); //end bundleSolutionInfo } @@ -1660,10 +1693,15 @@ namespace Isis { reader()); } else if (localName == "imageList") { - // m_xmlHandlerBundleSolutionInfo->m_images->append(new ImageList(m_xmlHandlerProject, reader())); m_xmlHandlerBundleSolutionInfo->m_adjustedImages->append( new ImageList(m_xmlHandlerProject, reader())); } + else if (localName == "outputControl") { + FileName outputControlPath = FileName(m_xmlHandlerProject->bundleSolutionInfoRoot() + "/" + + m_xmlHandlerBundleSolutionInfo->runTime()); + + m_xmlHandlerBundleSolutionInfo->m_outputControl = new Control(outputControlPath, reader()); + } } return true; } @@ -1699,11 +1737,15 @@ namespace Isis { else if (localName == "runTime") { m_xmlHandlerBundleSolutionInfo->m_runTime = m_xmlHandlerCharacters; } - else if (localName == "fileName") { - assert(m_xmlHandlerBundleSolutionInfo->m_controlNetworkFileName == NULL); - m_xmlHandlerBundleSolutionInfo->m_controlNetworkFileName = new FileName( + else if (localName == "inputFileName") { + assert(m_xmlHandlerBundleSolutionInfo->m_inputControlNetFileName == NULL); + m_xmlHandlerBundleSolutionInfo->m_inputControlNetFileName = new FileName( projectRoot + m_xmlHandlerCharacters); } + else if (localName == "bundleOutTXT") { + m_xmlHandlerBundleSolutionInfo->m_txtBundleOutputFilename = + projectRoot + m_xmlHandlerCharacters; + } else if (localName == "imagesCSV") { m_xmlHandlerBundleSolutionInfo->m_csvSavedImagesFilename = projectRoot + m_xmlHandlerCharacters; diff --git a/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.h b/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.h index 1d63e18fc397341bf606187ec2457094b50cab59..1991c81fb5fa3c4e451fad00f8c74bec539c31ea 100755 --- a/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.h +++ b/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.h @@ -36,6 +36,7 @@ class QXmlStreamWriter; namespace Isis { class BundleResults; + class Control; class FileName; class ImageList; class Project; //TODO does xml stuff need project??? @@ -119,6 +120,27 @@ namespace Isis { * @history 2018-01-17 Tracie Sucharski - Added conditional code to check for null project in * xml serialization to allow the unitTest to use xml serialization * without having a project. References #5104. + * @history 2018-03-21 Ken Edmundson - Added... + * 1) member variable m_inputControlNetFileName, accessor method, and + * serialization support. Also added input control net filename to + * constructor. + * 2) member variable m_outputControl, associated mutator/accessor, and + * serialization support. + * 3) member variable m_txtBundleOutputFilename and associated accessor + * for bundleout.txt file. + * @history 2018-03-23 Ken Edmundson - modified... + * 1) removed serialization of output control filename + * 2) serialization of output control to be more robust, ensuring that + * the control's id is added to project upon reading back in. Also + * ensures that an open cneteditor widget containing a + * bundlesolutioninfo's output control is serialized properly. + * @history 2018-03-26 Ken Edmundson - modified save method to properly save output control + * network file. + * @history 2018-05-22 Ken Edmundson - changed default and copy constructors and assignment + * operator to private to prevent developer from calling them. Done + * because BundleSolutionInfo is derived from QObject (see comment + * below). Removed copy constructor and assignment operator from cpp + * file. */ class BundleSolutionInfo : public QObject { Q_OBJECT @@ -131,22 +153,24 @@ namespace Isis { BundleSolutionInfo(Project *project, XmlStackedHandlerReader *xmlReader, QObject *parent = 0); //TODO does xml stuff need project??? - BundleSolutionInfo(const BundleSolutionInfo &src); ~BundleSolutionInfo(); - BundleSolutionInfo &operator=(const BundleSolutionInfo &src); + QString savedBundleOutputFilename(); QString savedImagesFilename(); QString savedPointsFilename(); QString savedResidualsFilename(); void addAdjustedImages(ImageList *images); void setOutputStatistics(BundleResults statisticsResults); + void setOutputControl(Control *outputControl); void setRunTime(QString runTime); void setName(QString name); QList<ImageList *> adjustedImages() const; QString id() const; - QString controlNetworkFileName() const; + QString inputControlNetFileName() const; + QString outputControlNetFileName() const; + Control *control() const; BundleSettingsQsp bundleSettings(); BundleResults bundleResults(); QList<ImageList *> imageList(); @@ -198,28 +222,40 @@ namespace Isis { }; private: + // NOTE: BundleSolutionInfo is derived from QObject as it has one slot (perhaps more signals + // and slots in the future? As a child of QObject it should have no copy constructor or + // assignment operator. See for example... + // + // http://doc.qt.io/qt-5/qobject.html#no-copy-constructor + // + // These methods are declared as private to prevent the developer from calling default + // operators. These will generate a compiler error if the developer attempts to use + // them. BundleSolutionInfo(); + BundleSolutionInfo(const BundleSolutionInfo &src); + BundleSolutionInfo &operator=(const BundleSolutionInfo &src); //! A unique ID for this BundleSolutionInfo object (useful for others to reference this //! object when saving to disk). QUuid *m_id; - QString m_name; //!< The name of the bundle. Defaults to the id - QString m_runTime; //!< The run time of the bundle adjust - FileName *m_controlNetworkFileName; //!< The name of the control network - BundleSettingsQsp m_settings; //!< The settings from the bundle adjust - BundleResults *m_statisticsResults; //!< The results of the bundle adjust - QList<ImageList *> *m_images; //!< The list of images as input to the bundle - QList<ImageList *> *m_adjustedImages; //!< The list of images that were adjsuted - - // In theory the path in the BundlesSettings can change while running. So we save the + QString m_name; //!< Name of the bundle. Defaults to the id + QString m_runTime; //!< Run time of the bundle adjustment + FileName *m_inputControlNetFileName; //!< Input control network file name + Control *m_outputControl; //!< Output control + BundleSettingsQsp m_settings; //!< Bundle settings + BundleResults *m_statisticsResults; //!< Bundle statistical results + QList<ImageList *> *m_images; //!< Input image list + QList<ImageList *> *m_adjustedImages; //!< Adjusted image list + + // In theory the path in the BundleSettings can change while running. So we save the // filenames actually used when the most recent save of the file was done. + QString m_txtBundleOutputFilename; QString m_csvSavedImagesFilename; QString m_csvSavedPointsFilename; QString m_csvSavedResidualsFilename; }; // end BundleSolutionInfo class - void setStringAttribute(int locationId, QString locationName, QString attributeName, QString attributeValue); QString getStringAttribute(int locationId, QString locationName, QString attributeName); diff --git a/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.truth b/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.truth index 8bcf28baf2a7a29d516a7516b8135fdcff49aca3..d94fd75d91e90fb84e38433e3c1fdf0be65bbebf 100644 --- a/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.truth +++ b/isis/src/control/objs/BundleSolutionInfo/BundleSolutionInfo.truth @@ -1,12 +1,14 @@ Unit test for BundleSolutionInfo... Serializing results from the settings/cnet/statistics constructor... +Created new BundleSettings... <bundleSolutionInfo> <generalAttributes> <name></name> <runTime></runTime> - <fileName>cnetfile.net</fileName> + <inputFileName></inputFileName> + <bundleOutTXT></bundleOutTXT> <imagesCSV></imagesCSV> <pointsCSV></pointsCSV> <residualsCSV></residualsCSV> @@ -99,7 +101,8 @@ Serializing test XML object to file... <name></name> <runTime></runTime> - <fileName>cnetfile.net</fileName> + <inputFileName></inputFileName> + <bundleOutTXT></bundleOutTXT> <imagesCSV></imagesCSV> <pointsCSV></pointsCSV> <residualsCSV></residualsCSV> @@ -191,280 +194,8 @@ Testing XML: Object deserialized as (should match object above): <name></name> <runTime></runTime> - <fileName>cnetfile.net</fileName> - <imagesCSV></imagesCSV> - <pointsCSV></pointsCSV> - <residualsCSV></residualsCSV> - </generalAttributes> - <bundleSettings> - <globalSettings> - <validateNetwork>Yes</validateNetwork> - <solveOptions solveObservationMode="No" solveRadius="No" updateCubeLabel="No" errorPropagation="No" createInverseMatrix="No"/> - <aprioriSigmas latitude="N/A" longitude="N/A" radius="N/A"/> - <outlierRejectionOptions rejection="No" multiplier="N/A"/> - <convergenceCriteriaOptions convergenceCriteria="Sigma0" threshold="1.0e-10" maximumIterations="50"/> - <maximumLikelihoodEstimation/> - <outputFileOptions fileNamePrefix=""/> - </globalSettings> - <observationSolveSettingsList> - <bundleObservationSolveSettings> - - <instrumentId></instrumentId> - <instrumentPointingOptions solveOption="AnglesOnly" numberCoefSolved="1" degree="2" solveDegree="2" solveTwist="Yes" solveOverExisting="No" interpolationType="3"> - <aprioriPointingSigmas> - <sigma>N/A</sigma> - </aprioriPointingSigmas> - </instrumentPointingOptions> - <instrumentPositionOptions solveOption="None" numberCoefSolved="0" degree="2" solveDegree="2" solveOverHermiteSpline="No" interpolationType="3"> - <aprioriPositionSigmas/> - </instrumentPositionOptions> - </bundleObservationSolveSettings> - </observationSolveSettingsList> - </bundleSettings> - <bundleResults> - <correlationMatrix correlationFileName="" covarianceFileName=""> - <imagesAndParameters/> - </correlationMatrix> - <generalStatisticsValues> - <numberFixedPoints>0</numberFixedPoints> - <numberIgnoredPoints>0</numberIgnoredPoints> - <numberHeldImages>0</numberHeldImages> - <rejectionLimit>0.0</rejectionLimit> - <numberRejectedObservations>0</numberRejectedObservations> - <numberObservations>0</numberObservations> - <numberImageParameters>0</numberImageParameters> - <numberConstrainedPointParameters>0</numberConstrainedPointParameters> - <numberConstrainedImageParameters>0</numberConstrainedImageParameters> - <numberConstrainedTargetParameters>0</numberConstrainedTargetParameters> - <numberUnknownParameters>0</numberUnknownParameters> - <degreesOfFreedom>-1</degreesOfFreedom> - <sigma0>0.0</sigma0> - <converged>No</converged> - </generalStatisticsValues> - <rms> - <residuals x="0.0" y="0.0" xy="0.0"/> - <sigmas lat="0.0" lon="0.0" rad="0.0"/> - <imageResidualsLists> - <residualsList listSize="0"/> - <sampleList listSize="0"/> - <lineList listSize="0"/> - </imageResidualsLists> - <imageSigmasLists> - <xSigmas listSize="0"/> - <ySigmas listSize="0"/> - <zSigmas listSize="0"/> - <raSigmas listSize="0"/> - <decSigmas listSize="0"/> - <twistSigmas listSize="0"/> - </imageSigmasLists> - </rms> - <elapsedTime time="0.0" errorProp="0.0"/> - <minMaxSigmas> - <minLat value="1000000000000.0" pointId=""/> - <maxLat value="0.0" pointId=""/> - <minLon value="1000000000000.0" pointId=""/> - <maxLon value="0.0" pointId=""/> - <minRad value="1000000000000.0" pointId=""/> - <maxRad value="0.0" pointId=""/> - </minMaxSigmas> - <maximumLikelihoodEstimation numberModels="0" maximumLikelihoodIndex="0" maximumLikelihoodMedianR2Residuals="0.0"> - <cumulativeProbabilityCalculator/> - <residualsCumulativeProbabilityCalculator/> - </maximumLikelihoodEstimation> - </bundleResults> -</bundleSolutionInfo> - - -Testing copy constructor... - -<bundleSolutionInfo> - <generalAttributes> - - <name></name> - <runTime></runTime> - <fileName>cnetfile.net</fileName> - <imagesCSV></imagesCSV> - <pointsCSV></pointsCSV> - <residualsCSV></residualsCSV> - </generalAttributes> - <bundleSettings> - <globalSettings> - <validateNetwork>Yes</validateNetwork> - <solveOptions solveObservationMode="No" solveRadius="No" updateCubeLabel="No" errorPropagation="No" createInverseMatrix="No"/> - <aprioriSigmas latitude="N/A" longitude="N/A" radius="N/A"/> - <outlierRejectionOptions rejection="No" multiplier="N/A"/> - <convergenceCriteriaOptions convergenceCriteria="Sigma0" threshold="1.0e-10" maximumIterations="50"/> - <maximumLikelihoodEstimation/> - <outputFileOptions fileNamePrefix=""/> - </globalSettings> - <observationSolveSettingsList> - <bundleObservationSolveSettings> - - <instrumentId></instrumentId> - <instrumentPointingOptions solveOption="AnglesOnly" numberCoefSolved="1" degree="2" solveDegree="2" solveTwist="Yes" solveOverExisting="No" interpolationType="3"> - <aprioriPointingSigmas> - <sigma>N/A</sigma> - </aprioriPointingSigmas> - </instrumentPointingOptions> - <instrumentPositionOptions solveOption="None" numberCoefSolved="0" degree="2" solveDegree="2" solveOverHermiteSpline="No" interpolationType="3"> - <aprioriPositionSigmas/> - </instrumentPositionOptions> - </bundleObservationSolveSettings> - </observationSolveSettingsList> - </bundleSettings> - <bundleResults> - <correlationMatrix correlationFileName="" covarianceFileName=""> - <imagesAndParameters/> - </correlationMatrix> - <generalStatisticsValues> - <numberFixedPoints>0</numberFixedPoints> - <numberIgnoredPoints>0</numberIgnoredPoints> - <numberHeldImages>0</numberHeldImages> - <rejectionLimit>0.0</rejectionLimit> - <numberRejectedObservations>0</numberRejectedObservations> - <numberObservations>0</numberObservations> - <numberImageParameters>0</numberImageParameters> - <numberConstrainedPointParameters>0</numberConstrainedPointParameters> - <numberConstrainedImageParameters>0</numberConstrainedImageParameters> - <numberConstrainedTargetParameters>0</numberConstrainedTargetParameters> - <numberUnknownParameters>0</numberUnknownParameters> - <degreesOfFreedom>-1</degreesOfFreedom> - <sigma0>0.0</sigma0> - <converged>No</converged> - </generalStatisticsValues> - <rms> - <residuals x="0.0" y="0.0" xy="0.0"/> - <sigmas lat="0.0" lon="0.0" rad="0.0"/> - <imageResidualsLists> - <residualsList listSize="0"/> - <sampleList listSize="0"/> - <lineList listSize="0"/> - </imageResidualsLists> - <imageSigmasLists> - <xSigmas listSize="0"/> - <ySigmas listSize="0"/> - <zSigmas listSize="0"/> - <raSigmas listSize="0"/> - <decSigmas listSize="0"/> - <twistSigmas listSize="0"/> - </imageSigmasLists> - </rms> - <elapsedTime time="0.0" errorProp="0.0"/> - <minMaxSigmas> - <minLat value="1000000000000.0" pointId=""/> - <maxLat value="0.0" pointId=""/> - <minLon value="1000000000000.0" pointId=""/> - <maxLon value="0.0" pointId=""/> - <minRad value="1000000000000.0" pointId=""/> - <maxRad value="0.0" pointId=""/> - </minMaxSigmas> - <maximumLikelihoodEstimation numberModels="0" maximumLikelihoodIndex="0" maximumLikelihoodMedianR2Residuals="0.0"> - <cumulativeProbabilityCalculator/> - <residualsCumulativeProbabilityCalculator/> - </maximumLikelihoodEstimation> - </bundleResults> -</bundleSolutionInfo> - - -Testing assignment operator to set this equal to itself... - -<bundleSolutionInfo> - <generalAttributes> - - <name></name> - <runTime></runTime> - <fileName>cnetfile.net</fileName> - <imagesCSV></imagesCSV> - <pointsCSV></pointsCSV> - <residualsCSV></residualsCSV> - </generalAttributes> - <bundleSettings> - <globalSettings> - <validateNetwork>Yes</validateNetwork> - <solveOptions solveObservationMode="No" solveRadius="No" updateCubeLabel="No" errorPropagation="No" createInverseMatrix="No"/> - <aprioriSigmas latitude="N/A" longitude="N/A" radius="N/A"/> - <outlierRejectionOptions rejection="No" multiplier="N/A"/> - <convergenceCriteriaOptions convergenceCriteria="Sigma0" threshold="1.0e-10" maximumIterations="50"/> - <maximumLikelihoodEstimation/> - <outputFileOptions fileNamePrefix=""/> - </globalSettings> - <observationSolveSettingsList> - <bundleObservationSolveSettings> - - <instrumentId></instrumentId> - <instrumentPointingOptions solveOption="AnglesOnly" numberCoefSolved="1" degree="2" solveDegree="2" solveTwist="Yes" solveOverExisting="No" interpolationType="3"> - <aprioriPointingSigmas> - <sigma>N/A</sigma> - </aprioriPointingSigmas> - </instrumentPointingOptions> - <instrumentPositionOptions solveOption="None" numberCoefSolved="0" degree="2" solveDegree="2" solveOverHermiteSpline="No" interpolationType="3"> - <aprioriPositionSigmas/> - </instrumentPositionOptions> - </bundleObservationSolveSettings> - </observationSolveSettingsList> - </bundleSettings> - <bundleResults> - <correlationMatrix correlationFileName="" covarianceFileName=""> - <imagesAndParameters/> - </correlationMatrix> - <generalStatisticsValues> - <numberFixedPoints>0</numberFixedPoints> - <numberIgnoredPoints>0</numberIgnoredPoints> - <numberHeldImages>0</numberHeldImages> - <rejectionLimit>0.0</rejectionLimit> - <numberRejectedObservations>0</numberRejectedObservations> - <numberObservations>0</numberObservations> - <numberImageParameters>0</numberImageParameters> - <numberConstrainedPointParameters>0</numberConstrainedPointParameters> - <numberConstrainedImageParameters>0</numberConstrainedImageParameters> - <numberConstrainedTargetParameters>0</numberConstrainedTargetParameters> - <numberUnknownParameters>0</numberUnknownParameters> - <degreesOfFreedom>-1</degreesOfFreedom> - <sigma0>0.0</sigma0> - <converged>No</converged> - </generalStatisticsValues> - <rms> - <residuals x="0.0" y="0.0" xy="0.0"/> - <sigmas lat="0.0" lon="0.0" rad="0.0"/> - <imageResidualsLists> - <residualsList listSize="0"/> - <sampleList listSize="0"/> - <lineList listSize="0"/> - </imageResidualsLists> - <imageSigmasLists> - <xSigmas listSize="0"/> - <ySigmas listSize="0"/> - <zSigmas listSize="0"/> - <raSigmas listSize="0"/> - <decSigmas listSize="0"/> - <twistSigmas listSize="0"/> - </imageSigmasLists> - </rms> - <elapsedTime time="0.0" errorProp="0.0"/> - <minMaxSigmas> - <minLat value="1000000000000.0" pointId=""/> - <maxLat value="0.0" pointId=""/> - <minLon value="1000000000000.0" pointId=""/> - <maxLon value="0.0" pointId=""/> - <minRad value="1000000000000.0" pointId=""/> - <maxRad value="0.0" pointId=""/> - </minMaxSigmas> - <maximumLikelihoodEstimation numberModels="0" maximumLikelihoodIndex="0" maximumLikelihoodMedianR2Residuals="0.0"> - <cumulativeProbabilityCalculator/> - <residualsCumulativeProbabilityCalculator/> - </maximumLikelihoodEstimation> - </bundleResults> -</bundleSolutionInfo> - - -Testing assignment operator to create a new results object... - -<bundleSolutionInfo> - <generalAttributes> - - <name></name> - <runTime></runTime> - <fileName>cnetfile.net</fileName> + <inputFileName></inputFileName> + <bundleOutTXT></bundleOutTXT> <imagesCSV></imagesCSV> <pointsCSV></pointsCSV> <residualsCSV></residualsCSV> @@ -555,7 +286,8 @@ Testing mutator methods... <name>xxx</name> <runTime>xxx</runTime> - <fileName>cnetfile.net</fileName> + <inputFileName></inputFileName> + <bundleOutTXT></bundleOutTXT> <imagesCSV></imagesCSV> <pointsCSV></pointsCSV> <residualsCSV></residualsCSV> @@ -657,7 +389,8 @@ Serializing test XML object to file... <name>xxx</name> <runTime>xxx</runTime> - <fileName>cnetfile.net</fileName> + <inputFileName></inputFileName> + <bundleOutTXT>bundleout.txt</bundleOutTXT> <imagesCSV>bundleout_images.csv</imagesCSV> <pointsCSV>bundleout_points.csv</pointsCSV> <residualsCSV>residuals.csv</residualsCSV> @@ -760,7 +493,8 @@ Testing XML: Object deserialized as (should match object above): <name>xxx</name> <runTime>xxx</runTime> - <fileName>cnetfile.net</fileName> + <inputFileName></inputFileName> + <bundleOutTXT>bundleout.txt</bundleOutTXT> <imagesCSV>bundleout_images.csv</imagesCSV> <pointsCSV>bundleout_points.csv</pointsCSV> <residualsCSV>residuals.csv</residualsCSV> diff --git a/isis/src/control/objs/BundleSolutionInfo/unitTest.cpp b/isis/src/control/objs/BundleSolutionInfo/unitTest.cpp index 7b9c8932d2ccc8e388fc939aa0a83251c6490a23..b6f9a017bfd27af609c506bcc0efb91ea18fee38 100755 --- a/isis/src/control/objs/BundleSolutionInfo/unitTest.cpp +++ b/isis/src/control/objs/BundleSolutionInfo/unitTest.cpp @@ -76,8 +76,11 @@ namespace Isis { * @internal * @history 2015-09-03 Jeannie Backer - Commented out xml code test until we determine whether * we will keep this code. - * @history 2016-10-13 Ian Humphrey - Changed addnew call to addNew(). References #4293. - * @history 2017-04-24 Ian Humphrey - Replaced pvlObject() with XML save(). Fixes #4797. + * @history 2016-10-13 Ian Humphrey - Changed addnew call to addNew(). References #4293. + * @history 2017-04-24 Ian Humphrey - Replaced pvlObject() with XML save(). Fixes #4797. + * @history 2018-05-24 Ken Edmundson - Removed testing for copy constructor and assignment + * operator because these have been removed from + * BundleSolutionInfo. */ int main(int argc, char *argv[]) { Preference::Preferences(true); @@ -90,6 +93,8 @@ int main(int argc, char *argv[]) { // create default settings and statistics objects to pass into results object BundleSettingsQsp settings = BundleSettingsQsp(new BundleSettings); + qDebug() << "Created new BundleSettings..."; + settings->setOutputFilePrefix(""); FileName cnetFile("cnetfile.net"); BundleResults statistics; @@ -132,16 +137,13 @@ int main(int argc, char *argv[]) { "ObservationNumber1", "Instrument1", BundleSettingsQsp(new BundleSettings)); - statistics.setBundleControlPoints(bundleControlPointVector); statistics.setOutputControlNet(ControlNetQsp(new ControlNet(outNet))); statistics.setObservations(observationVector); QList<ImageList *> imgList; BundleSolutionInfo results(settings, cnetFile, statistics, imgList, parent); - printXml(results); - qDebug() << ""; qDebug() << "Testing XML serialization 1: round trip serialization of BundleSolution object..."; qDebug() << "Serializing test XML object to file..."; @@ -168,23 +170,6 @@ int main(int argc, char *argv[]) { qDebug() << "Testing XML: Object deserialized as (should match object above):"; printXml(bsFromXml1); // Save comparison output to log file - - - qDebug() << "Testing copy constructor..."; - - BundleSolutionInfo copySolutionInfo(results); - printXml(copySolutionInfo); - - qDebug() << "Testing assignment operator to set this equal to itself..."; - results = results; - printXml(results); - - qDebug() << "Testing assignment operator to create a new results object..."; - - BundleSolutionInfo assignmentOpSolutionInfo = results; - assignmentOpSolutionInfo = results; - printXml(assignmentOpSolutionInfo); - qDebug() << "Testing mutator methods..."; statistics.setRejectionLimit(0.5); results.setOutputStatistics(statistics); @@ -212,8 +197,6 @@ int main(int argc, char *argv[]) { } qDebug() << ""; - - Statistics rmsStats; rmsStats.SetValidRange(0, 100); rmsStats.AddData(0); diff --git a/isis/src/control/objs/ControlNet/ControlNet.cpp b/isis/src/control/objs/ControlNet/ControlNet.cpp index 6c204b30eb716d7cf0cdc068a72652f8865f754b..9c3a06ebe3c344225ac88ac12f089b671b6e3587 100644 --- a/isis/src/control/objs/ControlNet/ControlNet.cpp +++ b/isis/src/control/objs/ControlNet/ControlNet.cpp @@ -237,14 +237,24 @@ namespace Isis { * parent prematurely to be able to set the radii * in ControlPoint. * @history 2017-12-21 Jesse Mapel - Modified to use the ControlNetVersioner. - * + * @history 2018-04-05 Adam Goins - Added a check to the versionedReader targetRadii + * group to set radii values to those ingested from the versioner + * if they exist. Otherwise, we call SetTarget with the targetname. */ void ControlNet::ReadControl(const QString &filename, Progress *progress) { FileName cnetFileName(filename); ControlNetVersioner versionedReader(cnetFileName, progress); - - SetTarget( versionedReader.targetName() ); + if ( versionedReader.hasTargetRadii() ) { + p_targetName = versionedReader.targetName(); + p_targetRadii.clear(); + foreach (Distance distance, versionedReader.targetRadii()) { + p_targetRadii.push_back(distance); + } + } + else { + SetTarget( versionedReader.targetName() ); + } p_networkId = versionedReader.netId(); p_userName = versionedReader.userName(); p_created = versionedReader.creationDate(); @@ -346,8 +356,8 @@ namespace Isis { /** - * Adds a whole point to the control net graph. - * + * Adds a whole point to the control net graph. + * * @throws IException::Programmer "NULL measure passed to ControlNet::AddControlCubeGraphNode!" * @throws IException::Programmer "Control measure with NULL parent passed to * ControlNet::AddControlCubeGraphNode!" diff --git a/isis/src/control/objs/ControlNet/ControlNet.h b/isis/src/control/objs/ControlNet/ControlNet.h index 56b9f3bead79667853001f1dea34bec2694ad7cd..5ae923fbb948664c0e450fae647fd12c126e3486 100644 --- a/isis/src/control/objs/ControlNet/ControlNet.h +++ b/isis/src/control/objs/ControlNet/ControlNet.h @@ -212,7 +212,11 @@ namespace Isis { * @history 2017-01-19 Jesse Mapel - Added a method to get all of the valid measures in an * image. Previously, this had to be done throug the graph. * @history 2018-01-26 Kristin Berry - Added pointAdded() function to eliminate redundant measure - * adds to the control network. + * adds to the control network. + * @history 2018-04-05 Adam Goins - Added a check to the versionedReader targetRadii + * group to set radii values to those ingested from the versioner + * if they exist. Otherwise, we call SetTarget with the targetname. + * Fixes #5361. */ class ControlNet : public QObject { Q_OBJECT diff --git a/isis/src/control/objs/ControlNet/ControlNet.truth b/isis/src/control/objs/ControlNet/ControlNet.truth index 13ef6e7272d3f04b3b627134210ad082582a58b9..caa915ff646a406d8487be8b9ef4db5a01aeefe1 100644 --- a/isis/src/control/objs/ControlNet/ControlNet.truth +++ b/isis/src/control/objs/ControlNet/ControlNet.truth @@ -147,6 +147,7 @@ Object = ControlNetwork Created = 2010-07-10T12:50:15 LastModified = 2010-07-10T12:50:55 Description = "UnitTest of ControlNetwork" + TargetRadii = (3396190.0, 3396190.0, 3376200.0) Version = 5 Object = ControlPoint diff --git a/isis/src/control/objs/ControlNetVersioner/ControlNetFileHeaderV0005.proto b/isis/src/control/objs/ControlNetVersioner/ControlNetFileHeaderV0005.proto index d04e6ca50192996502979d04aff06a18883fe063..424fad3c98ec62f99f7bbcd2f3bdc1b3ac92aafa 100644 --- a/isis/src/control/objs/ControlNetVersioner/ControlNetFileHeaderV0005.proto +++ b/isis/src/control/objs/ControlNetVersioner/ControlNetFileHeaderV0005.proto @@ -9,6 +9,6 @@ message ControlNetFileHeaderV0005 { optional string lastModified = 4; optional string description = 5; optional string userName = 6; - optional int32 numPoints = 7; + optional int32 numPoints = 7; + repeated double targetRadii = 10; } - diff --git a/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.cpp b/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.cpp index f02c607873ca0537c9562ce24ad9341501adb3cd..b261b4c94f5c1c6470c2950034fca9d34d43c030 100644 --- a/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.cpp +++ b/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.cpp @@ -63,6 +63,14 @@ namespace Isis { header.lastModified = net->GetLastModified(); header.description = net->Description(); header.userName = net->GetUserName(); + + std::vector<Distance> netRadii = net->GetTargetRadii(); + if ( netRadii.size() >= 3 && + netRadii[0].isValid() && + netRadii[1].isValid() && + netRadii[2].isValid() ) { + header.targetRadii = net->GetTargetRadii(); + } createHeader(header); } @@ -158,6 +166,25 @@ namespace Isis { } + /** + * Returns true if the targetRadii in the header has values. + * + * @return @b boolean True if the targetRadii in the header is populated. + */ + bool ControlNetVersioner::hasTargetRadii() const { + return m_header.targetRadii.empty() ? false : true; + } + + /** + * Returns the targetRadii Distance vector located in the header. + * + * @return @b std::vector<Distance> A vector containing the target body radii. + */ + std::vector<Distance> ControlNetVersioner::targetRadii() const { + return m_header.targetRadii; + } + + /** * Returns the number of points that have been read in or are ready to write out. * @@ -202,24 +229,20 @@ namespace Isis { network += PvlKeyword("Created", m_header.created); network += PvlKeyword("LastModified", m_header.lastModified); network += PvlKeyword("Description", m_header.description); + + // Grab TargetRadii if they exist. + if (!m_header.targetRadii.empty()) { + PvlKeyword pvlRadii("TargetRadii"); + for (uint i = 0; i < m_header.targetRadii.size(); i++) { + pvlRadii += toString(m_header.targetRadii[i].meters()); + } + network += pvlRadii; + } // optionally add username to output? // This is the Pvl version we're converting to network += PvlKeyword("Version", "5"); - // Get Target Radii from naif kernel - PvlGroup pvlRadii; - QString target = (QString)network.findKeyword("TargetName",Pvl::Traverse); - if ( target != "" ) { - try { - NaifStatus::CheckErrors(); - pvlRadii = Target::radiiGroup(target); - } - catch (IException) { - // leave pvlRadii empty if target is not recognized by NAIF - } - } - foreach (ControlPoint *controlPoint, m_points) { PvlObject pvlPoint("ControlPoint"); @@ -341,11 +364,11 @@ namespace Isis { matrix += toString(aprioriCovarianceMatrix(1, 2)); matrix += toString(aprioriCovarianceMatrix(2, 2)); - if ( pvlRadii.hasKeyword("EquatorialRadius") && pvlRadii.hasKeyword("PolarRadius") ) { + if ( !m_header.targetRadii.empty() ) { - aprioriSurfacePoint.SetRadii( Distance(pvlRadii["EquatorialRadius"], Distance::Meters), - Distance(pvlRadii["EquatorialRadius"], Distance::Meters), - Distance(pvlRadii["PolarRadius"], Distance::Meters) ); + aprioriSurfacePoint.SetRadii( m_header.targetRadii[0], + m_header.targetRadii[1], + m_header.targetRadii[2] ); if ( aprioriSurfacePoint.GetLatSigmaDistance().meters() != Isis::Null && aprioriSurfacePoint.GetLonSigmaDistance().meters() != Isis::Null @@ -424,11 +447,11 @@ namespace Isis { matrix += toString(adjustedCovarianceMatrix(1, 2)); matrix += toString(adjustedCovarianceMatrix(2, 2)); - if ( pvlRadii.hasKeyword("EquatorialRadius") && pvlRadii.hasKeyword("PolarRadius") ) { + if ( !m_header.targetRadii.empty() ) { - adjustedSurfacePoint.SetRadii(Distance(pvlRadii["EquatorialRadius"], Distance::Meters), - Distance(pvlRadii["EquatorialRadius"], Distance::Meters), - Distance(pvlRadii["PolarRadius"], Distance::Meters) ); + adjustedSurfacePoint.SetRadii( m_header.targetRadii[0], + m_header.targetRadii[1], + m_header.targetRadii[2] ); if ( adjustedSurfacePoint.GetLatSigmaDistance().meters() != Isis::Null && adjustedSurfacePoint.GetLonSigmaDistance().meters() != Isis::Null @@ -716,6 +739,7 @@ namespace Isis { try { PvlObject pointObject = network.object(objectIndex); ControlPointV0002 point(pointObject); + m_points.append( createPoint(point) ); if (progress) { @@ -847,6 +871,16 @@ namespace Isis { header.lastModified = network.findKeyword("LastModified")[0]; header.description = network.findKeyword("Description")[0]; header.userName = network.findKeyword("UserName")[0]; + if (network.hasKeyword("TargetRadii")) { + header.targetRadii.clear(); + for (int i = 0; i < network.findKeyword("TargetRadii").size(); i++) { + Distance distance = Distance(toDouble(network.findKeyword("TargetRadii")[i]), + Distance::Meters); + if ( distance.isValid() ) { + header.targetRadii.push_back(distance); + } + } + } createHeader(header); } catch (IException &e) { @@ -1170,6 +1204,7 @@ namespace Isis { void ControlNetVersioner::readProtobufV0005(const Pvl &header, const FileName netFile, Progress *progress) { + // read the header protobuf object const PvlObject &protoBufferInfo = header.findObject("ProtoBuffer"); const PvlObject &protoBufferCore = protoBufferInfo.findObject("Core"); @@ -1228,6 +1263,15 @@ namespace Isis { header.lastModified = protoHeader.lastmodified().c_str(); header.description = protoHeader.description().c_str(); header.userName = protoHeader.username().c_str(); + if ( protoHeader.targetradii_size() >= 3 ) { + header.targetRadii.clear(); + for (int i = 0; i < protoHeader.targetradii_size(); i++) { + Distance distance = Distance(protoHeader.targetradii(i), Distance::Meters); + if ( distance.isValid() ) { + header.targetRadii.push_back(distance); + } + } + } createHeader(header); } catch (IException &e) { @@ -1278,7 +1322,7 @@ namespace Isis { uint32_t size; pointCodedInStream.ReadRaw(reinterpret_cast<char *>(&size), sizeof(size)); - + size = lsb.Uint32_t(&size); CodedInputStream::Limit oldPointLimit = pointCodedInStream.PushLimit(size); @@ -1357,6 +1401,7 @@ namespace Isis { * @return @b ControlPoint* The ControlPoint constructed from the given point. */ ControlPoint *ControlNetVersioner::createPoint(ControlPointV0003 &point) { + ControlPointFileEntryV0002 protoPoint = point.pointData(); ControlPoint *controlPoint = new ControlPoint; @@ -1521,16 +1566,19 @@ namespace Isis { controlPoint->SetAdjustedSurfacePoint(adjustedSurfacePoint); } + if ( !m_header.targetRadii.empty() && + m_header.targetRadii[0].isValid() && + m_header.targetRadii[1].isValid() && + m_header.targetRadii[2].isValid() ) { - if ( m_header.equatorialRadius.isValid() && m_header.polarRadius.isValid() ) { SurfacePoint aprioriSurfacePoint = controlPoint->GetAprioriSurfacePoint(); SurfacePoint adjustedSurfacePoint = controlPoint->GetAdjustedSurfacePoint(); - aprioriSurfacePoint.SetRadii(m_header.equatorialRadius, - m_header.equatorialRadius, - m_header.polarRadius); - adjustedSurfacePoint.SetRadii(m_header.equatorialRadius, - m_header.equatorialRadius, - m_header.polarRadius); + aprioriSurfacePoint.SetRadii(m_header.targetRadii[0], + m_header.targetRadii[1], + m_header.targetRadii[2]); + adjustedSurfacePoint.SetRadii(m_header.targetRadii[0], + m_header.targetRadii[1], + m_header.targetRadii[2]); controlPoint->SetAdjustedSurfacePoint(adjustedSurfacePoint); controlPoint->SetAprioriSurfacePoint(aprioriSurfacePoint); } @@ -1670,12 +1718,22 @@ namespace Isis { m_header.targetName = "Mars"; } - if ( !m_header.targetName.isEmpty() ) { + if ( m_header.targetRadii.empty() ) { try { - // attempt to get target radii values... - PvlGroup pvlRadii = Target::radiiGroup(m_header.targetName); - m_header.equatorialRadius.setMeters(pvlRadii["EquatorialRadius"]); - m_header.polarRadius.setMeters(pvlRadii["PolarRadius"]); + // attempt to get target radii values... + // The target body raii values are read from the PvlV0005 and BinaryV0005 + // Networks. In the event these values weren't read (from an older network) + // then we must grab them from the Target::radii group. + if ( !m_header.targetName.isEmpty() ) { + + PvlGroup pvlRadii = Target::radiiGroup(m_header.targetName); + m_header.targetRadii.push_back(Distance(pvlRadii["EquatorialRadius"], + Distance::Meters)); + m_header.targetRadii.push_back(Distance(pvlRadii["EquatorialRadius"], + Distance::Meters)); + m_header.targetRadii.push_back(Distance(pvlRadii["PolarRadius"], + Distance::Meters)); + } } catch (IException &e) { // do nothing @@ -1725,6 +1783,12 @@ namespace Isis { protobufHeader.set_description(m_header.description.toLatin1().data()); protobufHeader.set_username(m_header.userName.toLatin1().data()); + if ( !m_header.targetRadii.empty() ) { + for (uint i = 0; i < m_header.targetRadii.size(); i++) { + protobufHeader.add_targetradii(m_header.targetRadii[i].meters()); + } + } + streampos coreHeaderSize = protobufHeader.ByteSize(); Pvl p; @@ -1748,12 +1812,20 @@ namespace Isis { netInfo.addComment("This group is for informational purposes only"); netInfo += PvlKeyword("NetworkId", protobufHeader.networkid().c_str()); netInfo += PvlKeyword("TargetName", protobufHeader.targetname().c_str()); + + // Grab TargetRadii if they exist. + if (!m_header.targetRadii.empty()) { + PvlKeyword pvlRadii("TargetRadii"); + for (uint i = 0; i < m_header.targetRadii.size(); i++) { + pvlRadii += toString(m_header.targetRadii[i].meters()); + } + netInfo += pvlRadii; + } netInfo += PvlKeyword("UserName", protobufHeader.username().c_str()); netInfo += PvlKeyword("Created", protobufHeader.created().c_str()); netInfo += PvlKeyword("LastModified", protobufHeader.lastmodified().c_str()); netInfo += PvlKeyword("Description", protobufHeader.description().c_str()); netInfo += PvlKeyword("NumberOfPoints", toString(numPoints)); - netInfo += PvlKeyword("NumberOfMeasures", toString(numMeasures)); netInfo += PvlKeyword("Version", "5"); protoObj.addGroup(netInfo); @@ -1789,6 +1861,12 @@ namespace Isis { protobufHeader.set_description(m_header.description.toLatin1().data()); protobufHeader.set_username(m_header.userName.toLatin1().data()); + if ( !m_header.targetRadii.empty() ) { + for (uint i = 0; i < m_header.targetRadii.size(); i++) { + protobufHeader.add_targetradii(m_header.targetRadii[i].meters()); + } + } + // Write out the header if ( !protobufHeader.SerializeToOstream(output) ) { QString msg = "Failed to write output control network file."; diff --git a/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.h b/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.h index 14f15a7e01179b3b1e34dcaae323059ea7448e04..03f3484408a7559b50f5264ea696070a83f9dc74 100644 --- a/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.h +++ b/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.h @@ -403,6 +403,12 @@ namespace Isis { * describing the different file format versions. * @history 2018-01-30 Adam Goins - Ensured point sizes are written/read as lsb by using * EndianSwapper. + * @history 2018-03-28 Adam Goins - Added targetRadii groups to the header. Changed the + * versioner to write these values out in a targetRadii group for + * both binary V0005 and PvlV0005 networks. Fixes #5361. + * @history 2018-04-05 Adam Goins - Added hasTargetRadii() and targetRadii() to the versioner + * so that these values can be grabbed from a ControlNet on read. + * Also Fixes #5361. */ class ControlNetVersioner { @@ -417,6 +423,8 @@ namespace Isis { QString lastModificationDate() const; QString description() const; QString userName() const; + bool hasTargetRadii() const; + std::vector<Distance> targetRadii() const; int numPoints() const; ControlPoint *takeFirstPoint(); @@ -471,12 +479,9 @@ namespace Isis { * The equatorial radius of the target body * used to convert from spherical to rectangular coordinates */ - Distance equatorialRadius; - /** - * The equatorial radius of the target body - * used to convert from spherical to rectangular coordinates - */ - Distance polarRadius; + + std::vector<Distance> targetRadii; + }; //! Typedef for consistent naming of containers for version 2 diff --git a/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.truth b/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.truth index 956be921b7b9d6f1a0aff1cb670ee89a19e4f8d2..af4a14e71a77d131815baea9b758b3ae5846130a 100644 --- a/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.truth +++ b/isis/src/control/objs/ControlNetVersioner/ControlNetVersioner.truth @@ -20,6 +20,7 @@ Object = ControlNetwork Created = Null LastModified = Null Description = Null + TargetRadii = (3396190.0, 3396190.0, 3376200.0) Version = 5 Object = ControlPoint @@ -76,6 +77,7 @@ Object = ControlNetwork Created = Null LastModified = Null Description = "Test Network" + TargetRadii = (2575000.0, 2575000.0, 2575000.0) Version = 5 Object = ControlPoint @@ -132,6 +134,7 @@ Object = ControlNetwork Created = 2010-07-10T12:50:15 LastModified = 2010-07-10T12:50:55 Description = "UnitTest of ControlNetwork" + TargetRadii = (3396190.0, 3396190.0, 3376200.0) Version = 5 Object = ControlPoint @@ -329,6 +332,7 @@ Object = ControlNetwork Created = 2012-01-04T12:09:57 LastModified = 2012-01-04T12:09:57 Description = "Themis Day IR Network: Lunae Palus, Lat(0,30) Lon(270-315)" + TargetRadii = (3396190.0, 3396190.0, 3376200.0) Version = 5 Object = ControlPoint @@ -559,7 +563,12 @@ After reading and writing to a binary form does Pvl match? Conversion to Pvl stays consistent Reading/Writing control network is consistent Check conversions between the binary format and the pvl format. -The conversion methods for pvl->bin and bin->pvl are correct. +8c8,9 +< Version = 3 +--- +> TargetRadii = (3396190.0, 3396190.0, 3376200.0) +> Version = 5 +The conversion from pvl to binary is incorrect. Reading: $control/testData/unitTest_ControlNetVersioner_PvlNetwork5_PvlV0003.pvl... diff --git a/isis/src/juno/apps/junocam2isis/junocam2isis.cpp b/isis/src/juno/apps/junocam2isis/junocam2isis.cpp index b593686592c5628b99fb20bd1a4d72ea764f482b..bac45bad14b828da73aa0faa4e949f8319c01983 100644 --- a/isis/src/juno/apps/junocam2isis/junocam2isis.cpp +++ b/isis/src/juno/apps/junocam2isis/junocam2isis.cpp @@ -27,8 +27,10 @@ using namespace Isis; void translateLabel(Pvl &inputLabel, Pvl &outputLabel); void processFramelets(Buffer &in); void processFullFrames(Buffer &in); +void openNextCube(int index); QList<Cube *> g_outputCubes; +QList<QString> g_outputCubeFileNames; int g_frameletLines = 0; QStringList g_filterList; QList<int> g_filterOffsetList; @@ -125,6 +127,8 @@ void IsisMain() { + ".cub"); fullFrameCube->create(fullFrameCubeFileName.expanded()); g_outputCubes.append(fullFrameCube); + fullFrameCube->close(); + g_outputCubeFileNames.append(fullFrameCubeFileName.expanded()); allCubesListWriter << fullFrameCubeFileName.baseName() << ".cub\n"; } progress.CheckStatus(); @@ -141,7 +145,10 @@ void IsisMain() { for (int i = 0; i < numFullFrames; i++) { progress.CheckStatus(); for (int j = 0; j < outputLabel.findObject("IsisCube").groups(); j++) { - g_outputCubes[i]->putGroup(outputLabel.findObject("IsisCube").group(j)); + if (!g_outputCubes[i]->isOpen()) { + g_outputCubes[i]->open(g_outputCubeFileNames[i], "rw"); + } + g_outputCubes[i]->putGroup(outputLabel.findObject("IsisCube").group(j)); } // Update the labels Pvl *fullFrameLabel = g_outputCubes[i]->label(); @@ -163,7 +170,6 @@ void IsisMain() { progress.CheckStatus(); } else { - // Process individual framelets: For now, keep processing the "old" way. int numSubimages = importPds.Lines() / g_frameletLines; int frameletsPerFilter = numSubimages / g_filterList.size(); @@ -184,6 +190,7 @@ void IsisMain() { Progress progress; progress.SetText("Setting up output framelet cubes."); progress.SetMaximumSteps(numSubimages); + for (int i = 0; i < numSubimages; i++) { progress.CheckStatus(); Cube *frameletCube = new Cube(); @@ -196,10 +203,12 @@ void IsisMain() { + "_" + g_filterList[filterIndex] + "_" + frameletNumString + ".cub"); - frameletCube->create(frameletCubeFileName.expanded()); + frameletCube->create(frameletCubeFileName.expanded()); g_outputCubes.append(frameletCube); - + frameletCube->close(); + g_outputCubeFileNames.append(frameletCubeFileName.expanded()); + QFile filterListFile(outputBaseName + "_" + g_filterList[filterIndex] + ".lis"); if ( (frameletNumber == 1 && !filterListFile.open(QFile::WriteOnly | QFile::Text)) || (frameletNumber > 1 && !filterListFile.open(QFile::Append | QFile::Text)) ) { @@ -212,6 +221,7 @@ void IsisMain() { filterListWriter << frameletCubeFileName.baseName() << ".cub\n"; filterListFile.close(); } + progress.CheckStatus(); allCubesListFile.close(); @@ -224,7 +234,12 @@ void IsisMain() { progress.SetText("Updating labels of output cubes."); progress.SetMaximumSteps(numSubimages); for (int i = 0; i < numSubimages; i++) { - // fix labels + // re-open cube + QString cubeFileName = g_outputCubes[i]->fileName(); + if ( !g_outputCubes[i]->isOpen() ) { + g_outputCubes[i]->open(g_outputCubeFileNames[i], "rw"); + } + // fromeix labels progress.CheckStatus(); for (int j = 0; j < outputLabel.findObject("IsisCube").groups(); j++) { g_outputCubes[i]->putGroup(outputLabel.findObject("IsisCube").group(j)); @@ -349,6 +364,20 @@ void translateLabel(Pvl &inputLabel, Pvl &outputLabel) { } +/** + * Opens cube from g_outputCubes at provided index, closes cube at index-1 (last cube) + */ +void openNextCube(int nextCubeIndex) { + if (nextCubeIndex >= 1) { + if (g_outputCubes[nextCubeIndex-1]->isOpen()) { + g_outputCubes[nextCubeIndex - 1]->close(); + } + } + if (!g_outputCubes[nextCubeIndex]->isOpen()) { + g_outputCubes[nextCubeIndex]->open(g_outputCubeFileNames[nextCubeIndex], "rw"); + } +} + /** * Separates each of the individual frames into their own file. @@ -359,6 +388,12 @@ void processFramelets(Buffer &in) { // get the index for the correct output cube int outputCube = (in.Line() - 1) / g_frameletLines % g_outputCubes.size(); + // When we move to a new framlet, close the old cube and open the next one to avoid + // having too many cubes open and hitting the open file limit. + if( ((in.Line() - 1) % g_frameletLines) == 0 ) { + openNextCube(outputCube); + } + LineManager mgr(*g_outputCubes[outputCube]); int outputCubeLineNumber = (in.Line()-1) % g_frameletLines + 1; mgr.SetLine(outputCubeLineNumber, 1); @@ -379,6 +414,12 @@ void processFullFrames(Buffer &in) { // get the index for the correct output cube int outputCube = (in.Line() - 1) / g_fullFrameLines % g_outputCubes.size(); + // When we move to a new framlet, close the old cube and open the next one to avoid + // having too many cubes open and hitting the open file limit. + if( ((in.Line() - 1) % g_fullFrameLines) == 0 ) { + openNextCube(outputCube); + } + LineManager mgr(*g_outputCubes[outputCube]); int outputCubeLineNumber = ((in.Line()-1) % g_fullFrameLines); diff --git a/isis/src/juno/apps/junocam2isis/junocam2isis.xml b/isis/src/juno/apps/junocam2isis/junocam2isis.xml index d23d0dcd183dc69d03d4c1675ce871a71276f1b5..b984d970c3753d9088b0234464a93d7fe22246a7 100644 --- a/isis/src/juno/apps/junocam2isis/junocam2isis.xml +++ b/isis/src/juno/apps/junocam2isis/junocam2isis.xml @@ -88,6 +88,9 @@ xsi:noNamespaceSchemaLocation="http://isis.astrogeology.usgs.gov/Schemas/Applica <change name="Kaitlyn Lee" date="2018-02-07"> Added missionItem under category to classify the program under Juno. </change> + <change name="Kristin Berry" date="2018-03-27"> + Fixed problem with having too many open files. See #5232 for more information. + </change> </history> <category> diff --git a/isis/src/juno/objs/JunoCamera/JunoCamera.cpp b/isis/src/juno/objs/JunoCamera/JunoCamera.cpp index 3fbb754ec474c68d79728d9fbda49d81e4415121..f7c098c86486cc50eb85315b126d6b0cb2acda68 100644 --- a/isis/src/juno/objs/JunoCamera/JunoCamera.cpp +++ b/isis/src/juno/objs/JunoCamera/JunoCamera.cpp @@ -48,7 +48,7 @@ namespace Isis { m_spacecraftNameLong = "Juno"; m_spacecraftNameShort = "Juno"; - + NaifStatus::CheckErrors(); // Set up the camera characteristics @@ -73,7 +73,7 @@ namespace Isis { detMap->SetDetectorSampleSumming(summing); detMap->SetDetectorLineSumming(summing); } - + // Juno codes int junoCode = naifIkCode(); QString juno = toString(junoCode); @@ -111,7 +111,7 @@ namespace Isis { // get start et for this frame, in seconds double frameStartEt = observationStartEt + startTimeBias + (frameNumber - 1) - * (exposureDur + interFrameDelay + interFrameDelayBias); + * (interFrameDelay + interFrameDelayBias); // Set start time to center of exposure time to ensure the proper SPICE data is cached. setTime(frameStartEt + exposureDur / 2.0); @@ -123,24 +123,24 @@ namespace Isis { /** * Destroys the JunoCamera object. */ - JunoCamera::~JunoCamera() { + JunoCamera::~JunoCamera() { } /** * Returns the shutter open and close times. The user should pass in the * ExposureDuration keyword value, converted from milliseconds to seconds, and - * the SpacecraftClockCount keyword value, converted to ephemeris time. The - * StartTime keyword value from the labels represents the shutter open time of - * the observation. This method uses the FramingCamera class implementation, - * returning the given time value as the shutter open and the sum of the time + * the SpacecraftClockCount keyword value, converted to ephemeris time. The + * StartTime keyword value from the labels represents the shutter open time of + * the observation. This method uses the FramingCamera class implementation, + * returning the given time value as the shutter open and the sum of the time * value and exposure duration as the shutter close. - * + * * @param exposureDuration Exposure duration value from the labels, converted * to seconds. - * @param time The SpacecraftClockCount value from the labels, converted to + * @param time The SpacecraftClockCount value from the labels, converted to * ephemeris time - * + * * @return @b pair < @b iTime, @b iTime > The first value is the shutter * open time and the second is the shutter close time. */ @@ -152,9 +152,9 @@ namespace Isis { /** - * Retrieves the CK frame ID for the JunoCam instrument. - * - * @return @b int The appropriate instrument code for the "Camera-matrix" + * Retrieves the CK frame ID for the JunoCam instrument. + * + * @return @b int The appropriate instrument code for the "Camera-matrix" * Kernel Frame ID. */ int JunoCamera::CkFrameId() const { @@ -162,9 +162,9 @@ namespace Isis { } - /** - * Retrieves the J2000 CK Reference ID for the JunoCam instrument. - * + /** + * Retrieves the J2000 CK Reference ID for the JunoCam instrument. + * * @return @b int The appropriate instrument code for the "Camera-matrix" * Kernel Reference ID. */ @@ -184,10 +184,10 @@ namespace Isis { } - /** + /** * Retrieves the J2000 SPK Reference ID for the JunoCam instrument. - * - * @return @b int The appropriate instrument code for the Spacecraft + * + * @return @b int The appropriate instrument code for the Spacecraft * Kernel Reference ID. */ int JunoCamera::SpkReferenceId() const { diff --git a/isis/src/juno/objs/JunoCamera/JunoCamera.h b/isis/src/juno/objs/JunoCamera/JunoCamera.h index 142edd90c4ddaded2286a737382a35b65ae54372..a61108f25c785899452562f9d814fbe212dbca9a 100644 --- a/isis/src/juno/objs/JunoCamera/JunoCamera.h +++ b/isis/src/juno/objs/JunoCamera/JunoCamera.h @@ -34,20 +34,22 @@ namespace Isis { * framing instrument. This is * also a more flexible camera model since it will make controlling the * individual framelets alot easier. - * + * * @ingroup SpiceInstrumentsAndCameras * @ingroup Juno * @author 2017-07-22 Jeannie Backer * * @internal - * @history 2017-07-22 Jeannie Backer - Original version. + * @history 2017-07-22 Jeannie Backer - Original version. + * @history 2018-04-25 Jesse Mapel - Modified frame start calculation to not + * use exposure duration. Fixes #5236. */ class JunoCamera : public FramingCamera { public: JunoCamera(Cube &cube); ~JunoCamera(); - virtual std::pair <iTime, iTime> ShutterOpenCloseTimes(double time, + virtual std::pair <iTime, iTime> ShutterOpenCloseTimes(double time, double exposureDuration); virtual int CkFrameId() const; virtual int CkReferenceId() const; diff --git a/isis/src/qisis/apps/cneteditor/main.cpp b/isis/src/qisis/apps/cneteditor/main.cpp index eb14ee5096183dbfbcf532e24baaa9c867e5078c..66ec01dbfbc1b5e41ab41af30b2e4638734df3c3 100644 --- a/isis/src/qisis/apps/cneteditor/main.cpp +++ b/isis/src/qisis/apps/cneteditor/main.cpp @@ -1,5 +1,7 @@ #include "IsisDebug.h" +#include <iostream> + #include "CnetEditorWindow.h" #include "QIsisApplication.h" @@ -7,6 +9,10 @@ using namespace Isis; int main(int argc, char ** argv) { + if (getenv("ISISROOT") == NULL || QString(getenv("ISISROOT")) == "") { + std::cerr << "Please set ISISROOT before running any Isis applications" << std::endl; + exit(1); + } QIsisApplication app(argc, argv); CnetEditorWindow window; window.show(); diff --git a/isis/src/qisis/apps/ipce/IpceMainWindow.cpp b/isis/src/qisis/apps/ipce/IpceMainWindow.cpp index d33730594b8a1045e4acaf598a589b8a41f400d2..b16393e6c57490f3ba0ac1a3f3434069d34e1002 100644 --- a/isis/src/qisis/apps/ipce/IpceMainWindow.cpp +++ b/isis/src/qisis/apps/ipce/IpceMainWindow.cpp @@ -91,6 +91,7 @@ namespace Isis { m_directory = new Directory(this); connect(m_directory, SIGNAL( newWidgetAvailable(QWidget *) ), this, SLOT( addView(QWidget *) ) ); + connect(m_directory, SIGNAL(viewClosed(QWidget *)), this, SLOT(removeView(QWidget *))); connect(m_directory, SIGNAL( directoryCleaned() ), this, SLOT( removeAllViews() ) ); connect(m_directory->project(), SIGNAL(projectLoaded(Project *)), @@ -231,6 +232,38 @@ namespace Isis { } } } + + + /** + * @description This slot is connected from Directory::viewClosed(QWidget *) signal. It will + * close the given QMdiSubWindow from the QMdiArea. This will also delete the widget contained + * within the subwindow which is an AbstractProjectItemView. + * + * @param view QWidget* + * + */ + void IpceMainWindow::removeView(QWidget *view) { + + QMdiArea *mdiArea = qobject_cast<QMdiArea *>( centralWidget() ); + if (mdiArea){ + // Get all QMdiSubWindows, then find subwindow that hold widget + QList<QMdiSubWindow *> subWindowList = mdiArea->subWindowList(); + foreach (QMdiSubWindow *sub, subWindowList) { + if (sub->widget() == view) { + sub->close(); + break; + } + } +// QMdiSubWindow *window = qobject_cast<QMdiSubWindow *>(view); +// qDebug()<<"IpceMainWindow::removeView activewindow = "<<window; +// mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow *>(view)); +// qDebug()<<"IpceMainWindow::removeView"; +// mdiArea->closeActiveSubWindow(); + delete view; + } + } + + /** * Removes All Views in main window, connected to directory signal directoryCleaned() */ @@ -238,12 +271,12 @@ namespace Isis { setWindowTitle("ipce"); QMdiArea *mdiArea = qobject_cast<QMdiArea *>( centralWidget() ); if (mdiArea){ - QMdiSubWindow* window = new QMdiSubWindow(); - window->show(); - window->activateWindow(); - mdiArea->addSubWindow(window); +// QMdiSubWindow* window = new QMdiSubWindow(); +// window->show(); +// window->activateWindow(); +// mdiArea->addSubWindow(window); mdiArea->closeAllSubWindows(); - delete window; +// delete window; } if (!m_detachedViews.isEmpty()) { foreach ( QMainWindow* view, m_detachedViews ) { @@ -411,7 +444,13 @@ namespace Isis { m_permToolBar->addAction(action); } foreach (QAction *action, m_permToolBarActions) { - m_permToolBar->addAction(action); + if (action->text() == "&Save Active Control Network") { + m_permToolBar->addSeparator(); + } + m_permToolBar->addAction(action); + if (action->text() == "&Save Active Control Network") { + m_permToolBar->addSeparator(); + } } m_permToolBar->addSeparator(); if (m_activeView) { @@ -515,6 +554,30 @@ namespace Isis { m_fileMenuActions.append(exitAction); m_permToolBarActions.append(exitAction); + QAction *saveNet = new QAction("&Save Active Control Network", this); + saveNet->setIcon( QIcon::fromTheme("document-save") ); + saveNet->setShortcut(Qt::CTRL + Qt::Key_S); + saveNet->setToolTip("Save current active control network"); + saveNet->setStatusTip("Save current active control network"); + QString whatsThis = "<b>Function:</b> Saves the current active<i>" + "control network</i>"; + saveNet->setWhatsThis(whatsThis); + connect(saveNet, SIGNAL(triggered()), m_directory, SLOT(saveActiveControl())); + m_permToolBarActions.append(saveNet); + +// m_saveAsNet = new QAction(QPixmap(toolIconDir() + "/mActionFileSaveAs.png"), +// "Save Control Network &As...", +// m_matchTool); +// m_saveAsNet->setToolTip("Save current control network to chosen file"); +// m_saveAsNet->setStatusTip("Save current control network to chosen file"); +// whatsThis = "<b>Function:</b> Saves the current <i>" +// "control network</i> under chosen filename"; +// m_saveAsNet->setWhatsThis(whatsThis); +// connect(m_saveAsNet, SIGNAL(triggered()), this, SLOT(saveAsNet())); + + + + QAction *undoAction = m_directory->undoAction(); undoAction->setShortcut(Qt::Key_Z | Qt::CTRL); @@ -806,7 +869,11 @@ namespace Isis { * state information before forwarding the event to the QMainWindow. */ void IpceMainWindow::closeEvent(QCloseEvent *event) { - if (!m_directory->project()->isClean()) { + + // The active control is checked here for modification because this was the simplest solution + // vs changing the project clean state every time the control is modified or saved. + if (!m_directory->project()->isClean() || (m_directory->project()->activeControl() && + m_directory->project()->activeControl()->isModified())) { QMessageBox *box = new QMessageBox(QMessageBox::NoIcon, QString("Current Project Has Unsaved Changes"), QString("Would you like to save your current project?"), NULL, qobject_cast<QWidget *>(parent()), Qt::Dialog); @@ -1045,7 +1112,7 @@ namespace Isis { menuBar->addMenu(viewMenu); if ( !view->settingsMenuActions().isEmpty() ) { - QMenu *settingsMenu = new QMenu("&Settings", newWindow); + QMenu *settingsMenu = new QMenu("S&ettings", newWindow); foreach ( QAction *action, view->settingsMenuActions() ) { settingsMenu->addAction(action); } diff --git a/isis/src/qisis/apps/ipce/IpceMainWindow.h b/isis/src/qisis/apps/ipce/IpceMainWindow.h index f65ab04bf6eee7cd0e52182f538bf487c8ca29d7..b56d732babaae7b345f0f0f71351546a769e7e3b 100644 --- a/isis/src/qisis/apps/ipce/IpceMainWindow.h +++ b/isis/src/qisis/apps/ipce/IpceMainWindow.h @@ -123,6 +123,13 @@ namespace Isis { * the history dock. Fixes #5151. * @history 2018-03-02 Tracie Sucharski - added static keyword to the m_maxRecentProject member * variable, fixes OSX compile warning. References #5341. + * @history 2018-04-04 Tracie Sucharski - Added removeView slot which removes the view + * containing the given widget. In the closeEvent method check whether + * there is an active control and if it has been modified as additional + * test to determine whether project needs saving. + * @history 2018-05-01 Tracie Sucharski - Code accidently left commented from previous checking. + * Fixes #5412. + * */ class IpceMainWindow : public QMainWindow { Q_OBJECT @@ -132,6 +139,7 @@ namespace Isis { public slots: void addView(QWidget *newWidget); + void removeView(QWidget *view); void removeAllViews(); void setActiveView(AbstractProjectItemView *view); diff --git a/isis/src/qisis/apps/ipce/ipce.cpp b/isis/src/qisis/apps/ipce/ipce.cpp index 39b482c1c2492dba8b92e5f7b89cb8eb151bc827..71d15134f7d5482f641515aad40b691e74eb22a9 100644 --- a/isis/src/qisis/apps/ipce/ipce.cpp +++ b/isis/src/qisis/apps/ipce/ipce.cpp @@ -26,6 +26,7 @@ #include <QLocale> #include <QTranslator> +#include "FileName.h" #include "Gui.h" #include "IException.h" #include "IpceMainWindow.h" @@ -35,15 +36,27 @@ using namespace std; using namespace Isis; int main(int argc, char *argv[]) { - + if (getenv("ISISROOT") == NULL || QString(getenv("ISISROOT")) == "") { + std::cerr << "Please set ISISROOT before running any Isis applications" << std::endl; + exit(1); + } Gui::checkX11(); try { + + // Add the Qt plugin directory to the library path + FileName qtpluginpath("$ISISROOT/3rdParty/plugins"); + QCoreApplication::addLibraryPath(qtpluginpath.expanded()); + QApplication *app = new QIsisApplication(argc, argv); QApplication::setApplicationName("ipce"); IpceMainWindow *mainWindow = new IpceMainWindow(); + // For OSX, had problems with cneteditor view because it has it's own menus, caused the + // menubar on OSX to lockup + QCoreApplication::setAttribute(Qt::AA_DontUseNativeMenuBar, true); + // We do not want a showMaximized call, as that will negate the settings read during the main // window's initialization. References #4358. mainWindow->show(); diff --git a/isis/src/qisis/apps/qmos/qmos.cpp b/isis/src/qisis/apps/qmos/qmos.cpp index b39bec5ef856d2005dec12459219cc3455b34878..2036d20443b9b74c36edf1c4e1e40049292e3eab 100644 --- a/isis/src/qisis/apps/qmos/qmos.cpp +++ b/isis/src/qisis/apps/qmos/qmos.cpp @@ -13,6 +13,10 @@ using namespace std; using namespace Isis; int main(int argc, char *argv[]) { + if (getenv("ISISROOT") == NULL || QString(getenv("ISISROOT")) == "") { + std::cerr << "Please set ISISROOT before running any Isis applications" << std::endl; + exit(1); + } Isis::Gui::checkX11(); // Add the Qt plugin directory to the library path diff --git a/isis/src/qisis/apps/qnet/qnet.cpp b/isis/src/qisis/apps/qnet/qnet.cpp index cdcfe8ae6cbd232b5efd9dae69f2d27d81b49798..0783844c4ceccf9930131be06e6204ae3567585e 100644 --- a/isis/src/qisis/apps/qnet/qnet.cpp +++ b/isis/src/qisis/apps/qnet/qnet.cpp @@ -40,6 +40,10 @@ ToolClass *createTool(ViewportMainWindow *viewportMainWindow, ToolList *tools) { } int main(int argc, char *argv[]) { + if (getenv("ISISROOT") == NULL || QString(getenv("ISISROOT")) == "") { + std::cerr << "Please set ISISROOT before running any Isis applications" << std::endl; + exit(1); + } Isis::Gui::checkX11(); try { diff --git a/isis/src/qisis/apps/qtie/qtie.cpp b/isis/src/qisis/apps/qtie/qtie.cpp index 852a869d11122f8acb1de8248fc08dec0e992dd1..004e928ad18b00a37af047148398751296ba616d 100644 --- a/isis/src/qisis/apps/qtie/qtie.cpp +++ b/isis/src/qisis/apps/qtie/qtie.cpp @@ -33,7 +33,10 @@ ToolClass *createTool(ViewportMainWindow *viewportMainWindow, ToolList *tools) { } int main(int argc, char *argv[]) { - + if (getenv("ISISROOT") == NULL || QString(getenv("ISISROOT")) == "") { + std::cerr << "Please set ISISROOT before running any Isis applications" << std::endl; + exit(1); + } Isis::Gui::checkX11(); try { diff --git a/isis/src/qisis/apps/qview/qview.cpp b/isis/src/qisis/apps/qview/qview.cpp index 95253f46c577b247fe09fe950cab6f20c2428e61..5dcf578b49f58c95c231db5204ff3296e263e249 100644 --- a/isis/src/qisis/apps/qview/qview.cpp +++ b/isis/src/qisis/apps/qview/qview.cpp @@ -60,6 +60,10 @@ ToolClass *createTool(ViewportMainWindow *viewportMainWindow, ToolList *tools) { } int main(int argc, char *argv[]) { + if (getenv("ISISROOT") == NULL || QString(getenv("ISISROOT")) == "") { + std::cerr << "Please set ISISROOT before running any Isis applications" << std::endl; + exit(1); + } Isis::Gui::checkX11(); // Add the Qt plugin directory to the library path diff --git a/isis/src/qisis/apps/qview/qview.xml b/isis/src/qisis/apps/qview/qview.xml index 535a410b75762fa39694a31863a639cb60147b6f..3e7cd5c56aad197ab2db793dbcadddae4a54d50b 100644 --- a/isis/src/qisis/apps/qview/qview.xml +++ b/isis/src/qisis/apps/qview/qview.xml @@ -6,7 +6,103 @@ </brief> <description> - This program will display cubes and allow for interactive analysis. + <p> + This program will display cubes and allow for interactive analysis. Although the program + comprises a number of individual tools to perform analysis on your data, only the Spatial + Plot Tool is discussed here until further notice. + </p> + <h3>Spatial Plot Tool</h3> + <p> + This tool is used for analyzing manually selected pixel DN values. It works with two + different modes: linear and rotated rectangle. It is also capable of handling three different + modes of interpolation: Nearest Neighbor, BiLinear and Cubic Convolution. + </p> + <h4>Linear</h4> + <p> + This mode involves drawing a + line across an open cube. The selection is started by clicking and holding the mouse where + you would like to start your calculations, at which point you may drag the mouse in any + direction and release the click to establish the end of your selection. + </p> + <p> + The tool calculates the length of the line in pixels, rounding to the nearest full pixel + value. It then divides the actual length of the line by this rounded length to achieve a + step-size. <strong>Please note:</strong> This step size may be slightly bigger or smaller + than a pixel length, but this difference becomes negligible for larger selections. For + example, if the length of the drawn line was 2.91 pixels, the tool would round the length to + 3 and the step-size would be 2.91/3 (or 0.97). + </p> + <p> + A plot window will be generated with the calculated DN values of the pixels. The first value + to be calculated is the value where the original mouse click was made. At each increment, + according to step size, the tool calculates the value along the line until it reaches where the + mouse-click was released. This means that for a line with a rounded length of 3, the plot would show a + total of 4 plotted DN values. <strong>Please note:</strong> For a line with a rounded length of + <i>n</i>, the tool will calculate <i>n</i> + 1 values. + </p> + <image src="assets/image/LinearSelection.png" height="400" /> + <image src="assets/image/LinearPlot.png" height="400" /> + <p> + The images above include an example of the line as drawn in the cube view and the + associated plot window. Marking has been added to delineate where mouse clicks were made and + the DN values were calculated. The mouse was first clicked at dileneation marked "1" on the + cube, and was released at "4". The number from the cube view correlates with the "Pixel + Number" on the plot. + + </p> + <h4>Rotated Rectangle</h4> + <p> + This mode of the Spatial Plot Tool involves drawing a + rectangle across an open cube. The selection starts by clicking and holding the mouse + where you would like to start your calculations, at which point you may drag the mouse in any + direction and release the click to establish one edge of your selection. You may then + drag the mouse away from this original line to expand in the other direction. A single mouse + click establishes your final selection. <strong>Please note:</strong> The tool will lock + angles to be perpendicular and so your selections will always be a perfect rectangle. + </p> + + <p> + Similar to the linear mode of this tool, the lengths of the lines in pixels are rounded to the + nearest full pixel value, and then the lengths are divided by their rounded lengths to establish + a step-size. <strong>Please note:</strong> + The step-size along one edge of the selection may differ from the step-size of the + perpendicular edge, this becomes negligible for larger selections. For + example, if the length of the line in one direction was 2.91 pixels, the step-size would be 2.91/3 + (or 0.97), whereas if the length of the line in the perpendicular direction was 4.92, the step + size would be 4.92/5 (0.98). + </p> + <p> + A plot window will be generated with the calculated DN values. This is done by calculating the + value where the original mouse click was made, then continuing in the direction of that + first-drawn line, calculating the DN value at each step-sized increment until it reaches where + the original mouse-click was released. The tool will then calculate the average of these + values. This average becomes the first value in the plot. + </p> + <p> + The tool will then shift a step-size along the perpendicular edge, and calculate the average DN + value along a line running parallel to the first-drawn line. This average becomes the second + value in the plot. The tool continues this pattern until it has reached the opposite edge of + the rectangle as the first-drawn line. + </p> + <image src="assets/image/RRSelection.png" height="400" /> + <image src="assets/image/RRSelectionMarked.png" height="400" /> + <image src="assets/image/RRPlot.png" height="400" /> + <p> + The first image is the original selection. The second image + is the same view that has been marked for reference purposes. Finally, the last image + is the associated plot window. The original mouse click was made at delineation + "1" within the cube view, the original mouse release was made at "5", and the final + mouse click was made at "15". The Spatial Plot Tool calculates the average of the DN values at + delineations 1-5, and this value is stored as "Pixel Value" 1 in the plot window, while the + averages of 6-10 are stored in 2, and 7-15 are stored in 3. + </p> + <h4>Interpolations</h4> + <p> + Spatial Plot Tool makes use of Nearest Nieghbor, BiLinear and Cubic Convolution interpolations + when calculating the DN values at particular points. <strong>Do be aware that when the tool is + calculating a DN value at a particular point, it is calculating the interpolated DN value at + that point.</strong> + </p> </description> <category> @@ -164,5 +260,8 @@ Readded help menu for the 2D and 3D plot tools. Now properly display in both tools. Fixes #2126. </change> + <change name="Summer Stapleton" date="2018-03-14"> + Included documentation for Spatial Plot Tool in this .xml. References #5281. + </change> </history> </application> diff --git a/isis/src/qisis/objs/BundleObservationView/AS15_16_test_bundleout_images.csv b/isis/src/qisis/objs/BundleObservationView/AS15_16_test_bundleout_images.csv deleted file mode 100755 index d80600ac85f6d629ea8ecb138613fbb977055f1c..0000000000000000000000000000000000000000 --- a/isis/src/qisis/objs/BundleObservationView/AS15_16_test_bundleout_images.csv +++ /dev/null @@ -1,8 +0,0 @@ -Image,rms,rms,rms,X,X,X,X,X,Y,Y,Y,Y,Y,Z,Z,Z,Z,Z,RA,RA,RA,RA,RA,DEC,DEC,DEC,DEC,DEC,TWIST,TWIST,TWIST,TWIST,TWIST, -Filename,sample res,line res,total res,Initial,Correction,Final,Apriori Sigma,Adj Sigma,Initial,Correction,Final,Apriori Sigma,Adj Sigma,Initial,Correction,Final,Apriori Sigma,Adj Sigma,Initial,Correction,Final,Apriori Sigma,Adj Sigma,Initial,Correction,Final,Apriori Sigma,Adj Sigma,Initial,Correction,Final,Apriori Sigma,Adj Sigma, -/work/projects/ApolloMetric/METRIC/Calibrated/AS15/SUB4_MSK_InstrumentStartTime/Sub4-AS15-M-1757_msk.cub,0.51845694436147,0.97524424269876,0.78099261714619,-1676.1866244276,0.3170026774516,-1675.8696217502,500.0,0.1690797492717,776.01842700262,0.18308214004334,776.20150914267,500.0,0.17709880748748,190.83692567603,0.67934738703117,191.51627306306,500.0,0.16934724936719,-114.81847479623,0.14786430851052,-114.67061048772,0.5,0.097887257746279,84.286744189607,0.14301001677591,84.429754206383,0.5,0.085518977881851,135.10580640169,-0.073755435116957,135.03205096657,0.5,0.10209077775713 -/work/projects/ApolloMetric/METRIC/Calibrated/AS15/SUB4_MSK_InstrumentStartTime/Sub4-AS15-M-1758_msk.cub,0.48914157340128,0.96409831563102,0.76444262081337,-1661.0556247296,0.24305052799097,-1660.8125742016,500.0,0.17883341616719,800.60462193458,0.26766384701447,800.87228578159,500.0,0.17894270116668,219.62524418461,0.81713498430798,220.44237916892,500.0,0.17548613324839,-115.68927691479,0.15112876410579,-115.53814815068,0.5,0.097663328471951,83.287864615961,0.14571379590631,83.433578411867,0.5,0.085317156538059,135.24236174012,-0.081063071500818,135.16129866862,0.5,0.10243445718908 -/work/projects/ApolloMetric/METRIC/Calibrated/AS15/SUB4_MSK_InstrumentStartTime/Sub4-AS15-M-1759_msk.cub,0.3234786200299,1.0445725353158,0.77323030177063,-1645.118297281,0.18547301310201,-1644.9328242679,500.0,0.20684835804294,824.80203432912,0.37787280348465,825.17990713261,500.0,0.20520137756462,248.30682152756,0.97427898916589,249.28110051673,500.0,0.20458947672359,-116.55201321842,0.1414520464547,-116.41056117197,0.5,0.097506040940435,82.310079123292,0.14270993562181,82.452789058913,0.5,0.085163168400858,135.38610126297,-0.069324655588454,135.31677660738,0.5,0.10281378780214 -/work/projects/ApolloMetric/METRIC/Calibrated/AS16/SUB4_MSK_NewStartTime/Sub4-AS16-M-0392_msk.cub,0.49188485000562,1.1397636203373,0.8777846592159,1747.0424536016,-0.25503937331921,1746.7874142282,500.0,0.18429641470036,633.3492820035,0.49395906374671,633.84324106725,500.0,0.1830184566499,81.070798243394,-0.49125912498146,80.579539118413,500.0,0.19512758266095,110.34149860419,0.3735945369789,110.71509314116,0.5,0.088850090823099,87.09334362033,-0.10691005392567,86.986433566404,0.5,0.094783462079425,-149.90233460871,-0.036238357509029,-149.93857296621,0.5,0.10327678221121 -/work/projects/ApolloMetric/METRIC/Calibrated/AS16/SUB4_MSK_NewStartTime/Sub4-AS16-M-0393_msk.cub,0.745496019873,1.1426404871033,0.96472576373138,1760.2742054268,-0.034511936246684,1760.2396934906,500.0,0.17301063061067,597.66419620361,0.45091683878255,598.11511304239,500.0,0.1749682885975,58.98892575481,-0.51847411988065,58.47045163493,500.0,0.17712241769798,109.18883286426,0.37607709864275,109.56490996291,0.5,0.088840587895256,87.796840611543,-0.09134753252743,87.705493079016,0.5,0.094319465492397,-149.84701529934,-0.033154227141492,-149.88016952649,0.5,0.10364410342365 -/work/projects/ApolloMetric/METRIC/Calibrated/AS16/SUB4_MSK_NewStartTime/Sub4-AS16-M-0394_msk.cub,0.57994567220543,1.0445737373178,0.84482876235478,1772.5152690217,0.19274695792245,1772.7080159796,500.0,0.18900862793942,561.64149498279,0.39235269508021,562.03384767787,500.0,0.19507829017625,36.873141324453,-0.50650471222111,36.366636612232,500.0,0.18962962942032,108.01512683489,0.38747308139741,108.40259991629,0.5,0.088957785858698,88.534523650897,-0.1083766713918,88.426146979505,0.5,0.093815486035816,-149.80439189401,-0.018129130140166,-149.82252102415,0.5,0.10404865355201 diff --git a/isis/src/qisis/objs/BundleObservationView/BundleObservationView.cpp b/isis/src/qisis/objs/BundleObservationView/BundleObservationView.cpp index cb3f0ec51c019781e501cd158d288526905bcb15..7b29484de477f96218e5f28bda24b5dbd3091b58 100755 --- a/isis/src/qisis/objs/BundleObservationView/BundleObservationView.cpp +++ b/isis/src/qisis/objs/BundleObservationView/BundleObservationView.cpp @@ -23,6 +23,7 @@ #include <QDebug> #include <QFile> +#include <QFontDatabase> #include <QHeaderView> #include <QSizePolicy> #include <QStandardItem> @@ -30,71 +31,130 @@ #include <QString> #include <QStringList> #include <QTableView> +#include <QTextEdit> #include <QTextStream> #include <QVBoxLayout> - namespace Isis { - - /** - * Creates a view showing the CSV file from BundleObservation. + * Creates a view showing the CSV or text files from BundleSolutionInfo. * - * @param FileItemQsp fileItem QSharedPointer to the fileItem from the ProjectItemModel + * @param FileItemQsp fileItem QSharedPointer to the fileItem from the ProjectItemModel */ BundleObservationView::BundleObservationView(FileItemQsp fileItem, QWidget *parent): AbstractProjectItemView(parent) { + if (fileItem->fileName().contains(".csv")) { + displayCsvFile(fileItem); + } + else if (fileItem->fileName().contains(".txt")) { + displayTextFile(fileItem); + } + } + + + /** + * Creates a view showing the CSV file from BundleSolutionInfo. + * + * @param FileItemQsp fileItem QSharedPointer to the fileItem from the ProjectItemModel + */ + void BundleObservationView::displayCsvFile(FileItemQsp fileItem) { QStandardItemModel *model = new QStandardItemModel; + + if (!QFile::exists(fileItem->fileName())) { + return; + } + QFile file(fileItem->fileName()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + return; + } - if (file.open(QIODevice::ReadOnly)) { + int numHeaderLines = 3; + if (fileItem->fileName().contains("images")) { + numHeaderLines = 2; + } - int lineindex = 0; // file line counter - QTextStream in(&file); // read to text stream + QTextStream in(&file); // read to text stream + + // read and populate header from first two or three lines + QString header1; + QString header2; + QString header3; + QStringList lineToken1; + QStringList lineToken2; + QStringList lineToken3; + + header1 = in.readLine(); + lineToken1 = header1.split(","); + header2 = in.readLine(); + lineToken2 = header2.split(","); + + if (numHeaderLines == 2) { + for (int i = 0; i < lineToken1.size(); i++) { + QString t1 = lineToken1.at(i); + QString t2 = lineToken2.at(i); + QString head = t1 + "\n" + t2; + QStandardItem *v1 = new QStandardItem(head); + model->setHorizontalHeaderItem(i,v1); + } + } + if (numHeaderLines == 3) { + header3 = in.readLine(); + lineToken3 = header3.split(","); + + lineToken1.append(""); + lineToken2.append(""); + + for (int i = 0; i < lineToken3.size(); i++) { + QString t1 = lineToken1.at(i); + QString t2 = lineToken2.at(i); + QString t3 = lineToken3.at(i); + QString head = t1 + "\n" + t2 + "\n" + t3; + QStandardItem *v1 = new QStandardItem(head); + model->setHorizontalHeaderItem(i,v1); + } + } - while (!in.atEnd()) { + // populate remainder of table + int lineindex = 0; + while (!in.atEnd()) { + QString fileLine = in.readLine(); - // read one line from textstream(separated by "\n") - QString fileLine = in.readLine(); + // parse line into separate pieces(tokens) with "," as the delimiter + QStringList lineToken = fileLine.split(",", QString::SkipEmptyParts); - // parse the read line into separate pieces(tokens) with "," as the delimiter - QStringList lineToken = fileLine.split(",", QString::SkipEmptyParts); + bool rejected = false; + if (lineToken.at(lineToken.size()-1) == "*") { + rejected = true; + } - // load parsed data to model accordingly - for (int j = 0; j < lineToken.size(); j++) { - QString value = lineToken.at(j); + // load parsed data to model accordingly + for (int i = 0; i < lineToken.size(); i++) { + QString value = lineToken.at(i); - // First 2 lines are header, load into model header data - if (lineindex < 2) { - //qDebug()<<"header = "<<value; - //model->setHeaderData(j, Qt::Horizontal, value); - //qDebug()<<"header = "<<value; - QStandardItem *v1 = new QStandardItem(value); + QStandardItem *item = new QStandardItem(value); - model->setHorizontalHeaderItem(j,v1); - //model->setHeaderData(j, Qt::Horizontal, value); - } - else { - QStandardItem *item = new QStandardItem(value); - model->setItem(lineindex, j, item); - } + if (rejected) { + item->setData(QColor(200,0,0), Qt::BackgroundRole); } - lineindex++; + model->setItem(lineindex, i, item); } - - file.close(); + lineindex++; } + file.close(); + QTableView *qtable=new QTableView(); qtable->setModel(model); qtable->setSortingEnabled(true); - - QHeaderView *headerView = qtable->horizontalHeader(); - headerView->setStretchLastSection(true); + + // resizes to contents based on entire column + // NOTE: QHeaderView::ResizeToContents does not allow user to resize by dragging column divider + qtable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); QVBoxLayout *layout = new QVBoxLayout; setLayout(layout); @@ -104,17 +164,58 @@ namespace Isis { policy.setHorizontalPolicy(QSizePolicy::Expanding); policy.setVerticalPolicy(QSizePolicy::Expanding); setSizePolicy(policy); - } + } /** - * Destructor + * Creates a view showing a text file from BundleSolutionInfo. + * + * @param FileItemQsp fileItem QSharedPointer to the fileItem from the ProjectItemModel */ - BundleObservationView::~BundleObservationView() { + void BundleObservationView::displayTextFile(FileItemQsp fileItem) { + + if (!QFile::exists(fileItem->fileName())) { + return; + } + + QFile file(fileItem->fileName()); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + return; + } + QTextStream in(&file); + QTextEdit *qText=new QTextEdit(); + + // From QFontDatabase::systemFont(SystemFont type) method description: returns most adequate + // font for a given typecase (here FixedFont) for proper integration with system's look and + // feel. + const QFont fixedFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); + qText->setFontFamily(fixedFont.family()); + + while (!in.atEnd()) { + qText->append(in.readLine()); + } + + file.close(); + + QVBoxLayout *layout = new QVBoxLayout; + setLayout(layout); + layout->addWidget(qText); + + qText->moveCursor(QTextCursor::Start); + + QSizePolicy policy = sizePolicy(); + policy.setHorizontalPolicy(QSizePolicy::Expanding); + policy.setVerticalPolicy(QSizePolicy::Expanding); + setSizePolicy(policy); } + /** + * Destructor + */ + BundleObservationView::~BundleObservationView() { + } } diff --git a/isis/src/qisis/objs/BundleObservationView/BundleObservationView.h b/isis/src/qisis/objs/BundleObservationView/BundleObservationView.h index 2a5b0f267f3547bd0ab15a5b74aec5da23b43950..6921c422ac902a4d41bd08703598d1ff8bc9c2ae 100755 --- a/isis/src/qisis/objs/BundleObservationView/BundleObservationView.h +++ b/isis/src/qisis/objs/BundleObservationView/BundleObservationView.h @@ -22,7 +22,6 @@ */ #include "AbstractProjectItemView.h" - #include "FileItem.h" namespace Isis{ @@ -36,8 +35,18 @@ namespace Isis{ * @internal * @history 2017-05-01 Tyler Wilson - Original version. * @history 2017-05-05 Tracie Sucharski - Changed for the serialization of BundleObservation - * files. This was implemented create a new ProjectItem type called + * files. This was implemented create a new ProjectItem type called * FileItemQsp. Fixes #4839, #4840. + * @history 2018-03-21 Ken Edmundson - Added capability to display either csv or text files. + * Fixed problem for display of multi-line headers for csv files. + * Set SectionResizeMode to QHeaderView::ResizeToContents so columns are + * displayed at the width of the maximum size of the column content. + * Fixes #4850. + * @history 2018-03-26 Ken Edmundson - Modified displayTextFile method to query for system's + * fixed width font. + * @history 2018-04-16 Ken Edmundson - Modified display of residuals.csv to properly show the + * rejected column if there are rejected measures. Also displays + * rejected measure row in red. */ class BundleObservationView : public AbstractProjectItemView @@ -45,8 +54,11 @@ namespace Isis{ Q_OBJECT public: BundleObservationView(FileItemQsp fileItem, QWidget *parent=0); - //BundleObservationView(const BundleObservationView &other); ~BundleObservationView(); + + private: + void displayCsvFile(FileItemQsp fileItem); + void displayTextFile(FileItemQsp fileItem); }; } #endif diff --git a/isis/src/qisis/objs/CnetEditorView/CnetEditorView.cpp b/isis/src/qisis/objs/CnetEditorView/CnetEditorView.cpp new file mode 100644 index 0000000000000000000000000000000000000000..eca23209c60b0dfd915fd4dfaec8dc7e3d71a19e --- /dev/null +++ b/isis/src/qisis/objs/CnetEditorView/CnetEditorView.cpp @@ -0,0 +1,328 @@ +/** + * @file + * $Date$ + * $Revision$ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include "IsisDebug.h" + +#include "CnetEditorView.h" + +#include <QAction> +#include <QGridLayout> +#include <QList> +#include <QMap> +#include <QMapIterator> +#include <QMenu> +#include <QMenuBar> +#include <QSize> +#include <QSizePolicy> +#include <QString> +#include <QTabWidget> +#include <QToolBar> +#include <QtXml> +#include <QVBoxLayout> +#include <QWidgetAction> + +#include "Control.h" +#include "ControlNet.h" +#include "CnetEditorWidget.h" +#include "Directory.h" +#include "FileName.h" +#include "Project.h" +#include "ToolPad.h" +#include "XmlStackedHandlerReader.h" + + +namespace Isis { + /** + * Constructor. + */ + CnetEditorView::CnetEditorView(Directory *directory, Control *control, FileName configFile, + QWidget *parent) : AbstractProjectItemView(parent) { + + // TODO: This layout should be inside of the cnet editor widget, but I put it here to not + // conflict with current work in the cnet editor widget code. + //QWidget *result = new QWidget; + QGridLayout *resultLayout = new QGridLayout; + setLayout(resultLayout); + + int row = 0; + + QMenuBar *menuBar = new QMenuBar; + resultLayout->addWidget(menuBar, row, 0, 1, 2); + row++; + + m_cnetEditorWidget = new CnetEditorWidget(control, configFile.expanded()); + m_control = control; + + resultLayout->addWidget(m_cnetEditorWidget, row, 0, 1, 2); + row++; + + // Populate the menu... + QMap< QAction *, QList< QString > > actionMap = m_cnetEditorWidget->menuActions(); + QMapIterator< QAction *, QList< QString > > actionMapIterator(actionMap); + + QMap<QString, QMenu *> topLevelMenus; + + while ( actionMapIterator.hasNext() ) { + actionMapIterator.next(); + QAction *actionToAdd = actionMapIterator.key(); + QList< QString > location = actionMapIterator.value(); + + QMenu *menuToPutActionInto = NULL; + + if ( location.count() ) { + QString topLevelMenuTitle = location.takeFirst(); + if (!topLevelMenus[topLevelMenuTitle]) { + topLevelMenus[topLevelMenuTitle] = menuBar->addMenu(topLevelMenuTitle); + } + + menuToPutActionInto = topLevelMenus[topLevelMenuTitle]; + } + + foreach (QString menuName, location) { + bool foundSubMenu = false; + foreach ( QAction *possibleSubMenu, menuToPutActionInto->actions() ) { + if (!foundSubMenu && + possibleSubMenu->menu() && possibleSubMenu->menu()->title() == menuName) { + foundSubMenu = true; + menuToPutActionInto = possibleSubMenu->menu(); + } + } + + if (!foundSubMenu) { + menuToPutActionInto = menuToPutActionInto->addMenu(menuName); + } + } + + menuToPutActionInto->addAction(actionToAdd); + } + + QTabWidget *treeViews = new QTabWidget; + treeViews->addTab( m_cnetEditorWidget->pointTreeView(), tr("Point View") ); + treeViews->addTab( m_cnetEditorWidget->serialTreeView(), tr("Serial View") ); + treeViews->addTab( m_cnetEditorWidget->connectionTreeView(), tr("Connection View") ); + resultLayout->addWidget(treeViews, row, 0, 1, 1); + + QTabWidget *filterViews = new QTabWidget; + filterViews->addTab( m_cnetEditorWidget->pointFilterWidget(), tr("Filter Points and Measures") ); + filterViews->addTab( m_cnetEditorWidget->serialFilterWidget(), tr("Filter Images and Points") ); + filterViews->addTab( m_cnetEditorWidget->connectionFilterWidget(), tr("Filter Connections") ); + resultLayout->addWidget(filterViews, row, 1, 1, 1); + row++; + + + + + + m_permToolBar = new QToolBar("Standard Tools", 0); + m_permToolBar->setObjectName("permToolBar"); + m_permToolBar->setIconSize(QSize(22, 22)); + //toolBarLayout->addWidget(m_permToolBar); + + m_activeToolBar = new QToolBar("Active Tool", 0); + m_activeToolBar->setObjectName("activeToolBar"); + m_activeToolBar->setIconSize(QSize(22, 22)); + //toolBarLayout->addWidget(m_activeToolBar); + + m_toolPad = new ToolPad("Tool Pad", 0); + m_toolPad->setObjectName("toolPad"); + //toolBarLayout->addWidget(m_toolPad); + + +// m_cnetEditorWidget->addToPermanent(m_permToolBar); +// m_cnetEditorWidget->addTo(m_activeToolBar); +// m_cnetEditorWidget->addTo(m_toolPad); + + m_activeToolBarAction = new QWidgetAction(this); + m_activeToolBarAction->setDefaultWidget(m_activeToolBar); + + setAcceptDrops(true); + + QSizePolicy policy = sizePolicy(); + policy.setHorizontalPolicy(QSizePolicy::Expanding); + policy.setVerticalPolicy(QSizePolicy::Expanding); + setSizePolicy(policy); + + } + + + /** + * Destructor + */ + CnetEditorView::~CnetEditorView() { + + delete m_cnetEditorWidget; + delete m_permToolBar; + delete m_activeToolBar; + delete m_toolPad; + + m_permToolBar = 0; + m_activeToolBar = 0; + m_toolPad = 0; + } + + + /** + * Returns the cnetEditorWidget. + * + * @return (cnetEditorWidget *) The cnetEditorWidget used to + * display the footprints. + */ + CnetEditorWidget *CnetEditorView::cnetEditorWidget() { + return m_cnetEditorWidget; + } + + + /** + * @description Returns the Control displayed in the CnetEditorWidget + * + * @return (Control *) The Control displayed in the CnetEditorWidget + */ + Control *CnetEditorView::control() { + return m_control; + } + + + /** + * Returns the suggested size for the widget. + * + * @return (QSize) The size + */ + QSize CnetEditorView::sizeHint() const { + return QSize(800, 600); + } + + + /** + * Returns a list of actions for the permanent tool bar. + * + * @return (QList<QAction *>) The actions + */ + QList<QAction *> CnetEditorView::permToolBarActions() { + return m_permToolBar->actions(); + } + + + /** + * Returns a list of actions for the active tool bar. + * + * @return (QList<QAction *>) The actions + */ + QList<QAction *> CnetEditorView::activeToolBarActions() { + QList<QAction *> actions; + actions.append(m_activeToolBarAction); + return actions; + } + + + /** + * Returns a list of actions for the tool pad. + * + * @return (QList<QAction *>) The actions + */ + QList<QAction *> CnetEditorView::toolPadActions() { + return m_toolPad->actions(); + } + + + + + /** + * This method pushes a new XmlHandler into the parser stack. + * + * @param xmlReader This is the parser stack. + */ + void CnetEditorView::load(XmlStackedHandlerReader *xmlReader) { + xmlReader->pushContentHandler(new XmlHandler(this)); + } + + + /** + * This method saves the Controls object ids to the stream. + * + * @param stream The stream that will output to directory.xml + * @param project The project to save the users settings to + * @param newProjectRoot New project's root directory + */ + void CnetEditorView::save(QXmlStreamWriter &stream, Project *, FileName) const { + + stream.writeStartElement("control"); + stream.writeAttribute("id", m_control->id()); + stream.writeEndElement(); + } + + + /** + * Creates an XmlHandler for cnetEditor + * + * @param cnetEditor The widget to be serialized + */ + CnetEditorView::XmlHandler::XmlHandler(CnetEditorView *cnetEditorView) { + m_cnetEditorView = cnetEditorView; + } + + + /** + * Destructor + */ + CnetEditorView::XmlHandler::~XmlHandler() { + delete m_cnetEditorView; + m_cnetEditorView = NULL; + } + + + /** + * Placeholder for later serialization of CnetEditorViews + * + * @param cnetEditor The CnetEditorView to be serialized + * @param namespaceURI ??? + * @param localName Determines what attributes to retrieve from atts. + * @param qName ??? + * @param atts Stores the attributes. + * + * @return @b bool The result of XmlStackedHandler's startElement() method. + */ + bool CnetEditorView::XmlHandler::startElement(const QString &namespaceURI, + const QString &localName, const QString &qName, const QXmlAttributes &atts) { + + bool result = XmlStackedHandler::startElement(namespaceURI, localName, qName, atts); + return result; + } + + + /** + * This method calls XmlStackedHandler's endElement() and dereferences pointers according to + * the value of localName. + * + * @param namespaceURI ??? + * @param localName Determines which pointers to dereference. + * @param qName ??? + * + * @return @b bool The result of XmlStackedHandler's endElement() method. + */ + bool CnetEditorView::XmlHandler::endElement(const QString &namespaceURI, + const QString &localName, const QString &qName) { + + bool result = XmlStackedHandler::endElement(namespaceURI, localName, qName); + return result; + } +} + diff --git a/isis/src/qisis/objs/CnetEditorView/CnetEditorView.h b/isis/src/qisis/objs/CnetEditorView/CnetEditorView.h new file mode 100644 index 0000000000000000000000000000000000000000..21e98d307d8b70e01d33be604cbad736408612e6 --- /dev/null +++ b/isis/src/qisis/objs/CnetEditorView/CnetEditorView.h @@ -0,0 +1,113 @@ +#ifndef CnetEditorView_h +#define CnetEditorView_h +/** + * @file + * $Date$ + * $Revision$ + * + * Unless noted otherwise, the portions of Isis written by the USGS are + * public domain. See individual third-party library and package descriptions + * for intellectual property information, user agreements, and related + * information. + * + * Although Isis has been used by the USGS, no warranty, expressed or + * implied, is made by the USGS as to the accuracy and functioning of such + * software and related material nor shall the fact of distribution + * constitute any such warranty, and no responsibility is assumed by the + * USGS in connection therewith. + * + * For additional information, launch + * $ISISROOT/doc//documents/Disclaimers/Disclaimers.html + * in a browser or see the Privacy & Disclaimers page on the Isis website, + * http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on + * http://www.usgs.gov/privacy.html. + */ +#include <QList> +#include <QMap> +#include <QPointer> +#include <QSize> + +#include "AbstractProjectItemView.h" +#include "FileName.h" +#include "XmlStackedHandler.h" + +class QAction; +class QToolBar; +class QWidgetAction; +class QXmlStreamWriter; + +namespace Isis { + class Control; + class CnetEditorWidget; + class Directory; + class FileName; + class Project; + class ToolPad; + class XmlStackedHandlerReader; + + /** + * Ipce view containing the CnetEditorWidget + * + * @author 2018-04-04 Tracie Sucharski + * + * @internal + */ + +class CnetEditorView : public AbstractProjectItemView { + + Q_OBJECT + + public: + CnetEditorView(Directory *directory, Control *control, FileName configFile, + QWidget *parent = 0); + ~CnetEditorView(); + + virtual QList<QAction *> permToolBarActions(); + virtual QList<QAction *> activeToolBarActions(); + virtual QList<QAction *> toolPadActions(); + + CnetEditorWidget *cnetEditorWidget(); + Control *control(); + + QSize sizeHint() const; + + void load(XmlStackedHandlerReader *xmlReader); + void save(QXmlStreamWriter &stream, Project *project, FileName newProjectRoot) const; + + + private: + /** + * @author 2012-09-?? Steven Lambright + * + * @internal + * @history 2018-04-04 Tracie Sucharski - Implemented for CnetEditorView + */ + class XmlHandler : public XmlStackedHandler { + public: + XmlHandler(CnetEditorView *cnetEditorView); + ~XmlHandler(); + + virtual bool startElement(const QString &namespaceURI, const QString &localName, + const QString &qName, const QXmlAttributes &atts); + virtual bool endElement(const QString &namespaceURI, const QString &localName, + const QString &qName); + + private: + Q_DISABLE_COPY(XmlHandler); + + CnetEditorView *m_cnetEditorView; //!< The view we are working with + }; + + private: + QPointer<CnetEditorWidget> m_cnetEditorWidget; + QPointer<Control> m_control; + + QToolBar *m_permToolBar; //!< The permanent tool bar + QToolBar *m_activeToolBar; //!< The active tool bar + ToolPad *m_toolPad; //!< The tool pad + + QWidgetAction *m_activeToolBarAction; //!< Stores the active tool bar + }; +} + +#endif // CNETEDITORVIEW_H diff --git a/isis/src/qisis/objs/CnetEditorView/Makefile b/isis/src/qisis/objs/CnetEditorView/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..f122bc88227c5c7ebd108dea5d339d1d2e074d82 --- /dev/null +++ b/isis/src/qisis/objs/CnetEditorView/Makefile @@ -0,0 +1,7 @@ +ifeq ($(ISISROOT), $(BLANK)) +.SILENT: +error: + echo "Please set ISISROOT"; +else + include $(ISISROOT)/make/isismake.objs +endif \ No newline at end of file diff --git a/isis/src/qisis/objs/CnetEditorWidget/CnetEditorWidget.cpp b/isis/src/qisis/objs/CnetEditorWidget/CnetEditorWidget.cpp index b55d7c57cc08ed2a1ec9de6a53d50a456abeb414..30dbba1a8c973bf8963801b298563b15286d0ab6 100644 --- a/isis/src/qisis/objs/CnetEditorWidget/CnetEditorWidget.cpp +++ b/isis/src/qisis/objs/CnetEditorWidget/CnetEditorWidget.cpp @@ -98,6 +98,7 @@ namespace Isis { * Destructor */ CnetEditorWidget::~CnetEditorWidget() { + writeSettings(); delete m_workingVersion; @@ -1040,82 +1041,4 @@ namespace Isis { m_connectionModel->setFrozen(false); } } - - - /** - * This method pushes a new XmlHandler into the parser stack. - * - * @param xmlReader This is the parser stack. - */ - void CnetEditorWidget::load(XmlStackedHandlerReader *xmlReader) { - xmlReader->pushContentHandler(new XmlHandler(this)); - } - - - /** - * This method saves the Controls object ids to the stream. - * - * @param stream The stream that will output to directory.xml - * @param project The project to save the users settings to - * @param newProjectRoot New project's root directory - */ - void CnetEditorWidget::save(QXmlStreamWriter &stream, Project *project, FileName newProjectRoot) { - stream.writeStartElement("control"); - stream.writeAttribute("id", m_control->id()); - stream.writeEndElement(); - } - - - /** - * Creates an XmlHandler for cnetEditor - * - * @param cnetEditor The widget to be serialized - */ - CnetEditorWidget::XmlHandler::XmlHandler(CnetEditorWidget *cnetEditor) { - m_cnetEditor = cnetEditor; - } - - - /** - * Destructor - */ - CnetEditorWidget::XmlHandler::~XmlHandler() { - delete m_cnetEditor; - m_cnetEditor = NULL; - } - - - /** - * Placeholder for later serialization of CnetEditorWidgets - * - * @param cnetEditor The widget to be serialized - * @param namespaceURI ??? - * @param localName Determines what attributes to retrieve from atts. - * @param qName ??? - * @param atts Stores the attributes. - * - * @return @b bool The result of XmlStackedHandler's startElement() method. - */ - bool CnetEditorWidget::XmlHandler::startElement(const QString &namespaceURI, - const QString &localName, const QString &qName, const QXmlAttributes &atts) { - bool result = XmlStackedHandler::startElement(namespaceURI, localName, qName, atts); - return result; - } - - - /** - * This method calls XmlStackedHandler's endElement() and dereferences pointers according to - * the value of localName. - * - * @param namespaceURI ??? - * @param localName Determines which pointers to dereference. - * @param qName ??? - * - * @return @b bool The result of XmlStackedHandler's endElement() method. - */ - bool CnetEditorWidget::XmlHandler::endElement(const QString &namespaceURI, - const QString &localName, const QString &qName) { - bool result = XmlStackedHandler::endElement(namespaceURI, localName, qName); - return result; - } } diff --git a/isis/src/qisis/objs/CnetEditorWidget/CnetEditorWidget.h b/isis/src/qisis/objs/CnetEditorWidget/CnetEditorWidget.h index bdbe010105569f0db7e73b2566a94e270f0fcc32..e66c559403d103365c789babd46b6e2cb814e7ec 100644 --- a/isis/src/qisis/objs/CnetEditorWidget/CnetEditorWidget.h +++ b/isis/src/qisis/objs/CnetEditorWidget/CnetEditorWidget.h @@ -71,6 +71,8 @@ namespace Isis { * a ControlNet. Added load and save methods as well as an XmlHandler * to allow for serialization of the widget into the project. * Fixes #4989. + * @history 2018-04-11 Tracie Sucharski - Moved the Xml serialization to the newly created + * CnetEditorView class for ipce. */ class CnetEditorWidget : public QWidget { Q_OBJECT @@ -116,9 +118,6 @@ namespace Isis { void setPointTableSortingEnabled(bool enabled); void setPointTableSortLimit(int limit); - void load(XmlStackedHandlerReader *xmlReader); - void save(QXmlStreamWriter &stream, Project *project, FileName newProjectRoot); - public slots: void configSorting(); @@ -191,34 +190,6 @@ namespace Isis { QMap< QString, QList< QAction * > > * m_toolBarActions; //!< QMap of tool bar actions QString *m_settingsPath; //!< Path to read/write settings - - - private: - /** - * This class is a placeholder for future plans to serialize more of - * CnetEditorWidget's configurations when saving a project. - * - * @author 2017-07-25 Christopher Combs - * @internal - * @history 2017-07-25 Christopher Combs - Added Xml StackedHandler class - * to implement serialization of the CnetEditorWidget. - * References #4989. - */ - class XmlHandler : public XmlStackedHandler { - public: - XmlHandler(CnetEditorWidget *cnetEditor); - ~XmlHandler(); - - virtual bool startElement(const QString &namespaceURI, const QString &localName, - const QString &qName, const QXmlAttributes &atts); - virtual bool endElement(const QString &namespaceURI, const QString &localName, - const QString &qName); - - private: - Q_DISABLE_COPY(XmlHandler); - - CnetEditorWidget *m_cnetEditor; - }; }; } diff --git a/isis/src/qisis/objs/Control/Control.cpp b/isis/src/qisis/objs/Control/Control.cpp index c71ac7db4dac83a9f4194d58a44faeca9096edc9..751cc3f83c62614fe951e2f4ec568e9aceafd58e 100644 --- a/isis/src/qisis/objs/Control/Control.cpp +++ b/isis/src/qisis/objs/Control/Control.cpp @@ -31,6 +31,7 @@ namespace Isis { m_controlNet = NULL; m_displayProperties = NULL; m_project = NULL; + m_modified = false; try { openControlNet(); @@ -59,6 +60,7 @@ namespace Isis { m_controlNet = NULL; m_displayProperties = NULL; m_project = project; + m_modified = false; m_displayProperties = new ControlDisplayProperties(FileName(m_fileName).name(), this); @@ -82,6 +84,7 @@ namespace Isis { m_controlNet = controlNet; m_displayProperties = NULL; m_project = NULL; + m_modified = false; m_displayProperties = new ControlDisplayProperties(FileName(m_fileName).name(), this); @@ -103,6 +106,7 @@ namespace Isis { m_displayProperties = NULL; m_id = NULL; m_project = NULL; + m_modified = false; xmlReader->pushContentHandler(new XmlHandler(this, cnetFolder)); } @@ -122,6 +126,9 @@ namespace Isis { // destructor will take care of deleting the display props. See call to // DisplayProperties' constructor. m_displayProperties = NULL; + + // TODO: If control net is modified, prompt for save before destroying?? + } @@ -154,6 +161,7 @@ namespace Isis { if (m_project) { m_controlNet->SetMutex(m_project->mutex()); } + m_modified = false; } catch (IException &e) { @@ -163,6 +171,33 @@ namespace Isis { } + /** + * @description Write control net to disk. This method is used instead of calling + * ControlNet::Write directly so that Control knows the modification state of the control net. + * Note that if there is not a control net opened, there should no be any changes to write. + * + * @return @b bool Returns false if there is not a control net open to write + * + * @throws IException::Programmer "Cannot write control net to disk" + */ + bool Control::write() { + + if (!m_controlNet) { + return false; + } + + try { + m_controlNet->Write(fileName()); + } + catch (IException &e) { + throw IException(e, IException::Programmer, "Cannot write control net.", _FILEINFO_); + } + + m_modified = false; + return true; + } + + /** * Cleans up the ControlNet pointer. This method should be called * once there is no more need for this network because the OS will limit @@ -173,6 +208,31 @@ namespace Isis { delete m_controlNet; m_controlNet = NULL; } + m_modified = false; + } + + + /** + * @description Has this control been modified? + * + * @return @b bool Has this control been modified? + * + */ + bool Control::isModified() { + return m_modified; + } + + + /** + * @description Sets the modification state of this control. This is needed for now since many + * classes make changes to the control net contained in this object, but the control does not + * know the state of the control net. + * TODO: Change this class to always know the state of the control Net. + * + */ + void Control::setModified(bool modified) { + + m_modified = modified; } @@ -224,17 +284,35 @@ namespace Isis { * will be copied. */ void Control::copyToNewProjectRoot(const Project *project, FileName newProjectRoot) { - if (FileName(newProjectRoot).toString() != FileName(project->projectRoot()).toString()) { + if (FileName(newProjectRoot).toString() != FileName(project->projectRoot()).toString()) { + QString newNetworkPath = project->cnetRoot(newProjectRoot.toString()) + "/" + FileName(m_fileName).dir().dirName() + "/" + FileName(m_fileName).name(); - QString oldNetworkPath = project->cnetRoot(project->projectRoot()) + "/" + - FileName(m_fileName).dir().dirName() + "/" + FileName(m_fileName).name(); - if (!QFile::copy(oldNetworkPath,newNetworkPath) ) { - throw IException(IException::Io, "Error saving control net.", _FILEINFO_); + // If there is active control & it has been modified, write to disk instead of copying + // Leave control net at old location in unmodified state + if (isModified()) { + controlNet()->Write(newNetworkPath); + setModified(false); + } + else { + QString oldNetworkPath = project->cnetRoot(project->projectRoot()) + "/" + + FileName(m_fileName).dir().dirName() + "/" + FileName(m_fileName).name(); + if (!QFile::copy(oldNetworkPath,newNetworkPath) ) { + throw IException(IException::Io, "Error saving control net.", _FILEINFO_); + } + } + } + // Project "Save" to current location, if active control exists & is modified, write to disk + // Note: It does not look like this code is ever executed. If project is saved with a + // "Save" this method is not called. + else { + if (isModified()) { + write(); + setModified(false); } - }//end outer-if + } } @@ -256,6 +334,7 @@ namespace Isis { // If we're the last thing in the folder, remove the folder too. QDir dir; dir.rmdir(FileName(m_fileName).path()); + m_modified = false; } diff --git a/isis/src/qisis/objs/Control/Control.h b/isis/src/qisis/objs/Control/Control.h index c1d21862789471ae4f73f3563bb0e518109f6b99..a3d10118410f9d358adad416c05b92721da7365d 100644 --- a/isis/src/qisis/objs/Control/Control.h +++ b/isis/src/qisis/objs/Control/Control.h @@ -67,13 +67,21 @@ namespace Isis { * to compare project roots. References #4804, #4849. * @history 2018-01-19 Tracie Sucharski - Do not copy control unless the project root has * changed. References #5212. + * @history 2018-03-30 Tracie Sucharski - Added setModified and is Modified methods to keep + * track of the modification state of the control net. Add write method + * to write the control net to disk. This write method should be called + * by ipce classes instead of calling the ControlNet::Write directly so + * that control knows the state of the control net. If a project + * is performing a "Save As", and there is a modified active control,the + * cnet is written out to the new location, it is not save in the old + * project location. */ class Control : public QObject { Q_OBJECT public: ControlNet *m_controlNet; /**< A pointer to the ControlNet object associated with this Control object.*/ - explicit Control(QString cnetFileName, QObject *parent = 0); + explicit Control(QString cnetFileName, QObject *parent = 0); explicit Control(Project *project, QString cnetFileName, QObject *parent = 0); explicit Control(ControlNet *controlNet, QString cnetFileName, QObject *parent = 0); Control(FileName cnetFolder, XmlStackedHandlerReader *xmlReader, QObject *parent = 0); @@ -87,6 +95,10 @@ namespace Isis { QString id() const; + bool isModified(); + void setModified(bool modified = true); + bool write(); + void save(QXmlStreamWriter &stream, const Project *project, FileName newProjectRoot) const; void copyToNewProjectRoot(const Project *project, FileName newProjectRoot); void deleteFromDisk(); @@ -123,6 +135,8 @@ namespace Isis { Control(const Control &other); Control &operator=(const Control &rhs); + bool m_modified; + ControlDisplayProperties *m_displayProperties; /**< Contains the display properties for this Control object.*/ Project *m_project; //! Project associated with this control diff --git a/isis/src/qisis/objs/ControlNetTool/ControlNetTool.cpp b/isis/src/qisis/objs/ControlNetTool/ControlNetTool.cpp index 6228df16ed397a8e44cf72db2d2e334f0fa2d851..221b544edaed81080d3a75e4191b638aae4a745c 100644 --- a/isis/src/qisis/objs/ControlNetTool/ControlNetTool.cpp +++ b/isis/src/qisis/objs/ControlNetTool/ControlNetTool.cpp @@ -35,9 +35,10 @@ using namespace std; namespace Isis { /** - * Ipce (Qnet) tool - Handles mouse button actions and drawing control points on viewports + * ControlNet tool - Handles mouse button actions and drawing control points on viewports in the + * CubeDnView for the ipce application. * - * @param parent Pointer to the parent widget for the Ipce tool + * @param parent Pointer to the parent widget for the ControlNet tool * * @author 2016-09-01 Tracie Sucharski * @@ -56,10 +57,10 @@ namespace Isis { /** - * Adds the Ipce tool action to the tool pad. + * Adds the ControlNet tool action to the tool pad. * * @param pad Tool pad - * @return @b QAction* Pointer to Tie tool action + * @return @b QAction* Pointer to ControlNet tool action * * @internal * @history 2017-07-25 Tyler Wilson - Set the @@ -73,6 +74,8 @@ namespace Isis { QAction *action = new QAction(this); action->setIcon(QPixmap(toolIconDir()+"/HILLBLU_molecola.png")); action->setToolTip("Control Point Editor (T)"); + action->setStatusTip("If tool disabled, make sure you have a control net in your project and " + "it is set to the active control."); action->setShortcut(Qt::Key_T); //The object name is being set and used as a key to search with for this action in @@ -99,13 +102,16 @@ namespace Isis { */ void ControlNetTool::setControlNet(ControlNet *cnet) { m_controlNet = cnet; - // TODO: TLS 7-25-17 This method is called by Project::open before there are any viewports, - // so the following command seg faults. Need to add check for viewports or ?? - //paintAllViewports(); + // Cannot use Tool::cubeViewportList() because it does not properly return a NULL if viewports + // don't exist. + if (workspace() && workspace()->cubeViewportList()) { + paintAllViewports(); + } } void ControlNetTool::loadNetwork() { + setControlNet(m_directory->project()->activeControl()->controlNet()); } @@ -122,7 +128,7 @@ namespace Isis { */ void ControlNetTool::mouseButtonRelease(QPoint p, Qt::MouseButton s) { MdiCubeViewport *cvp = cubeViewport(); - if (cvp == NULL) return; + if (m_controlNet == NULL || cvp == NULL) return; // Determine if the cvp is a Shape // Get all ShapeLists from Project diff --git a/isis/src/qisis/objs/ControlNetTool/ControlNetTool.h b/isis/src/qisis/objs/ControlNetTool/ControlNetTool.h index 1bc0ab089ba5a01eb4cf76b5de9d2a285658052d..de4ce7b7bac7c87dc33526a6c5004aa1de688f77 100644 --- a/isis/src/qisis/objs/ControlNetTool/ControlNetTool.h +++ b/isis/src/qisis/objs/ControlNetTool/ControlNetTool.h @@ -29,8 +29,8 @@ namespace Isis { class UniversalGroundMap; /** - * @brief ControlNetTool operations ipce, handles mouse events on views for control point editing - * for the ipce app. + * @brief ControlNetTool Handles mouse events on CubeDnViews for control point editing for the + * ipce app. * * @ingroup Visualization Tools * @@ -52,6 +52,12 @@ namespace Isis { * @history 2017-08-08 Cole Neubauer - Renamed from IpceTool. Fixes #5090. * @history 2017-08-09 Cole Neubauer - Added loadNetwork() for changing inbetween active * networks Fixes #4567 + * @history 2018-03-12 Tracie Sucharski - Fixed some documentation leftover from renaming from + * IpceTool. References #5090. + * @history 2018-03-27 Tracie Sucharski - Redraw cube viewports when a new control net is + * loaded. + * @history 2018-04-13 Tracie Sucharski - In mouseButtonRelease method return if a control net + * has not been set. */ class ControlNetTool : public Tool { Q_OBJECT diff --git a/isis/src/qisis/objs/ControlPointEditWidget/ControlPointEditWidget.cpp b/isis/src/qisis/objs/ControlPointEditWidget/ControlPointEditWidget.cpp index 0622c49712370aa9e965148b7929ae886cbd66e2..7e657d0df4cd2ed6c15f04f06afa22d7771a4012 100644 --- a/isis/src/qisis/objs/ControlPointEditWidget/ControlPointEditWidget.cpp +++ b/isis/src/qisis/objs/ControlPointEditWidget/ControlPointEditWidget.cpp @@ -579,21 +579,44 @@ namespace Isis { /** * New control network being edited * - * @param cnet (ControlNet *) The control network to edit - * @param filename (Qstring) Need filename to write to widget label. ControlNet doesn't - * contain a filename. + * @param cnet (Control *) The control network to edit + * * @internal */ void ControlPointEditWidget::setControl(Control *control) { // TODO more error checking + m_control = control; m_controlNet = control->controlNet(); m_cnetFileName = control->fileName(); + + m_cnetFileNameLabel->setText("Control Network: " + m_cnetFileName); setWindowTitle("Control Point Editor- Control Network File: " + m_cnetFileName); emit newControlNetwork(m_controlNet); } + /** + * New active control was set from ipce + * + * TODO: This will need to be redesigned with the ::setControl method to better handle editing + * points from different cnets. + */ + void ControlPointEditWidget::setControlFromActive() { + + if (m_directory->project()->activeControl()) { + m_control = m_directory->project()->activeControl(); + m_controlNet = m_control->controlNet(); + m_cnetFileName = m_control->fileName(); + + m_cnetFileNameLabel->setText("Control Network: " + m_cnetFileName); + setWindowTitle("Control Point Editor- Control Network File: " + m_cnetFileName); + + emit newControlNetwork(m_controlNet); + } + } + + /** * @brief Create a temporary measure to hold the ground point info for ground source * @@ -687,7 +710,6 @@ namespace Isis { FileName ControlPointEditWidget::findGroundFile() { FileName groundFile(m_editPoint->GetAprioriSurfacePointSourceFile()); - if (m_changeAllGroundLocation) { QFileInfo oldFile(groundFile.expanded()); QFileInfo newFile(m_newGroundDir, oldFile.fileName()); @@ -782,17 +804,35 @@ namespace Isis { // is selected if (controlPoint->Parent() == NULL) { m_editPoint = controlPoint; + // New point in editor, so colorize all save buttons + colorizeAllSaveButtons("red"); } else { m_editPoint = new ControlPoint; *m_editPoint = *controlPoint; + + // New point loaded, make sure all save button's text is default black color + colorizeAllSaveButtons("black"); } loadPoint(serialNumber); loadTemplateFile(m_measureEditor->templateFileName()); + } + + + void ControlPointEditWidget::colorizeAllSaveButtons(QString color) { - // New point loaded, make sure Save Measure Button text is default + if (color == "black") { + // Don't need to colorize save measure button, when loading new measure, the measure editor + // will set back to default palette. m_savePoint->setPalette(m_saveDefaultPalette); + m_saveNet->setPalette(m_saveDefaultPalette); + } + else if (color == "red") { + m_measureEditor->colorizeSaveButton(); + colorizeSavePointButton(); + colorizeSaveNetButton(); + } } @@ -1005,7 +1045,7 @@ namespace Isis { Camera *cam; for (int i = 0; i < m_serialNumberList->size(); i++) { -// if (m_serialNumberList->serialNumber(i) == m_groundSN) continue; + if (m_serialNumberList->serialNumber(i) == m_groundSN) continue; cam = m_controlNet->Camera(i); if (cam->SetUniversalGround(latitude, longitude)) { // Make sure point is within image boundary @@ -1159,7 +1199,7 @@ namespace Isis { } } - this->setVisible(false); + //this->setVisible(false); // remove this point from the control network if (m_controlNet->DeletePoint(m_editPoint->GetId()) == ControlPoint::PointLocked) { @@ -1168,8 +1208,8 @@ namespace Isis { return; } if (m_editPoint != NULL && m_editPoint->Parent() == NULL) { - delete m_editPoint; - m_editPoint = NULL; +// delete m_editPoint; +// m_editPoint = NULL; } } @@ -1224,6 +1264,7 @@ namespace Isis { // emit a signal to alert user to save when exiting emit cnetModified(); + emit saveControlNet(); if (m_editPoint != NULL) { // Change Save Point button text to red @@ -2443,12 +2484,18 @@ namespace Isis { * * @author 2014-07-11 Tracie Sucharski */ - void ControlPointEditWidget::colorizeSaveNetButton() { + void ControlPointEditWidget::colorizeSaveNetButton(bool reset) { + if (reset) { + // Change Save Net button text back to default black + m_saveNet->setPalette(m_saveDefaultPalette); + } + else { QColor qc = Qt::red; QPalette p = m_savePoint->palette(); p.setColor(QPalette::ButtonText,qc); m_saveNet->setPalette(p); + } } @@ -2490,7 +2537,7 @@ namespace Isis { */ void ControlPointEditWidget::saveNet() { - m_controlNet->Write(m_cnetFileName); + m_control->write(); // Change Save Measure button text back to default m_saveNet->setPalette(m_saveDefaultPalette); @@ -2499,7 +2546,8 @@ namespace Isis { } - /** + /** + * This was used when ipce used docked widgets. * This method is called from the constructor so that when the * Main window is created, it know's it's size and location. * diff --git a/isis/src/qisis/objs/ControlPointEditWidget/ControlPointEditWidget.h b/isis/src/qisis/objs/ControlPointEditWidget/ControlPointEditWidget.h index 735120a675dd0124bc53903762fbb1725cb89b14..29e62dae70160a281975101be1f8090a28cf4048 100644 --- a/isis/src/qisis/objs/ControlPointEditWidget/ControlPointEditWidget.h +++ b/isis/src/qisis/objs/ControlPointEditWidget/ControlPointEditWidget.h @@ -49,7 +49,7 @@ namespace Isis { class UniversalGroundMap; /** - * @brief Gui for editing ControlPoint + * @brief Gui for editing ControlPoints in ipce application * * @ingroup Visualization Tools * @@ -66,8 +66,8 @@ namespace Isis { * @history 2017-08-02 Tracie Sucharski - Added methods to return the current editPoint and * current editPoint Id. Removed measure table methods. Fixes #5007, * #5008. - * @history 2017-08-09 Adam Goins - Changed method references of SerialNumberList.Delete() to - * SerialNumberList.remove() + * @history 2017-08-09 Adam Goins - Changed method references of SerialNumberList.Delete() to + * SerialNumberList.remove() * @history 2017-08-09 Christopher Combs - Added QPushButton and slot for reloading a point's * measures in the ChipViewports. Fixes #5070. * @history 2017-08-09 Christopher Combs - Added Apriori Latitude, Longitude, and Radius to @@ -78,6 +78,18 @@ namespace Isis { * Fixes #4984. * @history 2017-08-15 Tracie Sucharski - When ControlPoint is deleted, set the visibility of * this widget to false, then to true in loadPoint(). Fixes #5073. + * @history 2018-03-23 Tracie Sucharski - Update the cnet filename with current cnet when it is + * changed. + * @history 2018-03-26 Tracie Sucharski - Added slot, setControlFromActive which update editor + * if a new active control net is set in ipce. References #4567. + * @history 2018-03-30 Tracie Sucharski - Save Control in addition to the control net and use + * Control to write the control net so Control can keep track of the + * modification state of the control net. + * @history 2018-04-25 Tracie Sucharski - Fix bug when creating a control point from CubeDnView + * or FootprintView if a ground source exists in the serial number list. + * Fixes #5399. + * @history 2018-05-02 Tracie Sucharski - Colorize save buttons properly when creating new + * control point and loading a different control point. */ class ControlPointEditWidget : public QWidget { Q_OBJECT @@ -99,11 +111,13 @@ namespace Isis { void newControlNetwork(ControlNet *); void stretchChipViewport(Stretch *, CubeViewport *); void measureChanged(); + // temporary signal for quick & dirty autosave in Ipce void saveControlNet(); public slots: void setSerialNumberList(SerialNumberList *snList); void setControl(Control *control); + void setControlFromActive(); void setEditPoint(ControlPoint *controlPoint, QString serialNumber = ""); void deletePoint(ControlPoint *controlPoint); @@ -111,6 +125,11 @@ namespace Isis { bool isGroundSource = false); void updatePointInfo(ControlPoint &updatedPoint); + // Changed colorizeSaveNetButton to public slot so it could be called from + // Directory::saveActiveControl(). This should be temporary until the modify/save functionality + // of active control is re-factored. Also added reset parameter, defaulting to false so button + // is red. This default was used so that current calls did not need to be changed. + void colorizeSaveNetButton(bool reset = false); protected: bool eventFilter(QObject *o,QEvent *e); @@ -138,6 +157,8 @@ namespace Isis { void measureSaved(); void checkReference(); void savePoint(); + + void colorizeAllSaveButtons(QString color); void colorizeSavePointButton(); void openTemplateFile(); @@ -150,8 +171,6 @@ namespace Isis { void writeTemplateFile(QString); void clearEditPoint(); - void colorizeSaveNetButton(); - private: void createActions(); @@ -232,9 +251,10 @@ namespace Isis { QPointer<QMainWindow> m_measureWindow; //!< Main window for the the measure table widget QPointer<QTableWidget> m_measureTable; //!< Table widget for the measures - QPointer<ControlPoint> m_editPoint; //!< The control point being edited + QPointer<ControlPoint> m_editPoint; //!< The control point being edited SerialNumberList *m_serialNumberList; //!< Serial number list for the loaded cubes - QPointer<ControlNet> m_controlNet; //!< Current control net + QPointer<ControlNet> m_controlNet; //!< Current control net + QPointer<Control> m_control; //!< Current Control QPointer<ControlPoint> m_newPoint; //!< New control point QString m_lastUsedPointId; //!< Point id of the last used control point diff --git a/isis/src/qisis/objs/Directory/BundleObservationViewWorkOrder.cpp b/isis/src/qisis/objs/Directory/BundleObservationViewWorkOrder.cpp index 65eb26e5229c9e497ee41a54a1248945b4ebca2a..cd553f2ac94a09d0347c431fea78948a476c80bd 100755 --- a/isis/src/qisis/objs/Directory/BundleObservationViewWorkOrder.cpp +++ b/isis/src/qisis/objs/Directory/BundleObservationViewWorkOrder.cpp @@ -25,6 +25,7 @@ #include "Directory.h" #include "BundleObservationView.h" #include "Project.h" +#include "ProjectItemModel.h" namespace Isis { @@ -113,7 +114,7 @@ namespace Isis { * */ void BundleObservationViewWorkOrder::execute() { - //ProjectItem * selectedItem = project()->directory()->model()->selectedItems(); +// ProjectItem * selectedItem = project()->directory()->model()->selectedItems(); project()->directory()->addBundleObservationView(fileItem()); project()->setClean(false); } diff --git a/isis/src/qisis/objs/Directory/CnetEditorViewWorkOrder.cpp b/isis/src/qisis/objs/Directory/CnetEditorViewWorkOrder.cpp index e565f110bb79f06586fe155da4a3d0d03e65a18d..9553e11e2da820e17f2c283fe7dac81ca8a28537 100644 --- a/isis/src/qisis/objs/Directory/CnetEditorViewWorkOrder.cpp +++ b/isis/src/qisis/objs/Directory/CnetEditorViewWorkOrder.cpp @@ -24,17 +24,13 @@ #include <QtDebug> -#include <QFileDialog> -#include <QInputDialog> -#include <QMessageBox> +#include <QAction> +#include <QUndoCommand> -#include "CnetEditorWidget.h" +#include "CnetEditorView.h" #include "Control.h" #include "ControlList.h" -#include "ControlDisplayProperties.h" #include "Directory.h" -#include "MosaicSceneItem.h" -#include "MosaicSceneWidget.h" #include "Project.h" namespace Isis { diff --git a/isis/src/qisis/objs/Directory/CnetEditorViewWorkOrder.h b/isis/src/qisis/objs/Directory/CnetEditorViewWorkOrder.h index ac70e046582035cc20e21a347b56bc6bac596621..b069b97d5fd403cd16e59013dd23714bb23a8676 100644 --- a/isis/src/qisis/objs/Directory/CnetEditorViewWorkOrder.h +++ b/isis/src/qisis/objs/Directory/CnetEditorViewWorkOrder.h @@ -25,6 +25,10 @@ #include "WorkOrder.h" namespace Isis { +class ControlList; +class Directory; +class Project; + /** * @brief This work order allows the user to open a cnet editor (table) view of a single control network. * This workorder is synchronous and undoable. @@ -42,6 +46,7 @@ namespace Isis { * @history 2017-11-02 Tyler Wilson - Added a null pointer check on the ControList *controls * pointer in the isExecutable(...) function to prevent potential * segfaults. References #4492. + * @history 2018-04-07 Tracie Sucharski - Clean up includes. */ class CnetEditorViewWorkOrder : public WorkOrder { Q_OBJECT diff --git a/isis/src/qisis/objs/Directory/Directory.cpp b/isis/src/qisis/objs/Directory/Directory.cpp index c7a2dafc82226e169dc4e2ae2eab30553eab94f7..ea9f9194872e92d948262d1d9f63bd5e047cc047 100644 --- a/isis/src/qisis/objs/Directory/Directory.cpp +++ b/isis/src/qisis/objs/Directory/Directory.cpp @@ -45,12 +45,14 @@ #include "BundleObservationViewWorkOrder.h" #include "ChipViewportsWidget.h" #include "CloseProjectWorkOrder.h" +#include "CnetEditorView.h" #include "CnetEditorViewWorkOrder.h" #include "CnetEditorWidget.h" #include "Control.h" #include "ControlDisplayProperties.h" #include "ControlList.h" #include "ControlNet.h" +#include "ControlNetTool.h" #include "ControlPointEditView.h" #include "ControlPointEditWidget.h" #include "CubeDnView.h" @@ -110,8 +112,6 @@ namespace Isis { * because the WorkOrders we are attempting to add to the Directory are corrupt. */ Directory::Directory(QObject *parent) : QObject(parent) { - //qDebug()<<"Directory::Directory"; - try { m_project = new Project(*this); @@ -131,17 +131,18 @@ namespace Isis { //connect( m_project, SIGNAL(guiCamerasAdded(GuiCameraList *) ), //this, SLOT(guiCamerasAddedToProject(GuiCameraList *) ) ); - connect( m_project, SIGNAL(projectLoaded(Project *) ), + connect( m_project, SIGNAL(projectLoaded(Project *) ), this, SLOT(updateRecentProjects(Project *) ) ); + connect(this, SIGNAL(cnetModified()), m_project, SLOT(activeControlModified())); connect(m_project, SIGNAL(activeControlSet(bool)), this, SLOT(newActiveControl(bool))); + connect(m_project, SIGNAL(discardActiveControlEdits()), + this, SLOT(reloadActiveControlInCnetEditorView())); m_projectItemModel = new ProjectItemModel(this); m_projectItemModel->addProject(m_project); - connect(m_projectItemModel, SIGNAL(cleanProject(bool)), SIGNAL(cleanProject(bool))); - -// qDebug()<<"Directory::Directory model row counter after addProject = "<<m_projectItemModel->rowCount(); + connect(m_projectItemModel, SIGNAL(cleanProject(bool)), this, SIGNAL(cleanProject(bool))); try { @@ -531,15 +532,46 @@ namespace Isis { } + /** + * @description This slot was created specifically for the CnetEditorWidgets when user chooses a + * new active control and wants to discard any edits in the old active control. The only view + * which will not be updated with the new control are any CnetEditorViews showing the old active + * control. CnetEditorWidget classes do not have the ability to reload a control net, so the + * CnetEditor view displaying the old control is removed, then recreated. + * + */ + void Directory::reloadActiveControlInCnetEditorView() { + + foreach(CnetEditorView *cnetEditorView, m_cnetEditorViewWidgets) { + if (cnetEditorView->control() == project()->activeControl()) { + emit viewClosed(cnetEditorView); + project()->activeControl()->closeControlNet(); + project()->activeControl()->openControlNet(); + addCnetEditorView(project()->activeControl()); + } + } + } + + void Directory::newActiveControl(bool newControl) { - foreach(CnetEditorWidget *cnetEditorView, m_cnetEditorViewWidgets) { - if (cnetEditorView->control() == project()->activeControl()->controlNet()) { - cnetEditorView->pointTableView()->content()->setActiveControlNet(true); - cnetEditorView->measureTableView()->content()->setActiveControlNet(true); + +// if (newControl && m_controlPointEditViewWidget) { +// bool closed = m_controlPointEditViewWidget->close(); +// qDebug()<<"Directory::newActiveControl CPEditor closed = "<<closed; +// emit viewClosed(m_controlPointEditViewWidget); +// delete m_controlPointEditViewWidget; +// } + + // If the new active control is the same as what is showing in the cnetEditorWidget, allow + // editing of control points from the widget, otherwise turnoff from context menu + foreach(CnetEditorView *cnetEditorView, m_cnetEditorViewWidgets) { + if (cnetEditorView->control() == project()->activeControl()) { + cnetEditorView->cnetEditorWidget()->pointTableView()->content()->setActiveControlNet(true); + cnetEditorView->cnetEditorWidget()->measureTableView()->content()->setActiveControlNet(true); } else { - cnetEditorView->pointTableView()->content()->setActiveControlNet(false); - cnetEditorView->measureTableView()->content()->setActiveControlNet(false); + cnetEditorView->cnetEditorWidget()->pointTableView()->content()->setActiveControlNet(false); + cnetEditorView->cnetEditorWidget()->measureTableView()->content()->setActiveControlNet(false); } } } @@ -567,20 +599,34 @@ namespace Isis { m_bundleObservationViews.append(result); QString str = fileItem->fileName(); + FileName fileName = fileItem->fileName(); + + // strip out bundle results name from fileName + QString path = fileName.originalPath(); + int pos = path.lastIndexOf("/"); + QString bundleResultsName = ""; + if (pos != -1) { + bundleResultsName = path.remove(0,pos+1); + } + if (str.contains("bundleout")) { + result->setWindowTitle( tr("Summary (%1)"). + arg( bundleResultsName ) ); + result->setObjectName( result->windowTitle() ); + } if (str.contains("residuals")) { - result->setWindowTitle( tr("Measure Residuals"). - arg( m_bundleObservationViews.count() ) ); + result->setWindowTitle( tr("Measure Residuals (%1)"). + arg( bundleResultsName ) ); result->setObjectName( result->windowTitle() ); } else if (str.contains("points")) { - result->setWindowTitle( tr("Control Points"). - arg( m_bundleObservationViews.count() ) ); + result->setWindowTitle( tr("Control Points (%1)"). + arg( bundleResultsName ) ); result->setObjectName( result->windowTitle() ); } else if (str.contains("images")) { - result->setWindowTitle( tr("Images"). - arg( m_bundleObservationViews.count() ) ); + result->setWindowTitle( tr("Images (%1)"). + arg( bundleResultsName ) ); result->setObjectName( result->windowTitle() ); } @@ -592,92 +638,27 @@ namespace Isis { /** * @brief Add the widget for the cnet editor view to the window. - * @param network Control net to edit. - * @return @b (CnetEditorWidget *) The view to add to the window. + * @param Control to edit. + * @return @b (CnetEditorView *) The view to add to the window. */ - CnetEditorWidget *Directory::addCnetEditorView(Control *network) { - - QString title = tr("Cnet Editor View %1").arg( network->displayProperties()->displayName() ); + CnetEditorView *Directory::addCnetEditorView(Control *control) { + QString title = tr("Cnet Editor View %1").arg( control->displayProperties()->displayName() ); FileName configFile("$HOME/.Isis/" + QApplication::applicationName() + "/" + title + ".config"); - // TODO: This layout should be inside of the cnet editor widget, but I put it here to not - // conflict with current work in the cnet editor widget code. - QWidget *result = new QWidget; - QGridLayout *resultLayout = new QGridLayout; - result->setLayout(resultLayout); - - int row = 0; - - QMenuBar *menuBar = new QMenuBar; - resultLayout->addWidget(menuBar, row, 0, 1, 2); - row++; - CnetEditorWidget *mainWidget = new CnetEditorWidget(network, configFile.expanded()); - resultLayout->addWidget(mainWidget, row, 0, 1, 2); - row++; + CnetEditorView *result = new CnetEditorView(this, control, configFile); - // Populate the menu... - QMap< QAction *, QList< QString > > actionMap = mainWidget->menuActions(); - QMapIterator< QAction *, QList< QString > > actionMapIterator(actionMap); - - QMap<QString, QMenu *> topLevelMenus; - - while ( actionMapIterator.hasNext() ) { - actionMapIterator.next(); - QAction *actionToAdd = actionMapIterator.key(); - QList< QString > location = actionMapIterator.value(); - - QMenu *menuToPutActionInto = NULL; - - if ( location.count() ) { - QString topLevelMenuTitle = location.takeFirst(); - if (!topLevelMenus[topLevelMenuTitle]) { - topLevelMenus[topLevelMenuTitle] = menuBar->addMenu(topLevelMenuTitle); - } - - menuToPutActionInto = topLevelMenus[topLevelMenuTitle]; - } - - foreach (QString menuName, location) { - bool foundSubMenu = false; - foreach ( QAction *possibleSubMenu, menuToPutActionInto->actions() ) { - if (!foundSubMenu && - possibleSubMenu->menu() && possibleSubMenu->menu()->title() == menuName) { - foundSubMenu = true; - menuToPutActionInto = possibleSubMenu->menu(); - } - } - - if (!foundSubMenu) { - menuToPutActionInto = menuToPutActionInto->addMenu(menuName); - } - } - - menuToPutActionInto->addAction(actionToAdd); + if (project()->activeControl() && (control == project()->activeControl())) { + result->cnetEditorWidget()->pointTableView()->content()->setActiveControlNet(true); + result->cnetEditorWidget()->measureTableView()->content()->setActiveControlNet(true); } - QTabWidget *treeViews = new QTabWidget; - treeViews->addTab( mainWidget->pointTreeView(), tr("Point View") ); - treeViews->addTab( mainWidget->serialTreeView(), tr("Serial View") ); - treeViews->addTab( mainWidget->connectionTreeView(), tr("Connection View") ); - resultLayout->addWidget(treeViews, row, 0, 1, 1); - - QTabWidget *filterViews = new QTabWidget; - filterViews->addTab( mainWidget->pointFilterWidget(), tr("Filter Points and Measures") ); - filterViews->addTab( mainWidget->serialFilterWidget(), tr("Filter Images and Points") ); - filterViews->addTab( mainWidget->connectionFilterWidget(), tr("Filter Connections") ); - resultLayout->addWidget(filterViews, row, 1, 1, 1); - row++; - - if (project()->activeControl() && mainWidget->control() == project()->activeControl()->controlNet()) { - mainWidget->pointTableView()->content()->setActiveControlNet(true); - mainWidget->measureTableView()->content()->setActiveControlNet(true); - } - connect( result, SIGNAL( destroyed(QObject *) ), - this, SLOT( cleanupCnetEditorViewWidgets(QObject *) ) ); + // connect destroyed signal to cleanupCnetEditorViewWidgets slot + connect(result, SIGNAL( destroyed(QObject *) ), + this, SLOT( cleanupCnetEditorViewWidgets(QObject *) ) ); // Connections for control point editing between views - connect(mainWidget, SIGNAL(editControlPoint(ControlPoint *, QString)), + connect(result->cnetEditorWidget(), SIGNAL(editControlPoint(ControlPoint *, QString)), this, SLOT(modifyControlPoint(ControlPoint *, QString))); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -685,21 +666,21 @@ namespace Isis { // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // // Connection between cneteditor view & other views - connect(mainWidget, SIGNAL(cnetModified()), this, SIGNAL(cnetModified())); + connect(result->cnetEditorWidget(), SIGNAL(cnetModified()), this, SIGNAL(cnetModified())); // ControlPointEditWidget is only object that emits cnetModified when ControlPoint is // deleted or saved - connect(this, SIGNAL(cnetModified()), mainWidget, SLOT(rebuildModels())); + connect(this, SIGNAL(cnetModified()), result->cnetEditorWidget(), SLOT(rebuildModels())); - m_cnetEditorViewWidgets.append(mainWidget); - m_controlMap.insertMulti(network, result); + m_cnetEditorViewWidgets.append(result); + m_controlMap.insertMulti(control, result); result->setWindowTitle(title); result->setObjectName(title); emit newWidgetAvailable(result); - return mainWidget; + return result; } @@ -735,16 +716,19 @@ namespace Isis { connect(this, SIGNAL(redrawMeasures()), result, SIGNAL(redrawMeasures())); connect(this, SIGNAL(cnetModified()), result, SIGNAL(redrawMeasures())); - if (!project()->activeControl()) { - QList<QAction *> toolbar = result->toolPadActions(); - QAction* cnetAction = toolbar[0]; - MosaicControlNetTool *cnetButton = static_cast<MosaicControlNetTool *>(cnetAction->parent()); + // Note: This assumes the Control Net tool is the 1st in the toolpad. + QList<QAction *> toolbar = result->toolPadActions(); + QAction* cnetAction = toolbar[0]; + ControlNetTool *cnetTool = static_cast<ControlNetTool *>(cnetAction->parent()); + + connect (project(), SIGNAL(activeControlSet(bool)), + cnetAction, SLOT(setEnabled(bool))); + connect (project(), SIGNAL(activeControlSet(bool)), + cnetTool, SLOT(loadNetwork())); + // If an active control has not been set, make the control net tool inactive + if (!project()->activeControl()) { cnetAction->setEnabled(false); - connect (project(), SIGNAL(activeControlSet(bool)), - cnetAction, SLOT(setEnabled(bool))); - connect (project(), SIGNAL(activeControlSet(bool)), - cnetButton, SLOT(loadNetwork())); } return result; @@ -788,18 +772,19 @@ namespace Isis { // to be drawn with different color/shape. connect(this, SIGNAL(redrawMeasures()), result, SIGNAL(redrawMeasures())); - // Control Net tool will only be active if the project has an active Control. Note: This - // assumes the Control Net tool is the 4th in the toolpad. - if (!project()->activeControl()) { - QList<QAction *> toolbar = result->toolPadActions(); - QAction* cnetAction = toolbar[3]; - MosaicControlNetTool *cnetButton = static_cast<MosaicControlNetTool *>(cnetAction->parent()); + // Note: This assumes the Control Net tool is the 4th in the toolpad. + QList<QAction *> toolbar = result->toolPadActions(); + QAction* cnetAction = toolbar[3]; + MosaicControlNetTool *cnetTool = static_cast<MosaicControlNetTool *>(cnetAction->parent()); + connect (project(), SIGNAL(activeControlSet(bool)), + cnetAction, SLOT(setEnabled(bool))); + connect (project(), SIGNAL(activeControlSet(bool)), + cnetTool, SLOT(loadNetwork())); + + // Control Net tool will only be active if the project has an active Control. + if (!project()->activeControl()) { cnetAction->setEnabled(false); - connect (project(), SIGNAL(activeControlSet(bool)), - cnetAction, SLOT(setEnabled(bool))); - connect (project(), SIGNAL(activeControlSet(bool)), - cnetButton, SLOT(loadNetwork())); } return result; @@ -852,11 +837,17 @@ namespace Isis { // Create connections between signals from control point edit view and equivalent directory // signals that can then be connected to other views that display control nets. +// connect(mainWidget, SIGNAL(cnetModified()), +// this, SIGNAL(cnetModified())); connect(result->controlPointEditWidget(), SIGNAL(cnetModified()), this, SIGNAL(cnetModified())); + connect(result->controlPointEditWidget(), SIGNAL(cnetModified()), + m_project, SLOT(activeControlModified())); connect(result->controlPointEditWidget(), SIGNAL(saveControlNet()), this, SLOT(makeBackupActiveControl())); + connect (project(), SIGNAL(activeControlSet(bool)), + result->controlPointEditWidget(), SLOT(setControlFromActive())); } return controlPointEditView(); @@ -1053,25 +1044,44 @@ namespace Isis { * @brief Removes pointers to deleted CnetEditorWidget objects. */ void Directory::cleanupCnetEditorViewWidgets(QObject *obj) { - - CnetEditorWidget *cnetEditorWidget = static_cast<CnetEditorWidget *>(obj); - if (!cnetEditorWidget) { + + CnetEditorView *cnetEditorView = static_cast<CnetEditorView *>(obj); + if (!cnetEditorView) { return; } - Control *control = m_controlMap.key(cnetEditorWidget); - - m_controlMap.remove(control, cnetEditorWidget); + Control *control = m_controlMap.key(cnetEditorView); + m_controlMap.remove(control, cnetEditorView); - if ( m_controlMap.count(control) == 0 && project()->activeControl() != control) { + if ( m_controlMap.count(control) == 0 && project()->activeControl() != control) { control->closeControlNet(); } - m_cnetEditorViewWidgets.removeAll(cnetEditorWidget); + m_cnetEditorViewWidgets.removeAll(cnetEditorView); m_project->setClean(false); } + /** + * @description Return true if control is not currently being viewed in a CnetEditorWidget + * + * @param Control * Control used to search current CnetEditorWidgets + * + * @return @b (bool) Returns true if control is currently being viewed in CnetEditorWidget + */ + bool Directory::controlUsedInCnetEditorWidget(Control *control) { + + bool result; + if ( m_controlMap.count(control) == 0) { + result = false; + } + else { + result = true; + } + return result; + } + + /** * @brief Removes pointers to deleted CubeDnView objects. */ @@ -1123,6 +1133,7 @@ namespace Isis { if (!controlPointEditView) { return; } + m_controlPointEditViewWidget = NULL; m_project->setClean(false); } @@ -1205,12 +1216,12 @@ namespace Isis { /** * @brief Returns a list of all the control network views for this directory. - * @return @b QList<CnetEditorWidget *> A pointer list of all the CnetEditorWidget objects. + * @return @b QList<CnetEditorView *> A pointer list of all the CnetEditorWidget objects. */ - QList<CnetEditorWidget *> Directory::cnetEditorViews() { - QList<CnetEditorWidget *> results; + QList<CnetEditorView *> Directory::cnetEditorViews() { + QList<CnetEditorView *> results; - foreach (CnetEditorWidget *widget, m_cnetEditorViewWidgets) { + foreach (CnetEditorView *widget, m_cnetEditorViewWidgets) { results.append(widget); } @@ -1421,7 +1432,7 @@ namespace Isis { stream.writeStartElement("footprintViews"); foreach (Footprint2DView *footprint2DViewWidget, m_footprint2DViewWidgets) { - footprint2DViewWidget->mosaicSceneWidget()->save(stream, project(), newProjectRoot); + footprint2DViewWidget->save(stream, project(), newProjectRoot); } stream.writeEndElement(); @@ -1442,7 +1453,7 @@ namespace Isis { if ( !m_cnetEditorViewWidgets.isEmpty() ) { stream.writeStartElement("cnetEditorViews"); - foreach (CnetEditorWidget *cnetEditorWidget, m_cnetEditorViewWidgets) { + foreach (CnetEditorView *cnetEditorWidget, m_cnetEditorViewWidgets) { cnetEditorWidget->save(stream, project(), newProjectRoot); } @@ -1491,7 +1502,7 @@ namespace Isis { if (result) { if (localName == "footprint2DView") { - m_directory->addFootprint2DView()->mosaicSceneWidget()->load(reader()); + m_directory->addFootprint2DView()->load(reader()); } else if (localName == "imageFileList") { m_directory->addImageFileListView()->load(reader()); @@ -1780,6 +1791,22 @@ namespace Isis { } + /** + * Save the current active control. + * + */ + void Directory::saveActiveControl() { + + if (project()->activeControl()) { + project()->activeControl()->write(); + // add to HistoryTreeWidget + QString saveCnetHistoryEntry = project()->activeControl()->fileName() + + "has been saved."; + m_historyTreeWidget->addToHistory(saveCnetHistoryEntry); + } + } + + /** * Autosave for control net. The control net is auto saved to the same directory as the input * net. It is saved to controlNetFilename.net.bak. diff --git a/isis/src/qisis/objs/Directory/Directory.h b/isis/src/qisis/objs/Directory/Directory.h index 4f10a760e3baaca1188be1dc86cc46455678ab74..938ff71c6aa8ff46d41c6db254857392b2c8abe6 100644 --- a/isis/src/qisis/objs/Directory/Directory.h +++ b/isis/src/qisis/objs/Directory/Directory.h @@ -49,6 +49,7 @@ namespace Isis { class BundleObservation; class BundleObservationView; class ChipViewportsWidget; + class CnetEditorView; class CnetEditorWidget; class Control; class ControlNet; @@ -206,6 +207,35 @@ namespace Isis { * projects. Fixes #5216. * @history 2017-12-05 Christopher Combs - Added support for TemplateEditorWidget and * TemplateEditViewWorkOrder. Fixes #5168. + * @history 2018-03-14 Ken Edmundson - Modified m_controlMap value from QWidget to + * CnetEditorWidget and changed connection to take signal from + * a CnetEditorWidget instead of a QWidget for destruction of + * CnetEditorWidgets. Added ability to view bundleout.txt file in method + * addBundleObservationView. + * @history 2018-03-14 Tracie Sucharski - Changed MosaicControlNetTool to ControlNetTool in + * addCubeDnView. Added method controlUsedInCnetEditorWidget so Project + * knows whether it is safe to close a control net when a new active is + * set. References #5026. + * @history 2018-03-30 Tracie Sucharski - Use the Control::write to write the control net to + * disk instead of directly calling ControlNet::Write, so that the + * Control can keep track of the modified status of the control net. + * Connect cnetModified signal to Project::activeControlModified so + * modified state of the active control can be set so project knows + * that control has unsaved changes. + * @history 2018-04-02 Tracie Sucharski - Cleanup m_controlPointEditViewWidget pointer when + * the ControlPointEditView is deleted. Added slot to reload the active + * control net in cneteditor view, effectively discarding any edits. + * This was done because there is no way to re-load a control net in the + * CnetEditor widget classes. + * @history 2018-04-04 Tracie Sucharski - Created CnetEditorView class to use to add to QMdiArea + * instead of a CnetEditorWidget. This way there is no longer a + * disconnect between what has been added to the QMdiArea and what is + * stored in m_cnetEditorViewWidgets. + * @history 2018-05-08 Tracie Sucharski - When saving active control, reset the "Save Net" + * button to black in the ControlPointEditorWidget. + * @history 2018-05-14 Tracie Sucharski - Serialize Footprint2DView rather than + * MosaicSceneWidget. This will allow all parts of Footprint2DView to be + * saved/restored including the ImageFileListWidget. Fixes #5422. */ class Directory : public QObject { Q_OBJECT @@ -220,7 +250,7 @@ namespace Isis { QStringList recentProjectsList(); BundleObservationView *addBundleObservationView(FileItemQsp fileItem); - CnetEditorWidget *addCnetEditorView(Control *network); + CnetEditorView *addCnetEditorView(Control *control); CubeDnView *addCubeDnView(); Footprint2DView *addFootprint2DView(); MatrixSceneWidget *addMatrixView(); @@ -249,7 +279,7 @@ namespace Isis { QList<QAction *> toolPadActions(); QList<BundleObservationView *> bundleObservationViews(); - QList<CnetEditorWidget *> cnetEditorViews(); + QList<CnetEditorView *> cnetEditorViews(); QList<CubeDnView *> cubeDnViews(); QList<Footprint2DView *> footprint2DViews(); QList<MatrixSceneWidget *> matrixViews(); @@ -261,6 +291,8 @@ namespace Isis { ControlPointEditView *controlPointEditView(); // ChipViewportsWidget *controlPointChipViewports(); + bool controlUsedInCnetEditorWidget(Control *control); + // Return the control point Id currently in the ControlPointEditWidget, if it exists QString editPointId(); @@ -324,6 +356,8 @@ namespace Isis { void newWarning(); void newWidgetAvailable(QWidget *newWidget); + void viewClosed(QWidget *widget); + void cnetModified(); void redrawMeasures(); @@ -343,6 +377,7 @@ namespace Isis { //void imagesAddedToProject(ImageList *images); void updateControlNetEditConnections(); + void saveActiveControl(); // TODO temporary slot until autosave is implemented void makeBackupActiveControl(); @@ -360,6 +395,7 @@ namespace Isis { private slots: void initiateRenameProjectWorkOrder(QString projectName); void newActiveControl(bool newControl); + void reloadActiveControlInCnetEditorView(); private: /** @@ -415,7 +451,7 @@ namespace Isis { //!< List of BundleObservationView QList< QPointer<BundleObservationView> > m_bundleObservationViews; - QList< QPointer<CnetEditorWidget> > m_cnetEditorViewWidgets; //!< List of CnetEditorWidgets + QList< QPointer<CnetEditorView> > m_cnetEditorViewWidgets; //!< List of CnetEditorViews QList< QPointer<CubeDnView> > m_cubeDnViewWidgets; //!< List of CubeDnCiew obs QList< QPointer<ImageFileListWidget> > m_fileListWidgets; //!< List of ImageFileListWidgets QList< QPointer<Footprint2DView> > m_footprint2DViewWidgets; //!< List of Footprint2DView objs @@ -458,7 +494,7 @@ namespace Isis { QList<QAction *> m_activeToolBarActions; //!< List of active ToolBar actions QList<QAction *> m_toolPadActions; //!< List of ToolPad actions - QMultiMap<Control*, QWidget*> m_controlMap; //!< Map to hold every view with an open Control + QMultiMap<Control*, CnetEditorView *> m_controlMap; //!< Map to hold every view with an open Control QString m_editPointId; //!< Current control point that is in the ControlPointEditWidget diff --git a/isis/src/qisis/objs/Directory/ExportControlNetWorkOrder.cpp b/isis/src/qisis/objs/Directory/ExportControlNetWorkOrder.cpp index b0ccfce9e7ffe6521771b29f5ffa200581bad608..a7c43d919f8032c1075cc7ec1444b394529468a0 100644 --- a/isis/src/qisis/objs/Directory/ExportControlNetWorkOrder.cpp +++ b/isis/src/qisis/objs/Directory/ExportControlNetWorkOrder.cpp @@ -48,6 +48,7 @@ namespace Isis { m_isSynchronous = false; m_isUndoable = false; QAction::setText(tr("&Export Control Network...")); + QUndoCommand::setText(tr("Export Control Network...")); } @@ -97,7 +98,6 @@ namespace Isis { * true indicates that there is one control list in the project. */ bool ExportControlNetWorkOrder::isExecutable(ControlList *controls) { - // TODO: This shouldn't be executable (in the menu) if there are no imported control networks? if (controls) { return (controls->count() == 1); @@ -123,21 +123,19 @@ namespace Isis { QStringList internalData; Control *control = NULL; + // See if there are any other control lists in the project and give these to the user as // choices for control nets they can export. - - - if(project()) { + if (project()) { Project *proj = project(); QList<ControlList *> controls = proj->controls(); if (controls.count() > 0) { - ControlList *l=controls.first(); + ControlList *l = controls.first(); WorkOrder::setData(l); control = controlList()->first(); } - else { QMap<Control *, QString> cnetChoices; @@ -156,8 +154,6 @@ namespace Isis { control = cnetChoices.key(choice); internalData.append(control->id()); - - } } @@ -201,11 +197,9 @@ namespace Isis { control = controlList()->first(); } - try { - control->controlNet()->Write(destination); - } - catch (IException &e) { - m_warning = e.toString(); + QString currentLocation = control->fileName(); + if (!QFile::copy(currentLocation, destination) ) { + m_warning = "Error saving control net."; } } diff --git a/isis/src/qisis/objs/Directory/ExportControlNetWorkOrder.h b/isis/src/qisis/objs/Directory/ExportControlNetWorkOrder.h index cfef357b21be951c94e3dd97323a9d3155aa4df0..1a393d21a1862976b26ba1d4cf184a33e4ddaa19 100644 --- a/isis/src/qisis/objs/Directory/ExportControlNetWorkOrder.h +++ b/isis/src/qisis/objs/Directory/ExportControlNetWorkOrder.h @@ -26,7 +26,12 @@ namespace Isis { * it no longer causes a segmentation fault when the user attempts * to export a control network from the file menu. Fixes #4760. * @history 2017-11-02 Tyler Wilson - Added a null pointer check on the controls variable in - * isExecutable to prevent potential seg faults. References #4492. + * isExecutable to prevent potential seg faults. References #4760. + * @history 2018-03-13 Tracie Sucharski - Added Undo text to prevent runtime warning. Also + * correct redmine ticket number in previous history entry. + * @history 2018-03-30 Tracie Sucharski - Copy the control net instead of writing. This will + * be faster and will prevent another control net from being read into + * memory. */ class ExportControlNetWorkOrder : public WorkOrder { Q_OBJECT diff --git a/isis/src/qisis/objs/Directory/ImportImagesWorkOrder.cpp b/isis/src/qisis/objs/Directory/ImportImagesWorkOrder.cpp index dfacd50a17bdb5029132110b1950b16077f1151c..60137383daff0fa235591333b525fa59001b8952 100644 --- a/isis/src/qisis/objs/Directory/ImportImagesWorkOrder.cpp +++ b/isis/src/qisis/objs/Directory/ImportImagesWorkOrder.cpp @@ -412,7 +412,9 @@ namespace Isis { projectImage->relocateDnData(FileName(destination).name()); } - // Set new ecub to readOnly + // Set new ecub to readOnly. When closing cube, the labels were being re-written because + // the cube was read/write. This caused a segfault when imported large number of images + // because of a label template file being opened too many times. projectImage->reopen(); delete input; diff --git a/isis/src/qisis/objs/Directory/ImportShapesWorkOrder.cpp b/isis/src/qisis/objs/Directory/ImportShapesWorkOrder.cpp index 988209bcdfe51c195d3a19f2827b0ad51bcf735a..efbb6d0666dc3b888a63b609ffcc5b1a0acae537 100644 --- a/isis/src/qisis/objs/Directory/ImportShapesWorkOrder.cpp +++ b/isis/src/qisis/objs/Directory/ImportShapesWorkOrder.cpp @@ -318,6 +318,11 @@ namespace Isis { projectShape->relocateDnData(FileName(destination).name()); } + // Set new ecub to readOnly. When closing cube, the labels were being re-written because + // the cube was read/write. This caused a segfault when imported large number of images + // because of a label template file being opened too many times. + projectShape->reopen(); + delete input; result = projectShape; diff --git a/isis/src/qisis/objs/Directory/ImportShapesWorkOrder.h b/isis/src/qisis/objs/Directory/ImportShapesWorkOrder.h index a173d832446fce82235e76781551e14aded4bf19..5bdd5d3813efa5ef45fabfd63e51150dd440dec2 100644 --- a/isis/src/qisis/objs/Directory/ImportShapesWorkOrder.h +++ b/isis/src/qisis/objs/Directory/ImportShapesWorkOrder.h @@ -56,6 +56,10 @@ namespace Isis { * @history 2017-11-02 Tyler Wilson - Added a null pointer check on the ProjectItem *item * pointer in isExecutable to prevent potential seg faults. * References #4492. + * @history 2018-04-19 Tracie Sucharski - Fixed bug when importing shapes without DN data. Ecub + * labels were not complete due to a resulting ecub not being closed + * properly in thread. The resulting ecub needs to be re-opened as + * readOnly to prevent this problem. Fixes #5274. */ class ImportShapesWorkOrder : public WorkOrder { Q_OBJECT diff --git a/isis/src/qisis/objs/Directory/JigsawWorkOrder.cpp b/isis/src/qisis/objs/Directory/JigsawWorkOrder.cpp index 2df93cfc6bad805335d84ec652b3046eef2db7fd..f08ae306d9ede9efb0c013b05038bc9d8e8617de 100644 --- a/isis/src/qisis/objs/Directory/JigsawWorkOrder.cpp +++ b/isis/src/qisis/objs/Directory/JigsawWorkOrder.cpp @@ -30,6 +30,7 @@ #include <QInputDialog> #include <QMessageBox> +#include "BundleSolutionInfo.h" #include "Control.h" #include "Directory.h" #include "JigsawDialog.h" @@ -114,12 +115,15 @@ namespace Isis { bool success = WorkOrder::setupExecution(); if (success) { + + QStringList internalData; + // Create a blocking setup dialog initially and check to make sure we get valid info JigsawSetupDialog setup(project()); if (setup.exec() == QDialog::Accepted) { m_bundleSettings = setup.bundleSettings(); if (setup.selectedControl()) { - setInternalData(QStringList(setup.selectedControl()->id())); + internalData.append(QStringList(setup.selectedControl()->id())); } // This else should not happen, the work order should be disabled if there are no controls. else { @@ -127,13 +131,22 @@ namespace Isis { QMessageBox::critical(qobject_cast<QWidget *>(parent()), "Error", msg); success = false; } + // set output control network file name + if (!setup.outputControlName().isEmpty()) { + internalData.append(setup.outputControlName()); + } + else { + QString msg = "You must set an output control network filename."; + QMessageBox::critical(qobject_cast<QWidget *>(parent()), "Error", msg); + success = false; + } } else { success = false; } + setInternalData(internalData); } - return success; } @@ -159,9 +172,16 @@ namespace Isis { * @see WorkOrder::execute() */ void JigsawWorkOrder::execute() { + + Project *proj = project(); + // Get the selected control and bundle settings and give them to the JigsawDialog for now. - Control *selectedControl = project()->control(internalData().first()); - JigsawDialog *runDialog = new JigsawDialog(project(), m_bundleSettings, selectedControl); + Control *selectedControl = proj->control(internalData().first()); + + QString outputControlFileName = internalData().at(1); + + JigsawDialog *runDialog = new JigsawDialog(project(), m_bundleSettings, selectedControl, + outputControlFileName); runDialog->setAttribute(Qt::WA_DeleteOnClose); runDialog->show(); } diff --git a/isis/src/qisis/objs/Directory/JigsawWorkOrder.h b/isis/src/qisis/objs/Directory/JigsawWorkOrder.h index 3d480e8149a1a9ea192ad66f08aef3c8b6387496..49f3d81f72ea6a554cda91310569c848638c07e0 100644 --- a/isis/src/qisis/objs/Directory/JigsawWorkOrder.h +++ b/isis/src/qisis/objs/Directory/JigsawWorkOrder.h @@ -48,7 +48,14 @@ namespace Isis { * @history 2017-04-25 Ian Humphrey - Modified tool tip text. Fixes #4819. * @history 2017-07-25 Cole Neubauer - Added project()->setClean call #4969 * @history 2017-07-25 Cole Neubauer - Moved project()->setClean call to JigsawDialog because - * the workorder does not actually execute the bundle adjustment #4960 + * the workorder does not actually execute the bundle adjustment #4960 + * @history 2018-03-22 Ken Edmundson - Modified setupExecution method to append output control + * network filename to internalData. Modified execute method to look for + * input control network in BundleSolutionInfos if not found under main + * part of project tree. + * @history 2018-03-23 Ken Edmundson - In execute method, removed search for input control + * network in BundleSolutionInfos. No longer needed as control is now + * properly saved in projects m_idToControlMap. */ class JigsawWorkOrder : public WorkOrder { Q_OBJECT diff --git a/isis/src/qisis/objs/Directory/SetActiveControlWorkOrder.cpp b/isis/src/qisis/objs/Directory/SetActiveControlWorkOrder.cpp index a797cea008c21c06bee4ec3dec2c287dd5d7c2a0..e8885bf84ea3ed46437501f2efd7b0c52ec42d6a 100644 --- a/isis/src/qisis/objs/Directory/SetActiveControlWorkOrder.cpp +++ b/isis/src/qisis/objs/Directory/SetActiveControlWorkOrder.cpp @@ -80,6 +80,7 @@ namespace Isis { */ bool SetActiveControlWorkOrder::isExecutable(ControlList *controls) { + // Return false if more than 1 control was selected or if selected is already active if (controls) { if (controls->size() != 1 || project()->activeControl() == controls->at(0)) { return false; diff --git a/isis/src/qisis/objs/Directory/SetActiveImageListWorkOrder.cpp b/isis/src/qisis/objs/Directory/SetActiveImageListWorkOrder.cpp index b70d7b41c0f873024243dee35879865203d4cdd0..36caf06e6f15fdb61d3c8537e5d624109dca6062 100644 --- a/isis/src/qisis/objs/Directory/SetActiveImageListWorkOrder.cpp +++ b/isis/src/qisis/objs/Directory/SetActiveImageListWorkOrder.cpp @@ -76,10 +76,9 @@ namespace Isis { * @return @b bool True if we can set as active, False otherwise. */ bool SetActiveImageListWorkOrder::isExecutable(ImageList *imageList) { - - if(!imageList) + if (imageList->name() == "") { return false; - + } if (project()->activeImageList()) { if (project()->activeImageList()->name() == imageList->name()) { return false; diff --git a/isis/src/qisis/objs/Directory/SetActiveImageListWorkOrder.h b/isis/src/qisis/objs/Directory/SetActiveImageListWorkOrder.h index 6da70ad98ea68be87eb827505edb05138201bfa8..fc7b256adcc58fe76e508390f3a6bc05d748a035 100644 --- a/isis/src/qisis/objs/Directory/SetActiveImageListWorkOrder.h +++ b/isis/src/qisis/objs/Directory/SetActiveImageListWorkOrder.h @@ -45,8 +45,8 @@ namespace Isis { * @history 2017-08-03 Cole Neubauer - Created a try catch around a previously unprotected * error to handle errors thrown in the workorder that halted * execution. Fixes #5026 - * @history 2017-11-02 Tyler Wilson - Added a null pointer reference check to imageList variable - * in isExecutable to prevent potential seg faults. References #4492. + * @history 2017-10-18 Adam Paquette - Added a logical check in the isExecutable function + * to check for single images vs image lists. Fixes #5138. */ class SetActiveImageListWorkOrder : public WorkOrder { diff --git a/isis/src/qisis/objs/Footprint2DView/Footprint2DView.cpp b/isis/src/qisis/objs/Footprint2DView/Footprint2DView.cpp index c7d7ed814e0d869b4de0647390bd639381820093..6fda9c72a21f20347adc7c66ece8b6205dfd6834 100644 --- a/isis/src/qisis/objs/Footprint2DView/Footprint2DView.cpp +++ b/isis/src/qisis/objs/Footprint2DView/Footprint2DView.cpp @@ -41,17 +41,21 @@ #include <QVBoxLayout> #include <QWidget> #include <QWidgetAction> +#include <QXmlStreamWriter> #include "ControlPoint.h" #include "Cube.h" +#include "Directory.h" #include "Image.h" #include "ImageFileListWidget.h" #include "MosaicGraphicsView.h" #include "MosaicSceneWidget.h" +#include "Project.h" #include "ProjectItem.h" #include "ProjectItemModel.h" #include "Shape.h" #include "ToolPad.h" +#include "XmlStackedHandlerReader.h" namespace Isis { /** @@ -351,4 +355,92 @@ namespace Isis { QList<QAction *> Footprint2DView::toolPadActions() { return m_toolPad->actions(); } + + + /** + * @brief Loads the Footprint2DView from an XML file. + * @param xmlReader The reader that takes in and parses the XML file. + */ + void Footprint2DView::load(XmlStackedHandlerReader *xmlReader) { + xmlReader->pushContentHandler( new XmlHandler(this) ); + } + + + /** + * @brief Save the footprint view widgets (ImageFileListWidget and MosaicSceneWidget to an XML + * file. + * @param stream The XML stream writer + * @param newProjectRoot The FileName of the project this Directory is attached to. + * + * @internal + * @history 2016-11-07 Ian Humphrey - Restored saving of footprints (footprint2view). + * References #4486. + */ + void Footprint2DView::save(QXmlStreamWriter &stream, Project *project, + FileName newProjectRoot) const { + + stream.writeStartElement("footprint2DView"); + + m_fileListWidget->save(stream, project, newProjectRoot); + m_sceneWidget->save(stream, project, newProjectRoot); + + stream.writeEndElement(); + } + + + /** + * @brief This function sets the Directory pointer for the Directory::XmlHandler class + * @param directory The new directory we are setting XmlHandler's member variable to. + */ + Footprint2DView::XmlHandler::XmlHandler(Footprint2DView *footprintView) { + + m_footprintView = footprintView; + } + + + /** + * @brief The Destructor for Directory::XmlHandler + */ + Footprint2DView::XmlHandler::~XmlHandler() { + } + + + /** + * @brief The XML reader invokes this method at the start of every element in the + * XML document. This method expects <footprint2DView/> and <imageFileList/> + * elements. + * A quick example using this function: + * startElement("xsl","stylesheet","xsl:stylesheet",attributes) + * + * @param namespaceURI The Uniform Resource Identifier of the element's namespace + * @param localName The local name string + * @param qName The XML qualified string (or empty, if QNames are not available). + * @param atts The XML attributes attached to each element + * @return @b bool Returns True signalling to the reader the start of a valid XML element. If + * False is returned, something bad happened. + * + */ + bool Footprint2DView::XmlHandler::startElement(const QString &namespaceURI, const QString &localName, + const QString &qName, const QXmlAttributes &atts) { + bool result = XmlStackedHandler::startElement(namespaceURI, localName, qName, atts); + + if (result) { + if (localName == "mosaicScene") { + m_footprintView->mosaicSceneWidget()->load(reader()); + } + if (localName == "imageFileList") { + m_footprintView->m_fileListWidget->load(reader()); + } + } + return result; + } + + + bool Footprint2DView::XmlHandler::endElement(const QString &namespaceURI, + const QString &localName, const QString &qName) { + bool result = XmlStackedHandler::endElement(namespaceURI, localName, qName); + + return result; + } } + diff --git a/isis/src/qisis/objs/Footprint2DView/Footprint2DView.h b/isis/src/qisis/objs/Footprint2DView/Footprint2DView.h index d3a7a4e3942095111522e9a5761dd43bb60376d0..821fe9ae7049e1ad641c86c1f64838b79e124ba4 100644 --- a/isis/src/qisis/objs/Footprint2DView/Footprint2DView.h +++ b/isis/src/qisis/objs/Footprint2DView/Footprint2DView.h @@ -27,12 +27,15 @@ #include <QSize> #include "AbstractProjectItemView.h" +#include "FileName.h" +#include "XmlStackedHandler.h" class QAction; class QEvent; class QMainWindow; class QToolBar; class QWidgetAction; +class QXmlStreamWriter; namespace Isis { @@ -41,7 +44,9 @@ namespace Isis { class Image; class ImageFileListWidget; class MosaicSceneWidget; + class Project; class ToolPad; + class XmlStackedHandlerReader; /** * View for displaying footprints of images in a QMos like way. @@ -64,6 +69,9 @@ namespace Isis { * footprint. Fixes #5050. * @history 2017-08-02 Tracie Sucharski - Fixed connections between views for control point * editing. Fixes #5007, #5008. + * @history 2018-05-14 Tracie Sucharski - Serialize Footprint2DView rather than + * MosaicSceneWidget. This will allow all parts of Footprint2DView to be + * saved/restored including the ImageFileListWidget. Fixes #5422. */ class Footprint2DView : public AbstractProjectItemView { @@ -80,6 +88,9 @@ namespace Isis { QSize sizeHint() const; + void load(XmlStackedHandlerReader *xmlReader); + void save(QXmlStreamWriter &stream, Project *project, FileName newProjectRoot) const; + signals: void modifyControlPoint(ControlPoint *controlPoint); void deleteControlPoint(ControlPoint *controlPoint); @@ -97,6 +108,28 @@ namespace Isis { void onQueueSelectionChanged(); void onMosItemRemoved(Image *image); + private: + /** + * @author 2018-05-11 Tracie Sucharski + * + * @internal + */ + class XmlHandler : public XmlStackedHandler { + public: + XmlHandler(Footprint2DView *footprintView); + ~XmlHandler(); + + virtual bool startElement(const QString &namespaceURI, const QString &localName, + const QString &qName, const QXmlAttributes &atts); + virtual bool endElement(const QString &namespaceURI, const QString &localName, + const QString &qName); + + private: + Q_DISABLE_COPY(XmlHandler); + + Footprint2DView *m_footprintView; //!< The Footprint2DView + }; + private: MosaicSceneWidget *m_sceneWidget; //!< The scene widget ImageFileListWidget *m_fileListWidget; //!< The file list widget diff --git a/isis/src/qisis/objs/HistoryTreeWidget/HistoryTreeWidget.cpp b/isis/src/qisis/objs/HistoryTreeWidget/HistoryTreeWidget.cpp index bfadb7dd13d0afce1ea048cdd2c1d6b99f53b5da..eeb4b0cb8fce81c4daa0d2f5b61c95f33288c9dd 100644 --- a/isis/src/qisis/objs/HistoryTreeWidget/HistoryTreeWidget.cpp +++ b/isis/src/qisis/objs/HistoryTreeWidget/HistoryTreeWidget.cpp @@ -159,6 +159,43 @@ namespace Isis { } + /** + * Add a non-workorder history to the display. + * + * @param (QString) historyEntry The string displayed in the history tree + */ + void HistoryTreeWidget::addToHistory(QString historyEntry) { + + QString data = historyEntry; + + QStringList columnData; + columnData.append(data); + + QTreeWidgetItem *newItem = new QTreeWidgetItem(columnData); + + + // Do font for progress text + QFont progressFont = newItem->font(1); + progressFont.setItalic(true); + newItem->setFont(1, progressFont); + newItem->setForeground(1, Qt::gray); + + this->insertTopLevelItem(0, newItem); +// invisibleRootItem()->addChild(newItem); + + //Sometimes the pointer returned by this call is 0 (hence the check). + //So we are not creating a progress bar for every work order which would + //include those that do not need it. + +// if(workOrder->progressBar() ) { +// setItemWidget(newItem, 1, new ProgressBar); +//// this->setItemWidget(newItem, 1, workOrder->progressBar() ); +// } + scrollToItem(newItem); + refit(); + } + + /** * We need to manually manage these progress widgets because QTreeWidget does a poor job of it. * This should be called when the progress bar instances have changed (new progress, lost a diff --git a/isis/src/qisis/objs/HistoryTreeWidget/HistoryTreeWidget.h b/isis/src/qisis/objs/HistoryTreeWidget/HistoryTreeWidget.h index e0867f806e8aa4ae17df611ecf467f6f0b8585c4..b32eaf7c56cf73dd1599cbfd9aaa41cced41dd55 100644 --- a/isis/src/qisis/objs/HistoryTreeWidget/HistoryTreeWidget.h +++ b/isis/src/qisis/objs/HistoryTreeWidget/HistoryTreeWidget.h @@ -40,6 +40,11 @@ namespace Isis { * @history 2017-11-08 Tyler Wilson - Reverted the code change in #5096 to restore the * ProgressBar, and changed code in OpenRecentProjectsWorkOrder.cpp * to prevent the segfault which #5096 was addressing. Fixes #5149. + * @history 2018-04-07 Tracie Sucharski - Added method to force a history entry using a string + * rather than a WorkOrder. This should be a temporary method until + * saving a control is turned into a WorkOrder. This was done for the + * alpha release simply to notify the user that the control was saved. + * However, this history entry is not saved/restored to a project. * */ class HistoryTreeWidget : public QTreeWidget { @@ -48,6 +53,8 @@ namespace Isis { HistoryTreeWidget(Project *project, QWidget *parent = 0); virtual ~HistoryTreeWidget(); + void addToHistory(QString historyEntry); + protected: int sizeHintForColumn(int column) const; diff --git a/isis/src/qisis/objs/ImageFileListWidget/ImageFileListWidget.cpp b/isis/src/qisis/objs/ImageFileListWidget/ImageFileListWidget.cpp index 40c1d94921d31b3475c5c349c98f0629481b8c4b..260afa2a5c8feb603666ca45dc9f090bd69af69b 100644 --- a/isis/src/qisis/objs/ImageFileListWidget/ImageFileListWidget.cpp +++ b/isis/src/qisis/objs/ImageFileListWidget/ImageFileListWidget.cpp @@ -217,15 +217,6 @@ namespace Isis { return output; } - /** - * This method pushes a new XmlHandler into the parser stack. - * - * @param xmlReader This is the parser stack. - */ - void ImageFileListWidget::load(XmlStackedHandlerReader *xmlReader) { - xmlReader->pushContentHandler(new XmlHandler(this)); - } - /** * This method calls ImageTreeWidget::actions() which sets up a QAction * that sets a default for the file list columns and returns a QList of @@ -611,6 +602,17 @@ namespace Isis { return result; } + + /** + * This method pushes a new XmlHandler into the parser stack. + * + * @param xmlReader This is the parser stack. + */ + void ImageFileListWidget::load(XmlStackedHandlerReader *xmlReader) { + xmlReader->pushContentHandler(new XmlHandler(this)); + } + + /** * This method saves the FootprintColumns in the project and the settings associated * with every column. @@ -621,10 +623,11 @@ namespace Isis { */ void ImageFileListWidget::save(QXmlStreamWriter &stream, Project *project, FileName newProjectRoot) const { + stream.writeStartElement("imageFileList"); // Write QSettings - stream.writeStartElement("widgetGeometry"); +// stream.writeStartElement("widgetGeometry"); // QString geom = saveGeometry(); // //qDebug()<<"ImageFileListWidget::save geometry = "<<geom; // stream.writeAttribute("value", saveGeometry()); @@ -672,6 +675,7 @@ namespace Isis { stream.writeEndElement(); } + /** * This method saves the QTreeWidgetItem and the settings associated with the QTreeWidgetItem * to the stream. @@ -758,7 +762,7 @@ namespace Isis { bool ImageFileListWidget::XmlHandler::startElement(const QString &namespaceURI, const QString &localName, const QString &qName, const QXmlAttributes &atts) { bool result = XmlStackedHandler::startElement(namespaceURI, localName, qName, atts); - /* //tjw + if (result) { // if (localName == "geometry") { @@ -826,7 +830,6 @@ namespace Isis { } } - */ return result; } @@ -905,6 +908,4 @@ namespace Isis { } } } - - } diff --git a/isis/src/qisis/objs/ImageFileListWidget/ImageFileListWidget.h b/isis/src/qisis/objs/ImageFileListWidget/ImageFileListWidget.h index 0af97c7b8801c7bcbb02301481c62630db8988f3..2573dbbd910849ff0bf68cd29e4a54ef37e68bf4 100644 --- a/isis/src/qisis/objs/ImageFileListWidget/ImageFileListWidget.h +++ b/isis/src/qisis/objs/ImageFileListWidget/ImageFileListWidget.h @@ -52,6 +52,8 @@ namespace Isis { * @history 2017-07-18 Cole Neubauer - Added removeImages slot to be able to remove from the * ImageFileList in IPCE Fixes #4996 * @history 2017-08-22 Cole Neuabuer - Added ability to search ImageFileListWidget. Fixes #1556 + * @history 2018-05-15 Tracie Sucharski - Fixed xml serialization for Ipce project saves. Fixes + * #5422. */ class ImageFileListWidget : public QWidget { Q_OBJECT diff --git a/isis/src/qisis/objs/JigsawDialog/JigsawDialog.cpp b/isis/src/qisis/objs/JigsawDialog/JigsawDialog.cpp index 00a725104ec47285a19670ed1663e0159ede079c..1494b1f4a75d3b2b3920fd09c506f5771a8226d0 100644 --- a/isis/src/qisis/objs/JigsawDialog/JigsawDialog.cpp +++ b/isis/src/qisis/objs/JigsawDialog/JigsawDialog.cpp @@ -56,12 +56,13 @@ namespace Isis { JigsawDialog::JigsawDialog(Project *project, BundleSettingsQsp bundleSettings, Control *selectedControl, + QString outputControlFileName, QWidget *parent) : QDialog(parent), m_ui(new Ui::JigsawDialog) { - m_project = project; m_bundleSettings = bundleSettings; m_selectedControl = selectedControl; m_selectedControlName = FileName(selectedControl->fileName()).name(); + m_outputControlName = outputControlFileName; init(); } @@ -108,7 +109,7 @@ namespace Isis { this, SLOT(rejectBundleResults())); m_bundleAdjust = NULL; - m_bundleSolutionInfo = NULL; +// m_bundleSolutionInfo = NULL; m_bRunning = false; @@ -137,9 +138,9 @@ namespace Isis { * Destructor. */ JigsawDialog::~JigsawDialog() { - if (m_bundleSolutionInfo) { - delete m_bundleSolutionInfo; - } +// if (m_bundleSolutionInfo) { +// delete m_bundleSolutionInfo; +// } if (m_bundleAdjust) { delete m_bundleAdjust; m_bundleAdjust = NULL; @@ -147,7 +148,7 @@ namespace Isis { if (m_ui) { delete m_ui; } - m_bundleSolutionInfo = NULL; +// m_bundleSolutionInfo = NULL; m_ui = NULL; } @@ -175,6 +176,7 @@ namespace Isis { if (setupdlg.exec() == QDialog::Accepted) { m_selectedControlName = setupdlg.selectedControlName(); + m_outputControlName = setupdlg.outputControlName(); m_selectedControl = setupdlg.selectedControl(); m_bundleSettings = setupdlg.bundleSettings(); // The settings have been modified, might be misleading to keep this check after setup. @@ -209,7 +211,8 @@ namespace Isis { } // Grab the control name that was used in that bundle adjustment. - m_selectedControlName = FileName(bundleSolutionInfo.last()->controlNetworkFileName()).name(); + m_selectedControlName + = FileName(bundleSolutionInfo.last()->inputControlNetFileName()).name(); } // Clear the dialog displays. @@ -379,12 +382,24 @@ namespace Isis { // Write text summary file m_bundleSolutionInfo->outputText(); - // create output control net - // Write the new jigged control net with correct path to results folder + runtime - FileName jiggedControlName(m_project->bundleSolutionInfoRoot() + "/" + runTime + "/" + - FileName(m_bundleSolutionInfo->controlNetworkFileName()).name()); + // create output control net file name + FileName outputControlName; + if (!m_outputControlName.isEmpty()) { + outputControlName + = FileName(m_project->bundleSolutionInfoRoot() + "/" + runTime + "/" + + m_outputControlName); + } + else { + outputControlName + = FileName(m_project->bundleSolutionInfoRoot() + "/" + runTime + "/Out-" + runTime + "-" + + FileName(m_bundleSolutionInfo->inputControlNetFileName()).name()); + } + + // Write output control net with correct path to results folder + runtime + m_bundleSolutionInfo->bundleResults().outputControlNet()->Write(outputControlName.toString()); - m_bundleSolutionInfo->bundleResults().outputControlNet()->Write(jiggedControlName.toString()); + // create Control with output control net and add to m_bundleSolutionInfo + m_bundleSolutionInfo->setOutputControl(new Control(m_project, outputControlName.expanded())); // Iterate through all of the image lists (the "imports" in the project). QList<ImageList *> imageLists = m_bundleSolutionInfo->imageList(); @@ -448,7 +463,8 @@ namespace Isis { } // Tell the project about the BundleSolutionInfo - m_project->addBundleSolutionInfo( new BundleSolutionInfo(*m_bundleSolutionInfo) ); +// m_project->addBundleSolutionInfo( new BundleSolutionInfo(*m_bundleSolutionInfo) ); + m_project->addBundleSolutionInfo(m_bundleSolutionInfo); // Make sure that when we add our results, we let the use last settings box be checkable. m_ui->useLastSettings->setEnabled(true); @@ -486,8 +502,8 @@ namespace Isis { // Cleanup the results (bundle solution info) // How does this affect m_bundleSettings or m_bundleAdjustment? // How does this affect using the last (most recent) settings for the run? - delete m_bundleSolutionInfo; - m_bundleSolutionInfo = NULL; +// delete m_bundleSolutionInfo; +// m_bundleSolutionInfo = NULL; } diff --git a/isis/src/qisis/objs/JigsawDialog/JigsawDialog.h b/isis/src/qisis/objs/JigsawDialog/JigsawDialog.h index d120cdf7f5b8df602975a40ce458678d9c11daab..01fb118dadf009a124951bafa176fdb2e4c7b0b4 100644 --- a/isis/src/qisis/objs/JigsawDialog/JigsawDialog.h +++ b/isis/src/qisis/objs/JigsawDialog/JigsawDialog.h @@ -79,6 +79,15 @@ namespace Isis { * accepted. Fixes #4960 * @history 2017-11-01 Ian Humphrey - Create ecubs in the bundle results directory which contain * updated SPICE. Fixes #4804, #4849. + * @history 2018-03-22 Ken Edmundson - Added member variable QString m_outputControlName. Added + * argument QString outputControlFileName to constructor. Modified + * acceptBundleResults method to take output control network filename + * from the JigsawSetupDialog. + * @history 2018-05-22 Ken Edmundson - Modified init() method to not set m_BundleSolutionInfo to + * NULL because JigsawDialog no longer owns it. Modified destructor to + * not delete m_BundleSolutionInfo or set it to NULL. Note this is NOT + * ideal, m_BundleSolutionInfo should be a QSharedPointer, not a raw + * pointer. */ class JigsawDialog : public QDialog { Q_OBJECT @@ -88,6 +97,7 @@ namespace Isis { explicit JigsawDialog(Project *project, BundleSettingsQsp bundleSettings, Control *selectedControl, + QString outputControlFileName, QWidget *parent = 0); ~JigsawDialog(); @@ -106,6 +116,7 @@ namespace Isis { Project *m_project; Control *m_selectedControl; QString m_selectedControlName; + QString m_outputControlName; BundleSettingsQsp m_bundleSettings; private: diff --git a/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.cpp b/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.cpp index 1d5109eb27b7db142702882d65756bf49074c789..97cbd74ea632085f80aa1cc9950c24ff732bba91 100644 --- a/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.cpp +++ b/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.cpp @@ -60,6 +60,19 @@ namespace Isis { m_ui->controlNetworkComboBox->addItem(control->displayProperties()->displayName(), v); } } + // add control nets from bundle solutions, if any + int numBundles = project->bundleSolutionInfo().size(); + for (int i = 0; i < numBundles; i++) { + Control *bundleControl = project->bundleSolutionInfo().at(i)->control(); + + QVariant v = qVariantFromValue((void*)bundleControl); + + m_ui->controlNetworkComboBox->addItem(bundleControl->displayProperties()->displayName(), v); + } + + // initialize default output control network filename + FileName fname = m_ui->controlNetworkComboBox->currentText(); + m_ui->outputControlNet->setText(fname.baseName() + "-out.net"); QList<BundleSolutionInfo *> bundleSolutionInfo = m_project->bundleSolutionInfo(); if (useLastSettings && bundleSolutionInfo.size() > 0) { @@ -67,7 +80,7 @@ namespace Isis { // Retrieve the control net name used in the last bundle adjustment. // Note that this returns a fully specified path and filename, while the cnet combo box // only stores file names. - selectControl(bundleSolutionInfo.last()->controlNetworkFileName()); + selectControl(bundleSolutionInfo.last()->inputControlNetFileName()); fillFromSettings(lastBundleSettings); } @@ -86,8 +99,6 @@ namespace Isis { m_ui->pointingAprioriSigmaTable->setHorizontalHeaderLabels(tableHeaders); - - // initializations for target body tab // fill target combo box from project @@ -679,6 +690,11 @@ namespace Isis { } + QString JigsawSetupDialog::outputControlName() { + return QString(m_ui->outputControlNet->text()); + } + + void JigsawSetupDialog::makeReadOnly() { m_ui->controlNetworkComboBox->setEnabled(false); m_ui->observationModeCheckBox->setEnabled(false); @@ -1100,4 +1116,9 @@ namespace Isis { void JigsawSetupDialog::hideTargetParametersGroupBox() { m_ui->targetParametersGroupBox->setEnabled(false); } + + void Isis::JigsawSetupDialog::on_controlNetworkComboBox_currentTextChanged(const QString &arg1) { + FileName fname = arg1; + m_ui->outputControlNet->setText(fname.baseName() + "-out.net"); + } } diff --git a/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.h b/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.h index ce80da8d40d0d4457eb4a445a9171921c19f221b..7cc6e2e5409562845c158a5c02d9f8db11660af9 100644 --- a/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.h +++ b/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.h @@ -50,6 +50,13 @@ namespace Isis { * allows for proper restoring of user defined weightings. * @history 2017-08-14 Summer Stapleton - Updated icons/images to properly licensed or open * source images. Fixes #5105. + * @history 2018-03-19 Ken Edmundson - Added bundle output control network file name. Added + * method on_controlNetworkComboBox_currentTextChanged to update the + * output control network filename when the input control network + * selected filename changes. E.g. if input control net name is + * fred.net, the output filename QLineEdit is automatically changed to + * fred-out.net. The user can always manually change the output control + * net name to anything they choose. */ class JigsawSetupDialog : public QDialog { @@ -63,9 +70,10 @@ namespace Isis { QWidget *parent = 0); ~JigsawSetupDialog(); - Control *selectedControl();// TODO: return const references ??? - QString selectedControlName();// TODO: return const references ??? - BundleSettingsQsp bundleSettings();// TODO: return const references ??? + Control *selectedControl(); // TODO: return const references ??? + QString selectedControlName(); // TODO: return const references ??? + QString outputControlName(); // TODO: return const references ??? + BundleSettingsQsp bundleSettings(); // TODO: return const references ??? void loadSettings(const BundleSettingsQsp settings); void selectControl(const QString &controlName); @@ -78,6 +86,7 @@ namespace Isis { // general tab void on_positionComboBox_currentIndexChanged(int index); void on_pointingComboBox_currentIndexChanged(int index); + void on_controlNetworkComboBox_currentTextChanged(const QString &arg1); // maximum liklihood tab void on_maximumLikelihoodModel1ComboBox_currentIndexChanged(int index); diff --git a/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.ui b/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.ui index ff00971a6f9a3ea9da5a95e695ae532880a26893..3fb99daa8bc32f6e9c8254a52c1872de1ae86963 100644 --- a/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.ui +++ b/isis/src/qisis/objs/JigsawSetupDialog/JigsawSetupDialog.ui @@ -43,7 +43,7 @@ </sizepolicy> </property> <property name="currentIndex"> - <number>5</number> + <number>3</number> </property> <widget class="QWidget" name="generalSettingsTab"> <attribute name="title"> @@ -94,8 +94,13 @@ <property name="enabled"> <bool>false</bool> </property> + <property name="font"> + <font> + <italic>false</italic> + </font> + </property> <property name="text"> - <string>Multiplier</string> + <string>&Multiplier</string> </property> <property name="alignment"> <set>Qt::AlignCenter</set> @@ -172,7 +177,7 @@ <item row="11" column="0"> <widget class="QLabel" name="sigma0ThresholdLabel"> <property name="text"> - <string>Sigma0Threshold</string> + <string>Sigma&0 Threshold</string> </property> <property name="buddy"> <cstring>sigma0ThresholdLineEdit</cstring> @@ -182,7 +187,7 @@ <item row="12" column="0"> <widget class="QLabel" name="maximumIterationsLabel"> <property name="text"> - <string>Maximum Iterations</string> + <string>Ma&ximum Iterations</string> </property> <property name="buddy"> <cstring>maximumIterationsLineEdit</cstring> @@ -264,64 +269,39 @@ </item> <item> <layout class="QGridLayout" name="controlNetPositionAndPointingOptionsGridLayout"> - <item row="12" column="0" colspan="2"> - <widget class="QCheckBox" name="fitOverPointingCheckBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="minimumSize"> - <size> - <width>269</width> - <height>0</height> - </size> - </property> - <property name="text"> - <string>Fit Polynomial over Existing Pointing</string> - </property> - </widget> - </item> - <item row="6" column="0"> - <widget class="QLabel" name="spkDegreeLabel"> + <item row="10" column="0"> + <widget class="QLabel" name="spkSolveDegreeLabel"> <property name="enabled"> <bool>true</bool> </property> <property name="text"> - <string>SPKDegree</string> + <string>SPKSolveDegree</string> </property> <property name="buddy"> - <cstring>spkDegreeSpinBox</cstring> + <cstring>spkSolveDegreeSpinBox</cstring> </property> </widget> </item> - <item row="9" column="0" colspan="2"> - <widget class="QLabel" name="pointingSolveOptionsLabel"> + <item row="9" column="1"> + <widget class="QSpinBox" name="spkDegreeSpinBox"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="sizePolicy"> - <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="minimumSize"> - <size> - <width>269</width> - <height>0</height> - </size> - </property> - <property name="text"> - <string><html><head/><body><p><span style=" font-weight:600;">Instrument Pointing Solve Options</span></p></body></html></string> - </property> - <property name="scaledContents"> - <bool>false</bool> + <property name="minimum"> + <number>1</number> </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> + <property name="value"> + <number>2</number> </property> </widget> </item> - <item row="5" column="0" colspan="2"> + <item row="8" column="0" colspan="2"> <widget class="QCheckBox" name="hermiteSplineCheckBox"> <property name="enabled"> <bool>false</bool> @@ -337,56 +317,107 @@ </property> </widget> </item> - <item row="7" column="0"> - <widget class="QLabel" name="spkSolveDegreeLabel"> - <property name="enabled"> - <bool>true</bool> + <item row="5" column="0" colspan="2"> + <spacer name="controlNetworkToSpkOptionsVerticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> </property> - <property name="text"> - <string>SPKSolveDegree</string> + <property name="sizeType"> + <enum>QSizePolicy::Preferred</enum> </property> - <property name="buddy"> - <cstring>spkSolveDegreeSpinBox</cstring> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="15" column="0" colspan="2"> + <widget class="QCheckBox" name="fitOverPointingCheckBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>269</width> + <height>0</height> + </size> + </property> + <property name="text"> + <string>Fit Polynomial over Existing Pointing</string> </property> </widget> </item> - <item row="6" column="1"> - <widget class="QSpinBox" name="spkDegreeSpinBox"> - <property name="enabled"> - <bool>true</bool> + <item row="3" column="0"> + <widget class="QLabel" name="outputControlNet_2"> + <property name="text"> + <string>Output</string> </property> + </widget> + </item> + <item row="13" column="0" colspan="2"> + <widget class="QComboBox" name="pointingComboBox"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="minimum"> - <number>1</number> + <property name="toolTip"> + <string><html><head/><body><p>Instrument Pointing Options</p></body></html></string> </property> - <property name="value"> - <number>2</number> + <property name="currentIndex"> + <number>0</number> + </property> + <property name="frame"> + <bool>true</bool> </property> + <item> + <property name="text"> + <string>ANGLES</string> + </property> + </item> + <item> + <property name="text"> + <string>NONE</string> + </property> + </item> + <item> + <property name="text"> + <string>VELOCITIES</string> + </property> + </item> + <item> + <property name="text"> + <string>ACCELERATIONS</string> + </property> + </item> + <item> + <property name="text"> + <string>ALL</string> + </property> + </item> </widget> </item> - <item row="8" column="0" colspan="2"> - <spacer name="spkToCkOptionsverticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> + <item row="9" column="0"> + <widget class="QLabel" name="spkDegreeLabel"> + <property name="enabled"> + <bool>true</bool> </property> - <property name="sizeType"> - <enum>QSizePolicy::Preferred</enum> + <property name="text"> + <string>SPKDegree</string> </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> + <property name="buddy"> + <cstring>spkDegreeSpinBox</cstring> </property> - </spacer> + </widget> </item> - <item row="1" column="0" colspan="2"> - <widget class="QComboBox" name="controlNetworkComboBox"> + <item row="3" column="1"> + <widget class="QLineEdit" name="outputControlNet"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> @@ -395,63 +426,79 @@ </property> </widget> </item> - <item row="3" column="0" colspan="2"> - <widget class="QLabel" name="positionSolveOptionsLabel"> + <item row="1" column="0"> + <widget class="QLabel" name="inputControlNet"> <property name="text"> - <string><html><head/><body><p><span style=" font-weight:600;">Instrument Solve Options</span></p></body></html></string> - </property> - <property name="scaledContents"> - <bool>false</bool> + <string>Input</string> </property> <property name="alignment"> - <set>Qt::AlignCenter</set> + <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> </property> </widget> </item> - <item row="0" column="0" colspan="2"> - <widget class="QLabel" name="controlNetworkLabel"> + <item row="6" column="0" colspan="2"> + <widget class="QLabel" name="positionSolveOptionsLabel"> <property name="text"> - <string><html><head/><body><p><span style=" font-weight:600;">Control Network</span></p></body></html></string> + <string><html><head/><body><p><span style=" font-weight:600;">Instrument Solve Options</span></p></body></html></string> + </property> + <property name="scaledContents"> + <bool>false</bool> </property> <property name="alignment"> <set>Qt::AlignCenter</set> </property> </widget> </item> - <item row="14" column="1"> - <widget class="QSpinBox" name="ckSolveDegreeSpinBox"> - <property name="enabled"> - <bool>true</bool> - </property> + <item row="7" column="0" colspan="2"> + <widget class="QComboBox" name="positionComboBox"> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="value"> - <number>2</number> + <property name="toolTip"> + <string><html><head/><body><p>Instrument Solve Options</p></body></html></string> </property> + <item> + <property name="text"> + <string>NONE</string> + </property> + </item> + <item> + <property name="text"> + <string>POSITIONS</string> + </property> + </item> + <item> + <property name="text"> + <string>VELOCITIES</string> + </property> + </item> + <item> + <property name="text"> + <string>ACCELERATIONS</string> + </property> + </item> + <item> + <property name="text"> + <string>ALL</string> + </property> + </item> </widget> </item> - <item row="13" column="0"> - <widget class="QLabel" name="ckDegreeLabel"> - <property name="enabled"> - <bool>true</bool> - </property> + <item row="0" column="0" colspan="2"> + <widget class="QLabel" name="controlNetworkHeader"> <property name="text"> - <string>CKDegree</string> + <string><html><head/><body><p><span style=" font-weight:600;">Control Networks</span></p></body></html></string> </property> - <property name="buddy"> - <cstring>ckDegreeSpinBox</cstring> + <property name="alignment"> + <set>Qt::AlignCenter</set> </property> </widget> </item> - <item row="2" column="0" colspan="2"> - <spacer name="controlNetworkToSpkOptionsVerticalSpacer"> + <item row="11" column="0" colspan="2"> + <spacer name="spkToCkOptionsverticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> @@ -466,39 +513,74 @@ </property> </spacer> </item> - <item row="7" column="1"> - <widget class="QSpinBox" name="spkSolveDegreeSpinBox"> + <item row="17" column="0"> + <widget class="QLabel" name="ckSolveDegreeLabel"> <property name="enabled"> <bool>true</bool> </property> + <property name="text"> + <string>C&KSolveDegree</string> + </property> + <property name="buddy"> + <cstring>ckSolveDegreeSpinBox</cstring> + </property> + </widget> + </item> + <item row="16" column="0"> + <widget class="QLabel" name="ckDegreeLabel"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="text"> + <string>CKDegree</string> + </property> + <property name="buddy"> + <cstring>ckDegreeSpinBox</cstring> + </property> + </widget> + </item> + <item row="14" column="0" colspan="2"> + <widget class="QCheckBox" name="twistCheckBox"> <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="minimum"> - <number>1</number> + <property name="text"> + <string>Twist</string> </property> - <property name="value"> - <number>2</number> + <property name="checked"> + <bool>true</bool> </property> </widget> </item> - <item row="14" column="0"> - <widget class="QLabel" name="ckSolveDegreeLabel"> - <property name="enabled"> - <bool>true</bool> + <item row="12" column="0" colspan="2"> + <widget class="QLabel" name="pointingSolveOptionsLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="minimumSize"> + <size> + <width>269</width> + <height>0</height> + </size> </property> <property name="text"> - <string>CKSolveDegree</string> + <string><html><head/><body><p><span style=" font-weight:600;">Instrument Pointing Solve Options</span></p></body></html></string> </property> - <property name="buddy"> - <cstring>ckSolveDegreeSpinBox</cstring> + <property name="scaledContents"> + <bool>false</bool> + </property> + <property name="alignment"> + <set>Qt::AlignCenter</set> </property> </widget> </item> - <item row="13" column="1"> + <item row="16" column="1"> <widget class="QSpinBox" name="ckDegreeSpinBox"> <property name="enabled"> <bool>true</bool> @@ -517,102 +599,52 @@ </property> </widget> </item> - <item row="4" column="0" colspan="2"> - <widget class="QComboBox" name="positionComboBox"> + <item row="10" column="1"> + <widget class="QSpinBox" name="spkSolveDegreeSpinBox"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="toolTip"> - <string><html><head/><body><p>Instrument Solve Options</p></body></html></string> + <property name="minimum"> + <number>1</number> + </property> + <property name="value"> + <number>2</number> </property> - <item> - <property name="text"> - <string>NONE</string> - </property> - </item> - <item> - <property name="text"> - <string>POSITIONS</string> - </property> - </item> - <item> - <property name="text"> - <string>VELOCITIES</string> - </property> - </item> - <item> - <property name="text"> - <string>ACCELERATIONS</string> - </property> - </item> - <item> - <property name="text"> - <string>ALL</string> - </property> - </item> </widget> </item> - <item row="10" column="0" colspan="2"> - <widget class="QComboBox" name="pointingComboBox"> + <item row="17" column="1"> + <widget class="QSpinBox" name="ckSolveDegreeSpinBox"> + <property name="enabled"> + <bool>true</bool> + </property> <property name="sizePolicy"> <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="toolTip"> - <string><html><head/><body><p>Instrument Pointing Options</p></body></html></string> - </property> - <property name="currentIndex"> - <number>0</number> + <property name="minimum"> + <number>1</number> </property> - <property name="frame"> - <bool>true</bool> + <property name="value"> + <number>2</number> </property> - <item> - <property name="text"> - <string>ANGLES</string> - </property> - </item> - <item> - <property name="text"> - <string>NONE</string> - </property> - </item> - <item> - <property name="text"> - <string>VELOCITIES</string> - </property> - </item> - <item> - <property name="text"> - <string>ACCELERATIONS</string> - </property> - </item> - <item> - <property name="text"> - <string>ALL</string> - </property> - </item> </widget> </item> - <item row="11" column="0" colspan="2"> - <widget class="QCheckBox" name="twistCheckBox"> + <item row="1" column="1"> + <widget class="QComboBox" name="controlNetworkComboBox"> <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> <horstretch>0</horstretch> <verstretch>0</verstretch> </sizepolicy> </property> - <property name="text"> - <string>Twist</string> - </property> - <property name="checked"> - <bool>true</bool> - </property> </widget> </item> </layout> @@ -644,7 +676,7 @@ <bool>true</bool> </property> <property name="text"> - <string>SPK Initialization Polynomial Degree</string> + <string>SPK Initiali&zation Polynomial Degree</string> </property> <property name="wordWrap"> <bool>true</bool> @@ -785,7 +817,7 @@ <bool>true</bool> </property> <property name="text"> - <string>CK Initialization Polynomial Degree</string> + <string>C&K Initialization Polynomial Degree</string> </property> <property name="wordWrap"> <bool>true</bool> @@ -839,7 +871,7 @@ <bool>true</bool> </property> <property name="text"> - <string>CK Solve Polynomial Degree</string> + <string>CK Solve Polyno&mial Degree</string> </property> <property name="wordWrap"> <bool>true</bool> @@ -959,7 +991,7 @@ </size> </property> <property name="text"> - <string>meters</string> + <string>&meters</string> </property> <property name="buddy"> <cstring>pointLatitudeSigmaLineEdit</cstring> @@ -1365,7 +1397,7 @@ </size> </property> <property name="text"> - <string>meters per second squared</string> + <string>meters per second s&quared</string> </property> <property name="buddy"> <cstring>accelerationSigmaLineEdit</cstring> @@ -1404,7 +1436,7 @@ </widget> <widget class="QWidget" name="maximumLikelihoodTab"> <attribute name="title"> - <string>Maximum Liklihood</string> + <string>Maximum Likelihood</string> </attribute> <layout class="QGridLayout" name="gridLayout_4"> <item row="0" column="0"> @@ -1456,7 +1488,7 @@ </size> </property> <property name="text"> - <string>Maximum Likelihood Estimator Model 1</string> + <string>&Maximum Likelihood Estimator Model 1</string> </property> <property name="buddy"> <cstring>maximumLikelihoodModel1ComboBox</cstring> @@ -1481,7 +1513,7 @@ </size> </property> <property name="text"> - <string>Maximum Likelihood Estimator Model 3</string> + <string>Ma&ximum Likelihood Estimator Model 3</string> </property> <property name="buddy"> <cstring>maximumLikelihoodModel3ComboBox</cstring> @@ -1531,7 +1563,7 @@ </size> </property> <property name="text"> - <string>Maximum Likelihood Estimator Model 2</string> + <string>Maximum &Likelihood Estimator Model 2</string> </property> <property name="buddy"> <cstring>maximumLikelihoodModel2ComboBox</cstring> @@ -1544,7 +1576,7 @@ <bool>false</bool> </property> <property name="text"> - <string>Model 1 C Quantile</string> + <string>Model &1 C Quantile</string> </property> <property name="buddy"> <cstring>maximumLikelihoodModel1QuantileLineEdit</cstring> @@ -1573,7 +1605,7 @@ <bool>false</bool> </property> <property name="text"> - <string>Model 2 C Quantile</string> + <string>Model &2 C Quantile</string> </property> <property name="buddy"> <cstring>maximumLikelihoodModel2QuantileLineEdit</cstring> @@ -1678,7 +1710,7 @@ <bool>false</bool> </property> <property name="text"> - <string>Model 3 C Quantile</string> + <string>Model &3 C Quantile</string> </property> <property name="buddy"> <cstring>maximumLikelihoodModel3QuantileLineEdit</cstring> @@ -2296,7 +2328,7 @@ </font> </property> <property name="text"> - <string>mean radius</string> + <string>&mean radius</string> </property> <attribute name="buttonGroup"> <string notr="true">radiiButtonGroup</string> @@ -2460,7 +2492,7 @@ </font> </property> <property name="text"> - <string>triaxial radii</string> + <string>tria&xial radii</string> </property> <attribute name="buttonGroup"> <string notr="true">radiiButtonGroup</string> diff --git a/isis/src/qisis/objs/MosaicSceneWidget/MosaicSceneWidget.cpp b/isis/src/qisis/objs/MosaicSceneWidget/MosaicSceneWidget.cpp index ccbae1ecd0d5d7254ffa19c802d89e9b463f6518..93322567126eec550eebde003b88a338310fdddd 100644 --- a/isis/src/qisis/objs/MosaicSceneWidget/MosaicSceneWidget.cpp +++ b/isis/src/qisis/objs/MosaicSceneWidget/MosaicSceneWidget.cpp @@ -623,9 +623,9 @@ namespace Isis { } - void MosaicSceneWidget::save(QXmlStreamWriter &stream, Project *, FileName) const { + void MosaicSceneWidget::save(QXmlStreamWriter &stream, Project *, FileName ) const { if (m_projection) { - stream.writeStartElement("footprint2DView"); + stream.writeStartElement("mosaicScene"); stream.writeStartElement("projection"); PvlGroup mapping = m_projection->Mapping(); diff --git a/isis/src/qisis/objs/MosaicSceneWidget/MosaicSceneWidget.h b/isis/src/qisis/objs/MosaicSceneWidget/MosaicSceneWidget.h index 5c95ec06c254560144646f78221f60bd7d754546..8c314e31009bcb57b0beb8252b58f7a913f618bd 100644 --- a/isis/src/qisis/objs/MosaicSceneWidget/MosaicSceneWidget.h +++ b/isis/src/qisis/objs/MosaicSceneWidget/MosaicSceneWidget.h @@ -143,6 +143,9 @@ namespace Isis { * was deleted or added to the control net. Renamed deleteControlPoint * signal to controlPointDeleted. Removed some unneeded connections. * Fixes #5007, #5008. + * @history 2018-05-14 Tracie Sucharski - Change the xml tag from footprint2DView to + * mosaicScene. Reference #5422. + * */ class MosaicSceneWidget : public QWidget { Q_OBJECT diff --git a/isis/src/qisis/objs/NewControlPointDialog/NewControlPointDialog.cpp b/isis/src/qisis/objs/NewControlPointDialog/NewControlPointDialog.cpp index 1d288c8cac336737a51856f9d5fa6d00e9cfb9c4..fe9d667744bc84db07156373a9c6a30c966b7a82 100644 --- a/isis/src/qisis/objs/NewControlPointDialog/NewControlPointDialog.cpp +++ b/isis/src/qisis/objs/NewControlPointDialog/NewControlPointDialog.cpp @@ -20,9 +20,15 @@ namespace Isis { /** - * NewControlPointDialog constructor - * @param parent The parent widget for the - * cube points filter + * @description Create dialog for creating a new Control Point + * + * @param controlNet The control net the new control point will be contained in + * @param serialNumberList The serial number list corresponding to the controlNet + * @param defaultPointId The default pointID, usually empty string + * @param parent Parent widget + * @param pointType Show the Point Type combo box, default = false + * @param groundSource Show the Ground Source list, default = false + * @param subpixelRegisterMeasures Show the check box for sub-pixel registration option, default = false * * @internal * @history 2008-11-26 Jeannie Walldren - Set lastPointIdValue @@ -68,11 +74,12 @@ namespace Isis { m_pointTypeCombo->insertItem(i, ControlPoint::PointTypeToString( (ControlPoint::PointType) i)); } - m_pointTypeCombo->setCurrentIndex(2); - QLabel *pointTypeLabel = new QLabel("PointType:"); + m_pointTypeCombo->setCurrentText("Free"); + QLabel *pointTypeLabel = new QLabel("Point Type:"); pointTypeLayout->addWidget(pointTypeLabel); pointTypeLayout->addWidget(m_pointTypeCombo); - connect(m_pointTypeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(pointTypeChanged(int))); + connect(m_pointTypeCombo, SIGNAL(currentIndexChanged(QString)), + this, SLOT(pointTypeChanged(QString))); } @@ -99,6 +106,7 @@ namespace Isis { // Create OK & Cancel buttons m_okButton = new QPushButton("OK"); + // If the last point id used was never saved to network, do not set ok // button to faslse enableOkButton(""); @@ -147,7 +155,14 @@ namespace Isis { int NewControlPointDialog::pointType() const { - return m_pointTypeCombo->currentIndex(); + int result = ControlPoint::Free; + if (m_pointTypeCombo->currentText() == "Constrained") { + result = ControlPoint::Constrained; + } + if (m_pointTypeCombo->currentText() == "Fixed") { + result = ControlPoint::Fixed; + } + return result; } @@ -172,19 +187,33 @@ namespace Isis { } - void NewControlPointDialog::pointTypeChanged(int pointType) { - if (pointType == ControlPoint::Constrained || pointType == ControlPoint::Fixed) { + void NewControlPointDialog::pointTypeChanged(QString pointType) { + if (pointType == "Fixed" || pointType == "Constrained") { m_groundSourceCombo->setVisible(true); } } void NewControlPointDialog::setGroundSource(QStringList groundFiles, int numberShapesWithPoint) { - m_groundSourceCombo->addItems(groundFiles); - for (int i = 0; i < numberShapesWithPoint; i++) { - m_groundSourceCombo->setItemData(i, QColor(Qt::red), Qt::ForegroundRole); + // If groundFiles not empty, add to the list widget for selection + if (groundFiles.count() != 0) { + m_groundSourceCombo->addItems(groundFiles); + for (int i = 0; i < numberShapesWithPoint; i++) { + m_groundSourceCombo->setItemData(i, QColor(Qt::red), Qt::ForegroundRole); + } + m_groundSourceCombo->insertSeparator(numberShapesWithPoint); + } + // If groundFiles is empty, remove option to change point type to Constrained or Fixed, add a + // tooltip to give user hint as to why they don't have option to change point type and set + // default point type back to "Free". + else { + m_pointTypeCombo->setToolTip("The Point Type cannot be changed to \"Fixed\" or " + "\"Constrained\", because there are no shapes imported into " + "your project."); + m_pointTypeCombo->removeItem(m_pointTypeCombo->findText("Constrained")); + m_pointTypeCombo->removeItem(m_pointTypeCombo->findText("Fixed")); + m_pointTypeCombo->setCurrentText("Free"); } - m_groundSourceCombo->insertSeparator(numberShapesWithPoint); } @@ -227,7 +256,15 @@ namespace Isis { * to the ptIdValue */ void NewControlPointDialog::enableOkButton(const QString &) { - m_okButton->setEnabled(!m_ptIdEdit->text().isEmpty() && - !m_controlNet->ContainsPoint(m_ptIdEdit->text())); + bool enable = !m_ptIdEdit->text().isEmpty() && + !m_controlNet->ContainsPoint(m_ptIdEdit->text()); + m_okButton->setEnabled(enable); + if (enable) { + m_okButton->setToolTip(""); + } + else { + m_okButton->setToolTip("Cannot create point because Point Id is either empty or the active " + "control net already contains a control point with this point Id."); + } } } diff --git a/isis/src/qisis/objs/NewControlPointDialog/NewControlPointDialog.h b/isis/src/qisis/objs/NewControlPointDialog/NewControlPointDialog.h index d2a287b693f7fc5b93d027e6f104681d3120ea46..77af7f7a8123c693553afa5df9b3304e6d6e53db 100644 --- a/isis/src/qisis/objs/NewControlPointDialog/NewControlPointDialog.h +++ b/isis/src/qisis/objs/NewControlPointDialog/NewControlPointDialog.h @@ -33,8 +33,16 @@ namespace Isis { * @history 2016-10-18 Tracie Sucharski - Added method to return value of the * subpixelRegister radio button. If set, all measures in the control * point created will be subpixel registered. - * @history 2017-07-04 Christopher Combs - Added bools to toggle on specific elements of the - * dialog to remove similar classes like QnetNewPointDialog. Fixes #4383. + * @history 2017-07-04 Christopher Combs - Combined functionality of dialogs from qnet, + * qview and ipce applications by adding bools to toggle on specific + * elements of the dialog to remove similar classes like + * QnetNewPointDialog. Fixes #4383. + * @history 2018-05-02 Tracie Sucharski - If no shapes available remove option to change point + * type to "Constrained" or "Fixed". Because pointType combo dependent on + * having all 3 types to use ControlPoint's enum, change comparisons to + * check text instead of int values. Add tool tip explaining why point + * type cannot be changed. Set tool tip on Ok button explaining why it + * is not enabled. Fixes #5087. */ class NewControlPointDialog : public QDialog { @@ -58,7 +66,7 @@ namespace Isis { bool subpixelRegisterPoint(); private slots: - void pointTypeChanged(int pointType); + void pointTypeChanged(QString pointType); void enableOkButton(const QString &text); private: diff --git a/isis/src/qisis/objs/Project/Project.cpp b/isis/src/qisis/objs/Project/Project.cpp index d429037a86e051d48bfc9c103edf8b56fc9c19e1..b3f45a0882a13498fdfdb212e7ff6d75df8f58bb 100644 --- a/isis/src/qisis/objs/Project/Project.cpp +++ b/isis/src/qisis/objs/Project/Project.cpp @@ -66,6 +66,8 @@ #include "ProjectItem.h" #include "ProjectItemModel.h" #include "SerialNumberList.h" +#include "SetActiveControlWorkOrder.h" +#include "SetActiveImageListWorkOrder.h" #include "Shape.h" #include "ShapeList.h" #include "ShapeReader.h" @@ -109,7 +111,6 @@ namespace Isis { m_activeControl = NULL; m_activeImageList = NULL; - m_numImagesCurrentlyReading = 0; m_mutex = NULL; @@ -129,7 +130,6 @@ namespace Isis { m_name = "Project"; - // Look for old projects QDir tempDir = QDir::temp(); QStringList nameFilters; @@ -540,7 +540,7 @@ namespace Isis { tempDir.removeRecursively(); } } - + projectXml.close(); } @@ -569,7 +569,7 @@ namespace Isis { m_guiCameras->clear(); m_bundleSolutionInfo->clear(); m_workOrderHistory->clear(); - + directory()->clean(); setClean(true); } @@ -1100,13 +1100,18 @@ namespace Isis { /** * Loads bundle solution info into project + * * @param BundleSolutionInfo */ void Project::loadBundleSolutionInfo(BundleSolutionInfo *bundleSolutionInfo) { m_bundleSolutionInfo->append(bundleSolutionInfo); + // add BundleSolutionInfo to project's m_idToBundleSolutionInfoMap (*m_idToBundleSolutionInfoMap)[bundleSolutionInfo->id()] = bundleSolutionInfo; + // add BundleSolutionInfo's control to project's m_idToControlMap + (*m_idToControlMap)[bundleSolutionInfo->control()->id()] = bundleSolutionInfo->control(); + emit bundleSolutionInfoAdded(bundleSolutionInfo); } @@ -1570,6 +1575,7 @@ namespace Isis { /** * Change the project's name (GUI only, doesn't affect location on disk). */ + void Project::setName(QString newName) { m_name = newName; emit nameChanged(m_name); @@ -1697,16 +1703,46 @@ namespace Isis { * being chosen Fixes #4969 * @history 2017-08-02 Cole Neubauer - Added functionality to switch between active controls * Fixes #4567 + * @history 2018-03-30 Tracie Sucharski - If current activeControl has been modified, prompt for + * saving. Emit signal to discardActiveControlEdits. * */ void Project::setActiveControl(QString displayName) { - Control *previousControl = m_activeControl; + Control *previousControl = m_activeControl; if (m_activeControl) { + + // If the current active control has been modified, ask user if they want to save or discard + // changes. + if (m_activeControl->isModified()) { + QMessageBox msgBox; + msgBox.setText("Save current active control"); + msgBox.setInformativeText("The current active control has been modified. Do you want " + "to save before setting a new active control?"); + msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Save); + int ret = msgBox.exec(); + switch (ret) { + // Save current active control + case QMessageBox::Save: + m_activeControl->write(); + break; + // Discard any changes made to cnet + case QMessageBox::Discard: + emit discardActiveControlEdits(); + break; + // Cancel operation + case QMessageBox::Cancel: + return; + } + } emit activeControlSet(false); ProjectItem *item = directory()->model()->findItemData(m_activeControl-> displayProperties()->displayName(), Qt::DisplayRole); item->setTextColor(Qt::black); - m_activeControl->closeControlNet(); + // Make sure active not used in a CnetEditorWidget before closing + if (!directory()->controlUsedInCnetEditorWidget(m_activeControl)) { + m_activeControl->closeControlNet(); + } } ProjectItem *item = directory()->model()->findItemData(displayName, Qt::DisplayRole); @@ -1714,23 +1750,23 @@ namespace Isis { m_activeControl = item->control(); try { - activeControl()->controlNet()->SetImages(*(activeImageList()->serialNumberList())); - item->setTextColor(Qt::darkGreen); + m_activeControl->controlNet()->SetImages(*(activeImageList()->serialNumberList())); + item->setTextColor(Qt::darkGreen); } catch(IException e){ - if (previousControl) { - m_activeControl = previousControl; - item = directory()->model()->findItemData(m_activeControl-> - displayProperties()->displayName(), Qt::DisplayRole); - item->setTextColor(Qt::darkGreen); - activeControl()->controlNet()->SetImages(*(activeImageList()->serialNumberList())); - } - else { - m_activeControl = NULL; + if (previousControl) { + m_activeControl = previousControl; + item = directory()->model()->findItemData(m_activeControl-> + displayProperties()->displayName(), Qt::DisplayRole); + item->setTextColor(Qt::darkGreen); + m_activeControl->controlNet()->SetImages(*(activeImageList()->serialNumberList())); + } + else { + m_activeControl = NULL; + } + throw IException(e); } - throw IException(e); } - } emit activeControlSet(true); } @@ -1738,9 +1774,12 @@ namespace Isis { /** * @brief Return the Active Control (control network) * - * Returns the active control (control network) for views which need to operate on + * @description Returns the active control (control network) for views which need to operate on * the same control, ie. Footprint2dView, CubeDnView, ControlPointEditView. - * + * IMPORTANT: Returns NULL if no active Control. + * + * @return @b Control * Returns the active Control if set, otherwise returns NULL + * * @internal * @history 2016-06-23 Tracie Sucharski - Original version. * @history 2017-05-17 Tracie Sucharski - If no active control set & there is only one control @@ -1751,16 +1790,24 @@ namespace Isis { */ Control *Project::activeControl() { - if (!m_activeControl && m_controls->count() == 1) { - if (m_controls->at(0)->count() == 1 && m_images->count() > 1) { + if (!m_activeControl && (m_controls->count() == 1 && m_controls->at(0)->count() ==1)) { + // Can only set a default control if an active imageList exists or if a default can be set + if (activeImageList()) { QString controlName = m_controls->at(0)->at(0)->displayProperties()->displayName(); setActiveControl(controlName); } } + return m_activeControl; } + void Project::activeControlModified() { + + m_activeControl->setModified(true); + } + + /** * @brief Set the Active ImageList from the displayName which is saved in project.xml * @@ -1823,7 +1870,9 @@ namespace Isis { * @brief Returns the active ImageList * * Returns the active ImageList for views which need to operate on the - * same list of images, ie. Footprint2dView, CubeDnView, ControlPointEditView. + * same list of images, ie. Footprint2dView, CubeDnView, ControlPointEditView. + * IMPORTANT: Returns NULL if active ImageList is not set and a default cannot be set if there + * are multiple image lists in the project. * * @internal * @history 2016-06-23 Tracie Sucharski - Original version. @@ -1834,6 +1883,7 @@ namespace Isis { if (!m_activeImageList && m_images->count() == 1) { QString imageList = m_images->at(0)->name(); + setActiveImageList(imageList); } return m_activeImageList; @@ -2145,6 +2195,12 @@ namespace Isis { deleteAllProjectFiles(); relocateProjectRoot(newDestination); m_isTemporaryProject = false; + + // 2014-03-14 kle This is a lame kludge because we think that relocateProjectRoot is not + // working properly. For example, when we save a new project and try to view a control net + // the it thinks it's still in the /tmp area + // see ticket #5292 + open(newDestination); } // Dialog was cancelled else { @@ -2152,6 +2208,11 @@ namespace Isis { } } else { + // Save current active control if it has been modified + if (activeControl() && activeControl()->isModified()) { + activeControl()->write(); + } + save(m_projectRoot->absolutePath(), false); // if (newDestination != ) } @@ -2282,7 +2343,7 @@ namespace Isis { // TODO Set newpath member variable. This is used for some of the data copy methods and is not // the ideal way to handle this. Maybe change the data copy methods to either take the new // project root in addition to the data root or put the data root in the dataList (ImageList, - // etc.). + // etc.). If performing a "Save", m_newProjectRoot == m_projectRoot m_newProjectRoot = newPath.toString(); // For now set the member variable rather than calling setName which emits signal and updates @@ -2794,7 +2855,7 @@ namespace Isis { else if (localName == "imageList") { m_imageLists.append(new ImageList(m_project, reader())); } - else if (localName == "shapeLists") { + else if (localName == "shapeList") { m_shapeLists.append(new ShapeList(m_project, reader())); } else if (localName == "templateList") { @@ -2885,6 +2946,7 @@ namespace Isis { else if (localName == "results") { foreach (BundleSolutionInfo *bundleInfo, m_bundleSolutionInfos) { m_project->addBundleSolutionInfo(bundleInfo); + // If BundleSolutionInfo contains adjusted images, add to the project id map. if (bundleInfo->adjustedImages().count()) { foreach (ImageList *adjustedImageList, bundleInfo->adjustedImages()) { diff --git a/isis/src/qisis/objs/Project/Project.h b/isis/src/qisis/objs/Project/Project.h index 367f7ba8c5d32e1b59e8b36786d417337fafa4f5..848fc6101296af47f31b18def7dc1b008135eced 100644 --- a/isis/src/qisis/objs/Project/Project.h +++ b/isis/src/qisis/objs/Project/Project.h @@ -150,15 +150,11 @@ namespace Isis { * imports, shape imports, and bundle solution info. Fixes #4855, * #4979, #4980. * @history 2017-07-17 Cole Neubauer - Changed activeControl signal to emit a bool to be able - * - * @history 2017-07-24 Cole Neubauer - Added isOpen, isClean, setClean, and clear functions to - * allow for opening of a new project. Fixes #4969. - * @history 2017-07-17 Cole Neubauer - Changed activeControl signal to emit a bool to be able * to slot a setEnabled(bool) call to a QAction. This was necessary to * reenable the CNet Tool when a control net is made active. * Fixes #5046. * @history 2017-07-24 Cole Neubauer - Added isOpen, isClean, setClean, and clear functions to - * allow for opening of a new project. Fixes #4969 + * allow for opening of a new project. Fixes #4969. * @history 2017-07-27 Cole Neubauer - Added check before emmiting workOrderStarting() * Fixes #4715. * @history 2017-07-27 Cole Neubauer - Added a workordermutex to be used in workorder accessors @@ -221,6 +217,43 @@ namespace Isis { * Corrected the setting of the project root when pening a project from * the command line. Removed m_projectPath, it is no longer needed since * m_projectRoot contains the correct path. References #5104. + * @history 2018-03-14 Ken Edmundson - Modified save method to reopen project if we are saving + * a temporary project to ensure all project files are pointing to the + * correct directory. Note that this is NOT ideal, particularly it the + * project has many files. + * @history 2018-03-14 Tracie Sucharski - Call the appropriate workorder from the methods + * activeControl and activeImageList when returning a default value. + * This ensures that all the proper error checking is handled and + * prevents duplicate code. + * @history 2018-03-23 Ken Edmundson - Modified loadBundleSolutionInfo method to add the + * BundleSolutionInfo's output control id to the project member variable + * m_idToControlMap. + * @history 2018-03-26 Tracie Sucharski - When setting a new active control do not close the old + * active control net if it is still being viewed in a CnetEditorWidget. + * References #5026. + * @history 2018-03-27 Tracie Sucharski - Removed the calls to work orders from activeImageList + * and activeControl methods. Additional errors checks needed for + * default values that are not in work orders. Fixes #5256. + * @history 2018-03-30 Tracie Sucharski - Added public slot, activeControlModified, which sets + * the modified state on the active Control. This was done, so that a + * Control knows if its control net has been modified. Also added + * signal, discardActiveControlEdits if user does not want to save + * edits. This is needed for CnetEditorWidgets that are displaying + * the modified active control, it will effectively close that + * CnetEditorView and reload with the original control net. It was + * done this way because there is no easy way to reload a control net in + * the CnetEditor widgets. When saving Project, if there is an active + * control and it has been modified, write active control to disk. + * Unfortunately this is done in 2 different places depending on whether + * a project "Save" or "Save As" is being done. If "Save As", a + * modified active cnet is not written out to the original project only + * to the new project, so this had to be done in + * Control::copyToNewProjectRoot. If simply saving current projct, + * the write is done here in the save method. + * @history 2018-04-25 Tracie Sucharski - Fixed typo in XmlHandler::startElement reading + * imported shapes from a project which caused the shapes to be put in + * the wrong place on the project tree. Fixes #5274. + * */ class Project : public QObject { Q_OBJECT @@ -462,9 +495,12 @@ namespace Isis { void templatesAdded(TemplateList *newTemplates); + void discardActiveControlEdits(); + public slots: void open(QString); void setClean(bool value); + void activeControlModified(); private slots: void controlClosed(QObject *control); diff --git a/isis/src/qisis/objs/ProjectItem/ProjectItem.cpp b/isis/src/qisis/objs/ProjectItem/ProjectItem.cpp index 50df8540eea74890dae6f10fdabb8e3ddf2cdba8..acca2e2ac78a44ea474c1820b3d6658a51e83673 100644 --- a/isis/src/qisis/objs/ProjectItem/ProjectItem.cpp +++ b/isis/src/qisis/objs/ProjectItem/ProjectItem.cpp @@ -142,10 +142,7 @@ namespace Isis { setBundleSolutionInfo(bundleSolutionInfo); appendRow( new ProjectItem( bundleSolutionInfo->bundleSettings() ) ); - QString cNetFileName = bundleSolutionInfo->controlNetworkFileName(); - Control *control = new Control(cNetFileName); - appendRow( new ProjectItem(control) ); - + appendRow( new ProjectItem(bundleSolutionInfo->control()) ); appendRow( new ProjectItem( bundleSolutionInfo->bundleResults() ) ); appendRow( new ProjectItem( bundleSolutionInfo->adjustedImages() ) ); } diff --git a/isis/src/qisis/objs/ProjectItem/ProjectItem.h b/isis/src/qisis/objs/ProjectItem/ProjectItem.h index fab1135a81b2494f3cc0ff5178f588ab97c911a7..9c648e60c05cb8b8d203159541725aea4c27349b 100644 --- a/isis/src/qisis/objs/ProjectItem/ProjectItem.h +++ b/isis/src/qisis/objs/ProjectItem/ProjectItem.h @@ -136,6 +136,9 @@ namespace Isis { * taking a BundleSolutionInfo. Fixes #4849. * @history 2017-11-03 Christopher Combs - Added support for new Template and TemplateList * classes. Fixes #5117. + * @history 2018-03-22 Ken Edmundson - Modified constructor taking a BundleSolutionInfo to + * append a row for a Control object containing the output control + * net from the bundle adjustment. * */ class ProjectItem : public QStandardItem { diff --git a/isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.cpp b/isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.cpp index 806cebafbbeedae3cd8e1dbc6ecf26883a073f0f..091c7508c96c57b487dd6b7b787f67c7979549b4 100644 --- a/isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.cpp +++ b/isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.cpp @@ -384,7 +384,13 @@ namespace Isis { ProjectItem *pItem = new ProjectItem(bundleSolutionInfo); resultsItem->appendRow( pItem ); - // Append the CSV files to the Statistics in the project + // Append text bundle summary and CSV files to the Statistics in the project + ProjectItem *bundleSummaryItem = new ProjectItem(FileItemQsp( + new FileItem(bundleSolutionInfo->savedBundleOutputFilename())), + "Summary", bundleSolutionInfo->savedBundleOutputFilename(), + QIcon(FileName("$base/icons/office-chart-pie.png") + .expanded())); + pItem->child(2)->appendRow(bundleSummaryItem); ProjectItem *residualsItem = new ProjectItem(FileItemQsp( new FileItem(bundleSolutionInfo->savedResidualsFilename())), "Measure Residuals", bundleSolutionInfo->savedResidualsFilename(), @@ -393,7 +399,7 @@ namespace Isis { pItem->child(2)->appendRow(residualsItem); ProjectItem *imagesItem = new ProjectItem(FileItemQsp( new FileItem(bundleSolutionInfo->savedImagesFilename())), - "Images", bundleSolutionInfo->savedImagesFilename(), + "Image", bundleSolutionInfo->savedImagesFilename(), QIcon(FileName("$base/icons/office-chart-pie.png") .expanded())); pItem->child(2)->appendRow(imagesItem); diff --git a/isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.h b/isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.h index 242f166cf9e9680da05a067e41c07859f6dda0af..820c7643b88ef48a08442d782c55ff78b96480b2 100644 --- a/isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.h +++ b/isis/src/qisis/objs/ProjectItemModel/ProjectItemModel.h @@ -126,6 +126,10 @@ namespace Isis { * not clean. Fixes #5174. * @history 2017-11-03 Christopher Combs - Added support for new Template and TemplateList * classes. Fixes #5117. + * @history 2018-03-22 Ken Edmundson - Modified method onBundleSolutionInfoAdded to append the + * bundleoutput.txt (Summary) file to the BundleSolution Statistics + * node. Also changed the name of the Images node under Statistics to + * Image to prevent Import Images to appear on it's context menu. */ class ProjectItemModel : public QStandardItemModel { diff --git a/isis/src/qisis/objs/QIsisApplication/QIsisApplication.cpp b/isis/src/qisis/objs/QIsisApplication/QIsisApplication.cpp index 6881dfa2c78d84605dd13b3e6bbe50a52661dab0..94598f1c237c0ee940e68e6c93394493c871440d 100644 --- a/isis/src/qisis/objs/QIsisApplication/QIsisApplication.cpp +++ b/isis/src/qisis/objs/QIsisApplication/QIsisApplication.cpp @@ -34,7 +34,6 @@ namespace Isis { QApplication(argc, argv) { // try to use US locale for numbers so we don't end up printing "," instead // of "." where it might count. - for (int i = 1; i < argc; i++) { QString arg(argv[i]); diff --git a/isis/src/qisis/objs/Workspace/Workspace.cpp b/isis/src/qisis/objs/Workspace/Workspace.cpp index 108f8042f915493a92b115b4c200aedfb90c72a8..4a640bfbd6af9582b07f663447da709b5cc5f0dc 100644 --- a/isis/src/qisis/objs/Workspace/Workspace.cpp +++ b/isis/src/qisis/objs/Workspace/Workspace.cpp @@ -338,13 +338,13 @@ namespace Isis { QList<QString> cubesToOpen; // If the file is a cub file, we add the path to it to our list of cubes to open. - if ( cubeFileName.suffix() == "cub" || cubeFileName.suffix() == "cube" ) { - // cubesToOpen.append(cubeFileName.absoluteFilePath()); - cubesToOpen.append(cubeFileName.filePath()); + if ( cubeFileName.suffix() == "cub" || cubeFileName.suffix() == "cube" || cubeFileName.suffix() == "lbl") { + // cubesToOpen.append(cubeFileName.absoluteFilePath()); + cubesToOpen.append(cubeFileName.filePath()); } else { - // If the file received isn't a .cub, it has to be a cubelist. We read every cube in the cubelist - // And append it to the cubesToOpen QList so that we can open them. + // If the file received isn't a cube or label, it has to be a cubelist. We read every cube in + // the cubelist and append it to the cubesToOpen QList so that we can open them. QFile file(cubename); file.open(QIODevice::ReadOnly); diff --git a/isis/src/qisis/objs/Workspace/Workspace.h b/isis/src/qisis/objs/Workspace/Workspace.h index 63c131af08fb121985304e437b9bacfa755a3c22..3c1393d5030118e3e7e5ec9a554535877f944c00 100644 --- a/isis/src/qisis/objs/Workspace/Workspace.h +++ b/isis/src/qisis/objs/Workspace/Workspace.h @@ -79,6 +79,8 @@ namespace Isis { * class, Shape, which also contains a cube, but not an Image. * @history 2017-09-11 Adam Goins - Added the ability to accept cubelists under any file format. * Fixes #5099. + * @history 2018-04-13 Christopher Combs - Added .lbl files to the list of single-cube file-extensions + * to check before reading a cube list in addCubeViewport. Fixes #5350. */ class Workspace : public QWidget { Q_OBJECT diff --git a/isis/src/rosetta/apps/rosvirtis2isis/rosvirtis2isis.cpp b/isis/src/rosetta/apps/rosvirtis2isis/rosvirtis2isis.cpp index 0b2760e1c44fd0e2ee43da914cd2bb0eb4f30661..a5591d78cb266cf580b8c6c8447c4dea3f514b0c 100644 --- a/isis/src/rosetta/apps/rosvirtis2isis/rosvirtis2isis.cpp +++ b/isis/src/rosetta/apps/rosvirtis2isis/rosvirtis2isis.cpp @@ -13,6 +13,7 @@ #include "FileName.h" #include "ImportPdsTable.h" +#include "LineManager.h" #include "ProcessImportPds.h" #include "Table.h" #include "UserInterface.h" @@ -89,233 +90,261 @@ void IsisMain () throw IException(IException::Unknown, msg, _FILEINFO_); } + int procLevel = (int) pdsLabel.findKeyword("PROCESSING_LEVEL_ID"); + // Override default DataTrailerBytes constructed from PDS header // Will this number ever change? Where did this # come from? - p.SetDataTrailerBytes(864); + if (procLevel == 2) { + p.SetDataTrailerBytes(864); + } + else if (procLevel == 3) { + p.SetDataTrailerBytes(0); + p.SetDataSuffixBytes(4); + } p.StartProcess(); - // Retrieve HK settings file and read in HK values. - QList<VirtisHK> hk; - // Get the directory where the Rosetta translation tables are. PvlGroup dataDir (Preference::Preferences().findGroup("DataDirectory")); QString transDir = (QString) dataDir["Rosetta"] + "/translations/"; - FileName hkTranslationFile = transDir + "virtis_housekeeping.txt"; - QFile hkFile(hkTranslationFile.toString()); + if (procLevel == 2) { - if(!hkFile.open(QIODevice::ReadOnly)) { - QString msg = "Unable to open Virtis Housekeeping information file [" + - hkFile.fileName() + "]"; - throw IException(IException::Io,msg, _FILEINFO_); - } + // Retrieve HK settings file and read in HK values. + QList<VirtisHK> hk; - QTextStream in(&hkFile); + FileName hkTranslationFile = transDir + "virtis_housekeeping.txt"; + QFile hkFile(hkTranslationFile.toString()); - while(!in.atEnd()) { - QString line = in.readLine(); - QStringList fields = line.split(","); - hk.append(VirtisHK(fields[0], fields[1], fields[2], fields[3], fields[4])); - } + if(!hkFile.open(QIODevice::ReadOnly)) { + QString msg = "Unable to open Virtis Housekeeping information file [" + + hkFile.fileName() + "]"; + throw IException(IException::Io,msg, _FILEINFO_); + } - hkFile.close(); + QTextStream in(&hkFile); - // Construct HK (housekeeping) table - TableRecord rec; + while(!in.atEnd()) { + QString line = in.readLine(); + QStringList fields = line.split(","); + hk.append(VirtisHK(fields[0], fields[1], fields[2], fields[3], fields[4])); + } - QList<TableField> tableFields; + hkFile.close(); - for (int i=0; i < hk.size(); i++) { - tableFields.append(hk[i].tableField()); - } + // Construct HK (housekeeping) table + TableRecord rec; - for (int i=0; i < tableFields.size(); i++) { - rec += tableFields[i]; - } + QList<TableField> tableFields; - Table table("VIRTISHouseKeeping", rec); + for (int i=0; i < hk.size(); i++) { + tableFields.append(hk[i].tableField()); + } - // VIRTIS-M (VIS and IR) Equations - // These are adapted from the VIRTIS IDL processing pipeline - // and pg. 66-67 of the VIRTIS-EAICD - QList<std::vector<double> > equationList; - for (int i=0; i < hk.size(); i++) { - equationList.append(hk[i].coefficients()); - } + for (int i=0; i < tableFields.size(); i++) { + rec += tableFields[i]; + } - QList<PolynomialUnivariate> equations; + Table table("VIRTISHouseKeeping", rec); - for (int s=0; s < equationList.size(); s++) { - equations.append(PolynomialUnivariate(2, equationList[s])); - } + // VIRTIS-M (VIS and IR) Equations + // These are adapted from the VIRTIS IDL processing pipeline + // and pg. 66-67 of the VIRTIS-EAICD + QList<std::vector<double> > equationList; + for (int i=0; i < hk.size(); i++) { + equationList.append(hk[i].coefficients()); + } - // Populate the Housekeeping table - // - // There are 3 categories of VIRTIS HK Values, in terms of converting from input byte to output - // value: - // - // (1) SCET (many-to-one) - // (2) Physical Quantities (one-to-one) - // (3) Flags or Statistics (one-to-many) - // - // SCET values are made up of 3 VIRTIS HK 2-byte words. The output value can be calculated - // using the translateScet helper function. - // - // Physical values are made up of 1 VIRTIS HK 2-byte word, which is converted to a physical value - // using an equation specified as a series of coefficients in the associated "assets" file. - // - // For Flags or Statistics Values, 1 VIRTIS HK 2-byte word is associated with several (a varaible - // number of) output Flag or Statistics values. These are all treated as special cases. - // - // Additionally, Sine and Cosine HK Values need to be pre-processed before conversion, but are - // otherwise treated as a normal "Physical Quantity" HK. - // - std::vector< char * > hkData = p.DataTrailer(); - for (unsigned int i=0; i < hkData.size() ; i++) { - const char *hk = hkData.at(i); - const unsigned short *uihk = reinterpret_cast<const unsigned short *> (hk); - - // Each data trailer can contain multiple 82-word records, but we only need 1 / line - int start = 0; - int tableNum = 0; - - // Loop through each 82-word record - // Each k is a byteNumber - for (int k=0; k<82*2; k=k+2) { - int temp = 0; - - // Convert non-SCET records (1 two-byte word each) using the appropriate equations - if (k !=0 && k!=14 && k!=38 && k!=58 && k!=116) { - temp = word(hk[start + k], hk[start+k+1]); - if (temp != 65535) { - - // If Sine or Cosine, pre-process before sending to conversion. - if (tableNum == 63) { // SIN - int HK_bit = (int) (((unsigned short int) temp) & 4095); - int HK_sign = (unsigned short int) (temp/4096.0) & 1; - rec[tableNum] = equations[tableNum].Evaluate((HK_sign * 1.0) * (HK_bit * 1.0)); - } else if (tableNum == 64) { // COS - temp = (int) (temp) & 4095; - rec[tableNum] = equations[tableNum].Evaluate(temp * 1.0); - } else if (tableNum == 2) { // # of Subslices / first seial num 2-3 - rec[tableNum] = hk[start+k]*1.0; - rec[tableNum+1] = hk[start+k+1]*1.0; - tableNum++; - } // Specical one-to-many cases (Flags or Statistics) - else if (tableNum == 4) { // Data Type 4-9 - rec[tableNum] = (int)(temp/-32768) & 1; - rec[tableNum+1] = (int)(temp/16384) & 1; - rec[tableNum+2] = (int)(temp/8192) & 1; - rec[tableNum+3] = (int)(temp/1024) & 7; - rec[tableNum+4] = (int)(temp/256) & 3; - rec[tableNum+5] = (int)(temp/1) & 255; - tableNum+=5; - } else if (tableNum == 12) { // V_MODE 12-14 - rec[tableNum] = 1.0* ((int)(temp/4096) & 15); - rec[tableNum+1] = 1.0* ((int)(temp/64) & 63); - rec[tableNum+2] = 1.0* ((int)(temp/1) & 63); - tableNum+=2; - } else if (tableNum == 15) { //ME_PWR_STAT 15 - 21 - rec[tableNum] = 1.0* ((int)(temp/1) & 1); - rec[tableNum+1] = 1.0* ((int)(temp/2) & 1); - rec[tableNum+2] = 1.0* ((int)(temp/4) & 1); - rec[tableNum+3] = 1.0* ((int)(temp/8) & 1); - rec[tableNum+4] = 1.0* ((int)(temp/16) & 1); - rec[tableNum+5] = 1.0* ((int)(temp/32) & 1); - rec[tableNum+6] = 1.0* ((int)(temp/-32786) & 1); - tableNum+=6; - } else if (tableNum == 30){ // M_ECA_STAT 30-31 - rec[tableNum] = 1.0* ((int)(temp/1) & 1); - rec[tableNum+1] = 1.0* ((int)(temp/256) & 1); - tableNum++; - } else if (tableNum == 32) { // M_COOL_STAT 32-34 - rec[tableNum] = 1.0* ((int)(temp/1) & 1); - rec[tableNum+1] = 1.0* ((int)(temp/16) & 1); - rec[tableNum+2] = 1.0* ((int)(temp/256) & 1); - tableNum+=2; - } + QList<PolynomialUnivariate> equations; - else if (tableNum == 65) { // M_VIS_FLAG - rec[tableNum] = 1.0* ((int)(temp/1) & 1); - rec[tableNum+1] = 1.0* ((int)(temp/2) & 1); - rec[tableNum+2] = 1.0* ((int)(temp/4) & 1); - rec[tableNum+3] = 1.0* ((int)(temp/8) & 1); - rec[tableNum+4] = 1.0* ((int)(temp/16) & 1); - rec[tableNum+5] = 1.0* ((int)(temp/256) & 1); - tableNum+=5; - } - else if (tableNum == 91) { //M_IR_LAMP_SHUTTER - double lamp1 = 1.0* ((int)(temp/1) & 15); - rec[tableNum] = equations[tableNum].Evaluate(lamp1); - rec[tableNum+1] = 1.0* ((int)(temp/16) & 1); - double lamp2 = 1.0* ((int)(temp/256) & 15); - rec[tableNum+2] = equations[tableNum+1].Evaluate(lamp2); - rec[tableNum+3] = 1.0* ((int)(temp/4096) & 1); - tableNum+=3; - } - else if (tableNum == 95) { // M_IR_FLAG - rec[tableNum] = 1.0* ((int)(temp/1) & 1); - rec[tableNum+1] = 1.0* ((int)(temp/2) & 1); - rec[tableNum+2] = 1.0* ((int)(temp/4) & 1); - rec[tableNum+3] = 1.0* ((int)(temp/8) & 1); - rec[tableNum+4] = 1.0* ((int)(temp/16) & 1); - rec[tableNum+5] = 1.0* ((int)(temp/32) & 1); - rec[tableNum+6] = 1.0* ((int)(temp/64) & 1); - rec[tableNum+7] = 1.0* ((int)(temp/512) & 1); - rec[tableNum+8] = 1.0* ((int)(temp/4096) & 1); - rec[tableNum+9] = 1.0* ((int)(temp/8192) & 1); - rec[tableNum+10] = 1.0* ((int)(temp/16384) & 1); - tableNum+=10; + for (int s=0; s < equationList.size(); s++) { + equations.append(PolynomialUnivariate(2, equationList[s])); + } + + // Populate the Housekeeping table + // + // There are 3 categories of VIRTIS HK Values, in terms of converting from input byte to output + // value: + // + // (1) SCET (many-to-one) + // (2) Physical Quantities (one-to-one) + // (3) Flags or Statistics (one-to-many) + // + // SCET values are made up of 3 VIRTIS HK 2-byte words. The output value can be calculated + // using the translateScet helper function. + // + // Physical values are made up of 1 VIRTIS HK 2-byte word, which is converted to a physical value + // using an equation specified as a series of coefficients in the associated "assets" file. + // + // For Flags or Statistics Values, 1 VIRTIS HK 2-byte word is associated with several (a varaible + // number of) output Flag or Statistics values. These are all treated as special cases. + // + // Additionally, Sine and Cosine HK Values need to be pre-processed before conversion, but are + // otherwise treated as a normal "Physical Quantity" HK. + // + std::vector< char * > hkData = p.DataTrailer(); + for (unsigned int i=0; i < hkData.size() ; i++) { + const char *hk = hkData.at(i); + const unsigned short *uihk = reinterpret_cast<const unsigned short *> (hk); + + // Each data trailer can contain multiple 82-word records, but we only need 1 / line + int start = 0; + int tableNum = 0; + + // Loop through each 82-word record + // Each k is a byteNumber + for (int k=0; k<82*2; k=k+2) { + int temp = 0; + + // Convert non-SCET records (1 two-byte word each) using the appropriate equations + if (k !=0 && k!=14 && k!=38 && k!=58 && k!=116) { + temp = word(hk[start + k], hk[start+k+1]); + if (temp != 65535) { + + // If Sine or Cosine, pre-process before sending to conversion. + if (tableNum == 63) { // SIN + int HK_bit = (int) (((unsigned short int) temp) & 4095); + int HK_sign = (unsigned short int) (temp/4096.0) & 1; + rec[tableNum] = equations[tableNum].Evaluate((HK_sign * 1.0) * (HK_bit * 1.0)); + } else if (tableNum == 64) { // COS + temp = (int) (temp) & 4095; + rec[tableNum] = equations[tableNum].Evaluate(temp * 1.0); + } else if (tableNum == 2) { // # of Subslices / first seial num 2-3 + rec[tableNum] = hk[start+k]*1.0; + rec[tableNum+1] = hk[start+k+1]*1.0; + tableNum++; + } // Specical one-to-many cases (Flags or Statistics) + else if (tableNum == 4) { // Data Type 4-9 + rec[tableNum] = (int)(temp/-32768) & 1; + rec[tableNum+1] = (int)(temp/16384) & 1; + rec[tableNum+2] = (int)(temp/8192) & 1; + rec[tableNum+3] = (int)(temp/1024) & 7; + rec[tableNum+4] = (int)(temp/256) & 3; + rec[tableNum+5] = (int)(temp/1) & 255; + tableNum+=5; + } else if (tableNum == 12) { // V_MODE 12-14 + rec[tableNum] = 1.0* ((int)(temp/4096) & 15); + rec[tableNum+1] = 1.0* ((int)(temp/64) & 63); + rec[tableNum+2] = 1.0* ((int)(temp/1) & 63); + tableNum+=2; + } else if (tableNum == 15) { //ME_PWR_STAT 15 - 21 + rec[tableNum] = 1.0* ((int)(temp/1) & 1); + rec[tableNum+1] = 1.0* ((int)(temp/2) & 1); + rec[tableNum+2] = 1.0* ((int)(temp/4) & 1); + rec[tableNum+3] = 1.0* ((int)(temp/8) & 1); + rec[tableNum+4] = 1.0* ((int)(temp/16) & 1); + rec[tableNum+5] = 1.0* ((int)(temp/32) & 1); + rec[tableNum+6] = 1.0* ((int)(temp/-32786) & 1); + tableNum+=6; + } else if (tableNum == 30){ // M_ECA_STAT 30-31 + rec[tableNum] = 1.0* ((int)(temp/1) & 1); + rec[tableNum+1] = 1.0* ((int)(temp/256) & 1); + tableNum++; + } else if (tableNum == 32) { // M_COOL_STAT 32-34 + rec[tableNum] = 1.0* ((int)(temp/1) & 1); + rec[tableNum+1] = 1.0* ((int)(temp/16) & 1); + rec[tableNum+2] = 1.0* ((int)(temp/256) & 1); + tableNum+=2; + } + + else if (tableNum == 65) { // M_VIS_FLAG + rec[tableNum] = 1.0* ((int)(temp/1) & 1); + rec[tableNum+1] = 1.0* ((int)(temp/2) & 1); + rec[tableNum+2] = 1.0* ((int)(temp/4) & 1); + rec[tableNum+3] = 1.0* ((int)(temp/8) & 1); + rec[tableNum+4] = 1.0* ((int)(temp/16) & 1); + rec[tableNum+5] = 1.0* ((int)(temp/256) & 1); + tableNum+=5; + } + else if (tableNum == 91) { //M_IR_LAMP_SHUTTER + double lamp1 = 1.0* ((int)(temp/1) & 15); + rec[tableNum] = equations[tableNum].Evaluate(lamp1); + rec[tableNum+1] = 1.0* ((int)(temp/16) & 1); + double lamp2 = 1.0* ((int)(temp/256) & 15); + rec[tableNum+2] = equations[tableNum+1].Evaluate(lamp2); + rec[tableNum+3] = 1.0* ((int)(temp/4096) & 1); + tableNum+=3; + } + else if (tableNum == 95) { // M_IR_FLAG + rec[tableNum] = 1.0* ((int)(temp/1) & 1); + rec[tableNum+1] = 1.0* ((int)(temp/2) & 1); + rec[tableNum+2] = 1.0* ((int)(temp/4) & 1); + rec[tableNum+3] = 1.0* ((int)(temp/8) & 1); + rec[tableNum+4] = 1.0* ((int)(temp/16) & 1); + rec[tableNum+5] = 1.0* ((int)(temp/32) & 1); + rec[tableNum+6] = 1.0* ((int)(temp/64) & 1); + rec[tableNum+7] = 1.0* ((int)(temp/512) & 1); + rec[tableNum+8] = 1.0* ((int)(temp/4096) & 1); + rec[tableNum+9] = 1.0* ((int)(temp/8192) & 1); + rec[tableNum+10] = 1.0* ((int)(temp/16384) & 1); + tableNum+=10; + } + else { + // Convert a physical quantity to its output value (1 word -> 1 output physical value) + rec[tableNum] = equations[tableNum].Evaluate(temp * 1.0); + } } else { - // Convert a physical quantity to its output value (1 word -> 1 output physical value) - rec[tableNum] = equations[tableNum].Evaluate(temp * 1.0); + rec[tableNum] = 65535.0; // HK Data is Invalid } } else { - rec[tableNum] = 65535.0; // HK Data is Invalid - } - } - else { - // Convert SCET records (3 words -> one output SCET) - int uk = k/2; -#if 0 - int word1 = word(hk[start+k], hk[start+k+1]); - int word2 = word(hk[start+k+2], hk[start+k+3]); - int word3 = word(hk[start+k+4], hk[start+k+5]); -#else - int word1 = swapb(uihk[uk]); - int word2 = swapb(uihk[uk+1]); - int word3 = swapb(uihk[uk+2]); -#endif - - double result; - - // If any of the words comprising the SCET are invalid, the whole thing is invalid. - if (isValid(word1) && isValid(word2) && isValid(word3)) { - result = translateScet(word1, word2, word3); - } - else { - result = 65535; - } + // Convert SCET records (3 words -> one output SCET) + int uk = k/2; + #if 0 + int word1 = word(hk[start+k], hk[start+k+1]); + int word2 = word(hk[start+k+2], hk[start+k+3]); + int word3 = word(hk[start+k+4], hk[start+k+5]); + #else + int word1 = swapb(uihk[uk]); + int word2 = swapb(uihk[uk+1]); + int word3 = swapb(uihk[uk+2]); + #endif + + double result; + + // If any of the words comprising the SCET are invalid, the whole thing is invalid. + if (isValid(word1) && isValid(word2) && isValid(word3)) { + result = translateScet(word1, word2, word3); + } + else { + result = 65535; + } - // If we don't have a valid SCET, the whole line of HK data is not valid, so we skip it. - if (result == 0 || result == 65535) { - break; - } - else{ - rec[tableNum] = result*1.0; + // If we don't have a valid SCET, the whole line of HK data is not valid, so we skip it. + if (result == 0 || result == 65535) { + break; + } + else{ + rec[tableNum] = result*1.0; + } + // We used 3 words + k=k+4; } - // We used 3 words - k=k+4; + tableNum++; } - tableNum++; + table += rec; } - table += rec; - } - outcube->write(table); + outcube->write(table); + } + else if (procLevel == 3) { + std::vector<char *> hkData = p.DataTrailer(); + TableRecord rec; + TableField scETField("dataSCET", TableField::Double); + rec += scETField; + Table table("VIRTISHouseKeeping", rec); + for (unsigned int i=0; i < hkData.size() ; i++) { + const char *hk = hkData.at(i); + const unsigned short *uihk = reinterpret_cast<const unsigned short *> (hk); + int word1 = swapb(uihk[0]); + int word2 = swapb(uihk[1]); + int word3 = swapb(uihk[2]); + rec[0] = translateScet(word1, word2, word3); + table += rec; + } + outcube->write(table); + } // Create a PVL to store the translated labels in @@ -354,6 +383,26 @@ void IsisMain () } outcube->putGroup(kerns); + // NULL the dark current scans in level 2 images + if (procLevel == 2) { + const PvlKeyword &frameKey = outcube->group("Instrument").findKeyword("FrameParameter"); + // The third frame key is always the number of scans in between dark current scans. + // So, we need to add one to that in order to get the number of lines to next dark current. + int darkRate = toInt(frameKey[3]) + 1; + LineManager darkLineManager(*outcube); + + for (int band = 1; band <= outcube->bandCount(); band++) { + // The first line is always a dark current, so start there. + for (int line = 1; line <= outcube->lineCount(); line+=darkRate) { + darkLineManager.SetLine(line,band); + for (int sample = 0; sample < darkLineManager.size(); sample++) { + darkLineManager[sample] = Isis::Null; + } + outcube->write(darkLineManager); + } + } + } + p.EndProcess (); } diff --git a/isis/src/rosetta/apps/rosvirtis2isis/rosvirtis2isis.xml b/isis/src/rosetta/apps/rosvirtis2isis/rosvirtis2isis.xml index 0513adad79b1b88c226b88904308735f49b1b1ff..ca797fd4b497a13aab1dadbadc7c25fd0c776be0 100644 --- a/isis/src/rosetta/apps/rosvirtis2isis/rosvirtis2isis.xml +++ b/isis/src/rosetta/apps/rosvirtis2isis/rosvirtis2isis.xml @@ -9,10 +9,10 @@ <description> <p> This program will import and convert a PDS-formatted Rosetta VIRTIS-M or VIRTIS-H image into an ISIS cube. - This program is designed to work with data available in the draft data area on PDS as of 04/25/2016 and with any officially released data as of 11/01/2016. + This program is designed to work with data available in the draft data area on PDS as of 04/25/2016 and with any officially released data as of 11/01/2016. </p> <p> - The output cube will contain a substantial housekeeping data table named "HK." It contains, in order, the HK values for each line of the cube as described on pg 66-67 of the VIRTIS EAICD. + The output cube will contain a substantial housekeeping data table named "HK." It contains, in order, the HK values for each line of the cube as described on pg 66-67 of the VIRTIS EAICD. </p> <h3> Requirements </h3> <ul> @@ -26,35 +26,41 @@ <br/> <h2>Instrument Overview</h2> <p> - VIRTIS-M is a mapping spectrometer onboard the Rosetta mission comprised of two components: VIRTIS-M-VIS, and VIRTIS-M-IR. VIRTIS-M-VIS is the visible component, and VIRTIS-M-IR is the infrared component. + VIRTIS-M is a mapping spectrometer onboard the Rosetta mission comprised of two components: VIRTIS-M-VIS, and VIRTIS-M-IR. VIRTIS-M-VIS is the visible component, and VIRTIS-M-IR is the infrared component. VIRTIS-H is a high resolution infrared spectrometer (1840-4990 nm). </p> <h2>Data Archive</h2> <p> The Rosetta data are available from the - <a href="http://pds-smallbodies.astro.umd.edu/data_sb/missions/rosetta/index.shtml">NASA PDS Small + <a href="http://pds-smallbodies.astro.umd.edu/data_sb/missions/rosetta/index.shtml">NASA PDS Small Bodies Node</a>. </p> <h2>References</h2> <cite> </cite> - <br /> + <br /> </description> <history> <change name="Kristin Berry" date="2016-04-25"> - Original version + Original version </change> <change name="Kristin Berry" date="2016-11-01"> - Add ability to ingest housekeeping data. + Add ability to ingest housekeeping data. </change> <change name="Kaj Williams" date="2017-08-24"> - Add ability to ingest VIRTIS-H files. References #5130. + Add ability to ingest VIRTIS-H files. References #5130. </change> <change name="Kris Becker and Kaj Williams" date="2017-08-24"> Fix issues with the translation of housekeeping data. Fixes #5131. </change> + <change name="Jesse Mapel" date="2018-05-14"> + Fixed compiler warnings from new lvl3 ingestion code. + </change> + <change name="Jesse Mapel" date="2018-05-14"> + Nulled dark current scans in level 2 data. Fixes #5421. + </change> </history> <category> @@ -70,7 +76,7 @@ Input PDS formatted Rosetta VIRTIS image file </brief> <description> - Use this parameter to select the Rosetta VIRTIS filename. + Use this parameter to select the Rosetta VIRTIS filename. </description> <filter> *.qub diff --git a/isis/src/system/apps/kerneldbgen/SpiceDbGen.cpp b/isis/src/system/apps/kerneldbgen/SpiceDbGen.cpp index ab4949f2f8dbcea6543df32d957abc4eabb272ad..a7695155df4fa584f02d07fea5cc984efb502b09 100644 --- a/isis/src/system/apps/kerneldbgen/SpiceDbGen.cpp +++ b/isis/src/system/apps/kerneldbgen/SpiceDbGen.cpp @@ -40,7 +40,8 @@ const char *SpiceDbGen::calForm = "YYYY MON DD HR:MN:SC.###### TDB ::TDB"; */ SpiceDbGen::SpiceDbGen(QString type) { p_type = type; -// calForm = "YYYY MON DD HR:MN:SC.### TDB ::TDB"; + m_coverageLevel = "SEGMENT"; // default + // calForm = "YYYY MON DD HR:MN:SC.### TDB ::TDB"; } @@ -155,6 +156,17 @@ QStringList SpiceDbGen::GetFiles(FileName location, QString filter) { } +/** + * Sets the desired time coverage level of the Spice database. + * + * @param level The desired time coverage level. May be either Segment or + * Interval. + */ +void SpiceDbGen::setCoverageLevel(QString level) { + m_coverageLevel = level; +} + + /** * Format a single kernel file to include the file. * @@ -227,10 +239,16 @@ PvlGroup SpiceDbGen::AddSelection(FileName fileIn, double startOffset, double en SPICEDOUBLE_CELL(cover, 200000); ssize_c(0, &cover); ssize_c(200000, &cover); - ckcov_c(tmp.toLatin1().data(), body, SPICEFALSE, "SEGMENT", 0.0, "TDB", &cover); - NaifStatus::CheckErrors(); + // A SPICE SEGMENT is composed of SPICE INTERVALS + if (QString::compare(m_coverageLevel, "SEGMENT", Qt::CaseInsensitive) == 0 ) { + ckcov_c(tmp.toLatin1().data(), body, SPICEFALSE, "SEGMENT", 0.0, "TDB", &cover); + } + else { + ckcov_c(tmp.toLatin1().data(), body, SPICEFALSE, "INTERVAL", 0.0, "TDB", &cover); + } + NaifStatus::CheckErrors(); result = FormatIntervals(cover, currFile, startOffset, endOffset); } } diff --git a/isis/src/system/apps/kerneldbgen/SpiceDbGen.h b/isis/src/system/apps/kerneldbgen/SpiceDbGen.h index 616ff25a1993793043bb960cea165f6baf65f71e..9288a8c50548d9502ebdb7431ea0dbaf731907f5 100644 --- a/isis/src/system/apps/kerneldbgen/SpiceDbGen.h +++ b/isis/src/system/apps/kerneldbgen/SpiceDbGen.h @@ -47,6 +47,11 @@ * @history 2013-02-15 Steven Lambright - Added support for extra kernel dependencies * @history 2018-01-10 Christopher Combs - Added passing startOffset and endOffset to allow * the passing of time offsets to to FormatIntervals. Fixes #5272. + * @history 2018-05-09 Kristin Berry - Added information about the Spice time coverage level + * to this class: m_coverageLevel, setCoverageLevel, and this class will + * now select spice "time intervals" at the level specified. This is + * either a SPICE Segment (coarse) or a SPICE interval (fine.) + * Fixes #5410. * */ class SpiceDbGen { @@ -57,6 +62,7 @@ class SpiceDbGen { std::vector<QString> & filter, double startOffset, double endOffset); void FurnishDependencies(QList<Isis::FileName> sclks, QList<Isis::FileName> fks, QList<Isis::FileName> extras); + void setCoverageLevel(QString level); private: QStringList GetFiles(Isis::FileName location, QString filter); @@ -65,6 +71,7 @@ class SpiceDbGen { Isis::PvlGroup GetIntervals(SpiceCell &cover); //private instance variables QString p_type; + QString m_coverageLevel; //! The time coverage level of the database: INTERVAL or SEGMENT static const char *calForm; }; diff --git a/isis/src/system/apps/kerneldbgen/kerneldbgen.cpp b/isis/src/system/apps/kerneldbgen/kerneldbgen.cpp index fd69b7b53c4dea8b876a6394581b3a815718cd3b..af2a5d8ded458b3a8533222a831b1f04a094c9d6 100644 --- a/isis/src/system/apps/kerneldbgen/kerneldbgen.cpp +++ b/isis/src/system/apps/kerneldbgen/kerneldbgen.cpp @@ -15,19 +15,19 @@ void IsisMain() { UserInterface &ui = Application::GetUserInterface(); PvlGroup dependency("Dependencies"); - //create the database writer based on the kernel type + // Create the database writer based on the kernel type SpiceDbGen sdg(ui.GetString("TYPE")); - //Load the SCLK. If it exists, add its location to the dependency group - //If there is none, set a flag so that no file is searched for + // Load the SCLK. If it exists, add its location to the dependency group + // If there is none, set a flag so that no file is searched for QList<FileName> sclkFiles = evaluateDependencies(dependency, "SpacecraftClockKernel", "SCLK"); QList<FileName> lskFiles = evaluateDependencies(dependency, "LeapsecondKernel", "LSK"); QList<FileName> extraFiles = evaluateDependencies(dependency, "ExtraKernel", "EXTRA"); sdg.FurnishDependencies(sclkFiles, lskFiles, extraFiles); - //Determine the type of kernel that the user wants a database for. This will - //eventually become the name of the object in the output PVL + // Determine the type of kernel that the user wants a database for. This will + // eventually become the name of the object in the output PVL QString kernelType; if (ui.GetString("TYPE") == "CK") { kernelType = "SpacecraftPointing"; @@ -37,6 +37,17 @@ void IsisMain() { } PvlObject selections(kernelType); + // Specify whether to use SPICE segments (made up of SPICE intervals) + // or SPICE intervals for the SPICE database. Naif referes to this as "coverage level" + QString coverageLevel; + if (ui.GetString("LEVEL") == "SEGMENT") { + coverageLevel = "SEGMENT"; + } + else if (ui.GetString("LEVEL") == "INTERVAL") { + coverageLevel = "INTERVAL"; + } + sdg.setCoverageLevel(coverageLevel); + selections += PvlKeyword("RunTime", iTime::CurrentLocalTime()); selections.addGroup(dependency); diff --git a/isis/src/system/apps/kerneldbgen/kerneldbgen.xml b/isis/src/system/apps/kerneldbgen/kerneldbgen.xml index e12f3e126f9c02ae1df5f72435d0901933fad840..7879eaf24534a65babd3abe1482584672eed51eb 100644 --- a/isis/src/system/apps/kerneldbgen/kerneldbgen.xml +++ b/isis/src/system/apps/kerneldbgen/kerneldbgen.xml @@ -152,6 +152,10 @@ Added STARTOFFSET and ENDOFFSET parameters to allow for slight editing to start and end times. Fixes #5272. </change> + <change name="Kristin Berry" date="2018-05-09"> + Added the LEVEL=(SEGMENT*, INTERVAL) option to specify the time coverage level to be used for the generated database. SPICE segements are made up of SPICE intervals. + Segments (the only option in the past) are now the default, but interval can be selected if needed. Fixes #5410. + </change> </history> <groups> @@ -221,6 +225,37 @@ </list> </parameter> </group> + <group name="Coverage Level"> + <parameter name="LEVEL"> + <type>string</type> + <default> + <item>SEGMENT</item> + </default> + <brief> + The level of time-granularity for the time-coverage interval to be output to the SPICE database. + </brief> + <description> + </description> + <list> + <option value="SEGMENT"> + <brief> + SPICE Segment + </brief> + <description> + The coarsest level of time granularity, a SPICE segment is composed of SPICE intervals. + </description> + </option> + <option value="INTERVAL"> + <brief> + SPICE Interval + </brief> + <description> + A finer level of time granularity. + </description> + </option> + </list> + </parameter> + </group> <group name="Predict"> <parameter name="PREDICTDIR"> <type>string</type> diff --git a/isis/src/system/apps/kerneldbgen/tsts/coverageLevel/Makefile b/isis/src/system/apps/kerneldbgen/tsts/coverageLevel/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..ea023286f7edbf8dcf789d42d07046a69be34165 --- /dev/null +++ b/isis/src/system/apps/kerneldbgen/tsts/coverageLevel/Makefile @@ -0,0 +1,38 @@ +# Coverage Level Test for kerneldbgen +# +# This test creates an output database file from the kernel in the input file +# that follow the given filter for reconstructed ck file name patterns. A database +# is output with time coverage at the SPICE segment level and at the SPICE interval +# level. (There will be one output entry for the spice segment, and several for the +# SPICE interval because a SPICE segment is composed of SPICE intervals.) +# +# After the output PVL is created, when compared, the DIFF file indicates to +# ignore RunTime and File. The File keyword is ignored since, depending on +# where the test is run, files may have different paths. These paths can not be +# removed since they may be long enough to take up multiple lines. +# +# This test uses files from the TGO CaSSIS mission, as this is where the problem +# was identified. +# +# history 2018-05-09 Kristin Berry - Added test for newly added time coverage +# LEVEL=(SEGMENT*, INTERVAL) option. See #5410 +APPNAME = kerneldbgen +include $(ISISROOT)/make/isismake.tsts + +commands: + # Default output level=segment + $(APPNAME) to=$(OUTPUT)/kernel_segment.db.pvl \ + type=CK \ + recondir=$(INPUT) \ + reconfilter='em16_tgo_sc_??m_*.bc' \ + sclk=\$$tgo/kernels/sclk/em16_tgo_step_????????.tsc \ + lsk=\$$base/kernels/lsk/naif0012.tls > /dev/null; + + # Output with level=interval, needed for CaSSIS kernels and potentially other type-6 kernels + $(APPNAME) to=$(OUTPUT)/kernel_interval.db.pvl \ + type=CK \ + level=INTERVAL \ + recondir=$(INPUT) \ + reconfilter='em16_tgo_sc_??m_*.bc' \ + sclk=\$$tgo/kernels/sclk/em16_tgo_step_????????.tsc \ + lsk=\$$base/kernels/lsk/naif0012.tls > /dev/null;