/** * Calculates the lat/lon of the ControlNet. * * @param incubes The filename of the list of cubes in the ControlNet * @param cnet The filename of the ControlNet */ void setControlPointLatLon(SerialNumberList &snl, ControlNet &cnet) { CubeManager manager; manager.SetNumOpenCubes(50); //Should keep memory usage to around 1GB Progress progress; progress.SetText("Calculating Lat/Lon"); progress.SetMaximumSteps(cnet.GetNumPoints()); progress.CheckStatus(); for (int cp = 0; cp < cnet.GetNumPoints(); cp++) { ControlPoint *point = cnet.GetPoint(cp); ControlMeasure *cm = point->GetRefMeasure(); Cube *cube = manager.OpenCube(snl.FileName(cm->GetCubeSerialNumber())); try { cube->camera()->SetImage(cm->GetSample(), cm->GetLine()); g_surfacePoints[point->GetId()] = cube->camera()->GetSurfacePoint(); } catch (IException &e) { QString msg = "Unable to create camera for cube file ["; msg += snl.FileName(cm->GetCubeSerialNumber()) + "]"; throw IException(e, IException::Unknown, msg, _FILEINFO_); } cube = NULL; //Do not delete, manager still has ownership progress.CheckStatus(); } manager.CleanCubes(); }
//Helper function to load camera range. void LoadCameraRange() { UserInterface &ui = Application::GetUserInterface(); QString file = ui.GetFileName("FROM"); // Get the map projection file provided by the user Pvl userMap; userMap.read(ui.GetFileName("MAP")); // Open the input cube, get the camera object, and the cam map projection Cube c; c.open(file); Camera *cam = c.camera(); // Make the target info match the user mapfile double minrad, maxrad, minaz, maxaz; cam->ringRange(minrad, maxrad, minaz, maxaz, userMap); // Set ground range parameters in UI ui.Clear("MINRINGRAD"); ui.PutDouble("MINRINGRAD", minrad); ui.Clear("MAXRINGRAD"); ui.PutDouble("MAXRINGRAD", maxrad); ui.Clear("MINRINGLON"); ui.PutDouble("MINRINGLON", minaz); ui.Clear("MAXRINGLON"); ui.PutDouble("MAXRINGLON", maxaz); // Set default ground range param to camera ui.Clear("DEFAULTRANGE"); ui.PutAsString("DEFAULTRANGE", "CAMERA"); }
void IsisMain() { // Set the input image, get the camera model Process p; Cube *icube = p.SetInputCube("FROM"); Camera *cam = icube->camera(); // Get the ra/dec range and resolution double minRa, maxRa, minDec, maxDec; cam->RaDecRange(minRa, maxRa, minDec, maxDec); double res = cam->RaDecResolution(); // Get the center ra/dec cam->SetImage(icube->sampleCount() / 2.0, icube->lineCount() / 2.0); double centerRa = cam->RightAscension(); double centerDec = cam->Declination(); // Compute the rotation cam->SetRightAscensionDeclination(centerRa, centerDec + 2.0 * res); double x = cam->Sample() - icube->sampleCount() / 2.0; double y = cam->Line() - icube->lineCount() / 2.0; double rot = atan2(-y, x) * 180.0 / Isis::PI; rot = 90.0 - rot; if(rot < 0.0) rot += 360.0; // Setup and log results PvlGroup results("Range"); results += PvlKeyword("MinimumRightAscension", toString(minRa), "degrees"); results += PvlKeyword("MaximumRightAscension", toString(maxRa), "degrees"); results += PvlKeyword("MinimumDeclination", toString(minDec), "degrees"); results += PvlKeyword("MaximumDeclination", toString(maxDec), "degrees"); results += PvlKeyword("MinimumRightAscension", Projection::ToHMS(minRa), "hms"); results += PvlKeyword("MaximumRightAscension", Projection::ToHMS(maxRa), "hms"); results += PvlKeyword("MinimumDeclination", Projection::ToDMS(minDec), "dms"); results += PvlKeyword("MaximumDeclination", Projection::ToDMS(maxDec), "dms"); results += PvlKeyword("Resolution", toString(res), "degrees/pixel"); Application::Log(results); // Setup and log orientation PvlGroup orient("Orientation"); orient += PvlKeyword("CenterSample", toString(icube->sampleCount() / 2.0)); orient += PvlKeyword("CenterLine", toString(icube->lineCount() / 2.0)); orient += PvlKeyword("CenterRightAscension", toString(centerRa), "degrees"); orient += PvlKeyword("CenterDeclination", toString(centerDec), "degrees"); orient += PvlKeyword("CelestialNorthClockAngle", toString(rot), "degrees"); orient += PvlKeyword("Resolution", toString(res), "degrees/pixel"); Application::Log(orient); // Write the output file if requested UserInterface ui = Application::GetUserInterface(); if(ui.WasEntered("TO")) { Pvl temp; temp.addGroup(results); temp.addGroup(orient); temp.write(ui.GetFileName("TO", "txt")); } p.EndProcess(); }
void IsisMain() { UserInterface &ui = Application::GetUserInterface(); try { // Open the cube Cube cube; cube.open(ui.GetFileName("FROM"), "rw"); //check for existing polygon, if exists delete it if(cube.label()->hasObject("Polygon")) { cube.label()->deleteObject("Polygon"); } // Get the camera, interpolate to a parabola Camera *cam = cube.camera(); if(cam->DetectorMap()->LineRate() == 0.0) { QString msg = "[" + ui.GetFileName("FROM") + "] is not a line scan camera"; throw IException(IException::User, msg, _FILEINFO_); } cam->instrumentRotation()->SetPolynomial(); // Get the instrument pointing keyword from the kernels group and update // its value to table. Isis::PvlGroup kernels = cube.label()->findGroup("Kernels", Isis::Pvl::Traverse); // Save original kernels in keyword before changing to "Table" in the kernels group PvlKeyword origCk = kernels["InstrumentPointing"]; // Write out the "Table" label to the tabled kernels in the kernels group kernels["InstrumentPointing"] = "Table"; // And finally write out the original kernels after Table for (int i = 0; i < origCk.size(); i++) { kernels["InstrumentPointing"].addValue(origCk[i]); } cube.putGroup(kernels); // Pull out the pointing cache as a table and write it Table cmatrix = cam->instrumentRotation()->Cache("InstrumentPointing"); cmatrix.Label().addComment("Smoothed using spicefit"); cube.write(cmatrix); cube.close(); } catch(IException &e) { QString msg = "Unable to fit pointing for [" + ui.GetFileName("FROM") + "]"; throw IException(IException::User, msg, _FILEINFO_); } }
// Helper function to get output summing mode from input cube (FROM) void LoadInputSummingMode() { UserInterface &ui = Application::GetUserInterface(); // Get camera from cube to match QString file = ui.GetFileName("FROM"); // Open the input cube and get the camera object Cube c; c.open(file); Camera *cam = c.camera(); ui.Clear("SUMMINGMODE"); ui.PutDouble("SUMMINGMODE", cam->DetectorMap()->SampleScaleFactor()); ui.Clear("SOURCE"); ui.PutAsString("SOURCE", "FROMUSER"); }
/** * @brief Initializes an ISIS cube converting it into a SPICE segment * * This method is called to extract the perinent contents of an ISIS cube file * and accumulate generic information that is used to create the output SPICE * kernel segment. Other specific kernel types can use this class as its base * class and add to it additional elements to complete the needed content for * the NAIF kernel. * * @param cube ISIS cube file to accumulate information from */ void SpiceSegment::init(Cube &cube) { _kernels.UnLoad(); // Unload all active, owned kernels init(); // Init local variables _fname = cube.fileName(); // Extract ISIS CK blob and transform to CK 3 content NaifStatus::CheckErrors(); try { // Order is somewhat important here. The call to initialize Kernels // object checks the NAIF pool for existance. It logs their NAIF // status as loaded which may cause trouble from here on... Pvl *label = cube.label(); _kernels.Init(*label); Camera *camera = cube.camera(); // Determine segment ID from product ID if it exists, otherwise basename if ( _name.isEmpty() ) { _name = getKeyValue(*label, "ProductId"); if (_name.isEmpty() ) { _name = FileName(_fname).baseName(); } } // Get instrument and target ids QString value(""); value = getKeyValue(*label, "InstrumentId"); if (!value.isEmpty()) { _instId = value; } value = getKeyValue(*label, "TargetName"); if (!value.isEmpty()) { _target = value; } // Get default times for sorting purposes setStartTime(camera->cacheStartTime().Et()); setEndTime(camera->cacheEndTime().Et()); } catch ( IException &ie ) { ostringstream mess; mess << "Failed to construct Spice Segment basics from ISIS file " << _fname; throw IException(ie, IException::User, mess.str(), _FILEINFO_); } return; }
//Helper function to get camera resolution. void LoadCameraRes() { UserInterface &ui = Application::GetUserInterface(); QString file = ui.GetFileName("FROM"); // Open the input cube, get the camera object, and the cam map projection Cube c; c.open(file); Camera *cam = c.camera(); Pvl camMap; cam->BasicMapping(camMap); PvlGroup &camGrp = camMap.findGroup("Mapping"); ui.Clear("RESOLUTION"); ui.PutDouble("RESOLUTION", camGrp["PixelResolution"]); ui.Clear("PIXRES"); ui.PutAsString("PIXRES", "MPP"); }
// Helper function to get output summing mode from cube to MATCH void LoadMatchSummingMode() { QString file; UserInterface &ui = Application::GetUserInterface(); // Get camera from cube to match if((ui.GetString("SOURCE") == "FROMMATCH") && (ui.WasEntered("MATCH"))) { file = ui.GetFileName("MATCH"); } else { file = ui.GetFileName("FROM"); } // Open the input cube and get the camera object Cube c; c.open(file); Camera *cam = c.camera(); ui.Clear("SUMMINGMODE"); ui.PutDouble("SUMMINGMODE", cam->DetectorMap()->SampleScaleFactor()); ui.Clear("SOURCE"); ui.PutAsString("SOURCE", "FROMUSER"); }
void IsisMain() { // We will be processing by line ProcessByBrick p; UserInterface &ui = Application::GetUserInterface(); // Use the def file for filter constants Pvl uvvisDef("$clementine1/calibration/uvvis/uvvis.def"); // Setup the input and output cubes Cube *icube = p.SetInputCube("FROM"); Cube *dccube; if(ui.WasEntered("DCFILE")) { dccube = p.SetInputCube("DCFILE"); } else { QString dcfileloc = "$clementine1/calibration/uvvis/"; dcfileloc += "dark_5_15_96.cub"; CubeAttributeInput cubeAtt; dccube = p.SetInputCube(dcfileloc, cubeAtt); } QString filter = (QString)(icube->group("BandBin"))["FilterName"]; filter = filter.toLower(); Cube *ffcube; if(ui.WasEntered("FFFILE")) { ffcube = p.SetInputCube("FFFILE"); } else { // compute default fffile double compressRatio = (icube->group("Instrument"))["EncodingCompressionRatio"]; // check to see if cube is compressed or uncompressed if(compressRatio == 1.0) { QString fffileLoc = "$clementine1/calibration/uvvis/"; fffileLoc += "lu" + filter + "_uncomp_flat_long.cub"; CubeAttributeInput cubeAtt; ffcube = p.SetInputCube(fffileLoc, cubeAtt); } else { QString fffileLoc = "$clementine1/calibration/uvvis/"; fffileLoc += "lu" + filter + "_comp_flat_long.cub"; CubeAttributeInput cubeAtt; ffcube = p.SetInputCube(fffileLoc, cubeAtt); } } Cube *ocube = p.SetOutputCube("TO"); avgFF = uvvisDef.findGroup("Filter" + filter.toUpper())["AVGFF"]; cr = uvvisDef.findGroup("Filter" + filter.toUpper())["CO"]; gain = uvvisDef.findGroup(QString("GainModeID") + QString(icube->group("Instrument")["GainModeID"][0]))["GAIN"]; useDcconst = ui.WasEntered("DCCONST"); if(useDcconst) { dcconst = ui.GetDouble("DCCONST"); } else { dcconst = 0.0; } conv = ui.GetBoolean("CONV"); exposureDuration = icube->group("Instrument")["ExposureDuration"]; offsetModeID = icube->group("Instrument")["OffsetModeID"]; if(((QString)icube->group("Instrument")["FocalPlaneTemperature"]).compare("UNK") == 0) { //if FocalPlaneTemp is unknown set it to zero focalPlaneTemp = 0.0; } else { focalPlaneTemp = icube->group("Instrument")["FocalPlaneTemperature"]; } Camera *cam = icube->camera(); bool camSuccess = cam->SetImage(icube->sampleCount() / 2, icube->lineCount() / 2); if(!camSuccess) { throw IException(IException::Unknown, "Unable to calculate the Solar Distance for this cube.", _FILEINFO_); } dist = cam->SolarDistance(); // If temp. correction set to true, or focal plane temp is zero then use temperature correction if(ui.GetBoolean("TCOR") || abs(focalPlaneTemp) <= DBL_EPSILON) { // Temperature correction requires the use of the mission phase // (PRELAUNCH, EARTH, LUNAR) and the product ID. QString productID = (QString)(icube->group("Archive")["ProductID"]); QChar missionPhase = ((QString)((icube->group("Archive"))["MissionPhase"])).at(0); QString n1subQString(productID.mid(productID.indexOf('.') + 1, productID.length() - 1)); QString n2subQString(productID.mid(4, productID.indexOf('.') - 5)); int n1 = toInt(n1subQString); int n2 = toInt(n2subQString); int phase = 0; if(missionPhase == 'L') { phase = 0; } else if(missionPhase == 'E') { phase = 1; } else if(missionPhase == 'P') { phase = 2; } else { throw IException(IException::Unknown, "Invalid Mission Phase", _FILEINFO_); } // This formula makes the primary search critera the original product ID's extension, // the secondary search criteria the mission phase and finally the numerical part of the // original product ID. int imageID = (100000 * n1) + (10000 * phase) + n2; FixTemp(imageID); } if(focalPlaneTemp <= 0.0) { focalPlaneTemp = 272.5; } // Start the processing p.SetBrickSize(icube->sampleCount(), icube->lineCount(), 1); p.StartProcess(UvVisCal); // Add the radiometry group PvlGroup calgrp("Radiometry"); calgrp += PvlKeyword("FlatFieldFile", ffcube->fileName()); if(ui.GetString("DARKCURRENT").compare("DCFILE") == 0) { calgrp += PvlKeyword("DarkCurrentFile", dccube->fileName()); } else { calgrp += PvlKeyword("DarkCurrentConstant", toString(dcconst)); } calgrp += PvlKeyword("CorrectedFocalPlaneTemp", toString(focalPlaneTemp)); calgrp += PvlKeyword("C1", toString(avgFF)); calgrp += PvlKeyword("C2", toString(C2)); calgrp += PvlKeyword("C3", toString(C3)); calgrp += PvlKeyword("C4", toString(C4)); calgrp += PvlKeyword("C5", toString(C5)); calgrp += PvlKeyword("CR", toString(cr)); calgrp += PvlKeyword("FrameTransferTimePerRow", toString(cr)); calgrp += PvlKeyword("Gain", toString(gain)); calgrp += PvlKeyword("CorrectedExposureDuration", toString(correctedExposureDuration)); calgrp += PvlKeyword("ConvertToRadiance", toString(conv)); calgrp += PvlKeyword("ACO", toString(ACO)); calgrp += PvlKeyword("BCO", toString(BCO)); calgrp += PvlKeyword("CCO", toString(CCO)); calgrp += PvlKeyword("DCO", toString(DCO)); ocube->putGroup(calgrp); p.EndProcess(); }
void IsisMain() { // Open the match cube and get the camera model on it ProcessRubberSheet m; Cube *mcube = m.SetInputCube("MATCH"); Cube *ocube = m.SetOutputCube("TO"); // Set up the default reference band to the middle of the cube // If we have even bands it will be close to the middle int referenceBand = ocube->bandCount(); referenceBand += (referenceBand % 2); referenceBand /= 2; // See if the user wants to override the reference band UserInterface &ui = Application::GetUserInterface(); if(ui.WasEntered("REFBAND")) { referenceBand = ui.GetInteger("REFBAND"); } // Using the Camera method out of the object opack will not work, because the // filename required by the Camera is not passed by the process class in this // case. Use the CameraFactory to create the Camera instead to get around this // problem. Camera *outcam = CameraFactory::Create(*(mcube->label())); // Set the reference band we want to match PvlGroup instgrp = mcube->group("Instrument"); if(!outcam->IsBandIndependent()) { PvlKeyword rBand("ReferenceBand", toString(referenceBand)); rBand.addComment("# All bands are aligned to reference band"); instgrp += rBand; mcube->putGroup(instgrp); delete outcam; outcam = NULL; } // Only recreate the output camera if it was band dependent if(outcam == NULL) outcam = CameraFactory::Create(*(mcube->label())); // We might need the instrument group later, so get a copy before clearing the input // cubes. m.ClearInputCubes(); Cube *icube = m.SetInputCube("FROM"); incam = icube->camera(); // Set up the transform object which will simply map // output line/samps -> output lat/lons -> input line/samps Transform *transform = new cam2cam(icube->sampleCount(), icube->lineCount(), incam, ocube->sampleCount(), ocube->lineCount(), outcam); // Add the reference band to the output if necessary ocube->putGroup(instgrp); // Set up the interpolator Interpolator *interp = NULL; if(ui.GetString("INTERP") == "NEARESTNEIGHBOR") { interp = new Interpolator(Interpolator::NearestNeighborType); } else if(ui.GetString("INTERP") == "BILINEAR") { interp = new Interpolator(Interpolator::BiLinearType); } else if(ui.GetString("INTERP") == "CUBICCONVOLUTION") { interp = new Interpolator(Interpolator::CubicConvolutionType); } // See if we need to deal with band dependent camera models if(!incam->IsBandIndependent()) { m.BandChange(BandChange); } // Warp the cube m.StartProcess(*transform, *interp); m.EndProcess(); // Cleanup delete transform; delete interp; }
//! This function corrects the DNs in a given brick. //! It also stores results in frameletOffsetsForBand every time the //! band changes so it doesn't have to re-project at every framelet. //! Equivalent changes are calculated for the next framelet... that is, //! equivalent pixels. This function both calculates and applies these. void RemoveSeam(Buffer &out, int framelet, int band, bool matchIsEven) { // Apply fixes from last pass. Basically all changes happen in two // places, because the DNs exist in two cubes, this is the second // place. for(int fix = 0; fix < nextFrameletFixes.size(); fix ++) { QPair<int, int> fixLoc = nextFrameletFixes[fix].first; double fixDn = nextFrameletFixes[fix].second; try { int outIndex = out.Index(fixLoc.first, fixLoc.second, band); out[outIndex] = fixDn; } catch(IException &) { } } nextFrameletFixes.clear(); // Match == goodData. "goodData" is the top of the next framelet. Cube *goodDataCube = (matchIsEven) ? evenCube : oddCube; // "badData" is the bottom of the current framelet, what we were given. Cube *badDataCube = (matchIsEven) ? oddCube : evenCube; Camera *goodCam = goodDataCube->camera(); Camera *badCam = badDataCube->camera(); // Verify we're at the correct band goodCam->SetBand(band); badCam->SetBand(band); // Absolute line number for top of framelets. int goodDataStart = frameletSize * (framelet + 1); int badDataStart = frameletSize * framelet; // Start corrections to the current brick at this line int badLineStart = goodDataStart - overlapSize - 1; // End corrections to the current brick at this line int badLineEnd = goodDataStart - 1; int offsetSample = 0; int offsetLine = 0; // Loop left to right, top to bottom of problematic area at bottom of framelet for(int badLine = badLineStart; badLine <= badLineEnd; badLine ++) { for(int sample = 1; sample <= out.SampleDimension(); sample ++) { // A fair good data weight is the % across problematic area so fair double goodDataWeight = (double)(badLine - badLineStart) / (double)(badLineEnd - badLineStart); // But good data is good, so let's bias it towards the good data goodDataWeight *= 2; if(goodDataWeight > 1) goodDataWeight = 1; // Bad data weight is the inverse of the good data's weight. double badDataWeight = 1.0 - goodDataWeight; int outIndex = out.Index(sample, badLine, band); // This is the indexing scheme for frameletOffsetsForBand int optimizeIndex = (badLine - badLineStart) * out.SampleDimension() + sample - 1; // Does the optimized (pre-calculated) translation from bad to good // exist? if(optimizeIndex < frameletOffsetsForBand.size()) { // This offset any good? If not then do nothing. if(!frameletOffsetsForBand[optimizeIndex].Valid()) continue; // Use optimization! offsetSample = frameletOffsetsForBand[optimizeIndex].SampleOffset(); offsetLine = frameletOffsetsForBand[optimizeIndex].LineOffset(); ASSERT(frameletOffsetsForBand[optimizeIndex].Sample() == sample); } // There is no pre-calculated translation, calculate it else if(badCam->SetImage(sample, badLine)) { double lat = badCam->UniversalLatitude(); double lon = badCam->UniversalLongitude(); if(goodCam->SetUniversalGround(lat, lon)) { double goodSample = goodCam->Sample(); double goodLine = goodCam->Line(); // Set the current offset for correction offsetSample = (int)(goodSample - sample + 0.5); offsetLine = (int)(goodLine - badLine + 0.5); // Remember this calculation for future passes frameletOffsetsForBand.push_back(Offset(sample, badLine - badDataStart, offsetSample, offsetLine)); } else { // Don't do anything since we failed at this pixel; it will be copied // from the input directly frameletOffsetsForBand.push_back(Offset()); continue; } } // Translate current sample,line (bad) to (good) data's sample,line double goodSample = offsetSample + sample; double goodLine = offsetLine + badLine; // Get the pixel we're missing (good) Portal p(1, 1, goodDataCube->pixelType()); p.SetPosition(goodSample, goodLine, band); goodDataCube->read(p); // Attempt to apply weighted average if(!Isis::IsSpecial(p[0]) && !Isis::IsSpecial(out[outIndex])) { out[outIndex] = p[0] * goodDataWeight + out[outIndex] * badDataWeight; } else if(!Isis::IsSpecial(p[0])) { out[outIndex] = p[0]; } // Apply change to next framelet also QPair<int, int> fixLoc((int)(goodSample + 0.5), (int)(goodLine + 0.5)); QPair< QPair<int, int>, double > fix(fixLoc, out[outIndex]); nextFrameletFixes.push_back(fix); } } }
/** The ISIS smtk main application */ void IsisMain() { UserInterface &ui = Application::GetUserInterface(); // Open the first cube. It is the left hand image. Cube lhImage; CubeAttributeInput &attLeft = ui.GetInputAttribute("FROM"); vector<QString> bandLeft = attLeft.bands(); lhImage.setVirtualBands(bandLeft); lhImage.open(ui.GetFileName("FROM"),"r"); // Open the second cube, it is geomertricallty altered. We will be matching the // first to this one by attempting to compute a sample/line offsets Cube rhImage; CubeAttributeInput &attRight = ui.GetInputAttribute("MATCH"); vector<QString> bandRight = attRight.bands(); rhImage.setVirtualBands(bandRight); rhImage.open(ui.GetFileName("MATCH"),"r"); // Ensure only single bands if (lhImage.bandCount() != 1 || rhImage.bandCount() != 1) { QString msg = "Input Cubes must have only one band!"; throw IException(IException::User,msg,_FILEINFO_); } // Both images must have a Camera and can also have a Projection. We will // only deal with a Camera, however as a projected, non-mosaicked image // uses a Projection internal to the Camera object. Camera *lhCamera = NULL; Camera *rhCamera = NULL; try { lhCamera = lhImage.camera(); rhCamera = rhImage.camera(); } catch (IException &ie) { QString msg = "Both input images must have a camera"; throw IException(ie, IException::User, msg, _FILEINFO_); } // Since we are generating a DEM, we must turn off any existing // DEM that may have been initialized with spiceinit. lhCamera->IgnoreElevationModel(true); rhCamera->IgnoreElevationModel(true); // Get serial number QString serialLeft = SerialNumber::Compose(lhImage, true); QString serialRight = SerialNumber::Compose(rhImage, true); // This still precludes band to band registrations. if (serialLeft == serialRight) { QString sLeft = FileName(lhImage.fileName()).name(); QString sRight = FileName(rhImage.fileName()).name(); if (sLeft == sRight) { QString msg = "Cube Serial Numbers must be unique - FROM=" + serialLeft + ", MATCH=" + serialRight; throw IException(IException::User,msg,_FILEINFO_); } serialLeft = sLeft; serialRight = sRight; } Progress prog; prog.SetText("Finding Initial Seeds"); int nl = lhImage.lineCount(); int ns = lhImage.sampleCount(); BigInt numAttemptedInitialPoints = 0; // Declare Gruen matcher SmtkMatcher matcher(ui.GetFileName("REGDEF"), &lhImage, &rhImage); // Get line/sample linc/sinc parameters int space = ui.GetInteger("SPACE"); int linc (space), sinc(space); // Do we have a seed points from a control net file? bool useseed = ui.WasEntered("CNET"); // Base points on an input cnet SmtkQStack gstack; double lastEigen(0.0); if (useseed) { ControlNet cnet(ui.GetFileName("CNET")); prog.SetMaximumSteps(cnet.GetNumPoints()); prog.CheckStatus(); gstack.reserve(cnet.GetNumPoints()); for (int cpIndex = 0; cpIndex < cnet.GetNumPoints(); cpIndex ++) { ControlPoint *cp = cnet.GetPoint(cpIndex); if (!cp->IsIgnored()) { ControlMeasure *cmLeft(0), *cmRight(0); for(int cmIndex = 0; cmIndex < cp->GetNumMeasures(); cmIndex ++) { ControlMeasure *cm = cp->GetMeasure(cmIndex); if (!cm->IsIgnored()) { if (cm->GetCubeSerialNumber() == serialLeft) cmLeft = cp->GetMeasure(cmIndex); if (cm->GetCubeSerialNumber() == serialRight) cmRight = cp->GetMeasure(cmIndex); } } // If we have both left and right images in the control point, save it if ( (cmLeft != 0) && (cmRight != 0) ) { Coordinate left = Coordinate(cmLeft->GetLine(), cmLeft->GetSample()); Coordinate right = Coordinate(cmRight->GetLine(), cmRight->GetSample()); SmtkPoint spnt = matcher.Create(left, right); // Insert the point (unregistered) if ( spnt.isValid() ) { int line = (int) cmLeft->GetLine(); int samp = (int) cmLeft->GetSample(); matcher.isValid(spnt); gstack.insert(qMakePair(line, samp), spnt); lastEigen = spnt.GoodnessOfFit(); } } } prog.CheckStatus(); } } else { // We want to create a grid of control points that is N rows by M columns. int rows = (lhImage.lineCount() + linc - 1)/linc; int cols = (lhImage.sampleCount() + sinc - 1)/sinc; prog.SetMaximumSteps(rows * cols); prog.CheckStatus(); // First pass stack and eigen value statistics SmtkQStack fpass; fpass.reserve(rows * cols); Statistics temp_mev; // Loop through grid of points and get statistics to compute // initial set of points for (int line = linc / 2 + 1; line < nl; line += linc) { for (int samp = sinc / 2 + 1 ; samp < ns; samp += sinc) { numAttemptedInitialPoints ++; SmtkPoint spnt = matcher.Register(Coordinate(line,samp)); if ( spnt.isValid() ) { matcher.isValid(spnt); fpass.insert(qMakePair(line, samp), spnt); temp_mev.AddData(spnt.GoodnessOfFit()); } prog.CheckStatus(); } } // Now select a subset of fpass points as the seed points cout << "Number of Potential Seed Points: " << fpass.size() << "\n"; cout << "Min / Max Eigenvalues Matched: " << temp_mev.Minimum() << ", " << temp_mev.Maximum() << "\n"; // How many seed points are requested double nseed = ui.GetDouble("NSEED"); int inseed; if (nseed >= 1.0) inseed = (int) nseed; else if (nseed > 0.0) inseed = (int) (nseed * (double) (fpass.size())); else inseed = (int) ((double) (fpass.size()) * 0.05); double seedsample = ui.GetDouble("SEEDSAMPLE"); // Generate a new stack gstack.reserve(inseed); while ((gstack.size() < inseed) && (!fpass.isEmpty() )) { SmtkQStack::iterator bestm; if (seedsample <= 0.0) { bestm = matcher.FindSmallestEV(fpass); } else { bestm = matcher.FindExpDistEV(fpass, seedsample, temp_mev.Minimum(), temp_mev.Maximum()); } // Add point to stack if (bestm != fpass.end()) { Coordinate right = bestm.value().getRight(); matcher.isValid(bestm.value()); gstack.insert(bestm.key(), bestm.value()); lastEigen = bestm.value().GoodnessOfFit(); fpass.erase(bestm); } } // If a user wants to see the seed network, write it out here if (ui.WasEntered("OSEEDNET")) { WriteCnet(ui.GetFileName("OSEEDNET"), gstack, lhCamera->target()->name(), serialLeft, serialRight); } } /////////////////////////////////////////////////////////////////////// // All done with seed points. Sanity check ensures we actually found // some. /////////////////////////////////////////////////////////////////////// if (gstack.size() <= 0) { QString msg = "No seed points found - may need to check Gruen parameters."; throw IException(IException::User, msg, _FILEINFO_); } // Report seed point status if (!useseed) { cout << "Number of Seed Points used: " << gstack.size() << "\n"; cout << "EV of last Seed Point: " << lastEigen << "\n"; } else { cout << "Number of Manual Seed Points: " << gstack.size() << "\n"; } // Use seed points (in stack) to grow SmtkQStack bmf; bmf.reserve(gstack.size()); // Probably need much more but for starters... BigInt numOrigPoints = gstack.size(); BigInt passpix2 = 0; int subcbox = ui.GetInteger("SUBCBOX"); int halfBox((subcbox-1)/2); while (!gstack.isEmpty()) { SmtkQStackIter cstack = matcher.FindSmallestEV(gstack); // Print number on stack if ((gstack.size() % 1000) == 0) { cout << "Number on Stack: " << gstack.size() << ". " << cstack.value().GoodnessOfFit() << "\n"; } // Test to see if already determined SmtkQStackIter bmfPt = bmf.find(cstack.key()); if (bmfPt == bmf.end()) { // Its not in the final stack, process it // Retrieve the point SmtkPoint spnt = cstack.value(); // Register if its not already registered if (!spnt.isRegistered()) { spnt = matcher.Register(spnt, spnt.getAffine()); } // Still must check for validity if the point was just registered, // otherwise should be good if ( spnt.isValid() ) { passpix2++; bmf.insert(cstack.key(), spnt); // inserts (0,0) offset excluded below int line = cstack.key().first; int sample = cstack.key().second; // Determine match points double eigen(spnt.GoodnessOfFit()); for (int sampBox = -halfBox ; sampBox <= halfBox ; sampBox++ ) { int csamp = sample + sampBox; for (int lineBox = -halfBox ; lineBox <= halfBox ; lineBox++) { int cline = line + lineBox; if ( !( (sampBox == 0) && (lineBox == 0)) ) {// Already added above SmtkQPair dupPair(cline, csamp); SmtkQStackIter temp = bmf.find(dupPair); SmtkPoint bmfpnt; if (temp != bmf.end()) { if (temp.value().GoodnessOfFit() > eigen) { // Create cloned point with better fit bmfpnt = matcher.Clone(spnt, Coordinate(cline,csamp)); } } else { // ISIS2 is BMF(SAMP,LINE,7) .EQ VALID_MAX4) // Clone new point for insert bmfpnt = matcher.Clone(spnt, Coordinate(cline,csamp)); } // Add if good point if (bmfpnt.isValid()) { bmf.insert(dupPair, bmfpnt); } } } } // Grow stack with spacing adding info to stack for (int i = -1 ; i <= 1 ; i ++) { // Sample for (int j = -1 ; j <= 1 ; j ++) { // Line // Don't re-add the original sample, line if ( !((i == 0) && (j == 0)) ) { // Grow based upon spacing double ssamp = sample + (i * space); double sline = line + (j * space); Coordinate pnt = Coordinate(sline, ssamp); SmtkPoint gpnt = matcher.Clone(spnt, pnt); if ( gpnt.isValid() ) { SmtkQPair growpt((int) sline, (int) ssamp); // double check we don't have a finalized result at this position SmtkQStackIter temp = bmf.find(growpt); if(temp == bmf.end()) { gstack.insert(growpt, gpnt); } } } } } } } // Remove the current point from the grow stack (hole) gstack.erase(cstack); } ///////////////////////////////////////////////////////////////////////// // All done with creating points. Perform output options. ///////////////////////////////////////////////////////////////////////// // If a TO parameter was specified, create DEM with errors if (ui.WasEntered("TO")) { // Create the output DEM cout << "\nCreating output DEM from " << bmf.size() << " points.\n"; Process p; Cube *icube = p.SetInputCube("FROM"); Cube *ocube = p.SetOutputCube("TO", icube->sampleCount(), icube->lineCount(), 3); p.ClearInputCubes(); int boxsize = ui.GetInteger("BOXSIZE"); double plotdist = ui.GetDouble("PLOTDIST"); TileManager dem(*ocube), eigen(*ocube), stErr(*ocube); dem.SetTile(1, 1); // DEM Data/elevation stErr.SetTile(1, 2); // Error in stereo computation eigen.SetTile(1, 3); // Eigenvalue of the solution int nBTiles(eigen.Tiles()/3); // Total tiles / 3 bands prog.SetText("Creating DEM"); prog.SetMaximumSteps(nBTiles); prog.CheckStatus(); Statistics stAng; while ( !eigen.end() ) { // Must use the last band for this!! PointPlot tm = for_each(bmf.begin(), bmf.end(), PointPlot(dem, plotdist)); tm.FillPoints(*lhCamera, *rhCamera, boxsize, dem, stErr, eigen, &stAng); ocube->write(dem); ocube->write(stErr); ocube->write(eigen); dem.next(); stErr.next(); eigen.next(); prog.CheckStatus(); } // Report Stereo separation angles PvlGroup stresultsPvl("StereoSeparationAngle"); stresultsPvl += PvlKeyword("Minimum", toString(stAng.Minimum()), "deg"); stresultsPvl += PvlKeyword("Average", toString(stAng.Average()), "deg"); stresultsPvl += PvlKeyword("Maximum", toString(stAng.Maximum()), "deg"); stresultsPvl += PvlKeyword("StandardDeviation", toString(stAng.StandardDeviation()), "deg"); Application::Log(stresultsPvl); // Update the label with BandBin keywords PvlKeyword filter("FilterName", "Elevation", "meters"); filter.addValue("ElevationError", "meters"); filter.addValue("GoodnessOfFit", "unitless"); PvlKeyword center("Center", "1.0"); center.addValue("1.0"); center.addValue("1.0"); PvlGroup &bandbin = ocube->label()->findGroup("BandBin", PvlObject::Traverse); bandbin.addKeyword(filter, PvlContainer::Replace); bandbin.addKeyword(center, PvlContainer::Replace); center.setName("Width"); bandbin.addKeyword(center, PvlContainer::Replace); p.EndProcess(); } // If a cnet file was entered, write the ControlNet pvl to the file if (ui.WasEntered("ONET")) { WriteCnet(ui.GetFileName("ONET"), bmf, lhCamera->target()->name(), serialLeft, serialRight); } // Create output data PvlGroup totalPointsPvl("Totals"); totalPointsPvl += PvlKeyword("AttemptedPoints", toString(numAttemptedInitialPoints)); totalPointsPvl += PvlKeyword("InitialSuccesses", toString(numOrigPoints)); totalPointsPvl += PvlKeyword("GrowSuccesses", toString(passpix2)); totalPointsPvl += PvlKeyword("ResultingPoints", toString(bmf.size())); Application::Log(totalPointsPvl); Pvl arPvl = matcher.RegistrationStatistics(); PvlGroup smtkresultsPvl("SmtkResults"); smtkresultsPvl += PvlKeyword("SpiceOffImage", toString(matcher.OffImageErrorCount())); smtkresultsPvl += PvlKeyword("SpiceDistanceError", toString(matcher.SpiceErrorCount())); arPvl.addGroup(smtkresultsPvl); for(int i = 0; i < arPvl.groups(); i++) { Application::Log(arPvl.group(i)); } // add the auto registration information to print.prt PvlGroup autoRegTemplate = matcher.RegTemplate(); Application::Log(autoRegTemplate); // Don't need the cubes opened anymore lhImage.close(); rhImage.close(); }
int main() { Preference::Preferences(true); QString inputFile = "$mgs/testData/ab102401.lev2.cub"; Cube cube; cube.open(inputFile); Camera *c = NULL; c = cube.camera(); Pvl pvl = *cube.label(); MyCamera cam(cube); double line = 453.0; double sample = 534.0; Latitude lat(18.221, Angle::Degrees); Longitude lon(226.671, Angle::Degrees); double ra = 347.016; double dec = -51.2677; cout << endl << "Camera* from: " << inputFile << endl; QList<QPointF> ifovOffsets = c->PixelIfovOffsets(); cout << "Pixel Ifov: " << endl; foreach (QPointF offset, ifovOffsets) { cout << offset.x() << " , " << offset.y() << endl; } cout << "Line: " << line << ", Sample: " << sample << endl; cout << "Lat: " << lat.degrees() << ", Lon: " << lon.degrees() << endl; cout << "RightAscension: " << ra << ", Declination: " << dec << endl << endl; cout << "SetImage (sample, line): " << c->SetImage(sample, line) << endl << endl; cout << "NorthAzimuth: " << c->NorthAzimuth() << endl; cout << "SunAzimuth: " << c->SunAzimuth() << endl; cout << "SpacecraftAzimuth: " << c->SpacecraftAzimuth() << endl; cout << "OffNadirAngle: " << c->OffNadirAngle() << endl << endl; cout << "GroundAzimuth in North: " << c->GroundAzimuth(18.221, 226.671, 20.0, 230.0) << endl; cout << "GroundAzimuth in North: " << c->GroundAzimuth(20.0, 226.671, 20.0, 230.0) << endl; cout << "GroundAzimuth in North: " << c->GroundAzimuth(18.221, 355.0, 20.0, 6.671) << endl; cout << "GroundAzimuth in North: " << c->GroundAzimuth(18.221, 6.671, 20.0, 355.0) << endl; cout << "GroundAzimuth in North: " << c->GroundAzimuth(18.221, 6.671, 20.0, 6.671) << endl; cout << "GroundAzimuth in South: " << c->GroundAzimuth(-18.221, 226.671, -20.0, 230.0) << endl; cout << "GroundAzimuth in South: " << c->GroundAzimuth(-20.0, 226.671, -20.0, 230.0) << endl; cout << "GroundAzimuth in South: " << c->GroundAzimuth(-18.221, 355.0, -20.0, 6.671) << endl; cout << "GroundAzimuth in South: " << c->GroundAzimuth(-18.221, 6.671, -20.0, 355.0) << endl; cout << "GroundAzimuth in South: " << c->GroundAzimuth(-18.221, 6.671, -20.0, 6.671) << endl << endl; cout << "SetUniversalGround(lat, lon): " << c->SetGround(lat, lon) << endl; cout << "SetRightAscensionDeclination(ra, dec): " << c->SetRightAscensionDeclination(ra, dec) << endl; cout << "HasProjection: " << c->HasProjection() << endl; cam.IsBandIndependent(); cout << "ReferenceBand: " << c->ReferenceBand() << endl; cout << "HasReferenceBand: " << c->HasReferenceBand() << endl; cam.SetBand(7); cout << "Sample: " << setprecision(3) << c->Sample() << endl; cout << "Line: " << setprecision(3) << c->Line() << endl; try { double lat = 0, lon = 0; cout << "GroundRange: " << c->GroundRange(lat, lat, lon, lon, pvl) << endl; cout << "IntersectsLongitudeDomain: " << c->IntersectsLongitudeDomain(pvl) << endl; } catch(IException &e) { cout << "No mapping group found, so GroundRange and " << endl << "IntersectsLongitudeDomain cannot run." << endl; } cout << "PixelResolution: " << c->PixelResolution() << endl; cout << "LineResolution: " << c->LineResolution() << endl; cout << "SampleResolution: " << c->SampleResolution() << endl; cout << "DetectorResolution: " << c->DetectorResolution() << endl; cout << "LowestImageResolution: " << setprecision(4) << c->LowestImageResolution() << endl; cout << "HighestImageResolution: " << setprecision(3) << c->HighestImageResolution() << endl; cout << "Calling BasicMapping (pvl)..." << endl; c->BasicMapping(pvl); double pixRes2 = pvl.findGroup("Mapping")["PixelResolution"]; pixRes2 *= 10000000; pixRes2 = round(pixRes2); pixRes2 /= 10000000; pvl.findGroup("Mapping")["PixelResolution"] = toString(pixRes2); cout << "BasicMapping PVL: " << endl << pvl << endl << endl; cout << "FocalLength: " << c->FocalLength() << endl; cout << "PixelPitch: " << c->PixelPitch() << endl; cout << "Samples: " << c->Samples() << endl; cout << "Lines: " << c->Lines() << endl; cout << "Bands: " << c->Bands() << endl; cout << "ParentLines: " << c->ParentLines() << endl; cout << "ParentSamples: " << c->ParentSamples() << endl; try { cout << c->RaDecRange(ra, ra, dec, dec) << endl; } catch(IException &e) { e.print(); } try { cout << c->RaDecResolution() << endl; } catch(IException &e) { e.print(); } cout << "Calling Distortion, FocalPlane, "; cout << "Detector, Ground, and Sky Map functions... "; c->DistortionMap(); c->FocalPlaneMap(); c->DetectorMap(); c->GroundMap(); c->SkyMap(); cout << "Done." << endl; cout << "Calling IgnoreProjection (false)..." << endl; c->IgnoreProjection(false); cout << endl << "Testing SetUniversalGround(lat,lon,radius)..." << endl; lat.setDegrees(18.221); lon.setDegrees(226.671); double radius = 3414033.72108798; c->SetUniversalGround(lat.degrees(), lon.degrees(), radius); c->SetGround(SurfacePoint(lat, lon, Distance(radius, Distance::Meters))); cout << "Has intersection " << c->HasSurfaceIntersection() << endl; cout << "Latitude = " << c->UniversalLatitude() << endl; cout << "Longitude = " << c->UniversalLongitude() << endl; cout << "Radius = " << c->LocalRadius().meters() << endl; double p[3]; c->Coordinate(p); cout << "Point = " << setprecision(4) << p[0] << " " << p[1] << " " << p[2] << endl << endl; cout << "Test Forward/Reverse Camera Calculations At Center Of Image..." << endl; sample = c->Samples() / 2.0; line = c->Lines() / 2.0; cout << "Sample = " << setprecision(3) << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << c->SetImage(sample, line) << endl; cout << "Latitude = " << c->UniversalLatitude() << endl; cout << "Longitude = " << c->UniversalLongitude() << endl; cout << "Radius = " << c->LocalRadius().meters() << endl; c->Coordinate(p); cout << "Point = " << setprecision(4) << p[0] << " " << p[1] << " " << p[2] << endl; cout << "SetUniversalGround (lat, lon, radius): " << c->SetUniversalGround(c->UniversalLatitude(), c->UniversalLongitude(), c->LocalRadius().meters()) << endl; cout << "Sample = " << c->Sample() << endl; cout << "Line = " << c->Line() << endl << endl; cout << endl << "/---------- Test Polar Boundary Conditions" << endl; inputFile = "$clementine1/testData/lub5992r.292.lev1.phot.cub"; cube.close(); cube.open(inputFile); pvl = *cube.label(); Camera *cam2 = CameraFactory::Create(cube); cube.close(); cout << endl; cout << "Camera* from: " << inputFile << endl; ifovOffsets = cam2->PixelIfovOffsets(); cout << "Pixel Ifov: " << endl; foreach (QPointF offset, ifovOffsets) { cout << offset.x() << " , " << offset.y() << endl; } cout << "Basic Mapping: " << endl; Pvl camMap; cam2->BasicMapping(camMap); double minLat = camMap.findGroup("Mapping")["MinimumLatitude"]; minLat *= 100; minLat = round(minLat); minLat /= 100; camMap.findGroup("Mapping")["MinimumLatitude"] = toString(minLat); double pixRes = camMap.findGroup("Mapping")["PixelResolution"]; pixRes *= 100; pixRes = round(pixRes); pixRes /= 100; camMap.findGroup("Mapping")["PixelResolution"] = toString(pixRes); double minLon = camMap.findGroup("Mapping")["MinimumLongitude"]; minLon *= 100000000000.0; minLon = round(minLon); minLon /= 100000000000.0; camMap.findGroup("Mapping")["MinimumLongitude"] = toString(minLon); cout << camMap << endl; cout << endl; cout << "180 Domain Range: " << endl; double minlat, maxlat, minlon, maxlon; camMap.findGroup("Mapping")["LongitudeDomain"][0] = "180"; cam2->GroundRange(minlat, maxlat, minlon, maxlon, camMap); cout << "Latitude Range: " << minlat << " to " << maxlat << endl; cout << "Longitude Range: " << minlon << " to " << maxlon << endl << endl; cout << "Test Forward/Reverse Camera Calculations At Center Of Image..." << endl; sample = cam2->Samples() / 2.0; line = cam2->Lines() / 2.0; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam2->SetImage(sample, line) << endl; cout << "Latitude = " << cam2->UniversalLatitude() << endl; cout << "Longitude = " << cam2->UniversalLongitude() << endl; cout << "Radius = " << cam2->LocalRadius().meters() << endl; cam2->Coordinate(p); cout << "Point = " << p[0] << " " << p[1] << " " << p[2] << endl; cout << "SetUniversalGround (cam2->UniversalLatitude(), " "cam2->UniversalLongitude()): " << cam2->SetUniversalGround(cam2->UniversalLatitude(), cam2->UniversalLongitude()) << endl; cout << "Sample = " << cam2->Sample() << endl; cout << "Line = " << cam2->Line() << endl << endl; cube.close(); delete cam2; cube.close(); cout << endl << "/---------- Test Local Photometric Angles..." << endl << endl; cout << "Flat DEM Surface..." << endl; inputFile = "$base/testData/f319b18_ideal_flat.cub"; cube.open(inputFile); pvl = *cube.label(); Camera *cam3 = CameraFactory::Create(cube); cube.close(); sample = cam3->Samples() / 2.0; line = cam3->Lines() / 2.0; cout << "Camera* from: " << inputFile << endl; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam3->SetImage(sample, line) << endl; double normal[3]; cam3->GetLocalNormal(normal); cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl; Angle phase; Angle incidence; Angle emission; bool success; cam3->LocalPhotometricAngles(phase,emission,incidence,success); if (success) { cout << "Phase = " << phase.degrees() << endl; cout << "Emission = " << emission.degrees() << endl; cout << "Incidence = " << incidence.degrees() << endl; } else { cout << "Angles could not be calculated." << endl; } delete cam3; cout << endl << "45 Degree DEM Surface Facing Left..." << endl; inputFile = "$base/testData/f319b18_ideal_45left.cub"; cube.open(inputFile); pvl = *cube.label(); Camera *cam4 = CameraFactory::Create(cube); cube.close(); sample = cam4->Samples() / 2.0; line = cam4->Lines() / 2.0; cout << "Camera* from: " << inputFile << endl; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam4->SetImage(sample, line) << endl; cam4->GetLocalNormal(normal); cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl; cam4->LocalPhotometricAngles(phase,emission,incidence,success); if (success) { cout << "Phase = " << phase.degrees() << endl; cout << "Emission = " << emission.degrees() << endl; cout << "Incidence = " << incidence.degrees() << endl; } else { cout << "Angles could not be calculated." << endl; } delete cam4; cout << endl << "45 Degree DEM Surface Facing Top..." << endl; inputFile = "$base/testData/f319b18_ideal_45top.cub"; cube.open(inputFile); pvl = *cube.label(); Camera *cam5 = CameraFactory::Create(cube); cube.close(); sample = cam5->Samples() / 2.0; line = cam5->Lines() / 2.0; cout << "Camera* from: " << inputFile << endl; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam5->SetImage(sample, line) << endl; cam5->GetLocalNormal(normal); cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl; cam5->LocalPhotometricAngles(phase,emission,incidence,success); if (success) { cout << "Phase = " << phase.degrees() << endl; cout << "Emission = " << emission.degrees() << endl; cout << "Incidence = " << incidence.degrees() << endl; } else { cout << "Angles could not be calculated." << endl; } delete cam5; cout << endl << "45 Degree DEM Surface Facing Right..." << endl; inputFile = "$base/testData/f319b18_ideal_45right.cub"; cube.open(inputFile); pvl = *cube.label(); Camera *cam6 = CameraFactory::Create(cube); cube.close(); sample = cam6->Samples() / 2.0; line = cam6->Lines() / 2.0; cout << "Camera* from: " << inputFile << endl; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam6->SetImage(sample, line) << endl; cam6->GetLocalNormal(normal); cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl; cam6->LocalPhotometricAngles(phase,emission,incidence,success); if (success) { cout << "Phase = " << phase.degrees() << endl; cout << "Emission = " << emission.degrees() << endl; cout << "Incidence = " << incidence.degrees() << endl; } else { cout << "Angles could not be calculated." << endl; } delete cam6; cout << endl << "45 Degree DEM Surface Facing Bottom..." << endl; inputFile = "$base/testData/f319b18_ideal_45bottom.cub"; cube.open(inputFile); pvl = *cube.label(); Camera *cam7 = CameraFactory::Create(cube); cube.close(); sample = cam7->Samples() / 2.0; line = cam7->Lines() / 2.0; cout << "Camera* from: " << inputFile << endl; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam7->SetImage(sample, line) << endl; cam7->GetLocalNormal(normal); cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl; cam7->LocalPhotometricAngles(phase,emission,incidence,success); if (success) { cout << "Phase = " << phase.degrees() << endl; cout << "Emission = " << emission.degrees() << endl; cout << "Incidence = " << incidence.degrees() << endl; } else { cout << "Angles could not be calculated." << endl; } delete cam7; cout << endl << "80 Degree DEM Surface Facing Left..." << endl; inputFile = "$base/testData/f319b18_ideal_80left.cub"; cube.open(inputFile); pvl = *cube.label(); Camera *cam8 = CameraFactory::Create(cube); cube.close(); sample = cam8->Samples() / 2.0; line = cam8->Lines() / 2.0; cout << "Camera* from: " << inputFile << endl; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam8->SetImage(sample, line) << endl; cam8->GetLocalNormal(normal); cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl; cam8->LocalPhotometricAngles(phase,emission,incidence,success); if (success) { cout << "Phase = " << phase.degrees() << endl; cout << "Emission = " << emission.degrees() << endl; cout << "Incidence = " << incidence.degrees() << endl; } else { cout << "Angles could not be calculated." << endl; } delete cam8; cout << endl << "80 Degree DEM Surface Facing Top..." << endl; inputFile = "$base/testData/f319b18_ideal_80top.cub"; cube.open(inputFile); pvl = *cube.label(); Camera *cam9 = CameraFactory::Create(cube); cube.close(); sample = cam9->Samples() / 2.0; line = cam9->Lines() / 2.0; cout << "Camera* from: " << inputFile << endl; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam9->SetImage(sample, line) << endl; cam9->GetLocalNormal(normal); cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl; cam9->LocalPhotometricAngles(phase,emission,incidence,success); if (success) { cout << "Phase = " << phase.degrees() << endl; cout << "Emission = " << emission.degrees() << endl; cout << "Incidence = " << incidence.degrees() << endl; } else { cout << "Angles could not be calculated." << endl; } delete cam9; cout << endl << "80 Degree DEM Surface Facing Right..." << endl; inputFile = "$base/testData/f319b18_ideal_80right.cub"; cube.open(inputFile); pvl = *cube.label(); Camera *cam10 = CameraFactory::Create(cube); cube.close(); sample = cam10->Samples() / 2.0; line = cam10->Lines() / 2.0; cout << "Camera* from: " << inputFile << endl; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam10->SetImage(sample, line) << endl; cam10->GetLocalNormal(normal); cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl; cam10->LocalPhotometricAngles(phase,emission,incidence,success); if (success) { cout << "Phase = " << phase.degrees() << endl; cout << "Emission = " << emission.degrees() << endl; cout << "Incidence = " << incidence.degrees() << endl; } else { cout << "Angles could not be calculated." << endl; } delete cam10; cout << endl << "80 Degree DEM Surface Facing Bottom..." << endl; inputFile = "$base/testData/f319b18_ideal_80bottom.cub"; cube.open(inputFile); pvl = *cube.label(); Camera *cam11 = CameraFactory::Create(cube); cube.close(); sample = cam11->Samples() / 2.0; line = cam11->Lines() / 2.0; cout << "Camera* from: " << inputFile << endl; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam11->SetImage(sample, line) << endl; cam11->GetLocalNormal(normal); cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl; cam11->LocalPhotometricAngles(phase,emission,incidence,success); if (success) { cout << "Phase = " << phase.degrees() << endl; cout << "Emission = " << emission.degrees() << endl; cout << "Incidence = " << incidence.degrees() << endl; } else { cout << "Angles could not be calculated." << endl; } delete cam11; cout << endl << "Point Does Not Intersect DEM..." << endl; inputFile = "$base/testData/f319b18_ideal_flat.cub"; cube.open(inputFile); pvl = *cube.label(); Camera *cam12 = CameraFactory::Create(cube); cube.close(); sample = 1.0; line = 1.0; cout << "Camera* from: " << inputFile << endl; cout << "Sample = " << sample << endl; cout << "Line = " << line << endl; cout << "SetImage (sample, line): " << cam12->SetImage(sample, line) << endl; cam12->GetLocalNormal(normal); cout << "Normal = " << normal[0] << ", " << normal[1] << ", " << normal[2] << endl; cam12->LocalPhotometricAngles(phase,emission,incidence,success); if (success) { cout << "Phase = " << phase.degrees() << endl; cout << "Emission = " << emission.degrees() << endl; cout << "Incidence = " << incidence.degrees() << endl; } else { cout << "Angles could not be calculated." << endl; } delete cam12; // Test PixelIfov for Vims which sets the field of view if it in hires mode. The Ifov is // rectangular instead of square. inputFile = "$base/testData/CM_1515945709_1.ir.cub"; cube.open(inputFile); Camera *cam13 = CameraFactory::Create(cube); cube.close(); cout << endl << endl << "Testing non-square pixel Ifov using Hires vims cube" << endl; cout << "Camera* from: " << inputFile << endl; ifovOffsets = cam13->PixelIfovOffsets(); cout << "Pixel Ifov: " << endl; foreach (QPointF offset, ifovOffsets) { cout << offset.x() << " , " << offset.y() << endl; } delete cam13; }
void IsisMain() { UserInterface &ui = Application::GetUserInterface(); double time0,//start time time1,//end time alti, //altitude of the spacecraftmore fmc, //forward motion compensation rad/sec horV, //horizontal velocity km/sec radV, //radial velocity km/sec rollV,//roll speed in rad/sec led; //line exposure duration in seconds Cube panCube; iTime isisTime; QString iStrTEMP; int i,j,k,scFrameCode,insCode; QString mission; SpicePosition *spPos; SpiceRotation *spRot; //int nlines,nsamples,nbands; double deg2rad = acos(-1.0)/180.0; ProcessImport jp; FileName transFile("$apollo15/translations/apollopantranstable.trn"); PvlTranslationTable transTable(transFile); PvlGroup kernels_pvlG; //scFrameCode and insCode from user input mission = ui.GetString("MISSION"); if (mission == "APOLLO12") scFrameCode = -912000; if (mission == "APOLLO14") scFrameCode = -914000; if (mission == "APOLLO15") scFrameCode = -915000; if (mission == "APOLLO16") scFrameCode = -916000; if (mission == "APOLLO17") scFrameCode = -917000; insCode = scFrameCode - 230; try { panCube.open(ui.GetFileName("FROM"),"rw"); } catch (IException &e) { throw IException(IException::User, "Unable to open the file [" + ui.GetFileName("FROM") + "] as a cube.", _FILEINFO_); } ////////////////////////////////////////////build the cube header instrament group PvlGroup inst_pvlG("Instrument"); PvlKeyword keyword; //four that are the same for every panaramic mission keyword.setName("SpacecraftName"); keyword.setValue(mission); inst_pvlG.addKeyword(keyword); keyword.setName("InstrumentName"); keyword.setValue(transTable.Translate("InstrumentName","whatever")); inst_pvlG.addKeyword(keyword); keyword.setName("InstrumentId"); keyword.setValue(transTable.Translate("InstrumentId","whatever")); inst_pvlG.addKeyword(keyword); keyword.setName("TargetName"); keyword.setValue(transTable.Translate("TargetName","whatever")); inst_pvlG.addKeyword(keyword); //three that need to be calculated from input values horV = ui.GetDouble("VEL_HORIZ"); radV = ui.GetDouble("VEL_RADIAL"); alti = ui.GetDouble("CRAFT_ALTITUDE"); //caculate the LineExposureDuration (led) if( ui.WasEntered("V/H_OVERRIDE") ) fmc = ui.GetDouble("V/H_OVERRIDE")/1000.0; else //forward motion compensation is directly equivalent to V/H fmc = sqrt(horV*horV + radV*radV)/alti; rollV = fmc*ROLLC; //roll angular velcoity is equal to V/H * constant (units rad/sec) //led = rad/mm * sec/rad = radians(2.5)/FIDL / rollV (final units: sec/mm) led = (2.5*acos(-1.0)/180.0)/rollV/FIDL; //use led and the number of mm to determine the start and stop times isisTime = ui.GetString("GMT"); //calculate starting and stoping times time0 = isisTime.Et() - led*FIDL*21.5; time1 = time0 + led*FIDL*43; isisTime = time0; keyword.setName("StartTime"); keyword.setValue(iStrTEMP=isisTime.UTC()); inst_pvlG.addKeyword(keyword); isisTime = time1; keyword.setName("StopTime"); keyword.setValue(iStrTEMP=isisTime.UTC()); inst_pvlG.addKeyword(keyword); keyword.setName("LineExposureDuration"); //converted led to msec/mm--negative sign to account for the anti-parallel time and line axes keyword.setValue(iStrTEMP=toString(-led),"sec/mm"); inst_pvlG.addKeyword(keyword); panCube.putGroup(inst_pvlG); ///////////////////////////////////The kernals group kernels_pvlG.setName("Kernels"); kernels_pvlG.clear(); keyword.setName("NaifFrameCode"); keyword.setValue(toString(insCode)); kernels_pvlG.addKeyword(keyword); keyword.setName("LeapSecond"); keyword.setValue( transTable.Translate("LeapSecond","File1") ); kernels_pvlG.addKeyword(keyword); keyword.setName("TargetAttitudeShape"); keyword.setValue( transTable.Translate("TargetAttitudeShape", "File1") ); keyword.addValue( transTable.Translate("TargetAttitudeShape", "File2") ); keyword.addValue( transTable.Translate("TargetAttitudeShape", "File3") ); kernels_pvlG.addKeyword(keyword); keyword.setName("TargetPosition"); keyword.setValue("Table"); keyword.addValue( transTable.Translate("TargetPosition", "File1") ); keyword.addValue( transTable.Translate("TargetPosition", "File2") ); kernels_pvlG.addKeyword(keyword); keyword.setName("ShapeModel"); keyword.setValue( transTable.Translate("ShapeModel", "File1") ); kernels_pvlG.addKeyword(keyword); keyword.setName("InstrumentPointing"); keyword.setValue("Table"); kernels_pvlG.addKeyword(keyword); keyword.setName("InstrumentPosition"); keyword.setValue("Table"); kernels_pvlG.addKeyword(keyword); keyword.setName("InstrumentAddendum"); keyword.setValue( transTable.Translate("InstrumentAddendum",mission)); kernels_pvlG.addKeyword(keyword); panCube.putGroup(kernels_pvlG); //Load all the kernals Load_Kernel(kernels_pvlG["TargetPosition"]); Load_Kernel(kernels_pvlG["TargetAttitudeShape"]); Load_Kernel(kernels_pvlG["LeapSecond"]); //////////////////////////////////////////attach a target rotation table char frameName[32]; SpiceInt frameCode; SpiceBoolean found; //get the framecode from the body code (301=MOON) cidfrm_c(301, sizeof(frameName), &frameCode, frameName, &found); if(!found) { QString naifTarget = QString("IAU_MOOM"); namfrm_c(naifTarget.toAscii().data(), &frameCode); if(frameCode == 0) { QString msg = "Can not find NAIF code for [" + naifTarget + "]"; throw IException(IException::Io, msg, _FILEINFO_); } } spRot = new SpiceRotation(frameCode); //create a table from starttime to endtime (streched by 3%) with NODES entries spRot->LoadCache(time0-0.015*(time1-time0), time1+0.015*(time1-time0), NODES); Table tableTargetRot = spRot->Cache("BodyRotation"); tableTargetRot.Label() += PvlKeyword("Description", "Created by apollopaninit"); panCube.write(tableTargetRot); //////////////////////////////////////////////////attach a sun position table spPos = new SpicePosition(10,301); //Position of the sun (10) WRT to the MOON (301) //create a table from starttime to endtime (stretched by 3%) with NODES entries spPos->LoadCache(time0-0.015*(time1-time0), time1+0.015*(time1-time0), NODES); Table tableSunPos = spPos->Cache("SunPosition"); tableSunPos.Label() += PvlKeyword("SpkTableStartTime", toString(time0-0.015*(time1-time0))); tableSunPos.Label() += PvlKeyword("SpkTablleEndTime", toString(time1+0.015*(time1-time0))); tableSunPos.Label() += PvlKeyword("Description", "Created by apollopaninit"); panCube.write(tableSunPos); //attach the table to the cube /////////////Finding the principal scan line position and orientation //get the radii of the MOON SpiceInt tempRadii = 0; bodvcd_c(301,"RADII",3,&tempRadii,R_MOON); //units are km double omega,phi,kappa; std::vector<double> posSel; //Seleno centric position std::vector<double> sunPos; //sunPosition used to transform to J2000 std::vector<double> posJ20; //camera position in J2000 posSel.resize(3); sunPos.resize(3); posJ20.resize(3); double temp, vel[3] = { 0.0, 0.0, 0.0 }, //the total velocity vector (combined Horizonatal and normal components) // in km/sec M[3][3] = { { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 }, { 0.0, 0.0, 0.0 } }, //rotation matrix zDir[] = { 0.0, 0.0, 1.0 }, //selenographic Z axis northPN[3] = { 0.0, 0.0, 0.0 }, //normal to the plane containing all the north/south directions, // that is plane containing // the origin, the z axis, and the primary point of intersection northL[3] = { 0.0, 0.0, 0.0 }, //north direction vector in local horizontal plane azm[3] = { 0.0, 0.0, 0.0 }, //azm direction of the veclocity vector in selenographic coordinates azmP[3] = { 0.0, 0.0, 0.0 }, //azm rotated (partially) and projected into the image plane norm[3] = { 0.0, 0.0, 0.0 }, //normal to the local horizontal plane look[3] = { 0.0, 0.0, 0.0 }; //unit direction vector in the pincipal cameral look direction, // parallel to the vector from the center of the moon through the spacecraft double pos0[3] = { 0.0, 0.0, 0.0 }, //coordinate of the camera position pInt[3] = { 0.0, 0.0, 0.0 }; //coordinate of the principle intersection point /////////////////calculating the camera position for the center (principal scan line) pos0[1] = ui.GetDouble("LON_NADIR")*deg2rad; pos0[0] = ui.GetDouble("LAT_NADIR")*deg2rad; pos0[2] = ui.GetDouble("CRAFT_ALTITUDE"); //units are km Geographic2GeocentricLunar(pos0,pos0); //function is written so the input can also be the // output /////////////////////calculating the camera orientation for the center (principal) scan line pInt[1] = ui.GetDouble("LON_INT")*deg2rad; pInt[0] = ui.GetDouble("LAT_INT")*deg2rad; pInt[2] = 0.0; Geographic2GeocentricLunar(pInt,pInt); //function is written so the input can also be the output //calculate the unit look direction vector in object space look[0] = -pos0[0] + pInt[0]; look[1] = -pos0[1] + pInt[1]; look[2] = -pos0[2] + pInt[2]; temp = sqrt(look[0]*look[0] + look[1]*look[1] + look[2]*look[2]); look[0] /= temp; look[1] /= temp; look[2] /= temp; //the local normal vector is equal to pInt0/|pInt0| temp = sqrt(pInt[0]*pInt[0] + pInt[1]*pInt[1] + pInt[2]*pInt[2]); norm[0] = pInt[0]/temp; norm[1] = pInt[1]/temp; norm[2] = pInt[2]/temp; //omega and phi are defined so that M(phi)M(omega)look = [0 0 -1] leaving only the roation // around z axis to be found omega = -atan2(look[1], look[2]); //omega rotation to zero look[1] phi = atan2(-look[0], sin(omega)*look[1] - cos(omega)*look[2]); //phi rotation to zero look[0] //use the horizontal velocity vector direction to solve for the last rotation; we will make the // image x axis parallel to the in-image-plane projection of the horizontal direction of flight. // The local normal cross the selenogrpahic z gives northPN (normal to the plane containing all // the north/south directions), that is, the plane containing the origin, the z axis, and the // primary point of intersection. crossp(northPN,norm,northL); //The normal to the plane containing all the north/south directions cross the local normal // direction gives the local north/south direction in the local normal plane crossp(norm, zDir, northPN); if (northL[2] < 0) { //if by chance we got the south direction change the signs northL[0] = -northL[0]; northL[1] = -northL[1]; northL[2] = -northL[2]; } //define the rotation matrix to convert northL to the azimuth of flight. // A left handed rotation of "VEL_AZM" around the positive normal direction will convert northL // to azm MfromVecLeftAngle(M,norm,ui.GetDouble("VEL_AZM")*deg2rad); azm[0] = M[0][0]*northL[0] + M[0][1]*northL[1] + M[0][2]*northL[2]; azm[1] = M[1][0]*northL[0] + M[1][1]*northL[1] + M[1][2]*northL[2]; azm[2] = M[2][0]*northL[0] + M[2][1]*northL[1] + M[2][2]*northL[2]; //apply the two rotations we already know MfromLeftEulers(M,omega,phi,0.0); azmP[0] = M[0][0]*azm[0] + M[0][1]*azm[1] + M[0][2]*azm[2]; azmP[1] = M[1][0]*azm[1] + M[1][1]*azm[1] + M[1][2]*azm[2]; azmP[2] = M[2][0]*azm[2] + M[2][1]*azm[1] + M[2][2]*azm[2]; //subtract that portion of the azm that is perpindicular to the image plane (also the portion // which is parallel to look) making azm a vector parrallel to the image plane // Further, since we're now rotated into some coordinate system that differs from // the image coordinate system by only a kappa rotation making the vector parrallel to the // image plan is as simple as zeroing the z component (and as pointless to further calculations // as a nat's fart in hurricane) nevertheless it completes the logical transition azmP[2] = 0.0; //finally the kappa rotation that will make azmP parallel (including sign) to the camera x axis kappa = -atan2(-azmP[1], azmP[0]); ////////////////////Add an instrument position table //Define the table records TableRecord recordPos; // reacord to be added to table // add x,y,z position labels and ephemeris time et to record TableField x("J2000X", TableField::Double); TableField y("J2000Y", TableField::Double); TableField z("J2000Z", TableField::Double); TableField t("ET", TableField::Double); recordPos += x; recordPos += y; recordPos += z; recordPos += t; Table tablePos("InstrumentPosition", recordPos); //now that the azm and norm vectors are defined // the total velocity vector can be calcualted (km/sec) vel[0] = horV*azm[0] + radV * norm[0]; vel[1] = horV*azm[1] + radV * norm[1]; vel[2] = horV*azm[2] + radV * norm[2]; //we'll provide a two ellement table (more is redundant because the motion is modeled as linear // at this point) we'll extend the nodes 3% beyond the edges of the images to be sure // rounding errors don't cause problems temp = 0.515*(time1-time0); //3% extension posSel[0] = pos0[0] - temp*vel[0]; //selenocentric coordinate calculation posSel[1] = pos0[1] - temp*vel[1]; posSel[2] = pos0[2] - temp*vel[2]; //converting to J2000 temp = time0 - 0.005*(time1-time0); //et just before the first scan line spPos->SetEphemerisTime(temp); spRot->SetEphemerisTime(temp); //Despite being labeled as J2000, the coordinates for the instrument position are in fact in // target centric coordinated rotated to a system centered at the target with aces parallel // to J2000, whatever that means posJ20 = spRot->J2000Vector(posSel); //J2000Vector calls rotates the position vector into J2000, // completing the transformation recordPos[0] = posJ20[0]; recordPos[1] = posJ20[1]; recordPos[2] = posJ20[2]; recordPos[3] = temp; //temp = et (right now anyway) tablePos += recordPos; tablePos.Label() += PvlKeyword("SpkTableStartTime",toString(temp)); //now the other node temp = 0.515*(time1-time0); //3% extension posSel[0] = pos0[0] + temp*vel[0]; //selenocentric coordinate calculation posSel[1] = pos0[1] + temp*vel[1]; posSel[2] = pos0[2] + temp*vel[2]; //converting to J2000 temp = time1 + 0.015*(time1-time0); //et just after the last scan line spPos->SetEphemerisTime(temp); spRot->SetEphemerisTime(temp); //Despite being labeled as J2000, the coordinates for the instrument position are in fact // in target centric coordinated rotated to a system centered at the target with aces // parallel to J2000, whatever that means posJ20 = spRot->J2000Vector(posSel); //J2000Vector calls rotates the position vector into J2000, // completing the transformation recordPos[0] = posJ20[0]; recordPos[1] = posJ20[1]; recordPos[2] = posJ20[2]; recordPos[3] = temp; //temp = et (right now anyway) tablePos += recordPos; tablePos.Label() += PvlKeyword("SpkTableEndTime",toString(temp)); tablePos.Label() += PvlKeyword("CacheType","Linear"); tablePos.Label() += PvlKeyword("Description","Created by apollopaninit"); panCube.write(tablePos); //now attach it to the table /////////////////////////////attach a camera pointing table double cacheSlope, //time between epoches in the table rollComb, //magnitude of roll relative to the center in the middle of the epoch relT, //relative time at the center of each epoch Q[NODES][5], //NODES four ellement unit quarternions and et (to be calculated). gimVec[3], //the direction of the gimbal rotation vector (to the cameras persepective // this is always changing because the camera is mounted to the roll frame // assembly which is mounted to the gimbal) M0[3][3], //rotation matrix of the previous epoch Mtemp1[3][3], //intermediate step in the multiplication of rotation matricies Mtemp2[3][3], //intermediate step in the multiplication of rotation matricies Mdg[3][3], //incremental rotation due the the gimbal motion in the camera frame Mdr[3][3]; //the contribution of the roll motion in the camera frame during time // cacheSlope std::vector <double> M_J2toT; //rotation matrix from J2000 to the target frame M_J2toT.resize(9); //Table Definition TableField q0("J2000Q0", TableField::Double); TableField q1("J2000Q1", TableField::Double); TableField q2("J2000Q2", TableField::Double); TableField q3("J2000Q3", TableField::Double); TableField et("ET", TableField::Double); TableRecord recordRot; recordRot += q0; recordRot += q1; recordRot += q2; recordRot += q3; recordRot += et; Table tableRot("InstrumentPointing",recordRot); //From the cameras perspective the gimbal motion is around a constantly changing axis, // this is handled by combining a series of incremental rotations MfromLeftEulers(M0, omega, phi, kappa); //rotation matrix in the center Q[(NOPDES-1)/2] spRot->SetEphemerisTime(isisTime.Et()); M_J2toT = spRot->Matrix(); //this actually gives the rotation from J2000 to target centric for(j=0; j<3; j++) //reformating M_J2toT to a 3x3 for(k=0; k<3; k++) Mtemp1[j][k] = M_J2toT[3*j+k]; mxm_c(M0, Mtemp1, Mtemp2); M2Q(Mtemp2, Q[(NODES-1)/2]); //save the middle scan line quarternion Q[(NODES-1)/2][4] = (time1 + time0)/2.0; //time in the center of the image //the total time is scaled up slightly so that nodes will extend just beyond the edge of the image cacheSlope = 1.03*(time1 - time0)/(NODES-1); //Mdr is constant for all the forward time computations MfromLeftEulers(Mdr,cacheSlope*rollV,0.0,0.0); for (i=(NODES-1)/2+1; i<NODES; i++) { //moving foward in time first Q[i][4] = Q[i-1][4] + cacheSlope; //new time epoch //epoch center time relative to the center line relT = double(i - (NODES-1)/2 - 0.5)*cacheSlope; rollComb = relT*rollV; gimVec[0] = 0.0; //gimbal rotation vector direction in the middle of the epoch gimVec[1] = cos(rollComb); gimVec[2] = -sin(rollComb); //incremental rotation due to the gimbal (forward motion compensation) MfromVecLeftAngle(Mdg, gimVec, fmc*cacheSlope); //the new rotation matrix is Transpose(Mdr)*Transpose(Mdg)*M0--NOTE the order swap and // transposes are needed because both Mdr and Mdg were caculated in image space and need to be // transposed to apply to object space mtxm_c(Mdg, M0, Mtemp1); //M0 is now what would typically be considered the rotation matrix of an image. It rotates a // vector from the target centric space into camera space. However, what is standard to // include in the cube labels is a rotation from camera space to J2000. M0 is therefore the // transpose of the first part of this rotation. Transpose(M0) is the rotation from camera // space to target centric space mtxm_c(Mdr, Mtemp1, M0); //now adding the rotation from the target frame to J2000 spRot->SetEphemerisTime(Q[i][4]); //this actually gives the rotation from J2000 to target centric--hence the mxmt_c function being // used later M_J2toT = spRot->Matrix(); for(j=0; j<3; j++) //reformating M_J2toT to a 3x3 for(k=0; k<3; k++) Mtemp1[j][k] = M_J2toT[3*j+k]; mxm_c(M0, Mtemp1, Mtemp2); M2Q(Mtemp2, Q[i]); //convert to a quarterion } MfromLeftEulers(M0, omega, phi, kappa); //rotation matrix in the center Q[(NOPDES-1)/2] //Mdr is constant for all the backward time computations MfromLeftEulers(Mdr, -cacheSlope*rollV, 0.0, 0.0); for (i=(NODES-1)/2-1; i>=0; i--) { //moving backward in time Q[i][4] = Q[i+1][4] - cacheSlope; //new time epoch //epoch center time relative to the center line relT = double(i - (NODES-1)/2 + 0.5)*cacheSlope; rollComb = relT*rollV; gimVec[0] = 0.0; //gimbal rotation vector direction in the middle of the epoch gimVec[1] = cos(rollComb); gimVec[2] = -sin(rollComb); //incremental rotation due to the gimbal (forward motion compensation) MfromVecLeftAngle(Mdg, gimVec, -fmc*cacheSlope); //the new rotation matrix is Transpose(Mdr)*Transpose(Mdg)*M0 NOTE the order swap and // transposes are needed because both Mdr and Mdg were caculated in image space and need to be // transposed to apply to object space mtxm_c(Mdg, M0, Mtemp1); //M0 is now what would typically be considered the rotation matrix of an image. It rotates a // vector from the target centric space into camera space. However, what is standard to // include in the cube labels is a rotation from camera space to J2000. M0 is therefore the // transpose of the first part of this rotation. Transpose(M0) is the rotation from camera // space to target centric space mtxm_c(Mdr, Mtemp1, M0); //now adding the rotation from the target frame to J2000 spRot->SetEphemerisTime(Q[i][4]); M_J2toT = spRot->Matrix(); for(j=0; j<3; j++) //reformating M_J2toT to a 3x3 for(k=0; k<3; k++) Mtemp1[j][k] = M_J2toT[3*j+k]; mxm_c(M0, Mtemp1, Mtemp2); M2Q(Mtemp2, Q[i]); //convert to a quarterion } //fill in the table for (i=0; i<NODES; i++) { recordRot[0] = Q[i][0]; recordRot[1] = Q[i][1]; recordRot[2] = Q[i][2]; recordRot[3] = Q[i][3]; recordRot[4] = Q[i][4]; tableRot += recordRot; } tableRot.Label() += PvlKeyword("CkTableStartTime", toString(Q[0][4])); tableRot.Label() += PvlKeyword("CkTableEndTime", toString(Q[NODES-1][4])); tableRot.Label() += PvlKeyword("Description", "Created by appollopan2isis"); keyword.setName("TimeDependentFrames"); keyword.setValue(toString(scFrameCode)); keyword.addValue("1"); tableRot.Label() += keyword; keyword.setName("ConstantFrames"); keyword.setValue(toString(insCode)); keyword.addValue(toString(scFrameCode)); tableRot.Label() += keyword; keyword.setName("ConstantRotation"); keyword.setValue("1"); for (i=1;i<9;i++) if (i%4 == 0) keyword.addValue("1"); else keyword.addValue("0"); tableRot.Label() += keyword; panCube.write(tableRot); /////////////////////////Attach a table with all the measurements of the fiducial mark locations. Chip patternS,searchS; //scaled pattern and search chips Cube fidC; //Fiducial image //line and sample coordinates for looping through the panCube double l=1,s=1,sample,line,sampleInitial=1,lineInitial=1,play; int regStatus, fidn, panS, refL, //number of lines in the patternS refS; //number of samples in the patternS Pvl pvl; bool foundFirst=false; QString fileName; panS = panCube.sampleCount(); //Table definition TableRecord recordFid; TableField indexFid("FID_INEX",TableField::Integer); TableField xFid("X_COORD",TableField::Double); TableField yFid("Y_COORD",TableField::Double); recordFid += indexFid; recordFid += xFid; recordFid += yFid; Table tableFid("Fiducial Measurement",recordFid); //read the image resolutions and scale the constants acordingly double resolution = ui.GetDouble("MICRONS"), //pixel size in microns scale = SCALE *5.0/resolution, //reduction scale for fast autoregistrations searchHeight = SEARCHh*5.0/resolution, //number of lines (in 5-micron-pixels) in // search space for the first fiducial searchCellSize = SEARCHc*5.0/resolution, //height/width of search chips block averageSamples = AVERs *5.0/resolution, //scaled smaples between fiducials averageLines = AVERl *5.0/resolution; //scaled average distance between the top and //bottom fiducials if( 15.0/resolution < 1.5) play=1.5; else play = 15.0/resolution; //copy the patternS chip (the entire ApolloPanFiducialMark.cub) FileName fiducialFileName("$apollo15/calibration/ApolloPanFiducialMark.cub"); fidC.open(fiducialFileName.expanded(),"r"); if( !fidC.isOpen() ) { QString msg = "Unable to open the fiducial patternS cube: ApolloPanFiducialMark.cub\n"; throw IException(IException::User, msg, _FILEINFO_); } refL = fidC.lineCount(); refS = fidC.sampleCount(); //scaled pattern chip for fast matching patternS.SetSize(int((refS-2)/SCALE), int((refL-2)/SCALE)); patternS.TackCube((refS-1)/2, (refL-1)/2); patternS.Load(fidC, 0, SCALE); //parameters for maximum correlation autoregestration // see: file:///usgs/pkgs/isis3nightly2011-09-21/isis/doc/documents/patternSMatch/patternSMatch.html#DistanceTolerance FileName fiducialPvl("$apollo15/templates/apolloPanFiducialFinder.pvl"); pvl.read(fiducialPvl.expanded()); //read in the autoreg parameters AutoReg *arS = AutoRegFactory::Create(pvl); *arS->PatternChip() = patternS; //patternS chip is constant //set up a centroid measurer CentroidApolloPan centroid(resolution); Chip inputChip,selectionChip; inputChip.SetSize(int(ceil(200*5.0/resolution)), int(ceil(200*5.0/resolution))); fileName = ui.GetFileName("FROM"); if( panCube.pixelType() == 1) //UnsignedByte centroid.setDNRange(12, 1e99); //8 bit bright target else centroid.setDNRange(3500, 1e99); //16 bit bright target Progress progress; progress.SetText("Locating Fiducials"); progress.SetMaximumSteps(91); //Search for the first fiducial, search sizes are constanst searchS.SetSize(int(searchCellSize/scale),int(searchCellSize/scale)); //now start searching along a horizontal line for the first fiducial mark for(l = searchCellSize/2; l<searchHeight+searchCellSize/2.0 && !foundFirst; l+=searchCellSize-125*5.0/resolution) { for (s = searchCellSize/2; s < averageSamples + searchCellSize/2.0 && !foundFirst; s += searchCellSize-125*5.0/resolution) { searchS.TackCube(s, l); searchS.Load(panCube, 0, scale); *arS->SearchChip() = searchS; regStatus = arS->Register(); if (regStatus == AutoReg::SuccessPixel) { inputChip.TackCube(arS->CubeSample(), arS->CubeLine()); inputChip.Load(panCube, 0, 1); inputChip.SetCubePosition(arS->CubeSample(), arS->CubeLine()); //continuous dynamic range selection centroid.selectAdaptive(&inputChip, &selectionChip); //elliptical trimming/smoothing if (centroid.elipticalReduction(&selectionChip, 95, play, 2000)) { //center of mass to reduce selection to a single measure centroid.centerOfMass(&selectionChip, &sample, &line); inputChip.SetChipPosition(sample, line); sampleInitial = inputChip.CubeSample(); lineInitial = inputChip.CubeLine(); foundFirst = true; //once the first fiducial is found stop } } } } if(s>=averageLines+searchCellSize/2.0) { QString msg = "Unable to locate a fiducial mark in the input cube [" + fileName + "]. Check FROM and MICRONS parameters."; throw IException(IException::Io, msg, _FILEINFO_); return; } progress.CheckStatus(); //record first fiducial measurement in the table recordFid[0] = 0; recordFid[1] = sampleInitial; recordFid[2] = lineInitial; tableFid += recordFid; for (s= sampleInitial, l=lineInitial, fidn=0; s<panS; s+=averageSamples, fidn++) { //corrections for half spacing of center fiducials if (fidn == 22) s -= averageSamples/2.0; if (fidn == 23) s -= averageSamples/2.0; //look for the bottom fiducial searchS.TackCube(s,l+averageLines); searchS.Load(panCube, 0, scale); *arS->SearchChip() = searchS; regStatus = arS->Register(); if (regStatus == AutoReg::SuccessPixel) { inputChip.TackCube(arS->CubeSample(), arS->CubeLine()); inputChip.Load(panCube,0,1); inputChip.SetCubePosition(arS->CubeSample(), arS->CubeLine()); } else { //if autoreg is unsuccessful, a larger window will be used inputChip.TackCube(s, l+averageLines); inputChip.Load(panCube, 0, 1); inputChip.SetCubePosition(s, l+averageLines); } centroid.selectAdaptive(&inputChip, &selectionChip); //continuous dynamic range selection //elliptical trimming/smoothing... if this fails move on if (centroid.elipticalReduction(&selectionChip, 95, play, 2000) != 0 ) { //center of mass to reduce selection to a single measure centroid.centerOfMass(&selectionChip, &sample, &line); inputChip.SetChipPosition(sample, line); sample = inputChip.CubeSample(); line = inputChip.CubeLine(); recordFid[0] = fidn*2+1; recordFid[1] = sample; recordFid[2] = line; tableFid += recordFid; } progress.CheckStatus(); //look for the top fiducial if (s == sampleInitial) //first time through the loop? continue; //then the top fiducial was already found searchS.TackCube(s, l); searchS.Load(panCube, 0, scale); *arS->SearchChip() = searchS; regStatus = arS->Register(); if (regStatus == AutoReg::SuccessPixel) { inputChip.TackCube(arS->CubeSample(), arS->CubeLine()); inputChip.Load(panCube, 0, 1); inputChip.SetCubePosition(arS->CubeSample(), arS->CubeLine()); } else { //if autoreg is unsuccessful, a larger window will be used inputChip.TackCube(s, l); inputChip.Load(panCube, 0, 1); inputChip.SetCubePosition(s, l); } centroid.selectAdaptive(&inputChip, &selectionChip);//continuous dynamic range selection //inputChip.Write("inputTemp.cub");//debug //selectionChip.Write("selectionTemp.cub");//debug //elliptical trimming/smoothing... if this fails move on if (centroid.elipticalReduction(&selectionChip, 95, play, 2000) !=0) { //center of mass to reduce selection to a single measure centroid.centerOfMass(&selectionChip, &sample, &line); inputChip.SetChipPosition(sample, line); //when finding the top fiducial both s and l are refined for a successful measurement, // this will help follow trends in the scaned image s = inputChip.CubeSample(); l = inputChip.CubeLine(); recordFid[0] = fidn*2; recordFid[1] = s; recordFid[2] = l; tableFid += recordFid; } progress.CheckStatus(); } panCube.write(tableFid); //close the new cube panCube.close(false); panCube.open(ui.GetFileName("FROM"),"rw"); delete spPos; delete spRot; //now instantiate a camera to make sure all of this is working ApolloPanoramicCamera* cam = (ApolloPanoramicCamera*)(panCube.camera()); //log the residual report from interior orientation PvlGroup residualStats("InteriorOrientationStats"); residualStats += PvlKeyword("FiducialsFound", toString(tableFid.Records())); residualStats += PvlKeyword("ResidualMax", toString(cam->intOriResidualMax()),"pixels"); residualStats += PvlKeyword("ResidualMean", toString(cam->intOriResidualMean()),"pixels"); residualStats += PvlKeyword("ResidualStdev", toString(cam->intOriResidualStdev()),"pixels"); Application::Log( residualStats ); return; }
void IsisMain() { Process p; Cube *icube = p.SetInputCube("FROM"); Camera *cam = icube->camera(); UserInterface &ui = Application::GetUserInterface(); QString from = ui.GetFileName("FROM"); int sinc = ui.GetInteger("SINC"); int linc = ui.GetInteger("LINC"); CameraStatistics camStats(cam, sinc, linc, from); // Send the Output to the log area Pvl statsPvl = camStats.toPvl(); for (int i = 0; i < statsPvl.groups(); i++) { Application::Log(statsPvl.group(i)); } if(ui.WasEntered("TO")) { QString outfile = FileName(ui.GetFileName("TO")).expanded(); bool exists = FileName(outfile).fileExists(); bool append = ui.GetBoolean("APPEND"); // If the user chose a format of PVL, then write to the output file ("TO") if(ui.GetString("FORMAT") == "PVL") { (append) ? statsPvl.append(outfile) : statsPvl.write(outfile); } else { // Create a flatfile of the data with columhn headings the flatfile is // comma-delimited and can be imported in to spreadsheets ofstream os; bool writeHeader = true; if(append) { os.open(outfile.toAscii().data(), ios::app); if(exists) { writeHeader = false; } } else { os.open(outfile.toAscii().data(), ios::out); } // if new file or append and no file exists then write header if(writeHeader) { os << "Filename," << "LatitudeMinimum," << "LatitudeMaximum," << "LatitudeAverage," << "LatitudeStandardDeviation," << "LongitudeMinimum," << "LongitudeMaximum," << "LongitudeAverage," << "LongitudeStandardDeviation," << "SampleResolutionMinimum," << "SampleResolutionMaximum," << "SampleResolutionAverage," << "SampleResolutionStandardDeviation," << "LineResolutionMinimum," << "LineResolutionMaximum," << "LineResolutionAverage," << "LineResolutionStandardDeviation," << "ResolutionMinimum," << "ResolutionMaximum," << "ResolutionAverage," << "ResolutionStandardDeviation," << "AspectRatioMinimum," << "AspectRatioMaximum," << "AspectRatioAverage," << "AspectRatioStandardDeviation," << "PhaseMinimum," << "PhaseMaximum," << "PhaseAverage," << "PhaseStandardDeviation," << "EmissionMinimum," << "EmissionMaximum," << "EmissionAverage," << "EmissionStandardDeviation," << "IncidenceMinimum," << "IncidenceMaximum," << "IncidenceAverage," << "IncidenceStandardDeviation," << "LocalSolarTimeMinimum," << "LocalSolarTimeMaximum," << "LocalSolarTimeAverage," << "LocalSolarTimeStandardDeviation," << "LocalRadiusMaximum," << "LocalRadiusMaximum," << "LocalRadiusAverage," << "LocalRadiusStandardDeviation," << "NorthAzimuthMinimum," << "NorthAzimuthMaximum," << "NorthAzimuthAverage," << "NorthAzimuthStandardDeviation," << endl; } os << FileName(from).expanded() << ","; //call the function to write out the values for each group writeFlat(os, camStats.getLatStat()); writeFlat(os, camStats.getLonStat()); writeFlat(os, camStats.getSampleResStat()); writeFlat(os, camStats.getLineResStat()); writeFlat(os, camStats.getResStat()); writeFlat(os, camStats.getAspectRatioStat()); writeFlat(os, camStats.getPhaseStat()); writeFlat(os, camStats.getEmissionStat()); writeFlat(os, camStats.getIncidenceStat()); writeFlat(os, camStats.getLocalSolarTimeStat()); writeFlat(os, camStats.getLocalRaduisStat()); writeFlat(os, camStats.getNorthAzimuthStat()); os << endl; } } if(ui.GetBoolean("ATTACH")) { QString cam_name = "CameraStatistics"; //Creates new CameraStatistics Table TableField fname("Name", Isis::TableField::Text, 20); TableField fmin("Minimum", Isis::TableField::Double); TableField fmax("Maximum", Isis::TableField::Double); TableField favg("Average", Isis::TableField::Double); TableField fstd("StandardDeviation", Isis::TableField::Double); TableRecord record; record += fname; record += fmin; record += fmax; record += favg; record += fstd; Table table(cam_name, record); // Place all the gathered camera statistics in a table and attach it to the // cube. Skip "User Parameters" group. for (int i = 1; i < statsPvl.groups(); i++) { PvlGroup &group = statsPvl.group(i); int entry = 0; record[entry] = group.name(); entry++; for (int j = 0; j < group.keywords(); j++) { record[entry] = toDouble(group[j][0]); entry++; } table += record; } icube->reopen("rw"); icube->write(table); p.WriteHistory(*icube); icube->close(); } }
void IsisMain() { // Use a regular Process Process p; // Get user parameters and error check UserInterface &ui = Application::GetUserInterface(); QString from = ui.GetFileName("FROM"); QString to = FileName(ui.GetFileName("TO")).expanded(); //TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS // double HRSCNadirCenterTime = ui.GetDouble("HRSC_NADIRCENTERTIME"); // Open input cube and Make sure this is a lev1 image (ie, not map projected) Cube cube; cube.open(from); if (cube.isProjected()) { QString msg = "Input images is a map projected cube ... not a level 1 image"; throw IException(IException::User, msg, _FILEINFO_); } // Initialize the camera Cube *input = p.SetInputCube("FROM"); Pvl *cubeHeader = input->label(); Camera *cam = input->camera(); CameraDetectorMap *detectorMap = cam->DetectorMap(); CameraFocalPlaneMap *focalMap = cam->FocalPlaneMap(); CameraDistortionMap *distortionMap = cam->DistortionMap(); CameraGroundMap *groundMap = cam->GroundMap(); // Make sure the image contains the InstrumentPointing (aka CK) blob/table PvlGroup test = cube.label()->findGroup("Kernels", Pvl::Traverse); QString InstrumentPointing = (QString) test["InstrumentPointing"]; if (InstrumentPointing != "Table") { QString msg = "Input image does not contain needed SPICE blobs...run spiceinit with attach=yes."; throw IException(IException::User, msg, _FILEINFO_); } // Open output line scanner keyword file ofstream toStrm; toStrm.open(to.toAscii().data(), ios::trunc); if (toStrm.bad()) { QString msg = "Unable to open output TO file"; throw IException(IException::User, msg, _FILEINFO_); } // Get required keywords from instrument and band groups PvlGroup inst = cube.label()->findGroup("Instrument", Pvl::Traverse); QString instrumentId = (QString) inst["InstrumentId"]; bool isMocNA = false; //TO DO: UNCOMMENT THIS LINES ONCE MOC IS WORKING IN SS // bool isMocWARed = false; bool isHiRise = false; bool isCTX = false; bool isLroNACL = false; bool isLroNACR = false; bool isHRSC = false; //TO DO: UNCOMMENT THESE LINE ONCE MOC IS WORKING IN SS // if (instrumentId == "MOC") { // PvlGroup band = cube.label()->findGroup("BandBin", Pvl::Traverse); // QString filter = (QString) band["FilterName"]; // // if (strcmp(filter.toAscii().data(), "BROAD_BAND") == 0) // isMocNA = true; // else if (strcmp(filter.toAscii().data(), "RED") == 0) // isMocWARed = true; // else if (strcmp(filter.toAscii().data(), "BLUE") == 0) { // QString msg = "MOC WA Blue filter images not supported for Socet Set mapping"; // throw IException(IException::User, msg, _FILEINFO_); // } // } // else if (instrumentId == "IdealCamera") { //TO DO: DELETE THIS LINE ONCE MOC IS WORKING IN SS if (instrumentId == "IdealCamera") { PvlGroup orig = cube.label()->findGroup("OriginalInstrument", Pvl::Traverse); QString origInstrumentId = (QString) orig["InstrumentId"]; if (origInstrumentId == "HIRISE") { isHiRise = true; } else { QString msg = "Unsupported instrument: " + origInstrumentId; throw IException(IException::User, msg, _FILEINFO_); } } else if (instrumentId == "HIRISE") { isHiRise = true; } else if (instrumentId == "CTX") { isCTX = true; } else if (instrumentId == "NACL") { isLroNACL = true; } else if (instrumentId == "NACR") { isLroNACR = true; } //TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS // else if (instrumentId == "HRSC") isHRSC = true; else { QString msg = "Unsupported instrument: " + instrumentId; throw IException(IException::User, msg, _FILEINFO_); } int ikCode = cam->naifIkCode(); // Get Focal Length. // NOTE: // For MOC Wide Angle, cam->focal_length returns the focal length // in pixels, so we must convert from pixels to mm using the PIXEL_SIZE // of 0.007 mm gotten from $ISIS3DATA/mgs/kernels/ik/moc20.ti. (The // PIXEL_PITCH value gotten from cam->PixelPitch is 1.0 since the // focal length used by ISIS in this case is in pixels) // For reference: the MOC WA blue filter pixel size needs an adjustment // of 1.000452 (see p_scale in MocWideAngleDistortionMap.cpp), so that // the final blue filter pixel size = (0.007 / 1.000452) // // For all other cameras, cam->focal_length returns the focal // length in mm, as needed by Socet Set double focal = cam->FocalLength(); // focal length returned in mm //TO DO: UNCOMMENT THESE LINES ONCE HRSC and MOC IS WORKING IN SS // if (isMocWARed) // focal = focal * 0.007; // pixel to mm conversion // else if (isHRSC) // { // switch (ikCode) { // case -41219: //S1: fwd stereo // focal = 184.88; // break; // case -41218: //IR: infra-red // focal = 181.57; // break; // case -41217: //P1: fwd photo // focal = 179.16; // break; // case -41216: // GREEN // focal = 175.31; // break; // case -41215: // NADIR // focal = 175.01; // break; // case -41214: // BLUE // focal = 175.53; // break; // case -41213: // P2: aft photo // focal = 179.19; // break; // case -41212: // RED // focal = 181.77; // break; // case -41211: // S2: aft stereo // focal = 184.88; // break; // default: // break; // } // } // Get instrument summing modes int csum = (int) detectorMap->SampleScaleFactor(); int dsum = (int) detectorMap->LineScaleFactor(); if (isLroNACL || isLroNACR || isHRSC) dsum = csum; // Calculate location of boresight in image space, these are zero-based values // // Note: For MOC NA, the boresight is at the image center // For MOC WA, MRO HiRISE, MRO CTX, LRO_NACL, LRO_NACR and HRSC the // boresight is not at the detector center, but the boresight is at the // center of a NOPROJ'ED MRO HIRISE image // Get line/samp of boresight pixel in detector space (summing == 1) focalMap->SetFocalPlane(0.0, 0.0); double detectorBoresightSample = focalMap->DetectorSample(); double detectorBoresightLine = focalMap->DetectorLine(); // Convert sample of boresight pixel in detector into image space // (summing, etc., is accounted for.) detectorMap->SetDetector(detectorBoresightSample, detectorBoresightLine); double boresightSample = detectorMap->ParentSample(); // Set Atmospheric correction coefficients to 0 double atmco[4] = {0.0, 0.0, 0.0, 0.0}; // Get totalLines, totalSamples and account for summed images int totalLines = cube.lineCount(); int totalSamples = cube.sampleCount(); // Get the Interval Time in seconds and calculate // scan duration in seconds double scanDuration = 0.0; double intTime = 0.0; //TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS // int numIntTimes = 0.0; // vector<LineRateChange> lineRates; // if (isHRSC) { // numIntTimes = GetHRSCLineRates(&cube, lineRates, totalLines, HRSCNadirCenterTime); // if (numIntTimes == 1) { // LineRateChange lrc = lineRates.at(0); // intTime = lrc.GetLineScanRate(); // } // if (numIntTimes <= 0) { // QString msg = "HRSC: Invalid number of scan times"; // throw IException(IException::Programmer, msg, _FILEINFO_); // } // else // scanDuration = GetHRSCScanDuration(lineRates, totalLines); // } // else { // // TO DO: indent the following two lines when HRSC is working in SS intTime = detectorMap->LineRate(); //LineRate is in seconds scanDuration = intTime * totalLines; //TO DO: UNCOMMENT THIS LINE ONCE HRSC IS WORKING IN SS // } // For reference, this is the code if calculating interval time // via LineExposureDuration keyword off image labels: // // if (isMocNA || isMocWARed) // intTime = exposureDuration * (double) dsum / 1000.0; // else if (isHiRise) // intTime = exposureDuration * (double) dsum / 1000000.0; // Get along and cross scan pixel size for NA and WA sensors. // NOTE: // 1) The MOC WA pixel size is gotten from moc20.ti and is 7 microns // HRSC pixel size is from the Instrument Addendum file // 2) For others, cam->PixelPitch() returns the pixel pitch (size) in mm. double alongScanPxSize = 0.0; double crossScanPxSize = 0.0; //TO DO: UNCOMMENT THESE LINES ONCE MOC IS WORKING IN SS // if (isMocWARed || isHRSC) { // alongScanPxSize = csum * 0.007; // crossScanPxSize = dsum * 0.007; // } // else { // // TO DO: indent the following 24 lines when HRSC is working in SS crossScanPxSize = dsum * cam->PixelPitch(); // Get the ephemeris time, ground position and undistorted focal plane X // coordinate at the center line/samp of image cam->SetImage(cube.sampleCount() / 2.0, cube.lineCount() / 2.0); double tMid = cam->time().Et(); const double latCenter = cam->UniversalLatitude(); const double lonCenter = cam->UniversalLongitude(); const double radiusCenter = cam->LocalRadius().meters(); double uXCenter = distortionMap->UndistortedFocalPlaneX(); // from the ground position at the image center, increment the ephemeris // time by the line rate and map the ground position into the sensor in // undistorted focal plane coordinates cam->setTime(iTime(tMid + intTime)); double uX, uY; groundMap->GetXY(latCenter, lonCenter, radiusCenter, &uX, &uY); // the along scan pixel size is the difference in focal plane X coordinates alongScanPxSize = abs(uXCenter - uX); //TO DO: UNCOMMENT THIS LINE ONCE MOC and HRSC IS WORKING IN SS // } // Now that we have totalLines, totalSamples, alongScanPxSize and // crossScanPxSize, fill the Interior Orientation Coefficient arrays double ioCoefLine[10]; double ioCoefSample[10]; for (int i = 0; i <= 9; i++) { ioCoefLine[i] = 0.0; ioCoefSample[i] = 0.0; } ioCoefLine[0] = totalLines / 2.0; ioCoefLine[1] = 1.0 / alongScanPxSize; ioCoefSample[0] = totalSamples / 2.0; ioCoefSample[2] = 1.0 / crossScanPxSize; // Update the Rectification Terms found in the base sensor class double rectificationTerms[6]; rectificationTerms[0] = totalLines / 2.0; rectificationTerms[1] = 0.0; rectificationTerms[2] = 1.0; rectificationTerms[3] = totalSamples / 2.0; rectificationTerms[4] = 1.0; rectificationTerms[5] = 0.0; // Fill the triangulation parameters array double triParams[18]; for (int i = 0; i <= 17; i++) triParams[i] = 0.0; triParams[15] = focal; // Set the Center Ground Point at the SOCET Set image, in radians double centerGp[3]; double radii[3] = {0.0, 0.0, 0.0}; Distance Dradii[3]; cam->radii(Dradii); radii[0] = Dradii[0].kilometers(); radii[1] = Dradii[1].kilometers(); radii[2] = Dradii[2].kilometers(); cam->SetImage(boresightSample, totalLines / 2.0); centerGp[0] = DEG2RAD * TProjection::ToPlanetographic(cam->UniversalLatitude(), radii[0], radii[2]); centerGp[1] = DEG2RAD * TProjection::To180Domain(cam->UniversalLongitude()); centerGp[2] = 0.0; //**** NOTE: in the import_pushbroom SOCET SET program, centerGp[2] will be set to the SS //**** project's gp_origin_z // Now get keyword values that depend on ephemeris data. // First get the ephemeris time and camera Lat Lon at image center line, boresight sample. double centerLine = double(totalLines) / 2.0; cam->SetImage(boresightSample, centerLine); //set to boresight of image double etCenter = cam->time().Et(); // Get the sensor position at the image center in ographic lat, // +E lon domain 180 coordinates, radians, height in meters double sensorPosition[3] = {0.0, 0.0, 0.0}; double ocentricLat, e360Lon; cam->subSpacecraftPoint(ocentricLat, e360Lon); sensorPosition[0] = DEG2RAD * TProjection::ToPlanetographic(ocentricLat, radii[0], radii[2]); sensorPosition[1] = DEG2RAD * TProjection::To180Domain(e360Lon); sensorPosition[2] = cam->SpacecraftAltitude() * 1000.0; // Build the ephem data. If the image label contains the InstrumentPosition // table, use it as a guide for number and spacing of Ephem points. // Otherwise (i.e, for dejittered HiRISE images), the number and spacing of // ephem points based on hardcoded dtEphem value // Using the InstrumentPosition table as a guide build the ephem data QList< QList<double> > ephemPts; QList< QList<double> > ephemRates; PvlGroup kernels = cube.label()->findGroup("Kernels", Pvl::Traverse); QString InstrumentPosition = (QString) kernels["InstrumentPosition"]; int numEphem = 0; // number of ephemeris points double dtEphem = 0.0; // delta time of ephemeris points, seconds if (InstrumentPosition == "Table") { // Labels contain SPK blob // set up Ephem pts/rates number and spacing Table tablePosition("InstrumentPosition", cubeHeader->fileName()); numEphem = tablePosition.Records(); // increase the number of ephem nodes by 20%. This is somewhat random but // generally intended to compensate for having equally time spaced nodes // instead of of the potentially more efficient placement used by spiceinit numEphem = int(double(numEphem) * 1.2); // if numEphem calcutated from SPICE blobs is too sparse for SOCET Set, // mulitiply it by a factor of 30 // (30X was settled upon emperically. In the future, make this an input parameter) if (numEphem <= 10) numEphem = tablePosition.Records() * 30; // make the number of nodes odd numEphem = (numEphem % 2) == 1 ? numEphem : numEphem + 1; // SOCET has a max number of ephem pts of 10000, and we're going to add twenty... if (numEphem > 10000 - 20) numEphem = 9979; dtEphem = scanDuration / double(numEphem); //build the tables of values double et = etCenter - (((numEphem - 1) / 2) * dtEphem); for (int i = 0; i < numEphem; i++) { cam->setTime(iTime(et)); SpiceRotation *bodyRot = cam->bodyRotation(); vector<double> pos = bodyRot->ReferenceVector(cam->instrumentPosition()->Coordinate()); //TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //vector<double> vel = bodyRot->ReferenceVector(cam->instrumentPosition()->Velocity()); //Add the ephemeris position and velocity to their respective lists, in meters and meters/sec QList<double> ephemPt; QList<double> ephemRate; ephemPts.append(ephemPt << pos[0] * 1000 << pos[1] * 1000 << pos[2] * 1000); //TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //ephemRates.append(ephemRate << vel[0] * 1000 << vel[1] * 1000 << vel[2] * 1000); et += dtEphem; } //TO DO: WHEN VELOCITY BLOBS ARE CORRECT IN ISIS, linearlly interpolate 10 nodes rather than 11 // (need 11 now for computation of velocity at first and last ephemeris point) // linearlly interpolate 11 additional nodes before line 1 (SOCET requires this) for (int i = 0; i < 11; i++) { double vec[3] = {0.0, 0.0, 0.0}; vec[0] = ephemPts[0][0] + (ephemPts[0][0] - ephemPts[1][0]); vec[1] = ephemPts[0][1] + (ephemPts[0][1] - ephemPts[1][1]); vec[2] = ephemPts[0][2] + (ephemPts[0][2] - ephemPts[1][2]); QList<double> ephemPt; ephemPts.prepend (ephemPt << vec[0] << vec[1] << vec[2]); //TO DO: UNCOMMENT THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //vec[0] = ephemRates[0][0] + (ephemRates[0][0] - ephemRates[1][0]); //vec[1] = ephemRates[0][1] + (ephemRates[0][1] - ephemRates[1][1]); //vec[2] = ephemRates[0][2] + (ephemRates[0][2] - ephemRates[1][2]); //QList<double> ephemRate; //ephemRates.prepend (ephemRate << vec[0] << vec[1] << vec[2]); } //TO DO: WHEN VELOCITY BLOBS ARE CORRECT IN ISIS, linearlly interpolate 10 nodes rather than 11 // (need 11 now for computation of velocity at first and last ephemeris point) // linearlly interpolate 11 additional nodes after the last line (SOCET requires this) for (int i = 0; i < 11; i++) { double vec[3] = {0.0, 0.0, 0.0}; int index = ephemPts.size() - 1; vec[0] = ephemPts[index][0] + (ephemPts[index][0] - ephemPts[index - 1][0]); vec[1] = ephemPts[index][1] + (ephemPts[index][1] - ephemPts[index - 1][1]); vec[2] = ephemPts[index][2] + (ephemPts[index][2] - ephemPts[index - 1][2]); QList<double> ephemPt; ephemPts.append(ephemPt << vec[0] << vec[1] << vec[2]); //TO DO: UNCOMMENT THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //vec[0] = ephemRates[index][0] + (ephemRates[index][0] - ephemRates[index - 1][0]); //vec[1] = ephemRates[index][1] + (ephemRates[index][1] - ephemRates[index - 1][1]); //vec[2] = ephemRates[index][2] + (ephemRates[index][2] - ephemRates[index - 1][2]); //QList<double> ephemRate; //ephemRates.append(ephemRate << vec[0] << vec[1] << vec[2]); } numEphem += 20; //TO DO: DELETE THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS // Compute the spacecraft velocity at each ephemeris point double deltaTime = 2.0 * dtEphem; for (int i = 0; i < numEphem; i++) { double vec[3] = {0.0, 0.0, 0.0}; vec[0] = (ephemPts[i+2][0] - ephemPts[i][0]) / deltaTime; vec[1] = (ephemPts[i+2][1] - ephemPts[i][1]) / deltaTime; vec[2] = (ephemPts[i+2][2] - ephemPts[i][2]) / deltaTime; QList<double> ephemRate; ephemRates.append(ephemRate << vec[0] << vec[1] << vec[2]); } } else { // Calculate the number of ephemeris points that are needed, based on the // value of dtEphem (Delta-Time-Ephemeris). SOCET SET needs the ephemeris // points to exceed the image range for interpolation. For now, attempt a // padding of 10 ephemeris points on either side of the image. if (isMocNA || isHiRise || isCTX || isLroNACL || isLroNACR || isHRSC) // Try increment of every 300 image lines dtEphem = 300 * intTime; // Make this a user definable increment? else // Set increment for WA images to one second dtEphem = 1.0; // Pad by 10 ephem pts on each side of the image numEphem = (int)(scanDuration / dtEphem) + 20; // if numEphem is even, make it odd so that the number of ephemeris points // is equal on either side of T_CENTER if ((numEphem % 2) == 0) numEphem++; //TO DO: DELETE THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS numEphem = numEphem + 2; // Add two for calcuation of velocity vectors... // Find the ephemeris time for the first ephemeris point, and from that, get // to_ephem needed by SOCET (to_ephem is relative to etCenter) double et = etCenter - (((numEphem - 1) / 2) * dtEphem); for (int i = 0; i < numEphem; i++) { cam->setTime(iTime(et)); SpiceRotation *bodyRot = cam->bodyRotation(); vector<double> pos = bodyRot->ReferenceVector(cam->instrumentPosition()->Coordinate()); //TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //vector<double> vel = bodyRot->ReferenceVector(cam->instrumentPosition()->Velocity()); //Add the ephemeris position and velocity to their respective lists, in meters and meters/sec QList<double> ephemPt; QList<double> ephemRate; ephemPts.append(ephemPt << pos[0] * 1000 << pos[1] * 1000 << pos[2] * 1000); //TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //ephemRates.append(ephemRate << vel[0] * 1000 << vel[1] * 1000 << vel[2] * 1000); et += dtEphem; } //TO DO: DELETE THE FOLLOWING LINES WHEN VELOCITY BLOBS ARE CORRECT IN ISIS // Compute the spacecraft velocity at each ephemeris point // (We must do this when blobs are not attached because the Spice Class // stores in memory the same data that would be in a blob...even when reading NAIF kernels) double deltaTime = 2.0 * dtEphem; numEphem = numEphem - 2; // set numEphem back to the number we need output for (int i = 0; i < numEphem; i++) { double vec[3] = {0.0, 0.0, 0.0}; vec[0] = (ephemPts[i+2][0] - ephemPts[i][0]) / deltaTime; vec[1] = (ephemPts[i+2][1] - ephemPts[i][1]) / deltaTime; vec[2] = (ephemPts[i+2][2] - ephemPts[i][2]) / deltaTime; QList<double> ephemRate; ephemRates.append(ephemRate << vec[0] << vec[1] << vec[2]); } } //update ephem stats double etFirstEphem = etCenter - (((numEphem - 1) / 2) * dtEphem); double t0Ephem = etFirstEphem - etCenter; // Using the intrumentPointing table as a guide build the quarternions // for simplicity sake we'll leave the mountingAngles as identity // and store the complete rotation from body fixed to camera in the // quarternions //set up quaternions number and spacing Table tablePointing("InstrumentPointing", cubeHeader->fileName()); //number of quaternions int numQuaternions = tablePointing.Records(); // increase the number of quaternions nodes by 20%. This is somewhat random but // generally intended to compensate for having equally time spaced nodes // instead of of the potentially more efficient placement used by spiceinit numQuaternions = (int)(numQuaternions * 1.2); // if numQuaternions calcutated from SPICE blobs is too sparse for SOCET Set, // mulitiply it by a factor of 30 // (30X was settled upon emperically. In the future, make this an input parameter) if (numQuaternions <= 10) numQuaternions = tablePointing.Records() * 30; //make the number of nodes odd numQuaternions = (numQuaternions % 2) == 1 ? numQuaternions : numQuaternions + 1; // SOCET has a max number of quaternions of 20000, and we're going to add twenty... if (numQuaternions > 20000 - 20) numQuaternions = 19179; double dtQuat = scanDuration / double(numQuaternions); // build the tables of values QList< QList<double> > quaternions; double et = etCenter - (((numQuaternions - 1) / 2) * dtQuat); for (int i = 0; i < numQuaternions; i++) { cam->setTime(iTime(et)); vector<double> j2000ToBodyFixedMatrixVector = cam->bodyRotation()->Matrix(); vector<double> j2000ToCameraMatrixVector = cam->instrumentRotation()->Matrix(); double quaternion[4] = {0.0, 0.0, 0.0, 0.0}; double j2000ToBodyFixedRotationMatrix[3][3], //rotation from J2000 to target (aka body, planet) j2000ToCameraRotationMatrix[3][3], //rotation from J2000 to spacecraft cameraToBodyFixedRotationMatrix[3][3]; //rotation from camera to target // reformat vectors to 3x3 rotation matricies for (int j = 0; j < 3; j++) { for (int k = 0; k < 3; k++) { j2000ToBodyFixedRotationMatrix[j][k] = j2000ToBodyFixedMatrixVector[3 * j + k]; j2000ToCameraRotationMatrix[j][k] = j2000ToCameraMatrixVector[3 * j + k]; } } // get the quaternion mxmt_c(j2000ToBodyFixedRotationMatrix, j2000ToCameraRotationMatrix, cameraToBodyFixedRotationMatrix); m2q_c(cameraToBodyFixedRotationMatrix, quaternion); // add the quaternion to the list of quaternions QList<double> quat; quaternions.append(quat << quaternion[1] << quaternion[2] << quaternion[3] << quaternion[0]); //note also that the order is changed to match socet et += dtQuat; } // linearlly interpolate 10 additional nodes before the first quaternion (SOCET requires this) for (int i = 0; i < 10; i++) { double vec[4] = {0.0, 0.0, 0.0, 0.0}; vec[0] = quaternions[0][0] + (quaternions[0][0] - quaternions[1][0]); vec[1] = quaternions[0][1] + (quaternions[0][1] - quaternions[1][1]); vec[2] = quaternions[0][2] + (quaternions[0][2] - quaternions[1][2]); vec[3] = quaternions[0][3] + (quaternions[0][3] - quaternions[1][3]); QList<double> quat; quaternions.prepend (quat << vec[0] << vec[1] << vec[2] << vec[3]); } // linearlly interpolate 10 additional nodes after the last quaternion (SOCET requires this) for (int i = 0; i < 10; i++) { double vec[4] = {0.0, 0.0, 0.0, 0.0}; int index = quaternions.size() - 1; vec[0] = quaternions[index][0] + (quaternions[index][0] - quaternions[index - 1][0]); vec[1] = quaternions[index][1] + (quaternions[index][1] - quaternions[index - 1][1]); vec[2] = quaternions[index][2] + (quaternions[index][2] - quaternions[index - 1][2]); vec[3] = quaternions[index][3] + (quaternions[index][3] - quaternions[index - 1][3]); QList<double> quat; quaternions.append(quat << vec[0] << vec[1] << vec[2] << vec[3]); } //update quaternions stats numQuaternions += 20; //ephemeris time of the first quarternion double et0Quat = etCenter - (((numQuaternions - 1) / 2) * dtQuat); //quadrtic time of the first quarternion double qt0Quat = et0Quat - etCenter; //query remaing transformation parameters from Camera Classes //transformation to distortionless focal plane double zDirection = distortionMap->ZDirection(); //transformation from DistortionlessFocalPlane to FocalPlane vector<double> opticalDistCoefs = distortionMap->OpticalDistortionCoefficients(); // For instruments with less than 3 distortion coefficients, set the // unused ones to 0.0 opticalDistCoefs.resize(3, 0); //transformation from focal plane to detector const double *iTransS = focalMap->TransS(); const double *iTransL = focalMap->TransL(); double detectorSampleOrigin = focalMap->DetectorSampleOrigin(); double detectorLineOrigin = focalMap->DetectorLineOrigin(); //transformation from dectector to cube double startingSample = detectorMap->AdjustedStartingSample(); double startingLine = detectorMap->AdjustedStartingLine(); double sampleSumming = detectorMap->SampleScaleFactor(); double etStart = ((LineScanCameraDetectorMap *)detectorMap)->StartTime(); double lineOffset = focalMap->DetectorLineOffset(); // We are done with computing keyword values, so output the Line Scanner // Keyword file. // This is the SOCET SET base sensor class keywords portion of support file: toStrm.setf(ios::scientific); toStrm << "RECTIFICATION_TERMS" << endl; toStrm << " " << setprecision(14) << rectificationTerms[0] << " " << rectificationTerms[1] << " " << rectificationTerms[2] << endl; toStrm << " " << rectificationTerms[3] << " " << rectificationTerms[4] << " " << rectificationTerms[5] << endl; toStrm << "GROUND_ZERO "; toStrm << centerGp[0] << " " << centerGp[1] << " " << centerGp[2] << endl; toStrm << "LOAD_PT "; toStrm << centerGp[0] << " " << centerGp[1] << " " << centerGp[2] << endl; toStrm << "COORD_SYSTEM 1" << endl; toStrm << "IMAGE_MOTION 0" << endl; // This is the line scanner sensor model portion of support file: toStrm << "SENSOR_TYPE USGSAstroLineScanner" << endl; toStrm << "SENSOR_MODE UNKNOWN" << endl; toStrm << "FOCAL " << focal << endl; toStrm << "ATMCO"; for (int i = 0; i < 4; i++) toStrm << " " << atmco[i]; toStrm << endl; toStrm << "IOCOEF_LINE"; for (int i = 0; i < 10; i++) toStrm << " " << ioCoefLine[i]; toStrm << endl; toStrm << "IOCOEF_SAMPLE"; for (int i = 0; i < 10; i++) toStrm << " " << ioCoefSample[i]; toStrm << endl; toStrm << "ABERR 0" << endl; toStrm << "ATMREF 0" << endl; toStrm << "PLATFORM 1" << endl; toStrm << "SOURCE_FLAG 1" << endl; toStrm << "SINGLE_EPHEMERIDE 0" << endl; //Note, for TRI_PARAMETERS, we print the first element separate from the rest so that the array //starts in the first column. Otherwise, SOCET Set will treat the array as a comment toStrm << "TRI_PARAMETERS" << endl; toStrm << triParams[0]; for (int i = 1; i < 18; i++) toStrm << " " << triParams[i]; toStrm << endl; toStrm << setprecision(25) << "T_CENTER "; double tCenter = 0.0; //TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS // if (isHRSC) { // tCenter = etCenter - HRSCNadirCenterTime; // toStrm << tCenter << endl; // } // else toStrm << tCenter << endl; toStrm << "DT_EPHEM " << dtEphem << endl; toStrm << "T0_EPHEM "; //TO DO: UNCOMMENT THESE LINES ONCE HRSC IS WORKING IN SS // if (isHRSC) { // double t = tCenter + t0Ephem; // toStrm << t << endl; // } // else toStrm << t0Ephem << endl; toStrm << "NUMBER_OF_EPHEM " << numEphem << endl; toStrm << "EPHEM_PTS" << endl; //TO DO: DELETE THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS for (int i = 1; i <= numEphem; i++) { //TO DO: UNCOMMENT THE FOLLOWING LINE WHEN VELOCITY BLOBS ARE CORRECT IN ISIS //for (int i = 0; i < numEphem; i++) { toStrm << " " << ephemPts[i][0]; toStrm << " " << ephemPts[i][1]; toStrm << " " << ephemPts[i][2] << endl; } toStrm << "\n\nEPHEM_RATES" << endl; for (int i = 0; i < numEphem; i++) { toStrm << " " << ephemRates[i][0]; toStrm << " " << ephemRates[i][1]; toStrm << " " << ephemRates[i][2] << endl; } toStrm << "\n\nDT_QUAT " << dtQuat << endl; toStrm << "T0_QUAT " << qt0Quat << endl; toStrm << "NUMBER_OF_QUATERNIONS " << numQuaternions << endl; toStrm << "QUATERNIONS" << endl; for (int i = 0; i < numQuaternions; i++) { toStrm << " " << quaternions[i][0]; toStrm << " " << quaternions[i][1]; toStrm << " " << quaternions[i][2]; toStrm << " " << quaternions[i][3] << endl; } toStrm << "\n\nSCAN_DURATION " << scanDuration << endl; // UNCOMMENT toStrm << "\nNUMBER_OF_INT_TIMES " << numIntTimes << endl; // // if (isHRSC) { // toStrm << "INT_TIMES" << endl; // for (int i = 0; i < numIntTimes; i++) { // LineRateChange lr = lineRates.at(i); // toStrm << " " << lr.GetStartEt(); // toStrm << " " << lr.GetLineScanRate(); // toStrm << " " << lr.GetStartLine() << endl; // } // } // else toStrm << "INT_TIME " << intTime << endl; toStrm << "\nALONG_SCAN_PIXEL_SIZE " << alongScanPxSize << endl; toStrm << "CROSS_SCAN_PIXEL_SIZE " << crossScanPxSize << endl; toStrm << "\nCENTER_GP"; for (int i = 0; i < 3; i++) toStrm << " " << centerGp[i]; toStrm << endl; toStrm << "SENSOR_POSITION"; for (int i = 0; i < 3; i++) toStrm << " " << sensorPosition[i]; toStrm << endl; toStrm << "MOUNTING_ANGLES"; double mountingAngles[3] = {0.0, 0.0, 0.0}; for (int i = 0; i < 3; i++) toStrm << " " << mountingAngles[i]; toStrm << endl; toStrm << "\nTOTAL_LINES " << totalLines << endl; toStrm << "TOTAL_SAMPLES " << totalSamples << endl; toStrm << "\n\n\n" << endl; toStrm << "IKCODE " << ikCode << endl; toStrm << "ISIS_Z_DIRECTION " << zDirection << endl; toStrm << "OPTICAL_DIST_COEF"; for (int i = 0; i < 3; i++) toStrm << " " << opticalDistCoefs[i]; toStrm << endl; toStrm << "ITRANSS"; for (int i = 0; i < 3; i++) toStrm << " " << iTransS[i]; toStrm << endl; toStrm << "ITRANSL"; for (int i = 0; i < 3; i++) toStrm << " " << iTransL[i]; toStrm << endl; toStrm << "DETECTOR_SAMPLE_ORIGIN " << detectorSampleOrigin << endl; toStrm << "DETECTOR_LINE_ORIGIN " << detectorLineOrigin << endl; toStrm << "DETECTOR_LINE_OFFSET " << lineOffset << endl; toStrm << "DETECTOR_SAMPLE_SUMMING " << sampleSumming << endl; toStrm << "STARTING_SAMPLE " << startingSample << endl; toStrm << "STARTING_LINE " << startingLine << endl; toStrm << "STARTING_EPHEMERIS_TIME " << setprecision(25) << etStart << endl; toStrm << "CENTER_EPHEMERIS_TIME " << etCenter << endl; } // end main
void IsisMain() { // Use a regular Process Process p; UserInterface &ui = Application::GetUserInterface(); QString from = ui.GetFileName("FROM"); QString to = FileName(ui.GetFileName("TO")).expanded(); QString socetProject = ui.GetString("SS_PROJECT"); QString socetImageLocation = ui.GetString("SS_IMG_LOC"); QString socetInputDataPath = ui.GetString("SS_INPUT_PATH"); QString socetCameraCalibrationPath = ui.GetString("SS_CAM_CALIB_PATH"); // Open input cube and make sure this is a lev1 image (ie, not map projected) Cube cube; cube.open(from); if (cube.isProjected()) { QString msg = QString("You can only create a SOCET Set Framing Camera or FrameOffAxis settings " "file for level 1 images. The input image [%1] is a map projected, level " "2, cube.").arg(from); throw IException(IException::User, msg, _FILEINFO_); } // Initialize the camera Cube *input = p.SetInputCube("FROM"); Camera *cam = input->camera(); CameraDetectorMap *detectorMap = cam->DetectorMap(); CameraFocalPlaneMap *focalMap = cam->FocalPlaneMap(); // Make sure the image contains the SPICE blobs/tables PvlGroup test = cube.label()->findGroup("Kernels", Pvl::Traverse); QString instrumentPointing = (QString) test["InstrumentPointing"]; if (instrumentPointing != "Table") { QString msg = QString("Input image [%1] does not contain needed SPICE blobs. Please run " "spiceinit on the image with attach=yes.").arg(from); throw IException(IException::User, msg, _FILEINFO_); } // Set the image at the boresight pixel to get the ephemeris time and SPICE data at that image // location double detectorSampleOrigin = focalMap->DetectorSampleOrigin(); double detectorLineOrigin = focalMap->DetectorSampleOrigin(); cam->SetImage(detectorSampleOrigin, detectorLineOrigin); double et = cam->time().Et(); Spice spice(*input); spice.setTime(et); // Get required keywords from instrument and band groups PvlGroup inst = cube.label()->findGroup("Instrument", Pvl::Traverse); QString instrumentId = (QString) inst["InstrumentId"]; QString spacecraftName = (QString) inst["SpacecraftName"]; // Compensate for noproj altering cube labels if (instrumentId == "IdealCamera") { PvlGroup orig = cube.label()->findGroup("OriginalInstrument", Pvl::Traverse); instrumentId = (QString) orig["InstrumentId"]; spacecraftName = (QString) orig["SpacecraftName"]; } // Get sensor position and orientation (opk) angles double ographicCamPos[3] = {0.0, 0.0, 0.0}; double omegaPhiKappa[3] = {0.0, 0.0, 0.0}; double isisFocalPlane2SocetPlateTranspose[3][3] = {{0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}, {0.0, 0.0, 0.0}}; getCamPosOPK(spice, spacecraftName, et, cam, ographicCamPos, omegaPhiKappa,isisFocalPlane2SocetPlateTranspose); // Determine the SOCET Set camera calibration file QString socetCamFile = socetCameraCalibrationPath; if (spacecraftName == "VIKING_ORBITER_1") { if (instrumentId == "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") { socetCamFile += "VIK1A.cam"; } else { socetCamFile += "VIK1B.cam"; } } else if (spacecraftName == "VIKING_ORBITER_2") { if (instrumentId == "VISUAL_IMAGING_SUBSYSTEM_CAMERA_A") { socetCamFile += "VIK2A.cam"; } else { socetCamFile += "VIK2B.cam"; } } //----------------------------------------.------------- //TO DO: Uncomment these lines when MEX SRC is supported //----------------------------------------.------------- // // Mars Express // else if (spacecraftName == "MARS_EXPRESS") { // socetCamFile += "SRC.cam"; // } //----------------------------------------------------- //TO DO: Uncomment these lines when Themis is supported //----------------------------------------------------- // // THEMIS VIS images (MARS Odyssey) // else if (spacecraftName == "MARS_ODYSSEY") { // socetCamFile += "THEMIS_VIS_F3.cam"; // } //----------------------------------------------------- //TO DO: Uncomment these lines when Apollo is supported //----------------------------------------------------- // else if (spacecraftName == "APOLLO 15") { // socetCamFile += "Apollo15_M_ASU.cam"; // } // else if (spacecraftName == "APOLLO 16") { // socetCamFile += "Apollo16_M_ASU.cam"; // } // else if (spacecraftName == "APOLLO 17") { // socetCamFile += "Apollo17_M_ASU.cam"; // } else if (spacecraftName == "Galileo Orbiter") { //Check if this image was aquired with the cover on or off iTime removeCoverDate("1994/04/01 00:00:00"); iTime imageDate((QString) inst["StartTime"]); if (imageDate < removeCoverDate) { socetCamFile += "Galileo_SSI_Cover.cam"; } else { socetCamFile += "Galileo_SSI.cam"; } } else if (spacecraftName == "Cassini-Huygens") { // Get the image filter and replace "/" with "_" PvlGroup bandBin = cube.label()->findGroup("BandBin", Pvl::Traverse); QString filter = (QString) bandBin["FilterName"]; filter.replace("/", "_"); socetCamFile += "Cassini_ISSNA_"; socetCamFile += filter; socetCamFile += ".cam"; } else if (spacecraftName == "Messenger") { if (instrumentId == "MDIS-NAC") { socetCamFile += "MDIS_NAC.cam"; } else { socetCamFile += "MDIS_WAC.cam"; } } else if (spacecraftName == "CLEMENTINE 1") { if (instrumentId == "UVVIS") { socetCamFile += "ClemUVVIS.cam"; } } // Throw exception for unsupported camera else { QString msg = QString("The ISIS to SOCET Set translation of input image [%1] is currently " "not supported for instrument [%2].").arg(from).arg(instrumentId); throw IException(IException::User, msg, _FILEINFO_); } // For THEMIS VIS, Galileo SSI, Cassini ISS get the image summation mode int summation = 1; //----------------------------------------------------- //TO DO: Uncomment these lines when Themis is supported //----------------------------------------------------- // if (spacecraftName == "MARS_ODYSSEY") { // try { // summation = (int) detectorMap->SampleScaleFactor(); // } // catch (IException &e) { // QString msg = "Error reading SpatialSumming from Instrument label"; // throw IException(IException::User, msg, _FILEINFO_); // } // } if (spacecraftName == "Galileo Orbiter") { try { summation = (int) detectorMap->SampleScaleFactor(); } catch (IException &e) { QString msg = "Error reading Summing from Instrument label"; throw IException(IException::User, msg, _FILEINFO_); } } if (spacecraftName == "Cassini-Huygens") { try { summation = (int) detectorMap->SampleScaleFactor(); } catch (IException &e) { QString msg = "Error reading Summing from Instrument label"; throw IException(IException::User, msg, _FILEINFO_); } } // Get NL/NS of image and calculate the size in x/y dimensions, in mm // Note: for THEMIS VIS, Galileo SSI and Cassini ISS summed images, calculate the size of the full // resolution image because our "isis2socet" scripts will enlarge the summed image for import into // Socet Set double pixelSize = 1.0 / cam->PixelPitch(); int numLines = cube.lineCount(); int numSamples = cube.sampleCount(); if (summation > 1) { // For Themis VIS, Galileo SSI, Cassini ISS: numLines *= summation; numSamples *= summation; } double sizeX = numSamples / pixelSize; double sizeY = numLines / pixelSize; // Make sure the Socet Set project name has the .prj extension if (socetProject.endsWith(".prj", Qt::CaseInsensitive) == FALSE) socetProject += ".prj"; // Find cube base name w/o extensions & establish the Socet Set support file name // Note: I'm using the QFileInfo class because the baseName method in the ISIS // FileName class only strips the last extension, and we need the core name // of the file without any extensions, or path QString baseName = QFileInfo(from).baseName(); QString socetSupFile = baseName + ".sup"; // Open and write to the SOCET Set Framing Camera settings file keywords and values // If this is a Messenger image, add the temperature-dependent focal length so as to overrride // the nominal focal lenghth stored in the SOCET Set camera calibration files ofstream toStrm; toStrm.open (to.toAscii().data(), ios::trunc); if (toStrm.bad()) { QString msg = "Unable to open output settings file"; throw IException(IException::User, msg, _FILEINFO_); } toStrm << "setting_file 1.1\n"; toStrm << "multi_frame.project " << socetProject << endl; toStrm << "multi_frame.cam_calib_filename " << socetCamFile << endl; toStrm << "multi_frame.create_files IMAGE_AND_SUPPORT\n"; toStrm << "multi_frame.atmos_ref 0\n"; toStrm << "multi_frame.auto_min YES\n"; toStrm << "multi_frame.digital_cam NO\n"; toStrm << "multi_frame.input_image_filename " << socetInputDataPath + baseName + ".raw" << endl; toStrm << "multi_frame.output_format img_type_vitec\n"; toStrm << "multi_frame.output_name " << socetSupFile << endl; toStrm << "multi_frame.output_location " << socetImageLocation << endl; toStrm << "multi_frame.cam_loc_ang_sys OPK\n"; toStrm << "multi_frame.cam_loc_ang_units UNIT_DEGREES\n"; toStrm << "multi_frame.cam_loc_xy_units UNIT_DEGREES\n"; if (spacecraftName == "Messenger") { // Overide the nominal focal length in the SOCET SET camera calibration file with the // Temperature Dependent Focal Length used in ISIS double focalLength = cam->FocalLength(); toStrm << "multi_frame.cam_loc_focal " << setprecision(17) << focalLength << endl; } toStrm << "multi_frame.cam_loc_y_or_lat " << setprecision(17) << ographicCamPos[0] << endl; toStrm << "multi_frame.cam_loc_x_or_lon " << ographicCamPos[1] << endl; toStrm << "multi_frame.cam_loc_elev " << ographicCamPos[2] << endl; toStrm << "multi_frame.cam_loc_omega " << omegaPhiKappa[0] << endl; toStrm << "multi_frame.cam_loc_phi " << omegaPhiKappa[1] << endl; toStrm << "multi_frame.cam_loc_kappa " << omegaPhiKappa[2] << endl; toStrm << "multi_frame.img_size_lines " << numLines << endl; toStrm << "multi_frame.img_size_samps " << numSamples << endl; toStrm << "multi_frame.sizex " << setprecision(6) << sizeX << endl; toStrm << "multi_frame.sizey " << sizeY << endl; toStrm << "multi_frame.orientation 1\n"; // Furthermore, if this is a Messenger image, get the needed keywords values needed for the // USGSAstro FrameOffAxis *support* file, and add them to the output settings file. // During frame import in SOCET Set, these values will be ignored, but then later accessed by // the USGSAstro import_frame SOCET Set program. // // Note: Summed Messenger images are handled in the FrameOffAxis sensor model, so no need to // account for enlarging Messenger images in the "socet2isis" scripts if (spacecraftName == "Messenger") { double originalHalfLines = numLines / 2.0; double originalHalfSamples = numSamples / 2.0; // Set the lens distortion coefficients // Note: These values were calculated for SOCET Set by Orrin Thomas in an MSExcel spreadsheet, // and are hardcoded here QString lenscoX; QString lenscoY; if (instrumentId == "MDIS-WAC") { lenscoX = QString("1.0913499678359500E-06 1.0000181809155400E+00 5.2705094712778700E-06 " "7.3086112844249500E-05 -2.1503011755973800E-06 -3.5311655893430800E-08 " "-5.3312743384716000E-06 -1.4642661005550900E-07 -5.4770856997706100E-06 " "-1.2364567692453900E-07 0.0000000000000000E+00 0.0000000000000000E+00 " "0.0000000000000000E+00 0.0000000000000000E+00 0.0000000000000000E+00"); lenscoY = QString("-4.8524316760252900E-08 -5.2704844291112000E-06 1.0000181808487100E+00 " "2.4702140905559800E-09 7.3084305868732200E-05 -2.1478354889239300E-06 " "1.2364567791040000E-07 -5.4663905009059100E-06 1.4516772126792600E-07 " "-5.3419626374895400E-06 0.0000000000000000E+00 0.0000000000000000E+00 " "0.0000000000000000E+00 0.0000000000000000E+00 0.0000000000000000E+00"); } else { //MDIS-NAC lens distortion coefficients: lenscoX = QString("-0.000000000000005 0.997948053760188 0.000000000000000 0.000000000000000 " "0.000542184519158 0.000000000000000 -0.000007008182254 0.000000000000000 " "-0.000006526474815 0.000000000000000 0.000000000000000 0.000000000000000 " "0.000000000000000 0.000000000000000 0.000000000000000"); lenscoY = QString("-0.000003746900328 0.000000000000000 0.999999575428613 -0.000880501428960 " "0.000000000000000 -0.000332760373453 0.000000000000000 -0.000008067196812 " "0.000000000000000 -0.000007553955548 0.000000000000000 0.000000000000000 " "0.000000000000000 0.000000000000000 0.000000000000000"); } // Get the image summation double sampleSumming = (int) detectorMap->SampleScaleFactor(); double lineSumming = (int) detectorMap->LineScaleFactor(); // Get the Starting Detector Line/Sample double startingSample = detectorMap->AdjustedStartingSample(); double startingLine = detectorMap->AdjustedStartingLine(); // Get the image plane corrdinates to pixel coordinates transformation matrices const double *iTransS = focalMap->TransS(); const double *iTransL = focalMap->TransL(); // Because of the options for applying light-time correction, capture the pertinent // ISIS keywords as a record to be stored in the settingsfile // Note: these values will not go into the Socet Set support file) QString ikCode; QString swapObserverTarget; QString lightTimeCorrection; QString ltSurfaceCorrect; PvlObject naifKeywordsObject = cube.label()->findObject("NaifKeywords"); if (instrumentId == "MDIS-NAC") { ikCode = "236820"; swapObserverTarget = (QString) naifKeywordsObject["INS-236820_SWAP_OBSERVER_TARGET"]; lightTimeCorrection = (QString) naifKeywordsObject["INS-236820_LIGHTTIME_CORRECTION"]; ltSurfaceCorrect = (QString) naifKeywordsObject["INS-236820_LT_SURFACE_CORRECT"]; } else { ikCode = "236800"; swapObserverTarget = (QString) naifKeywordsObject["INS-236800_SWAP_OBSERVER_TARGET"]; lightTimeCorrection = (QString) naifKeywordsObject["INS-236800_LIGHTTIME_CORRECTION"]; ltSurfaceCorrect = (QString) naifKeywordsObject["INS-236800_LT_SURFACE_CORRECT"]; } toStrm << "\nSENSOR_TYPE FrameOffAxis" << endl; toStrm << "USE_LENS_DISTORTION 1" << endl; toStrm << "ORIGINAL_HALF_LINES " << originalHalfLines << endl; toStrm << "ORIGINAL_HALF_SAMPLES " << originalHalfSamples << endl; toStrm << "LENSCOX " << lenscoX << endl; toStrm << "LENSCOY " << lenscoY << endl; toStrm << "SAMPLE_SUMMING " << sampleSumming << endl; toStrm << "LINE_SUMMING " << lineSumming << endl; toStrm << "STARTING_DETECTOR_SAMPLE " << setprecision(17) << startingSample << endl; toStrm << "STARTING_DETECTOR_LINE " << startingLine << endl; toStrm << "SAMPLE_BORESIGHT " << detectorSampleOrigin << endl; toStrm << "LINE_BORESIGHT " << detectorLineOrigin << endl; toStrm << "INS_ITRANSS"; for (int i = 0; i < 3; i++) toStrm << " " << setprecision(14) << iTransS[i]; toStrm << endl; toStrm << "INS_ITRANSL"; for (int i = 0; i < 3; i++) toStrm << " " << iTransL[i]; toStrm << endl; toStrm << "M_SOCET2ISIS_FOCALPLANE " << setprecision(2) << isisFocalPlane2SocetPlateTranspose[0][0] << " " << isisFocalPlane2SocetPlateTranspose[0][1] << " " << isisFocalPlane2SocetPlateTranspose[0][2] << endl; toStrm << " " << isisFocalPlane2SocetPlateTranspose[1][0] << " " << isisFocalPlane2SocetPlateTranspose[1][1] << " " << isisFocalPlane2SocetPlateTranspose[1][2] << endl; toStrm << " " << isisFocalPlane2SocetPlateTranspose[2][0] << " " << isisFocalPlane2SocetPlateTranspose[2][1] << " " << isisFocalPlane2SocetPlateTranspose[2][2] << endl; toStrm << "INS-" << ikCode << "_SWAP_OBSERVER_TARGET = '" << swapObserverTarget << "'\n"; toStrm << "INS-" << ikCode << "_LIGHTTIME_CORRECTION = '" << lightTimeCorrection << "'\n"; toStrm << "INS-" << ikCode << "_LT_SURFACE_CORRECT = '" << ltSurfaceCorrect <<"'\n"; } } //End IsisMain
void IsisMain() { const QString caminfo_program = "caminfo"; UserInterface &ui = Application::GetUserInterface(); QList< QPair<QString, QString> > *general = NULL, *camstats = NULL, *statistics = NULL; BandGeometry *bandGeom = NULL; // Get input filename FileName in = ui.GetFileName("FROM"); // Get the format QString sFormat = ui.GetAsString("FORMAT"); // if true then run spiceinit, xml default is FALSE // spiceinit will use system kernels if(ui.GetBoolean("SPICE")) { QString parameters = "FROM=" + in.expanded(); ProgramLauncher::RunIsisProgram("spiceinit", parameters); } Process p; Cube *incube = p.SetInputCube("FROM"); // General data gathering general = new QList< QPair<QString, QString> >; general->append(MakePair("Program", caminfo_program)); general->append(MakePair("IsisVersion", Application::Version())); general->append(MakePair("RunDate", iTime::CurrentGMT())); general->append(MakePair("IsisId", SerialNumber::Compose(*incube))); general->append(MakePair("From", in.baseName() + ".cub")); general->append(MakePair("Lines", toString(incube->lineCount()))); general->append(MakePair("Samples", toString(incube->sampleCount()))); general->append(MakePair("Bands", toString(incube->bandCount()))); // Run camstats on the entire image (all bands) // another camstats will be run for each band and output // for each band. if(ui.GetBoolean("CAMSTATS")) { camstats = new QList< QPair<QString, QString> >; QString filename = ui.GetAsString("FROM"); int sinc = ui.GetInteger("SINC"); int linc = ui.GetInteger("LINC"); CameraStatistics stats(filename, sinc, linc); Pvl camPvl = stats.toPvl(); PvlGroup cg = camPvl.findGroup("Latitude", Pvl::Traverse); camstats->append(MakePair("MinimumLatitude", cg["latitudeminimum"][0])); camstats->append(MakePair("MaximumLatitude", cg["latitudemaximum"][0])); cg = camPvl.findGroup("Longitude", Pvl::Traverse); camstats->append(MakePair("MinimumLongitude", cg["longitudeminimum"][0])); camstats->append(MakePair("MaximumLongitude", cg["longitudemaximum"][0])); cg = camPvl.findGroup("Resolution", Pvl::Traverse); camstats->append(MakePair("MinimumResolution", cg["resolutionminimum"][0])); camstats->append(MakePair("MaximumResolution", cg["resolutionmaximum"][0])); cg = camPvl.findGroup("PhaseAngle", Pvl::Traverse); camstats->append(MakePair("MinimumPhase", cg["phaseminimum"][0])); camstats->append(MakePair("MaximumPhase", cg["phasemaximum"][0])); cg = camPvl.findGroup("EmissionAngle", Pvl::Traverse); camstats->append(MakePair("MinimumEmission", cg["emissionminimum"][0])); camstats->append(MakePair("MaximumEmission", cg["emissionmaximum"][0])); cg = camPvl.findGroup("IncidenceAngle", Pvl::Traverse); camstats->append(MakePair("MinimumIncidence", cg["incidenceminimum"][0])); camstats->append(MakePair("MaximumIncidence", cg["incidencemaximum"][0])); cg = camPvl.findGroup("LocalSolarTime", Pvl::Traverse); camstats->append(MakePair("LocalTimeMinimum", cg["localsolartimeMinimum"][0])); camstats->append(MakePair("LocalTimeMaximum", cg["localsolartimeMaximum"][0])); } // Compute statistics for entire cube if(ui.GetBoolean("STATISTICS")) { statistics = new QList< QPair<QString, QString> >; LineManager iline(*incube); Statistics stats; Progress progress; progress.SetText("Statistics..."); progress.SetMaximumSteps(incube->lineCount()*incube->bandCount()); progress.CheckStatus(); iline.SetLine(1); for(; !iline.end() ; iline.next()) { incube->read(iline); stats.AddData(iline.DoubleBuffer(), iline.size()); progress.CheckStatus(); } // Compute stats of entire cube double nPixels = stats.TotalPixels(); double nullpercent = (stats.NullPixels() / (nPixels)) * 100; double hispercent = (stats.HisPixels() / (nPixels)) * 100; double hrspercent = (stats.HrsPixels() / (nPixels)) * 100; double lispercent = (stats.LisPixels() / (nPixels)) * 100; double lrspercent = (stats.LrsPixels() / (nPixels)) * 100; // Statitics output for band statistics->append(MakePair("MeanValue", toString(stats.Average()))); statistics->append(MakePair("StandardDeviation", toString(stats.StandardDeviation()))); statistics->append(MakePair("MinimumValue", toString(stats.Minimum()))); statistics->append(MakePair("MaximumValue", toString(stats.Maximum()))); statistics->append(MakePair("PercentHIS", toString(hispercent))); statistics->append(MakePair("PercentHRS", toString(hrspercent))); statistics->append(MakePair("PercentLIS", toString(lispercent))); statistics->append(MakePair("PercentLRS", toString(lrspercent))); statistics->append(MakePair("PercentNull", toString(nullpercent))); statistics->append(MakePair("TotalPixels", toString(stats.TotalPixels()))); } bool getFootBlob = ui.GetBoolean("USELABEL"); bool doGeometry = ui.GetBoolean("GEOMETRY"); bool doPolygon = ui.GetBoolean("POLYGON"); if(doGeometry || doPolygon || getFootBlob) { Camera *cam = incube->camera(); QString incType = ui.GetString("INCTYPE"); int polySinc, polyLinc; if(doPolygon && incType.toUpper() == "VERTICES") { ImagePolygon poly; poly.initCube(*incube); polySinc = polyLinc = (int)(0.5 + (((poly.validSampleDim() * 2) + (poly.validLineDim() * 2) - 3.0) / ui.GetInteger("NUMVERTICES"))); } else if (incType.toUpper() == "LINCSINC"){ if(ui.WasEntered("POLYSINC")) { polySinc = ui.GetInteger("POLYSINC"); } else { polySinc = (int)(0.5 + 0.10 * incube->sampleCount()); if(polySinc == 0) polySinc = 1; } if(ui.WasEntered("POLYLINC")) { polyLinc = ui.GetInteger("POLYLINC"); } else { polyLinc = (int)(0.5 + 0.10 * incube->lineCount()); if(polyLinc == 0) polyLinc = 1; } } else { QString msg = "Invalid INCTYPE option[" + incType + "]"; throw IException(IException::Programmer, msg, _FILEINFO_); } bandGeom = new BandGeometry(); bandGeom->setSampleInc(polySinc); bandGeom->setLineInc(polyLinc); bandGeom->setMaxIncidence(ui.GetDouble("MAXINCIDENCE")); bandGeom->setMaxEmission(ui.GetDouble("MAXEMISSION")); bool precision = ui.GetBoolean("INCREASEPRECISION"); if (getFootBlob) { // Need to read history to obtain parameters that were used to // create the footprint History hist("IsisCube", in.expanded()); Pvl pvl = hist.ReturnHist(); PvlObject::PvlObjectIterator objIter; bool found = false; PvlGroup fpgrp; for (objIter=pvl.endObject()-1; objIter>=pvl.beginObject(); objIter--) { if (objIter->name().toUpper() == "FOOTPRINTINIT") { found = true; fpgrp = objIter->findGroup("UserParameters"); break; } } if (!found) { QString msg = "Footprint blob was not found in input image history"; throw IException(IException::User, msg, _FILEINFO_); } QString prec = (QString)fpgrp.findKeyword("INCREASEPRECISION"); prec = prec.toUpper(); if (prec == "TRUE") { precision = true; } else { precision = false; } QString inctype = (QString)fpgrp.findKeyword("INCTYPE"); inctype = inctype.toUpper(); if (inctype == "LINCSINC") { int linc = fpgrp.findKeyword("LINC"); int sinc = fpgrp.findKeyword("SINC"); bandGeom->setSampleInc(sinc); bandGeom->setLineInc(linc); } else { int vertices = fpgrp.findKeyword("NUMVERTICES"); int lincsinc = (int)(0.5 + (((incube->sampleCount() * 2) + (incube->lineCount() * 2) - 3.0) / vertices)); bandGeom->setSampleInc(lincsinc); bandGeom->setLineInc(lincsinc); } if (fpgrp.hasKeyword("MAXINCIDENCE")) { double maxinc = fpgrp.findKeyword("MAXINCIDENCE"); bandGeom->setMaxIncidence(maxinc); } if (fpgrp.hasKeyword("MAXEMISSION")) { double maxema = fpgrp.findKeyword("MAXEMISSION"); bandGeom->setMaxEmission(maxema); } } bandGeom->collect(*cam, *incube, doGeometry, doPolygon, getFootBlob, precision); // Check if the user requires valid image center geometry if(ui.GetBoolean("VCAMERA") && (!bandGeom->hasCenterGeometry())) { QString msg = "Image center does not project in camera model"; throw IException(IException::Unknown, msg, _FILEINFO_); } } if(sFormat.toUpper() == "PVL") GeneratePVLOutput(incube, general, camstats, statistics, bandGeom); else GenerateCSVOutput(incube, general, camstats, statistics, bandGeom); // Clean the data delete general; general = NULL; if(camstats) { delete camstats; camstats = NULL; } if(statistics) { delete statistics; statistics = NULL; } if(bandGeom) { delete bandGeom; bandGeom = NULL; } }
/** * @brief Construct from PVL and Cube file * * @author Kris Becker - 2/21/2010 * * @param pvl Photometric parameter files * @param cube Input cube file */ Hillier::Hillier(PvlObject &pvl, Cube &cube) { _camera = cube.camera(); init(pvl, cube); }
void IsisMain() { // We will be processing by line ProcessByLine p; // Setup the input and make sure it is a mariner10 file UserInterface & ui = Application::GetUserInterface(); Isis::Pvl lab(ui.GetFileName("FROM")); Isis::PvlGroup & inst = lab.findGroup("Instrument", Pvl::Traverse); QString mission = inst["SpacecraftName"]; if (mission != "Mariner_10") { string msg = "This is not a Mariner 10 image. Mar10cal requires a Mariner 10 image."; throw IException(IException::User, msg, _FILEINFO_); } Cube * icube = p.SetInputCube("FROM", OneBand); // If it is already calibrated then complain if (icube->hasGroup("Radiometry")) { QString msg = "This Mariner 10 image [" + icube->fileName() + "] has " "already been radiometrically calibrated"; throw IException(IException::User, msg, _FILEINFO_); } // Get label parameters we will need for calibration equation QString instId = inst["InstrumentId"]; QString camera = instId.mid(instId.size()-1); QString filter = (QString)(icube->group("BandBin"))["FilterName"]; filter = filter.toUpper().mid(0,3); QString target = inst["TargetName"]; iTime startTime((QString) inst["StartTime"]); double exposure = inst["ExposureDuration"]; double exposureOffset = 0.0; if (ui.WasEntered("EXPOFF")) { exposureOffset = ui.GetDouble("EXPOFF"); } else { if (camera == "A") { exposureOffset = 0.316; } else if (camera == "B") { exposureOffset = 3.060; } else { QString msg = "Camera [" + camera + "] is not supported."; throw IException(IException::User, msg, _FILEINFO_); } } correctedExp = exposure + exposureOffset; Cube * dcCube; if (ui.WasEntered ("DCCUBE") ) { dcCube = p.SetInputCube("DCCUBE"); } else { // Mercury Dark current // ??? NOTE: Need to find Mark's dc for venus and moon ???? QString dcFile("$mariner10/calibration/mariner_10_" + camera + "_dc.cub"); CubeAttributeInput cubeAtt; dcCube = p.SetInputCube(dcFile, cubeAtt); } // Open blemish removal file Cube * blemCube = 0; useBlem = (ui.GetBoolean("BLEMMASK")) ? true : false; if (useBlem) { QString blemFile("$mariner10/calibration/mariner_10_blem_" + camera + ".cub"); CubeAttributeInput cubeAtt; blemCube = p.SetInputCube(blemFile, cubeAtt); } if (filter == "FAB" || filter == "WAF") { QString msg = "Filter type [" + filter + "] is not supported at this time."; throw IException(IException::User, msg, _FILEINFO_); } if (ui.WasEntered ("COEFCUBE")) { coCube.open(ui.GetFileName("COEFCUBE")); } else { FileName coFile("$mariner10/calibration/mariner_10_" + filter + "_" + camera + "_coef.cub"); coCube.open(coFile.expanded()); } coef = new Brick(icube->sampleCount(), 1, 6, coCube.pixelType()); if (ui.WasEntered("ABSCOEF")) { absCoef = ui.GetDouble("ABSCOEF"); } else { if (camera == "A") { absCoef = 16.0; } else if (camera == "B") { absCoef = 750.0; } else { QString msg = "Camera [" + camera + "] is not supported."; throw IException(IException::User, msg, _FILEINFO_); } } mask = ui.GetBoolean("MASK"); xparm = ui.GetDouble("XPARM"); // Get the distance between Mars and the Sun at the given time in // Astronomical Units (AU) Camera * cam = icube->camera(); bool camSuccess = cam->SetImage(icube->sampleCount()/2,icube->lineCount()/2); if (!camSuccess) { throw IException(IException::Unknown, "Unable to calculate the Solar Distance on [" + icube->fileName() + "]", _FILEINFO_); } sunDist = cam->SolarDistance(); // Setup the output cube Cube *ocube = p.SetOutputCube("TO"); // Add the radiometry group PvlGroup calgrp("Radiometry"); calgrp += PvlKeyword("DarkCurrentCube", dcCube->fileName()); if (useBlem) { calgrp += PvlKeyword("BlemishRemovalCube", blemCube->fileName()); } calgrp += PvlKeyword("CoefficientCube", coCube.fileName()); calgrp += PvlKeyword("AbsoluteCoefficient", toString(absCoef)); ocube->putGroup(calgrp); // Start the line-by-line calibration sequence p.StartProcess(Mar10Cal); p.EndProcess(); }
void IsisMain() { UserInterface &ui = Application::GetUserInterface(); // Get the camera information if this is not a mosaic. Otherwise, get the // projection information Process p1; Cube *icube = p1.SetInputCube("FROM", OneBand); if (ui.GetString("SOURCE") == "CAMERA") { noCamera = false; } else { noCamera = true; } if(noCamera) { try { proj = (TProjection *) icube->projection(); } catch(IException &e) { QString msg = "Mosaic files must contain mapping labels"; throw IException(e, IException::User, msg, _FILEINFO_); } } else { try { cam = icube->camera(); } catch(IException &e) { QString msg = "If " + FileName(ui.GetFileName("FROM")).name() + " is a mosaic, make sure the SOURCE " "option is set to PROJECTION"; throw IException(e, IException::User, msg, _FILEINFO_); } } // We will be processing by brick. ProcessByBrick p; // Find out which bands are to be created nbands = 0; phase = false; emission = false; incidence = false; localEmission = false; localIncidence = false; lineResolution = false; sampleResolution = false; detectorResolution = false; sunAzimuth = false; spacecraftAzimuth = false; offnadirAngle = false; subSpacecraftGroundAzimuth = false; subSolarGroundAzimuth = false; morphology = false; albedo = false; northAzimuth = false; if (!noCamera) { if((phase = ui.GetBoolean("PHASE"))) nbands++; if((emission = ui.GetBoolean("EMISSION"))) nbands++; if((incidence = ui.GetBoolean("INCIDENCE"))) nbands++; if((localEmission = ui.GetBoolean("LOCALEMISSION"))) nbands++; if((localIncidence = ui.GetBoolean("LOCALINCIDENCE"))) nbands++; if((lineResolution = ui.GetBoolean("LINERESOLUTION"))) nbands++; if((sampleResolution = ui.GetBoolean("SAMPLERESOLUTION"))) nbands++; if((detectorResolution = ui.GetBoolean("DETECTORRESOLUTION"))) nbands++; if((sunAzimuth = ui.GetBoolean("SUNAZIMUTH"))) nbands++; if((spacecraftAzimuth = ui.GetBoolean("SPACECRAFTAZIMUTH"))) nbands++; if((offnadirAngle = ui.GetBoolean("OFFNADIRANGLE"))) nbands++; if((subSpacecraftGroundAzimuth = ui.GetBoolean("SUBSPACECRAFTGROUNDAZIMUTH"))) nbands++; if((subSolarGroundAzimuth = ui.GetBoolean("SUBSOLARGROUNDAZIMUTH"))) nbands++; if ((morphology = ui.GetBoolean("MORPHOLOGY"))) nbands++; if ((albedo = ui.GetBoolean("ALBEDO"))) nbands++; if ((northAzimuth = ui.GetBoolean("NORTHAZIMUTH"))) nbands++; } if((dn = ui.GetBoolean("DN"))) nbands++; if((latitude = ui.GetBoolean("LATITUDE"))) nbands++; if((longitude = ui.GetBoolean("LONGITUDE"))) nbands++; if((pixelResolution = ui.GetBoolean("PIXELRESOLUTION"))) nbands++; if(nbands < 1) { QString message = "At least one photometry parameter must be entered" "[PHASE, EMISSION, INCIDENCE, LATITUDE, LONGITUDE...]"; throw IException(IException::User, message, _FILEINFO_); } // If outputting a a dn band, retrieve the orignal values for the filter name from the input cube, // if it exists. Otherwise, the default will be "DN" QString bname = "DN"; if ( dn && icube->hasGroup("BandBin") ) { PvlGroup &mybb = icube->group("BandBin"); if ( mybb.hasKeyword("Name") ) { bname = mybb["Name"][0]; } else if ( mybb.hasKeyword("FilterName") ) { bname = mybb["FilterName"][0]; } } // Create a bandbin group for the output label PvlKeyword name("Name"); if (dn) name += bname; if(phase) name += "Phase Angle"; if(emission) name += "Emission Angle"; if(incidence) name += "Incidence Angle"; if(localEmission) name += "Local Emission Angle"; if(localIncidence) name += "Local Incidence Angle"; if(latitude) name += "Latitude"; if(longitude) name += "Longitude"; if(pixelResolution) name += "Pixel Resolution"; if(lineResolution) name += "Line Resolution"; if(sampleResolution) name += "Sample Resolution"; if(detectorResolution) name += "Detector Resolution"; if(northAzimuth) name += "North Azimuth"; if(sunAzimuth) name += "Sun Azimuth"; if(spacecraftAzimuth) name += "Spacecraft Azimuth"; if(offnadirAngle) name += "OffNadir Angle"; if(subSpacecraftGroundAzimuth) name += "Sub Spacecraft Ground Azimuth"; if(subSolarGroundAzimuth) name += "Sub Solar Ground Azimuth"; if (morphology) name += "Morphology"; if (albedo) name += "Albedo"; // Create the output cube. Note we add the input cube to expedite propagation // of input cube elements (label, blobs, etc...). It will be cleared // prior to systematic processing only if the DN option is not selected. // If DN is chosen by the user, then we propagate the input buffer with a // different function - one that accepts both input and output buffers. (void) p.SetInputCube("FROM", OneBand); Cube *ocube = p.SetOutputCube("TO", icube->sampleCount(), icube->lineCount(), nbands); p.SetBrickSize(64, 64, nbands); if (dn) { // Process with input and output buffers p.StartProcess(phocubeDN); } else { // Toss the input file as stated above p.ClearInputCubes(); // Start the processing p.StartProcess(phocube); } // Add the bandbin group to the output label. If a BandBin group already // exists, remove all existing keywords and add the keywords for this app. // Otherwise, just put the group in. PvlObject &cobj = ocube->label()->findObject("IsisCube"); if(!cobj.hasGroup("BandBin")) { cobj.addGroup(PvlGroup("BandBin")); } PvlGroup &bb = cobj.findGroup("BandBin"); bb.addKeyword(name, PvlContainer::Replace); int nvals = name.size(); UpdateBandKey("Center", bb, nvals, "1.0"); if ( bb.hasKeyword("OriginalBand") ) { UpdateBandKey("OriginalBand", bb, nvals, "1.0"); } if ( bb.hasKeyword("Number") ) { UpdateBandKey("Number", bb, nvals, "1.0"); } UpdateBandKey("Width", bb, nvals, "1.0"); p.EndProcess(); }
void IsisMain() { UserInterface &ui = Application::GetUserInterface(); Cube cube; cube.open(ui.GetFileName("FROM"), "rw"); // Make sure cube has been run through spiceinit try { cube.camera(); } catch(IException &e) { string msg = "Spiceinit must be run before initializing the polygon"; throw IException(e, IException::User, msg, _FILEINFO_); } Progress prog; prog.SetMaximumSteps(1); prog.CheckStatus(); QString sn = SerialNumber::Compose(cube); ImagePolygon poly; if(ui.WasEntered("MAXEMISSION")) { poly.Emission(ui.GetDouble("MAXEMISSION")); } if(ui.WasEntered("MAXINCIDENCE")) { poly.Incidence(ui.GetDouble("MAXINCIDENCE")); } if(ui.GetString("LIMBTEST") == "ELLIPSOID") { poly.EllipsoidLimb(true); } int sinc = 1; int linc = 1; IString incType = ui.GetString("INCTYPE"); if(incType.UpCase() == "VERTICES") { poly.initCube(cube); sinc = linc = (int)(0.5 + (((poly.validSampleDim() * 2) + (poly.validLineDim() * 2) - 3.0) / ui.GetInteger("NUMVERTICES"))); if (sinc < 1.0 || linc < 1.0) sinc = linc = 1.0; } else if (incType.UpCase() == "LINCSINC"){ sinc = ui.GetInteger("SINC"); linc = ui.GetInteger("LINC"); } else { string msg = "Invalid INCTYPE option[" + incType + "]"; throw IException(IException::Programmer, msg, _FILEINFO_); } bool precision = ui.GetBoolean("INCREASEPRECISION"); try { poly.Create(cube, sinc, linc, 1, 1, 0, 0, 1, precision); } catch (IException &e) { QString msg = "Cannot generate polygon for [" + ui.GetFileName("FROM") + "]"; throw IException(e, IException::User, msg, _FILEINFO_); } if(ui.GetBoolean("TESTXY")) { Pvl cubeLab(ui.GetFileName("FROM")); PvlGroup inst = cubeLab.findGroup("Instrument", Pvl::Traverse); QString target = inst["TargetName"]; PvlGroup radii = Projection::TargetRadii(target); Pvl map(ui.GetFileName("MAP")); PvlGroup &mapping = map.findGroup("MAPPING"); if(!mapping.hasKeyword("TargetName")) mapping += Isis::PvlKeyword("TargetName", target); if(!mapping.hasKeyword("EquatorialRadius")) mapping += Isis::PvlKeyword("EquatorialRadius", (QString)radii["EquatorialRadius"]); if(!mapping.hasKeyword("PolarRadius")) mapping += Isis::PvlKeyword("PolarRadius", (QString)radii["PolarRadius"]); if(!mapping.hasKeyword("LatitudeType")) mapping += Isis::PvlKeyword("LatitudeType", "Planetocentric"); if(!mapping.hasKeyword("LongitudeDirection")) mapping += Isis::PvlKeyword("LongitudeDirection", "PositiveEast"); if(!mapping.hasKeyword("LongitudeDomain")) mapping += Isis::PvlKeyword("LongitudeDomain", "360"); if(!mapping.hasKeyword("CenterLatitude")) mapping += Isis::PvlKeyword("CenterLatitude", "0"); if(!mapping.hasKeyword("CenterLongitude")) mapping += Isis::PvlKeyword("CenterLongitude", "0"); sinc = poly.getSinc(); linc = poly.getLinc(); bool polygonGenerated = false; while (!polygonGenerated) { Projection *proj = NULL; geos::geom::MultiPolygon *xyPoly = NULL; try { proj = ProjectionFactory::Create(map, true); xyPoly = PolygonTools::LatLonToXY(*poly.Polys(), proj); polygonGenerated = true; } catch (IException &e) { if (precision && sinc > 1 && linc > 1) { sinc = sinc * 2 / 3; linc = linc * 2 / 3; poly.Create(cube, sinc, linc); } else { delete proj; delete xyPoly; e.print(); // This should be a NAIF error QString msg = "Cannot calculate XY for ["; msg += ui.GetFileName("FROM") + "]"; throw IException(e, IException::User, msg, _FILEINFO_); } } delete proj; delete xyPoly; } } cube.deleteBlob("Polygon", sn); cube.write(poly); if(precision) { PvlGroup results("Results"); results.addKeyword(PvlKeyword("SINC", toString(sinc))); results.addKeyword(PvlKeyword("LINC", toString(linc))); Application::Log(results); } Process p; p.SetInputCube("FROM"); p.WriteHistory(cube); cube.close(); prog.CheckStatus(); }
void IsisMain() { UserInterface &ui = Application::GetUserInterface(); FileList addList(ui.GetFileName("ADDLIST")); bool log = false; FileName logFile; if (ui.WasEntered("LOG")) { log = true; logFile = ui.GetFileName("LOG"); } Pvl results; results.setName("cnetadd_Results"); PvlKeyword added("FilesAdded"); PvlKeyword omitted("FilesOmitted"); PvlKeyword pointsModified("PointsModified"); bool checkMeasureValidity = ui.WasEntered("DEFFILE"); ControlNetValidMeasure validator; if (checkMeasureValidity) { Pvl deffile(ui.GetFileName("DEFFILE")); validator = ControlNetValidMeasure(deffile); } SerialNumberList *fromSerials = ui.WasEntered("FROMLIST") ? new SerialNumberList(ui.GetFileName("FROMLIST")) : new SerialNumberList(); ControlNet inNet = ControlNet(ui.GetFileName("CNET")); inNet.SetUserName(Application::UserName()); inNet.SetModifiedDate(iTime::CurrentLocalTime()); //This should be done in ControlNet's Write fn QString retrievalOpt = ui.GetString("RETRIEVAL"); PvlKeyword duplicates("DupSerialNumbers"); if (retrievalOpt == "REFERENCE") { FileList list1(ui.GetFileName("FROMLIST")); SerialNumberList addSerials(ui.GetFileName("ADDLIST")); //Check for duplicate files in the lists by serial number for (int i = 0; i < addSerials.Size(); i++) { // Check for duplicate SNs accross the lists if (fromSerials->HasSerialNumber(addSerials.SerialNumber(i))) { duplicates.addValue(addSerials.FileName(i)); } // Check for duplicate SNs within the addlist for (int j = i + 1; j < addSerials.Size(); j++) { if (addSerials.SerialNumber(i) == addSerials.SerialNumber(j)) { QString msg = "Add list files [" + addSerials.FileName(i) + "] and ["; msg += addSerials.FileName(j) + "] share the same serial number."; throw IException(IException::User, msg, _FILEINFO_); } } } // Get the lat/long coords from the existing reference measure setControlPointLatLon(*fromSerials, inNet); } else { for (int cp = 0; cp < inNet.GetNumPoints(); cp++) { // Get the surface point from the current control point ControlPoint *point = inNet.GetPoint(cp); SurfacePoint surfacePoint = point->GetBestSurfacePoint(); if (!surfacePoint.Valid()) { QString msg = "Unable to retreive lat/lon from Control Point ["; msg += point->GetId() + "]. RETREIVAL=POINT cannot be used unless "; msg += "all Control Points have Latitude/Longitude keywords."; throw IException(IException::User, msg, _FILEINFO_); } g_surfacePoints[point->GetId()] = surfacePoint; } } FileName outNetFile(ui.GetFileName("ONET")); Progress progress; progress.SetText("Adding Images"); progress.SetMaximumSteps(addList.size()); progress.CheckStatus(); STRtree coordTree; QList<ControlPoint *> pointList; bool usePolygon = ui.GetBoolean("POLYGON"); if (usePolygon) { for (int cp = 0; cp < inNet.GetNumPoints(); cp++) { ControlPoint *point = inNet.GetPoint(cp); SurfacePoint surfacePoint = g_surfacePoints[point->GetId()]; Longitude lon = surfacePoint.GetLongitude(); Latitude lat = surfacePoint.GetLatitude(); Coordinate *coord = new Coordinate(lon.degrees(), lat.degrees()); Envelope *envelope = new Envelope(*coord); coordTree.insert(envelope, point); } } else { for (int cp = 0; cp < inNet.GetNumPoints(); cp++) { pointList.append(inNet.GetPoint(cp)); } } // Loop through all the images for (int img = 0; img < addList.size(); img++) { Cube cube; cube.open(addList[img].toString()); Pvl *cubepvl = cube.label(); QString sn = SerialNumber::Compose(*cubepvl); Camera *cam = cube.camera(); // Loop through all the control points QList<ControlPoint *> validPoints = usePolygon ? getValidPoints(cube, coordTree) : pointList; bool imageAdded = false; for (int cp = 0; cp < validPoints.size(); cp++) { ControlPoint *point = validPoints[cp]; // If the point is locked and Apriori source is "AverageOfMeasures" // then do not add the measures. if (point->IsEditLocked() && point->GetAprioriSurfacePointSource() == ControlPoint::SurfacePointSource::AverageOfMeasures) { continue; } if (point->HasSerialNumber(sn)) continue; // Only use the surface point's latitude and longitude, rely on the DEM // for computing the radius. We do this because otherwise we will receive // inconsistent results from successive runs of this program if the // different DEMs are used, or the point X, Y, Z was generated from the // ellipsoid. SurfacePoint surfacePoint = g_surfacePoints[point->GetId()]; if (cam->SetGround( surfacePoint.GetLatitude(), surfacePoint.GetLongitude())) { // Make sure the samp & line are inside the image if (cam->InCube()) { ControlMeasure *newCm = new ControlMeasure(); newCm->SetCoordinate(cam->Sample(), cam->Line(), ControlMeasure::Candidate); newCm->SetAprioriSample(cam->Sample()); newCm->SetAprioriLine(cam->Line()); newCm->SetCubeSerialNumber(sn); newCm->SetDateTime(); newCm->SetChooserName("Application cnetadd"); // Check the measure for DEFFILE validity if (checkMeasureValidity) { if (!validator.ValidEmissionAngle(cam->EmissionAngle())) { //TODO: log that it was Emission Angle that failed the check newCm->SetIgnored(true); } else if (!validator.ValidIncidenceAngle(cam->IncidenceAngle())) { //TODO: log that it was Incidence Angle that failed the check newCm->SetIgnored(true); } else if (!validator.ValidResolution(cam->resolution())) { //TODO: log that it was Resolution that failed the check newCm->SetIgnored(true); } else if (!validator.PixelsFromEdge((int)cam->Sample(), (int)cam->Line(), &cube)) { //TODO: log that it was Pixels from Edge that failed the check newCm->SetIgnored(true); } else { Portal portal(1, 1, cube.pixelType()); portal.SetPosition(cam->Sample(), cam->Line(), 1); cube.read(portal); if (!validator.ValidDnValue(portal[0])) { //TODO: log that it was DN that failed the check newCm->SetIgnored(true); } } } point->Add(newCm); // Point takes ownership // Record the modified Point and Measure g_modifications[point->GetId()].insert(newCm->GetCubeSerialNumber()); newCm = NULL; // Do not delete because the point has ownership if (retrievalOpt == "POINT" && point->GetNumMeasures() == 1) point->SetIgnored(false); imageAdded = true; } } } cubepvl = NULL; cam = NULL; if (log) { PvlKeyword &logKeyword = (imageAdded) ? added : omitted; logKeyword.addValue(addList[img].baseName()); } progress.CheckStatus(); } if (log) { // Add the list of modified points to the output log file QList<QString> modifiedPointsList = g_modifications.keys(); for (int i = 0; i < modifiedPointsList.size(); i++) pointsModified += modifiedPointsList[i]; results.addKeyword(added); results.addKeyword(omitted); results.addKeyword(pointsModified); if (duplicates.size() > 0) { results.addKeyword(duplicates); } results.write(logFile.expanded()); } // List the modified points if (ui.WasEntered("MODIFIEDPOINTS")) { FileName pointList(ui.GetFileName("MODIFIEDPOINTS")); // Set up the output file for writing std::ofstream out_stream; out_stream.open(pointList.expanded().toAscii().data(), std::ios::out); out_stream.seekp(0, std::ios::beg); //Start writing from beginning of file QList<QString> modifiedPointsList = g_modifications.keys(); for (int i = 0; i < modifiedPointsList.size(); i++) out_stream << modifiedPointsList[i].toStdString() << std::endl; out_stream.close(); } // Modify the inNet to only have modified points/measures if (ui.GetString("EXTRACT") == "MODIFIED") { for (int cp = inNet.GetNumPoints() - 1; cp >= 0; cp--) { ControlPoint *point = inNet.GetPoint(cp); // If the point was not modified, delete // Even get rid of edit locked points in this case if (!g_modifications.contains(point->GetId())) { point->SetEditLock(false); inNet.DeletePoint(cp); } // Else, remove the unwanted measures from the modified point else { for (int cm = point->GetNumMeasures() - 1; cm >= 0; cm--) { ControlMeasure *measure = point->GetMeasure(cm); // Even get rid of edit locked measures in this case if (point->GetRefMeasure() != measure && !g_modifications[point->GetId()].contains( measure->GetCubeSerialNumber())) { measure->SetEditLock(false); point->Delete(cm); } } } } } // Generate the TOLIST if wanted if (ui.WasEntered("TOLIST")) { SerialNumberList toList; SerialNumberList addSerials(ui.GetFileName("ADDLIST")); const QList<QString> snList = inNet.GetCubeSerials(); for (int i = 0; i < snList.size(); i++) { QString sn = snList[i]; if (addSerials.HasSerialNumber(sn)) toList.Add(addSerials.FileName(sn)); else if (fromSerials->HasSerialNumber(sn)) toList.Add(fromSerials->FileName(sn)); } IString name(ui.GetFileName("TOLIST")); std::fstream out_stream; out_stream.open(name.c_str(), std::ios::out); out_stream.seekp(0, std::ios::beg); //Start writing from beginning of file for (int f = 0; f < (int) toList.Size(); f++) out_stream << toList.FileName(f) << std::endl; out_stream.close(); } inNet.Write(outNetFile.expanded()); delete fromSerials; }
int main() { Preference::Preferences(true); QString inputFile = "$mgs/testData/ab102401.cub"; Cube cube; cube.open(inputFile); Camera *c = cube.camera(); std::vector<Distance> radii = c->target()->radii(); Pvl &pvl = *cube.label(); Spice spi(cube); Target targ(&spi, pvl); targ.setRadii(radii); cout << "Begin testing Ellipsoid Shape Model class...." << endl; cout << endl << " Testing constructors..." << endl; EllipsoidShape shape(&targ, pvl); EllipsoidShape shape2(&targ); EllipsoidShape shape3; cout << " Shape1 name is " << shape.name() << endl; cout << " Shape2 name is " << shape2.name() << endl; cout << " Shape3 name is " << shape3.name() << endl; std::vector<double> sB(3); sB[0] = -2399.54; sB[1] = -2374.03; sB[2] = 1277.68; std::vector<double> lookB(3, 1.); lookB[0] = -1.; cout << endl << " Testing method intersectSurface with failure..." << endl; cout << " Do we have an intersection? " << shape.hasIntersection() << endl; shape.intersectSurface(sB, lookB); if (!shape.hasIntersection()) cout << " Intersection failed " << endl; cout << endl << "Testing method intersectSurface..." << endl; cout << " Do we have an intersection? " << shape.hasIntersection() << endl; cout << " Set a pixel in the image and check again." << endl; double line = 453.0; double sample = 534.0; c->SetImage(sample, line); c->instrumentPosition((double *) &sB[0]); std::vector<double> uB(3); c->sunPosition((double *) &uB[0]); c->SpacecraftSurfaceVector((double *) &lookB[0]); /* Sample/Line = 534/453 surface normal = -0.623384, -0.698838, 0.350738 Local normal = -0.581842, -0.703663, 0.407823 Phase = 40.787328112158 Incidence = 85.341094499768 Emission = 46.966269013795 */ if (!shape.intersectSurface(sB, lookB)) { cout << " ... intersectSurface method failed" << endl; return -1; } cout << " Do we have an intersection? " << shape.hasIntersection() << endl; SurfacePoint *sp = shape.surfaceIntersection(); cout << " surface point = (" << sp->GetX().kilometers() << ", " << sp->GetY().kilometers() << ", " << sp->GetZ().kilometers() << endl; cout << endl << " Testing class method calculateLocalNormal..." << endl; QVector<double *> notUsed(4); for (int i = 0; i < notUsed.size(); i ++) notUsed[i] = new double[3]; shape.calculateLocalNormal(notUsed); vector<double> myNormal(3); myNormal = shape.normal(); cout << " local normal = (" << myNormal[0] << ", " << myNormal[1] << ", " << myNormal[2] << endl; cout << endl << " Testing class method calculateSurfaceNormal..." << endl; shape.calculateSurfaceNormal(); myNormal = shape.normal(); cout << " surface normal = (" << myNormal[0] << ", " << myNormal[1] << ", " << myNormal[2] << endl; cout << endl << " Testing class method calculateDefaultNormal..." << endl; shape.calculateDefaultNormal(); myNormal = shape.normal(); cout << " default normal = (" << myNormal[0] << ", " << myNormal[1] << ", " << myNormal[2] << endl; cout << endl << " Testing localRadius method ..." << endl; cout << " Local radius = " << shape.localRadius(Latitude(20.532461495381, Angle::Degrees), Longitude(228.26609149754, Angle::Degrees)).kilometers() << endl; // Mars radii = 3397. 3397. 3375. cout << endl << " Testing setHasIntersection method" << endl; shape.setHasIntersection(false); cout << " Do we have an intersection? " << shape.hasIntersection() << endl; cout << endl << " Testing setSurfacePoint method ..." << endl; shape.setSurfacePoint(*sp); cout << " Do we have an intersection? " << shape.hasIntersection() << endl; cout << " surface point = (" << sp->GetX().kilometers() << ", " << sp->GetY().kilometers() << ", " << sp->GetZ().kilometers() << endl; cube.close(); }