/** * Set the output cube to specified file name and specified input images * and output attributes and lat,lons */ Isis::Cube *ProcessMapMosaic::SetOutputCube(const QString &inputFile, double xmin, double xmax, double ymin, double ymax, double slat, double elat, double slon, double elon, int nbands, CubeAttributeOutput &oAtt, const QString &mosaicFile) { Pvl fileLab(inputFile); PvlGroup &mapping = fileLab.findGroup("Mapping", Pvl::Traverse); mapping["UpperLeftCornerX"] = toString(xmin); mapping["UpperLeftCornerY"] = toString(ymax); mapping.addKeyword(PvlKeyword("MinimumLatitude", toString(slat)), Pvl::Replace); mapping.addKeyword(PvlKeyword("MaximumLatitude", toString(elat)), Pvl::Replace); mapping.addKeyword(PvlKeyword("MinimumLongitude", toString(slon)), Pvl::Replace); mapping.addKeyword(PvlKeyword("MaximumLongitude", toString(elon)), Pvl::Replace); Projection *firstProj = ProjectionFactory::CreateFromCube(fileLab); int samps = (int)(ceil(firstProj->ToWorldX(xmax) - firstProj->ToWorldX(xmin)) + 0.5); int lines = (int)(ceil(firstProj->ToWorldY(ymin) - firstProj->ToWorldY(ymax)) + 0.5); delete firstProj; if (p_createMosaic) { Pvl newMap; newMap.addGroup(mapping); // Initialize the mosaic CubeAttributeInput inAtt; ProcessByLine p; p.SetInputCube(inputFile, inAtt); p.PropagateHistory(false); p.PropagateLabels(false); p.PropagateTables(false); p.PropagatePolygons(false); p.PropagateOriginalLabel(false); // If track set, create the origin band if (GetTrackFlag()) { nbands += 1; } // For average priority, get the new band count else if (GetImageOverlay() == AverageImageWithMosaic) { nbands *= 2; } Cube *ocube = p.SetOutputCube(mosaicFile, oAtt, samps, lines, nbands); p.Progress()->SetText("Initializing mosaic"); p.ClearInputCubes(); p.StartProcess(ProcessMapMosaic::FillNull); // CreateForCube created some keywords in the mapping group that needs to be added ocube->putGroup(newMap.findGroup("Mapping", Pvl::Traverse)); p.EndProcess(); } Cube *mosaicCube = new Cube(); mosaicCube->open(mosaicFile, "rw"); mosaicCube->addCachingAlgorithm(new UniqueIOCachingAlgorithm(2)); AddOutputCube(mosaicCube); return mosaicCube; }
/** * Update the cube labels so that this cube indicates what tile size it used. * * @param labels The "Core" object in this Pvl will be updated */ void CubeTileHandler::updateLabels(Pvl &labels) { PvlObject &core = labels.findObject("IsisCube").findObject("Core"); core.addKeyword(PvlKeyword("Format", "Tile"), PvlContainer::Replace); core.addKeyword(PvlKeyword("TileSamples", toString(getSampleCountInChunk())), PvlContainer::Replace); core.addKeyword(PvlKeyword("TileLines", toString(getLineCountInChunk())), PvlContainer::Replace); }
PvlObject MosaicAreaTool::toPvl() const { PvlObject obj(projectPvlObjectName()); if(m_box) { obj += PvlKeyword("Latitude", m_latLineEdit->text()); obj += PvlKeyword("Longitude", m_lonLineEdit->text()); obj += PvlKeyword("Area", m_areaLineEdit->text()); obj += PvlKeyword("Visible", toString((int)(m_box != NULL))); } return obj; }
/** * @brief Return parameters used for all bands * * Method creates keyword vectors of band specific parameters * used in the photometric correction. * * @author Kris Becker - 2/22/2010 * * @param pvl Output PVL container write keywords */ void Hillier::Report ( PvlContainer &pvl ) { pvl.addComment("I/F = mu0/(mu0+mu) * F(phase)"); pvl.addComment(" where:"); pvl.addComment(" mu0 = cos(incidence)"); pvl.addComment(" mu = cos(incidence)"); pvl.addComment(" F(phase) = B0*exp(-B1*phase) + A0 + A1*phase + A2*phase^2 + A3*phase^3 + A4*phase^4"); pvl += PvlKeyword("Algorithm", "Hillier"); pvl += PvlKeyword("IncRef", toString(_iRef), "degrees"); pvl += PvlKeyword("EmaRef", toString(_eRef), "degrees"); pvl += PvlKeyword("PhaRef", toString(_gRef), "degrees"); PvlKeyword units("HillierUnits"); PvlKeyword phostd("PhotometricStandard"); PvlKeyword bbc("BandBinCenter"); PvlKeyword bbct("BandBinCenterTolerance"); PvlKeyword bbn("BandNumber"); PvlKeyword b0("B0"); PvlKeyword b1("B1"); PvlKeyword a0("A0"); PvlKeyword a1("A1"); PvlKeyword a2("A2"); PvlKeyword a3("A3"); PvlKeyword a4("A4"); for (unsigned int i = 0; i < _bandpho.size(); i++) { Parameters &p = _bandpho[i]; units.addValue(p.units); phostd.addValue(toString(p.phoStd)); bbc.addValue(toString(p.wavelength)); bbct.addValue(toString(p.tolerance)); bbn.addValue(toString(p.band)); b0.addValue(toString(p.b0)); b1.addValue(toString(p.b1)); a0.addValue(toString(p.a0)); a1.addValue(toString(p.a1)); a2.addValue(toString(p.a2)); a3.addValue(toString(p.a3)); a4.addValue(toString(p.a4)); } pvl += units; pvl += phostd; pvl += bbc; pvl += bbct; pvl += bbn; pvl += b0; pvl += b1; pvl += a0; pvl += a1; pvl += a2; pvl += a3; pvl += a4; return; }
/** * Convert to Pvl for project files. This stores all of the data associated * with all of the properties (but not what is supported). This also stores * the cube filename. */ PvlObject DisplayProperties::toPvl() const { PvlObject output("DisplayProperties"); output += PvlKeyword("DisplayName", displayName()); QBuffer dataBuffer; dataBuffer.open(QIODevice::ReadWrite); QDataStream propsStream(&dataBuffer); propsStream << *m_propertyValues; dataBuffer.seek(0); output += PvlKeyword("Values", QString(dataBuffer.data().toHex())); return output; }
/** * Constructs an PointPerspective object * * @param label This argument must be a Label containing the proper mapping * information as indicated in the Projection class. Additionally, * the point perspective projection requires the center longitude * to be defined in the keyword CenterLongitude. * * @param allowDefaults If set to false the constructor expects that a keyword * of CenterLongitude will be in the label. Otherwise it * will attempt to compute the center longitude using the * middle of the longitude range specified in the labels. * Defaults to false. * * @throws IException::Io */ PointPerspective::PointPerspective(Pvl &label, bool allowDefaults) : TProjection::TProjection(label) { try { // Try to read the mapping group PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse); // Compute and write the default center longitude if allowed and // necessary if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) { double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0; mapGroup += PvlKeyword("CenterLongitude", toString(lon)); } // Compute and write the default center latitude if allowed and // necessary if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLatitude"))) { double lat = (m_minimumLatitude + m_maximumLatitude) / 2.0; mapGroup += PvlKeyword("CenterLatitude", toString(lat)); } // Get the center longitude & latitude m_centerLongitude = mapGroup["CenterLongitude"]; m_centerLatitude = mapGroup["CenterLatitude"]; if (IsPlanetocentric()) { m_centerLatitude = ToPlanetographic(m_centerLatitude); } // convert to radians, adjust for longitude direction m_centerLongitude *= PI / 180.0; m_centerLatitude *= PI / 180.0; if (m_longitudeDirection == PositiveWest) m_centerLongitude *= -1.0; // Calculate sine & cosine of center latitude m_sinph0 = sin(m_centerLatitude); m_cosph0 = cos(m_centerLatitude); // Get the distance above planet center (the point of perspective from // the center of planet), and calculate P m_distance = mapGroup["Distance"]; m_distance *= 1000.; m_P = 1.0 + (m_distance / m_equatorialRadius); } catch(IException &e) { QString message = "Invalid label group [Mapping]"; throw IException(e, IException::Io, message, _FILEINFO_); } }
/** * Constructs a Sinusoidal object. * * @param label This argument must be a Label containing the proper mapping * information as indicated in the Projection class. Additionally, * the sinusoidal projection requires the center longitude to be * defined in the keyword CenterLongitude. * * @param allowDefaults If set to false the constructor expects that a keyword * of CenterLongitude will be in the label. Otherwise it * will attempt to compute the center longitude using the * middle of the longitude range specified in the labels. * Defaults to false * * @throws IException */ Sinusoidal::Sinusoidal(Pvl &label, bool allowDefaults) : TProjection::TProjection(label) { try { // Try to read the mapping group PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse); // Compute and write the default center longitude if allowed and // necessary if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) { double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0; mapGroup += PvlKeyword("CenterLongitude", toString(lon)); } // Get the center longitude m_centerLongitude = mapGroup["CenterLongitude"]; // convert to radians, adjust for longitude direction m_centerLongitude *= PI / 180.0; if (m_longitudeDirection == PositiveWest) m_centerLongitude *= -1.0; } catch(IException &e) { QString message = "Invalid label group [Mapping]"; throw IException(e, IException::Io, message, _FILEINFO_); } }
KernelSet Kernels::findKernels(const std::string &kname, KernelSet::KernelType ktype, Pvl &pvl, const std::string &blobname) const { // Get the kernel group and load main kernels PvlGroup &kernels = pvl.FindGroup("Kernels",Pvl::Traverse); KernelSet kkey(PvlKeyword(kname), ktype); // Check for the keyword if (kernels.HasKeyword(kname)) { kkey = KernelSet(kernels[kname], ktype); // Check for keyword design < 3.1.19 and update it to current state if (kkey.inTable() && (kkey.size() == 0)) { string bname(blobname); if (bname.empty()) bname = kname; const PvlObject &blob = findTable(bname, pvl); if (blob.HasKeyword("Kernels")) { PvlKeyword bkey = blob["Kernels"]; PvlKeyword newkey = kernels[kname]; // Found the Kernels keyword in BLOB. Get the filenames for (int i = 0 ; i < bkey.Size() ; i++) { newkey.AddValue(bkey[i]); } kkey = KernelSet(newkey, ktype); } else { kkey.Missing("Image has been jigsawed and/or kernels are gone"); } } } return (kkey); }
PvlObject MosaicControlNetTool::toPvl() const { PvlObject obj(projectPvlObjectName()); obj += PvlKeyword("FileName", m_controlNetFile); obj += PvlKeyword("Visible", Isis::toString((int)(m_controlNetGraphics && m_controlNetGraphics->isVisible()))); obj += PvlKeyword("Movement", toString(m_movementArrowColorSource)); if (maxMovementColorMeasureCount() != -1) { obj += PvlKeyword("MovementColorMaxMeasureCount", Isis::toString(m_measureCount)); } if (maxMovementColorResidualMagnitude() != Null) { obj += PvlKeyword("MovementColorMaxResidualMagnitude", Isis::toString(m_residualMagnitude)); } return obj; }
/** * This method looks for any naif errors that might have occurred. It * then compares the error to a list of known naif errors and converts * the error into an iException. * * @param resetNaif True if the NAIF error status should be reset (naif calls valid) */ void NaifStatus::CheckErrors(bool resetNaif) { if(!initialized) { SpiceChar returnAct[32] = "RETURN"; SpiceChar printAct[32] = "NONE"; erract_c ( "SET", sizeof(returnAct), returnAct); // Reset action to return errprt_c ( "SET", sizeof(printAct), printAct); // ... and print nothing initialized = true; } // Do nothing if NAIF didn't fail //getmsg_c("", 0, NULL); if(!failed_c()) return; // This method has been documented with the information provided // from the NAIF documentation at: // naif/cspice61/packages/cspice/doc/html/req/error.html // This message is a character string containing a very terse, usually // abbreviated, description of the problem. The message is a character // string of length not more than 25 characters. It always has the form: // SPICE(...) // Short error messages used in CSPICE are CONSTANT, since they are // intended to be used in code. That is, they don't contain any data which // varies with the specific instance of the error they indicate. // Because of the brief format of the short error messages, it is practical // to use them in a test to determine which type of error has occurred. const int SHORT_DESC_LEN = 26; SpiceChar naifShort[SHORT_DESC_LEN]; getmsg_c("SHORT", SHORT_DESC_LEN, naifShort); // This message may be up to 1840 characters long. The CSPICE error handling // mechanism makes no use of its contents. Its purpose is to provide human-readable // information about errors. Long error messages generated by CSPICE routines often // contain data relevant to the specific error they describe. const int LONG_DESC_LEN = 1841; SpiceChar naifLong[LONG_DESC_LEN]; getmsg_c("LONG", LONG_DESC_LEN, naifLong); // Search for known naif errors... iString errMsg; Pvl error; PvlGroup errorDescription("ErrorDescription"); errorDescription.AddKeyword(PvlKeyword("ShortMessage", naifShort)); errorDescription.AddKeyword(PvlKeyword("LongMessage", naifLong)); error.AddGroup(errorDescription); PvlTranslationManager trans(error, "$base/translations/NaifErrors.trn"); try { errMsg = trans.Translate("ShortMessage"); } catch(iException &e) { e.Clear(); errMsg = "An unknown NAIF error has been encountered."; } try { errMsg += " " + trans.Translate("LongMessage"); } catch(iException &e) { e.Clear(); } // Now process the error if(resetNaif) { reset_c(); } errMsg += " The short explanation "; errMsg += "provided by NAIF is [" + iString(naifShort) + "]. "; errMsg += "The Naif error is [" + iString(naifLong) + "]"; throw iException::Message(iException::Spice, errMsg, _FILEINFO_); }
/** * Get Groups by translating from correct Translation table * * @param label A pvl formatted label to be used to generate the serial number */ PvlGroup ObservationNumber::FindObservationTranslation(Pvl &label) { Pvl outLabel; static PvlGroup dataDir(Preference::Preferences().findGroup("DataDirectory")); // Get the mission name static QString missionTransFile = (QString) dataDir["base"] + "/translations/MissionName2DataDir.trn"; static PvlTranslationManager missionXlater(missionTransFile); missionXlater.SetLabel(label); QString mission = missionXlater.Translate("MissionName"); // Get the instrument name static QString instTransFile = (QString) dataDir["base"] + "/translations/Instruments.trn"; static PvlTranslationManager instrumentXlater(instTransFile); instrumentXlater.SetLabel(label); QString instrument = instrumentXlater.Translate("InstrumentName"); // We want to use this instrument's translation manager. It's much faster for // ObservationNumberList if we keep the translation manager in memory, so re-reading // from the disk is not necessary every time. To do this, we'll use a map to store // the translation managers and observation number keys with a string identifier to find them. // This identifier needs to have the mission name and the instrument name. static std::map<QString, std::pair<PvlTranslationManager, PvlKeyword> > missionTranslators; QString key = mission + "_" + instrument; std::map<QString, std::pair<PvlTranslationManager, PvlKeyword> >::iterator translationIterator = missionTranslators.find(key); if(translationIterator == missionTranslators.end()) { // Get the file FileName snFile((QString) dataDir[mission] + "/translations/" + instrument + "SerialNumber????.trn"); snFile = snFile.highestVersion(); // Delets the extra Pvl translation(snFile.expanded()); PvlKeyword observationKeys; if(translation.hasKeyword("ObservationKeys")) { observationKeys = translation["ObservationKeys"]; } // use the translation file to generate keywords missionTranslators.insert( std::pair<QString, std::pair<PvlTranslationManager, PvlKeyword> > (key, std::pair<PvlTranslationManager, PvlKeyword>(PvlTranslationManager(snFile.expanded()), observationKeys)) ); translationIterator = missionTranslators.find(key); } translationIterator->second.first.SetLabel(label); translationIterator->second.first.Auto(outLabel); PvlGroup snGroup = outLabel.findGroup("SerialNumberKeywords"); // Delets the extra if(!translationIterator->second.second.name().isEmpty()) { snGroup += translationIterator->second.second; } else { snGroup += PvlKeyword("ObservationKeys", toString(snGroup.keywords())); } return snGroup; }
/** * Find the lat/lon range of the image. This will use the image footprint, * camera, or projection in order to find a good result. * * @param Cube* This is required for estimation. You can pass in NULL (it will * disable estimation). * @param minLat This is an output: minimum latitude * @param maxLat This is an output: maximum latitude * @param minLon This is an output: minimum longitude * @param maxLon This is an output: maximum longitude * @param allowEstimation If this is true then extra efforts will be made to * guess the ground range of the input. This can still fail. * @return True if a ground range was found, false if no ground range could * be determined. Some lat/lon results may still be populated; their * values are undefined. */ bool UniversalGroundMap::GroundRange(Cube *cube, Latitude &minLat, Latitude &maxLat, Longitude &minLon, Longitude &maxLon, bool allowEstimation) { // Do we need a RingRange method? // For now just return false if (HasCamera()) if (p_camera->target()->shape()->name() == "Plane") return false; if (HasProjection()) if (p_projection->projectionType() == Projection::RingPlane) return false; minLat = Latitude(); maxLat = Latitude(); minLon = Longitude(); maxLon = Longitude(); // If we have a footprint, use it try { if (cube) { ImagePolygon poly; cube->read(poly); geos::geom::MultiPolygon *footprint = PolygonTools::MakeMultiPolygon( poly.Polys()->clone()); geos::geom::Geometry *envelope = footprint->getEnvelope(); geos::geom::CoordinateSequence *coords = envelope->getCoordinates(); for (unsigned int i = 0; i < coords->getSize(); i++) { const geos::geom::Coordinate &coord = coords->getAt(i); Latitude coordLat(coord.y, Angle::Degrees); Longitude coordLon(coord.x, Angle::Degrees); if (!minLat.isValid() || minLat > coordLat) minLat = coordLat; if (!maxLat.isValid() || maxLat < coordLat) maxLat = coordLat; if (!minLon.isValid() || minLon > coordLon) minLon = coordLon; if (!maxLon.isValid() || maxLon < coordLon) maxLon = coordLon; } delete coords; coords = NULL; delete envelope; envelope = NULL; delete footprint; footprint = NULL; } } catch (IException &) { } if (!minLat.isValid() || !maxLat.isValid() || !minLon.isValid() || !maxLon.isValid()) { if (HasCamera()) { // Footprint failed, ask the camera PvlGroup mappingGrp("Mapping"); mappingGrp += PvlKeyword("LatitudeType", "Planetocentric"); mappingGrp += PvlKeyword("LongitudeDomain", "360"); mappingGrp += PvlKeyword("LongitudeDirection", "PositiveEast"); Pvl mappingPvl; mappingPvl += mappingGrp; double minLatDouble; double maxLatDouble; double minLonDouble; double maxLonDouble; p_camera->GroundRange( minLatDouble, maxLatDouble, minLonDouble, maxLonDouble, mappingPvl); minLat = Latitude(minLatDouble, Angle::Degrees); maxLat = Latitude(maxLatDouble, Angle::Degrees); minLon = Longitude(minLonDouble, Angle::Degrees); maxLon = Longitude(maxLonDouble, Angle::Degrees); } else if (HasProjection()) { // Footprint failed, look in the mapping group PvlGroup mappingGrp = p_projection->Mapping(); if (mappingGrp.hasKeyword("MinimumLatitude") && mappingGrp.hasKeyword("MaximumLatitude") && mappingGrp.hasKeyword("MinimumLongitude") && mappingGrp.hasKeyword("MaximumLongitude")) { minLat = Latitude(mappingGrp["MinimumLatitude"], mappingGrp, Angle::Degrees); maxLat = Latitude(mappingGrp["MaximumLatitude"], mappingGrp, Angle::Degrees); minLon = Longitude(mappingGrp["MinimumLongitude"], mappingGrp, Angle::Degrees); maxLon = Longitude(mappingGrp["MaximumLongitude"], mappingGrp, Angle::Degrees); } else if (allowEstimation && cube) { // Footprint and mapping failed... no lat/lon range of any kind is // available. Let's test points in the image to try to make our own // extent. QList<QPointF> imagePoints; // Reset to TProjection TProjection *tproj = (TProjection *) p_projection; /* * This is where we're testing: * * |---------------| * |***************| * |** * **| * |* * * * *| * |* * * * *| * |***************| * |* * * * *| * |* * * * *| * |** * **| * |***************| * |---------------| * * We'll test at the edges, a plus (+) and an (X) to help DEMs work. */ int sampleCount = cube->sampleCount(); int lineCount = cube->lineCount(); int stepsPerLength = 20; //number of steps per length double aspectRatio = (double)lineCount / (double)sampleCount; double xStepSize = sampleCount / stepsPerLength; double yStepSize = xStepSize * aspectRatio; if (lineCount > sampleCount) { aspectRatio = (double)sampleCount / (double)lineCount; yStepSize = lineCount / stepsPerLength; xStepSize = yStepSize * aspectRatio; } double yWalked = 0.5; //3 vertical lines for (int i = 0; i < 3; i++) { double xValue = 0.5 + ( i * (sampleCount / 2) ); while (yWalked <= lineCount) { imagePoints.append( QPointF(xValue, yWalked) ); yWalked += yStepSize; } yWalked = 0.5; } double xWalked = 0.5; //3 horizontal lines for (int i = 0; i < 3; i++) { double yValue = 0.5 + ( i * (lineCount / 2) ); while (xWalked <= sampleCount) { imagePoints.append( QPointF(xWalked, yValue) ); xWalked += xStepSize; } xWalked = 0.5; } double xDiagonalWalked = 0.5; double yDiagonalWalked = 0.5; xStepSize = sampleCount / stepsPerLength; yStepSize = lineCount / stepsPerLength; //Top-Down Diagonal while ( (xDiagonalWalked <= sampleCount) && (yDiagonalWalked <= lineCount) ) { imagePoints.append( QPointF(xDiagonalWalked, yDiagonalWalked) ); xDiagonalWalked += xStepSize; yDiagonalWalked += yStepSize; } xDiagonalWalked = 0.5; //Bottom-Up Diagonal while ( (xDiagonalWalked <= sampleCount) && (yDiagonalWalked >= 0) ) { imagePoints.append( QPointF(xDiagonalWalked, yDiagonalWalked) ); xDiagonalWalked += xStepSize; yDiagonalWalked -= yStepSize; } foreach (QPointF imagePoint, imagePoints) { if (tproj->SetWorld(imagePoint.x(), imagePoint.y())) { Latitude latResult(tproj->UniversalLatitude(), Angle::Degrees); Longitude lonResult(tproj->UniversalLongitude(), Angle::Degrees); if (minLat.isValid()) minLat = qMin(minLat, latResult); else minLat = latResult; if (maxLat.isValid()) maxLat = qMax(maxLat, latResult); else maxLat = latResult; if (minLon.isValid()) minLon = qMin(minLon, lonResult); else minLon = lonResult; if (maxLon.isValid()) maxLon = qMax(maxLon, lonResult); else maxLon = lonResult; } } } } }
/** * Constructs a TransverseMercator object * * @param label This argument must be a Label containing the proper mapping * information as indicated in the Projection class. Additionally, * the transversemercator projection requires the center longitude * to be defined in the keyword CenterLongitude, and the scale * factor to be defined in the keyword ScaleFactor. * * @param allowDefaults If set to false the constructor expects that a keyword * of CenterLongitude and ScaleFactor will be in the label. * Otherwise it will attempt to compute the center * longitude using the middle of the longitude range * specified in the label, and the scale factor will * default to 1.0. Defaults to false. * * @throws IException */ TransverseMercator::TransverseMercator(Pvl &label, bool allowDefaults) : TProjection::TProjection(label) { try { // Try to read the mapping group PvlGroup &mapGroup = label.findGroup("Mapping", Pvl::Traverse); // Compute and write the default center longitude if allowed and // necessary if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLongitude"))) { double lon = (m_minimumLongitude + m_maximumLongitude) / 2.0; mapGroup += PvlKeyword("CenterLongitude", toString(lon)); } // Compute and write the default center latitude if allowed and // necessary if ((allowDefaults) && (!mapGroup.hasKeyword("CenterLatitude"))) { double lat = (m_minimumLatitude + m_maximumLatitude) / 2.0; mapGroup += PvlKeyword("CenterLatitude", toString(lat)); } // Get the center longitude & latitude m_centerLongitude = mapGroup["CenterLongitude"]; m_centerLatitude = mapGroup["CenterLatitude"]; // make sure the center latitude value is valid if (fabs(m_centerLatitude) >= 90.0) { string msg = "Invalid Center Latitude Value. Must be between -90 and 90"; throw IException(IException::Io, msg, _FILEINFO_); } // make sure the center longitude value is valid if (fabs(m_centerLongitude) > 360.0) { string msg = "Invalid Center Longitude Value. Must be between -360 and 360"; throw IException(IException::Io, msg, _FILEINFO_); } // convert latitude to planetographic if it is planetocentric if (IsPlanetocentric()) { m_centerLatitude = ToPlanetographic(m_centerLatitude); } // convert to radians and adjust for longitude direction if (m_longitudeDirection == PositiveWest) m_centerLongitude *= -1.0; m_centerLatitude *= PI / 180.0; m_centerLongitude *= PI / 180.0; // Compute other necessary variables. See Snyder, page 61 m_eccsq = Eccentricity() * Eccentricity(); m_esp = m_eccsq; m_e0 = 1.0 - 0.25 * m_eccsq * (1.0 + m_eccsq / 16.0 * (3.0 + 1.25 * m_eccsq)); m_e1 = 0.375 * m_eccsq * (1.0 + 0.25 * m_eccsq * (1.0 + 0.468750 * m_eccsq)); m_e2 = 0.058593750 * m_eccsq * m_eccsq * (1.0 + 0.750 * m_eccsq); m_e3 = m_eccsq * m_eccsq * m_eccsq * (35.0 / 3072.0); m_ml0 = m_equatorialRadius * (m_e0 * m_centerLatitude - m_e1 * sin(2.0 * m_centerLatitude) + m_e2 * sin(4.0 * m_centerLatitude) - m_e3 * sin(6.0 * m_centerLatitude)); // Set flag for sphere or ellipsiod m_sph = true; // Sphere if (Eccentricity() >= .00001) { m_sph = false; // Ellipsoid m_esp = m_eccsq / (1.0 - m_eccsq); } // Get the scale factor if ((allowDefaults) && (!mapGroup.hasKeyword("ScaleFactor"))) { mapGroup += PvlKeyword("ScaleFactor", toString(1.0)); } m_scalefactor = mapGroup["ScaleFactor"]; } catch(IException &e) { string message = "Invalid label group [Mapping]"; throw IException(e, IException::Io, message, _FILEINFO_); } }
/** * Creates a pvl of various useful data obtained by the overlap statistics * class. The pvl is returned in an output stream * * @param os The output stream to write to * @param stats The OverlapStatistics object to write to os * @return ostream Pvl of useful statistics */ std::ostream& operator<<(std::ostream &os, Isis::OverlapStatistics &stats) { // Output the private variables try { PvlObject o ("OverlapStatistics"); PvlGroup gX ("File1"); PvlKeyword stsX ("StartSample", stats.StartSampleX()); PvlKeyword ensX ("EndSample", stats.EndSampleX()); PvlKeyword stlX ("StartLine", stats.StartLineX()); PvlKeyword enlX ("EndLine", stats.EndLineX()); PvlKeyword avgX ("Average"); PvlKeyword stdX ("StandardDeviation"); PvlKeyword varX ("Variance"); for (int band=1; band<=stats.Bands(); band++) { if (stats.HasOverlap(band)) { avgX += stats.GetMStats(band).X().Average(); stdX += stats.GetMStats(band).X().StandardDeviation(); varX += stats.GetMStats(band).X().Variance(); } } gX += stsX; gX += ensX; gX += stlX; gX += enlX; gX += avgX; gX += stdX; gX += varX; PvlGroup gY ("File2"); PvlKeyword stsY ("StartSample", stats.StartSampleY()); PvlKeyword ensY ("EndSample", stats.EndSampleY()); PvlKeyword stlY ("StartLine", stats.StartLineY()); PvlKeyword enlY ("EndLine", stats.EndLineY()); PvlKeyword avgY ("Average"); PvlKeyword stdY ("StandardDeviation"); PvlKeyword varY ("Variance"); for (int band=1; band<=stats.Bands(); band++) { if (stats.HasOverlap(band)) { avgY += stats.GetMStats(band).Y().Average(); stdY += stats.GetMStats(band).Y().StandardDeviation(); varY += stats.GetMStats(band).Y().Variance(); } } gY += stsY; gY += ensY; gY += stlY; gY += enlY; gY += avgY; gY += stdY; gY += varY; o += PvlKeyword("File1", stats.FilenameX().Name()); o += PvlKeyword("File2", stats.FilenameY().Name()); o += PvlKeyword("Width", stats.Samples()); o += PvlKeyword("Height", stats.Lines()); o += PvlKeyword("SamplingPercent", stats.SampPercent()); o.AddGroup(gX); o.AddGroup(gY); PvlKeyword cov ("Covariance"); PvlKeyword cor ("Correlation"); PvlKeyword valid ("ValidOverlap"); PvlKeyword val ("ValidPixels"); PvlKeyword inv ("InvalidPixels"); PvlKeyword tot ("TotalPixels"); for (int band=1; band<=stats.Bands(); band++) { if (stats.HasOverlap(band)) { std::string validStr = "false"; if (stats.IsValid(band)) validStr = "true"; valid += validStr; cov += stats.GetMStats(band).Covariance(); cor += stats.GetMStats(band).Correlation(); val += stats.GetMStats(band).ValidPixels(); inv += stats.GetMStats(band).InvalidPixels(); tot += stats.GetMStats(band).TotalPixels(); } } o += valid; o += cov; o += cor; o += val; o += inv; o += tot; for (int band=1; band<=stats.Bands(); band++) { if (stats.HasOverlap(band)) { iString bandNum (band); std::string bandStr = "LinearRegression" + bandNum; PvlKeyword LinReg(bandStr); double a,b; try { stats.GetMStats(band).LinearRegression(a,b); LinReg += a; LinReg += b; } catch (iException &e) { // It is possible one of the overlaps was constant and therefore // the regression would be a vertical line (x=c instead of y=ax+b) e.Clear(); } o += LinReg; } } os << o << endl; return os; } catch (iException &e) { string msg = "Trivial overlap between [" + stats.FilenameX().Name(); msg += "] and [" + stats.FilenameY().Name() + "]"; throw iException::Message(iException::User,msg,_FILEINFO_); } }
/** * Set the output cube to specified file name and specified input images * and output attributes and lat,lons */ Isis::Cube *ProcessMapMosaic::SetOutputCube(FileList &propagationCubes, double slat, double elat, double slon, double elon, CubeAttributeOutput &oAtt, const QString &mosaicFile) { if (propagationCubes.size() < 1) { QString msg = "The list does not contain any data"; throw IException(IException::Programmer, msg, _FILEINFO_); } int samples, lines, bands = 0; Pvl label; label.read(propagationCubes[0].toString()); PvlGroup mGroup = label.findGroup("Mapping", Pvl::Traverse); mGroup.addKeyword(PvlKeyword("MinimumLatitude", toString(slat)), Pvl::Replace); mGroup.addKeyword(PvlKeyword("MaximumLatitude", toString(elat)), Pvl::Replace); mGroup.addKeyword(PvlKeyword("MinimumLongitude", toString(slon)), Pvl::Replace); mGroup.addKeyword(PvlKeyword("MaximumLongitude", toString(elon)), Pvl::Replace); if (mGroup.hasKeyword("UpperLeftCornerX")) mGroup.deleteKeyword("UpperLeftCornerX"); if (mGroup.hasKeyword("UpperLeftCornerY")) mGroup.deleteKeyword("UpperLeftCornerY"); Pvl mapPvl; mapPvl += mGroup; // Use CreateForCube because our range differs from any of the cubes (manually specified) Projection *proj = Isis::ProjectionFactory::CreateForCube(mapPvl, samples, lines, false); double xmin, xmax, ymin, ymax; proj->XYRange(xmin, xmax, ymin, ymax); // The xmin/ymax should be rounded for the labels xmin = mapPvl.findGroup("Mapping")["UpperLeftCornerX"]; ymax = mapPvl.findGroup("Mapping")["UpperLeftCornerY"]; for (int i = 0; i < propagationCubes.size(); i++) { Cube cube; cube.open(propagationCubes[i].toString()); bands = max(cube.bandCount(), bands); // See if the cube has a projection and make sure it matches // previous input cubes Projection *projNew = Isis::ProjectionFactory::CreateFromCube(*(cube.label())); if (proj == NULL) { } else if (*proj != *projNew) { QString msg = "Mapping groups do not match between cube [" + propagationCubes[i].toString() + "] and [" + propagationCubes[0].toString() + "]"; throw IException(IException::User, msg, _FILEINFO_); } if (proj) delete proj; proj = projNew; } if (proj) delete proj; return SetOutputCube(propagationCubes[0].toString(), xmin, xmax, ymin, ymax, slat, elat, slon, elon, bands, oAtt, mosaicFile); }
/** * Modifies a label for a file containing a subarea. The AlphaCube, Mapping, * and Instrument groups are all affected when a subarea is extracted from * another file. If the linc is not equal to the sinc, then the Instrument * and Mapping groups will be removed from the label because they will no * longer be valid. If the linc is equal to the sinc and they are not equal * to 1, then the map scale and resolution in the Mapping group needs to be * updated. The latitude and longitude ranges become invalid when the subarea * does not cover the entire sample and line range of the original cube. * Update the upper left corner x,y values if the projection is still valid * and the starting line and/or starting sample have been changed from their * location in the original file. * * @param icube This is the input cube that will have the subarea * extracted from it. The label of this cube will be used to * create updated Mapping, Instrument, and AlphaCube groups * for the label of the output cube containing the subarea. * * @param ocube This is the output cube file containing the subarea. The * label of this cube will be modified by extracting the Mapping, * Instrument, and AlphaCube groups from the input label and * putting them in this label. * * @param results This is the Results group that will go into the application * log file. This group must be created by the calling application. * Information will be added to it if the Mapping or Instrument * groups are deleted from the output image label. * */ void SubArea::UpdateLabel(Cube *icube, Cube *ocube, PvlGroup &results) { Pvl inlabel = *icube->label(); // If the linc and sinc are not equal, then the Instrument and // Mapping groups are no longer valid. if(p_linc != p_sinc) { if(inlabel.findObject("IsisCube").hasGroup("Mapping")) { inlabel.findObject("IsisCube").deleteGroup("Mapping"); results += PvlKeyword("MappingGroupDeleted", "True"); // We don't want to think our projected cube is unprojected, so if we // delete a mapping group and we have a camera there is a problem. // Remove the camera. if(inlabel.findObject("IsisCube").hasGroup("Instrument")) { inlabel.findObject("IsisCube").deleteGroup("Instrument"); results += PvlKeyword("InstrumentGroupDeleted", "True"); } } } if(inlabel.findObject("IsisCube").hasGroup("Mapping")) { // Update the upper left corner X,Y values if the starting line or // starting sample are changed. if(p_sl != 1 || p_ss != 1) { Projection &proj = *icube->projection(); proj.SetWorld(p_ss - 0.5, p_sl - 0.5); PvlGroup &mapgroup = inlabel.findObject("IsisCube").findGroup("Mapping", Pvl::Traverse); mapgroup.addKeyword(PvlKeyword("UpperLeftCornerX", toString(proj.XCoord())), Pvl::Replace); mapgroup.addKeyword(PvlKeyword("UpperLeftCornerY", toString(proj.YCoord())), Pvl::Replace); } // If the linc and sinc are not equal to 1, then update the // mapping scale and resolution. if(p_linc == p_sinc && p_linc != 1.0) { PvlGroup &mapgroup = inlabel.findObject("IsisCube").findGroup("Mapping", Pvl::Traverse); QString pixresUnit = mapgroup["PixelResolution"].unit(); double pixres = toDouble(mapgroup["PixelResolution"][0]); mapgroup["PixelResolution"] = toString(pixres * p_linc); mapgroup["PixelResolution"].setUnits(pixresUnit); QString scaleUnit = mapgroup["Scale"].unit(); double scale = mapgroup["Scale"]; mapgroup["Scale"] = toString(scale / p_linc); mapgroup["Scale"].setUnits(scaleUnit); } // If the outer bounds of the image are changed, then the // latitude,longitude range is no longer valid. if(p_sl != 1 || p_ss != 1 || p_el != p_nl || p_es != p_ns) { PvlGroup &mapgroup = inlabel.findObject("IsisCube").findGroup("Mapping", Pvl::Traverse); if(mapgroup.hasKeyword("MinimumLatitude")) { mapgroup.deleteKeyword("MinimumLatitude"); } if(mapgroup.hasKeyword("MaximumLatitude")) { mapgroup.deleteKeyword("MaximumLatitude"); } if(mapgroup.hasKeyword("MinimumLongitude")) { mapgroup.deleteKeyword("MinimumLongitude"); } if(mapgroup.hasKeyword("MaximumLongitude")) { mapgroup.deleteKeyword("MaximumLongitude"); } } } // Make changes to the output cube label if(ocube->hasGroup("Instrument")) { ocube->deleteGroup("Instrument"); } if(inlabel.findObject("IsisCube").hasGroup("Instrument")) { PvlGroup inst; inst = inlabel.findObject("IsisCube").findGroup("Instrument"); ocube->putGroup(inst); } if(ocube->hasGroup("Mapping")) { ocube->deleteGroup("Mapping"); } if(inlabel.findObject("IsisCube").hasGroup("Mapping")) { PvlGroup mapgrp; mapgrp = inlabel.findObject("IsisCube").findGroup("Mapping"); ocube->putGroup(mapgrp); } // Update the AlphaCube group - this group will only be updated if // a Mapping group does not exist in the labels. AlphaCube aCube(p_ns, p_nl, ocube->sampleCount(), ocube->lineCount(), p_ss - 0.5, p_sl - 0.5, p_es + 0.5, p_el + 0.5); aCube.UpdateGroup(*ocube->label()); }
/** * GetPointInfo builds the PvlGroup containing all the important * information derived from the Camera. * * @return PvlGroup* Data taken directly from the Camera and * drived from Camera information. Ownership passed. */ PvlGroup *CameraPointInfo::GetPointInfo(bool passed, bool allowOutside, bool allowErrors) { PvlGroup *gp = new PvlGroup("GroundPoint"); { gp->addKeyword(PvlKeyword("Filename")); gp->addKeyword(PvlKeyword("Sample")); gp->addKeyword(PvlKeyword("Line")); gp->addKeyword(PvlKeyword("PixelValue")); gp->addKeyword(PvlKeyword("RightAscension")); gp->addKeyword(PvlKeyword("Declination")); gp->addKeyword(PvlKeyword("PlanetocentricLatitude")); gp->addKeyword(PvlKeyword("PlanetographicLatitude")); gp->addKeyword(PvlKeyword("PositiveEast360Longitude")); gp->addKeyword(PvlKeyword("PositiveEast180Longitude")); gp->addKeyword(PvlKeyword("PositiveWest360Longitude")); gp->addKeyword(PvlKeyword("PositiveWest180Longitude")); gp->addKeyword(PvlKeyword("BodyFixedCoordinate")); gp->addKeyword(PvlKeyword("LocalRadius")); gp->addKeyword(PvlKeyword("SampleResolution")); gp->addKeyword(PvlKeyword("LineResolution")); gp->addKeyword(PvlKeyword("SpacecraftPosition")); gp->addKeyword(PvlKeyword("SpacecraftAzimuth")); gp->addKeyword(PvlKeyword("SlantDistance")); gp->addKeyword(PvlKeyword("TargetCenterDistance")); gp->addKeyword(PvlKeyword("SubSpacecraftLatitude")); gp->addKeyword(PvlKeyword("SubSpacecraftLongitude")); gp->addKeyword(PvlKeyword("SpacecraftAltitude")); gp->addKeyword(PvlKeyword("OffNadirAngle")); gp->addKeyword(PvlKeyword("SubSpacecraftGroundAzimuth")); gp->addKeyword(PvlKeyword("SunPosition")); gp->addKeyword(PvlKeyword("SubSolarAzimuth")); gp->addKeyword(PvlKeyword("SolarDistance")); gp->addKeyword(PvlKeyword("SubSolarLatitude")); gp->addKeyword(PvlKeyword("SubSolarLongitude")); gp->addKeyword(PvlKeyword("SubSolarGroundAzimuth")); gp->addKeyword(PvlKeyword("Phase")); gp->addKeyword(PvlKeyword("Incidence")); gp->addKeyword(PvlKeyword("Emission")); gp->addKeyword(PvlKeyword("NorthAzimuth")); gp->addKeyword(PvlKeyword("EphemerisTime")); gp->addKeyword(PvlKeyword("UTC")); gp->addKeyword(PvlKeyword("LocalSolarTime")); gp->addKeyword(PvlKeyword("SolarLongitude")); if (allowErrors) gp->addKeyword(PvlKeyword("Error")); } bool noErrors = passed; QString error = ""; if (!m_camera->HasSurfaceIntersection()) { error = "Requested position does not project in camera model; no surface intersection"; noErrors = false; if (!allowErrors) throw IException(IException::Unknown, error, _FILEINFO_); } if (!m_camera->InCube() && !allowOutside) { error = "Requested position does not project in camera model; not inside cube"; noErrors = false; if (!allowErrors) throw IException(IException::Unknown, error, _FILEINFO_); } if (!noErrors) { for (int i = 0; i < gp->keywords(); i++) { QString name = (*gp)[i].name(); // These three keywords have 3 values, so they must have 3 N/As if (name == "BodyFixedCoordinate" || name == "SpacecraftPosition" || name == "SunPosition") { (*gp)[i].addValue("N/A"); (*gp)[i].addValue("N/A"); (*gp)[i].addValue("N/A"); } else { (*gp)[i].setValue("N/A"); } } // Set all keywords that still have valid information gp->findKeyword("Error").setValue(error); gp->findKeyword("FileName").setValue(m_currentCube->fileName()); gp->findKeyword("Sample").setValue(toString(m_camera->Sample())); gp->findKeyword("Line").setValue(toString(m_camera->Line())); gp->findKeyword("EphemerisTime").setValue( toString(m_camera->time().Et()), "seconds"); gp->findKeyword("EphemerisTime").addComment("Time"); QString utc = m_camera->time().UTC(); gp->findKeyword("UTC").setValue(utc); gp->findKeyword("SpacecraftPosition").addComment("Spacecraft Information"); gp->findKeyword("SunPosition").addComment("Sun Information"); gp->findKeyword("Phase").addComment("Illumination and Other"); } else { Brick b(3, 3, 1, m_currentCube->pixelType()); int intSamp = (int)(m_camera->Sample() + 0.5); int intLine = (int)(m_camera->Line() + 0.5); b.SetBasePosition(intSamp, intLine, 1); m_currentCube->read(b); double pB[3], spB[3], sB[3]; QString utc; double ssplat, ssplon, sslat, sslon, pwlon, oglat; { gp->findKeyword("FileName").setValue(m_currentCube->fileName()); gp->findKeyword("Sample").setValue(toString(m_camera->Sample())); gp->findKeyword("Line").setValue(toString(m_camera->Line())); gp->findKeyword("PixelValue").setValue(PixelToString(b[0])); gp->findKeyword("RightAscension").setValue(toString( m_camera->RightAscension())); gp->findKeyword("Declination").setValue(toString( m_camera->Declination())); gp->findKeyword("PlanetocentricLatitude").setValue(toString( m_camera->UniversalLatitude())); // Convert lat to planetographic Distance radii[3]; m_camera->radii(radii); oglat = TProjection::ToPlanetographic(m_camera->UniversalLatitude(), radii[0].kilometers(), radii[2].kilometers()); gp->findKeyword("PlanetographicLatitude").setValue(toString(oglat)); gp->findKeyword("PositiveEast360Longitude").setValue(toString( m_camera->UniversalLongitude())); //Convert lon to -180 - 180 range gp->findKeyword("PositiveEast180Longitude").setValue(toString( TProjection::To180Domain(m_camera->UniversalLongitude()))); //Convert lon to positive west pwlon = TProjection::ToPositiveWest( m_camera->UniversalLongitude(), 360); gp->findKeyword("PositiveWest360Longitude").setValue(toString(pwlon)); //Convert pwlon to -180 - 180 range gp->findKeyword("PositiveWest180Longitude").setValue(toString( TProjection::To180Domain(pwlon))); m_camera->Coordinate(pB); gp->findKeyword("BodyFixedCoordinate").addValue(toString(pB[0]), "km"); gp->findKeyword("BodyFixedCoordinate").addValue(toString(pB[1]), "km"); gp->findKeyword("BodyFixedCoordinate").addValue(toString(pB[2]), "km"); gp->findKeyword("LocalRadius").setValue(toString( m_camera->LocalRadius().meters()), "meters"); gp->findKeyword("SampleResolution").setValue(toString( m_camera->SampleResolution()), "meters/pixel"); gp->findKeyword("LineResolution").setValue(toString( m_camera->LineResolution()), "meters/pixel"); //body fixed m_camera->instrumentPosition(spB); gp->findKeyword("SpacecraftPosition").addValue(toString(spB[0]), "km"); gp->findKeyword("SpacecraftPosition").addValue(toString(spB[1]), "km"); gp->findKeyword("SpacecraftPosition").addValue(toString(spB[2]), "km"); gp->findKeyword("SpacecraftPosition").addComment("Spacecraft Information"); gp->findKeyword("SpacecraftAzimuth").setValue(toString( m_camera->SpacecraftAzimuth())); gp->findKeyword("SlantDistance").setValue(toString( m_camera->SlantDistance()), "km"); gp->findKeyword("TargetCenterDistance").setValue(toString( m_camera->targetCenterDistance()), "km"); m_camera->subSpacecraftPoint(ssplat, ssplon); gp->findKeyword("SubSpacecraftLatitude").setValue(toString(ssplat)); gp->findKeyword("SubSpacecraftLongitude").setValue(toString(ssplon)); gp->findKeyword("SpacecraftAltitude").setValue(toString( m_camera->SpacecraftAltitude()), "km"); gp->findKeyword("OffNadirAngle").setValue(toString( m_camera->OffNadirAngle())); double subspcgrdaz; subspcgrdaz = m_camera->GroundAzimuth(m_camera->UniversalLatitude(), m_camera->UniversalLongitude(), ssplat, ssplon); gp->findKeyword("SubSpacecraftGroundAzimuth").setValue(toString(subspcgrdaz)); m_camera->sunPosition(sB); gp->findKeyword("SunPosition").addValue(toString(sB[0]), "km"); gp->findKeyword("SunPosition").addValue(toString(sB[1]), "km"); gp->findKeyword("SunPosition").addValue(toString(sB[2]), "km"); gp->findKeyword("SunPosition").addComment("Sun Information"); gp->findKeyword("SubSolarAzimuth").setValue(toString(m_camera->SunAzimuth())); gp->findKeyword("SolarDistance").setValue(toString( m_camera->SolarDistance()), "AU"); m_camera->subSolarPoint(sslat, sslon); gp->findKeyword("SubSolarLatitude").setValue(toString(sslat)); gp->findKeyword("SubSolarLongitude").setValue(toString(sslon)); double subsolgrdaz; subsolgrdaz = m_camera->GroundAzimuth(m_camera->UniversalLatitude(), m_camera->UniversalLongitude(), sslat, sslon); gp->findKeyword("SubSolarGroundAzimuth").setValue(toString(subsolgrdaz)); gp->findKeyword("Phase").setValue(toString(m_camera->PhaseAngle())); gp->findKeyword("Phase").addComment("Illumination and Other"); gp->findKeyword("Incidence").setValue(toString( m_camera->IncidenceAngle())); gp->findKeyword("Emission").setValue(toString( m_camera->EmissionAngle())); gp->findKeyword("NorthAzimuth").setValue(toString( m_camera->NorthAzimuth())); gp->findKeyword("EphemerisTime").setValue(toString( m_camera->time().Et()), "seconds"); gp->findKeyword("EphemerisTime").addComment("Time"); utc = m_camera->time().UTC(); gp->findKeyword("UTC").setValue(utc); gp->findKeyword("LocalSolarTime").setValue(toString( m_camera->LocalSolarTime()), "hour"); gp->findKeyword("SolarLongitude").setValue(toString( m_camera->solarLongitude().degrees())); if (allowErrors) gp->findKeyword("Error").setValue("N/A"); } } return gp; }
/** * GetPointInfo builds the PvlGroup containing all the important * information derived from the Camera. * * @return PvlGroup* Data taken directly from the Camera and * drived from Camera information. Ownership passed. */ PvlGroup * CameraPointInfo::GetPointInfo() { CheckConditions(); Brick b(3,3,1,currentCube->PixelType()); int intSamp = (int)(camera->Sample() + 0.5); int intLine = (int)(camera->Line() + 0.5); b.SetBasePosition(intSamp, intLine, 1); currentCube->Read(b); double pB[3], spB[3], sB[3]; string utc; double ssplat, ssplon, sslat, sslon, pwlon, oglat; // Create group with ground position PvlGroup * gp = new PvlGroup("GroundPoint"); { gp->AddKeyword(PvlKeyword("Filename",currentCube->Filename())); gp->AddKeyword(PvlKeyword("Sample",camera->Sample())); gp->AddKeyword(PvlKeyword("Line",camera->Line())); gp->AddKeyword(PvlKeyword("PixelValue",PixelToString(b[0]))); gp->AddKeyword(PvlKeyword("RightAscension",camera->RightAscension())); gp->AddKeyword(PvlKeyword("Declination",camera->Declination())); gp->AddKeyword(PvlKeyword("PlanetocentricLatitude", camera->UniversalLatitude())); // Convert lat to planetographic double radii[3]; camera->Radii(radii); oglat = Isis::Projection::ToPlanetographic(camera->UniversalLatitude(), radii[0],radii[2]); gp->AddKeyword(PvlKeyword("PlanetographicLatitude",oglat)); gp->AddKeyword(PvlKeyword("PositiveEast360Longitude", camera->UniversalLongitude())); //Convert lon to -180 - 180 range gp->AddKeyword(PvlKeyword("PositiveEast180Longitude", Isis::Projection::To180Domain( camera->UniversalLongitude()))); //Convert lon to positive west pwlon = Isis::Projection::ToPositiveWest(camera->UniversalLongitude(), 360); gp->AddKeyword(PvlKeyword("PositiveWest360Longitude",pwlon)); //Convert pwlon to -180 - 180 range gp->AddKeyword(PvlKeyword("PositiveWest180Longitude", Isis::Projection::To180Domain(pwlon))); camera->Coordinate(pB); PvlKeyword coord("BodyFixedCoordinate"); coord.AddValue(pB[0],"km"); coord.AddValue(pB[1],"km"); coord.AddValue(pB[2],"km"); gp->AddKeyword(coord); gp->AddKeyword(PvlKeyword("LocalRadius",camera->LocalRadius(),"m")); gp->AddKeyword(PvlKeyword("SampleResolution",camera->SampleResolution(),"m")); gp->AddKeyword(PvlKeyword("LineResolution",camera->LineResolution(),"m")); camera->InstrumentPosition(spB); PvlKeyword spcoord("SpacecraftPosition"); spcoord.AddValue(spB[0],"km"); spcoord.AddValue(spB[1],"km"); spcoord.AddValue(spB[2],"km"); spcoord.AddComment("Spacecraft Information"); gp->AddKeyword(spcoord); gp->AddKeyword(PvlKeyword("SpacecraftAzimuth",camera->SpacecraftAzimuth())); gp->AddKeyword(PvlKeyword("SlantDistance",camera->SlantDistance(),"km")); gp->AddKeyword(PvlKeyword("TargetCenterDistance",camera->TargetCenterDistance(),"km")); camera->SubSpacecraftPoint(ssplat,ssplon); gp->AddKeyword(PvlKeyword("SubSpacecraftLatitude",ssplat)); gp->AddKeyword(PvlKeyword("SubSpacecraftLongitude",ssplon)); gp->AddKeyword(PvlKeyword("SpacecraftAltitude",camera->SpacecraftAltitude(),"km")); gp->AddKeyword(PvlKeyword("OffNadirAngle",camera->OffNadirAngle())); double subspcgrdaz; subspcgrdaz = camera->GroundAzimuth(camera->UniversalLatitude(),camera->UniversalLongitude(), ssplat,ssplon); gp->AddKeyword(PvlKeyword("SubSpacecraftGroundAzimuth",subspcgrdaz)); camera->SunPosition(sB); PvlKeyword scoord("SunPosition"); scoord.AddValue(sB[0],"km"); scoord.AddValue(sB[1],"km"); scoord.AddValue(sB[2],"km"); scoord.AddComment("Sun Information"); gp->AddKeyword(scoord); gp->AddKeyword(PvlKeyword("SubSolarAzimuth",camera->SunAzimuth())); gp->AddKeyword(PvlKeyword("SolarDistance",camera->SolarDistance(),"AU")); camera->SubSolarPoint(sslat,sslon); gp->AddKeyword(PvlKeyword("SubSolarLatitude",sslat)); gp->AddKeyword(PvlKeyword("SubSolarLongitude",sslon)); double subsolgrdaz; subsolgrdaz = camera->GroundAzimuth(camera->UniversalLatitude(),camera->UniversalLongitude(), sslat,sslon); gp->AddKeyword(PvlKeyword("SubSolarGroundAzimuth",subsolgrdaz)); PvlKeyword phase("Phase",camera->PhaseAngle()); phase.AddComment("Illumination and Other"); gp->AddKeyword(phase); gp->AddKeyword(PvlKeyword("Incidence",camera->IncidenceAngle())); gp->AddKeyword(PvlKeyword("Emission",camera->EmissionAngle())); gp->AddKeyword(PvlKeyword("NorthAzimuth",camera->NorthAzimuth())); PvlKeyword et("EphemerisTime",camera->EphemerisTime(),"seconds"); et.AddComment("Time"); gp->AddKeyword(et); iTime t(camera->EphemerisTime()); utc = t.UTC(); gp->AddKeyword(PvlKeyword("UTC",utc)); gp->AddKeyword(PvlKeyword("LocalSolarTime",camera->LocalSolarTime(),"hour")); gp->AddKeyword(PvlKeyword("SolarLongitude",camera->SolarLongitude())); } return gp; }