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_); } }
void IsisMain () { ProcessImportPds p; Pvl pdsLabel; UserInterface &ui = Application::GetUserInterface(); FileName inFile = ui.GetFileName("FROM"); QString imageFile(""); if (ui.WasEntered("IMAGE")) { imageFile = ui.GetFileName("IMAGE"); } // Generate the housekeeping filenames QString hkLabel(""); QString hkData(""); if (ui.WasEntered("HKFROM") ) { hkLabel = ui.GetFileName("HKFROM"); } else { hkLabel = inFile.originalPath() + "/" + inFile.baseName() + "_HK.LBL"; // Determine the housekeeping file FileName hkFile(hkLabel); if (!hkFile.fileExists()) { hkFile = hkLabel.replace("_1B_", "_1A_"); if (hkFile.fileExists()) hkLabel = hkFile.expanded(); } } if (ui.WasEntered("HKTABLE")) { hkData = ui.GetFileName("HKTABLE"); } QString instid; QString missid; try { Pvl lab(inFile.expanded()); instid = (QString) lab.findKeyword ("CHANNEL_ID"); missid = (QString) lab.findKeyword ("INSTRUMENT_HOST_ID"); } catch (IException &e) { QString msg = "Unable to read [INSTRUMENT_ID] or [MISSION_ID] from input file [" + inFile.expanded() + "]"; throw IException(e, IException::Io,msg, _FILEINFO_); } instid = instid.simplified().trimmed(); missid = missid.simplified().trimmed(); if (missid != "DAWN" && instid != "VIS" && instid != "IR") { QString msg = "Input file [" + inFile.expanded() + "] does not appear to be a " + "DAWN Visual and InfraRed Mapping Spectrometer (VIR) EDR or RDR file."; throw IException(IException::Unknown, msg, _FILEINFO_); } QString target; if (ui.WasEntered("TARGET")) { target = ui.GetString("TARGET"); } // p.SetPdsFile (inFile.expanded(),imageFile,pdsLabel); // QString labelFile = ui.GetFileName("FROM"); p.SetPdsFile (inFile.expanded(),imageFile,pdsLabel); p.SetOrganization(Isis::ProcessImport::BIP); Cube *outcube = p.SetOutputCube ("TO"); // p.SaveFileHeader(); Pvl labelPvl (inFile.expanded()); p.StartProcess (); // Get the directory where the DAWN translation tables are. PvlGroup dataDir (Preference::Preferences().findGroup("DataDirectory")); QString transDir = (QString) dataDir["Dawn"] + "/translations/"; // Create a PVL to store the translated labels in Pvl outLabel; // Translate the BandBin group FileName transFile (transDir + "dawnvirBandBin.trn"); PvlTranslationManager bandBinXlater (labelPvl, transFile.expanded()); bandBinXlater.Auto(outLabel); // Translate the Archive group transFile = transDir + "dawnvirArchive.trn"; PvlTranslationManager archiveXlater (labelPvl, transFile.expanded()); archiveXlater.Auto(outLabel); // Translate the Instrument group transFile = transDir + "dawnvirInstrument.trn"; PvlTranslationManager instrumentXlater (labelPvl, transFile.expanded()); instrumentXlater.Auto(outLabel); // Update target if user specifies it if (!target.isEmpty()) { PvlGroup &igrp = outLabel.findGroup("Instrument",Pvl::Traverse); igrp["TargetName"] = target; } // Write the BandBin, Archive, and Instrument groups // to the output cube label outcube->putGroup(outLabel.findGroup("BandBin",Pvl::Traverse)); outcube->putGroup(outLabel.findGroup("Archive",Pvl::Traverse)); outcube->putGroup(outLabel.findGroup("Instrument",Pvl::Traverse)); PvlGroup kerns("Kernels"); if (instid == "VIS") { kerns += PvlKeyword("NaifFrameCode","-203211"); } else if (instid == "IR") { kerns += PvlKeyword("NaifFrameCode","-203213"); } else { QString msg = "Input file [" + inFile.expanded() + "] has an invalid " + "InstrumentId."; throw IException(IException::Unknown, msg, _FILEINFO_); } outcube->putGroup(kerns); // Now handle generation of housekeeping data try { ImportPdsTable hktable(hkLabel, hkData); hktable.setType("ScetTimeClock", "CHARACTER"); hktable.setType("ShutterStatus", "CHARACTER"); hktable.setType("MirrorSin", "DOUBLE"); hktable.setType("MirrorCos", "DOUBLE"); Table hktab = hktable.importTable("ScetTimeClock,ShutterStatus,MirrorSin,MirrorCos", "VIRHouseKeeping"); hktab.Label().addKeyword(PvlKeyword("SourceFile", hkLabel)); outcube->write(hktab); } catch (IException &e) { QString mess = "Cannot read/open housekeeping data"; throw IException(e, IException::User, mess, _FILEINFO_); } p.EndProcess (); }
bool TryKernels(Cube *icube, Process &p, Kernel lk, Kernel pck, Kernel targetSpk, Kernel ck, Kernel fk, Kernel ik, Kernel sclk, Kernel spk, Kernel iak, Kernel dem, Kernel exk) { Pvl lab = *icube->Label(); // Add the new kernel files to the existing kernels group PvlKeyword lkKeyword("LeapSecond"); PvlKeyword pckKeyword("TargetAttitudeShape"); PvlKeyword targetSpkKeyword("TargetPosition"); PvlKeyword ckKeyword("InstrumentPointing"); PvlKeyword ikKeyword("Instrument"); PvlKeyword sclkKeyword("SpacecraftClock"); PvlKeyword spkKeyword("InstrumentPosition"); PvlKeyword iakKeyword("InstrumentAddendum"); PvlKeyword demKeyword("ShapeModel"); PvlKeyword exkKeyword("Extra"); for (int i=0; i<lk.size(); i++) { lkKeyword.AddValue(lk[i]); } for (int i=0; i<pck.size(); i++) { pckKeyword.AddValue(pck[i]); } for (int i=0; i<targetSpk.size(); i++) { targetSpkKeyword.AddValue(targetSpk[i]); } for (int i=0; i<ck.size(); i++) { ckKeyword.AddValue(ck[i]); } for (int i=0; i<ik.size(); i++) { ikKeyword.AddValue(ik[i]); } for (int i=0; i<sclk.size(); i++) { sclkKeyword.AddValue(sclk[i]); } for (int i=0; i<spk.size(); i++) { spkKeyword.AddValue(spk[i]); } for (int i=0; i<iak.size(); i++) { iakKeyword.AddValue(iak[i]); } for (int i=0; i<dem.size(); i++) { demKeyword.AddValue(dem[i]); } for (int i=0; i<exk.size(); i++) { exkKeyword.AddValue(exk[i]); } PvlGroup originalKernels = icube->GetGroup("Kernels"); PvlGroup currentKernels = originalKernels; currentKernels.AddKeyword(lkKeyword, Pvl::Replace); currentKernels.AddKeyword(pckKeyword, Pvl::Replace); currentKernels.AddKeyword(targetSpkKeyword, Pvl::Replace); currentKernels.AddKeyword(ckKeyword, Pvl::Replace); currentKernels.AddKeyword(ikKeyword, Pvl::Replace); currentKernels.AddKeyword(sclkKeyword, Pvl::Replace); currentKernels.AddKeyword(spkKeyword, Pvl::Replace); currentKernels.AddKeyword(iakKeyword, Pvl::Replace); currentKernels.AddKeyword(demKeyword, Pvl::Replace); // report qualities PvlKeyword spkQuality("InstrumentPositionQuality"); spkQuality.AddValue(spiceInit::kernelTypeEnum(spk.kernelType)); currentKernels.AddKeyword(spkQuality, Pvl::Replace); PvlKeyword ckQuality("InstrumentPointingQuality"); ckQuality.AddValue(spiceInit::kernelTypeEnum(ck.kernelType)); currentKernels.AddKeyword(ckQuality, Pvl::Replace); if (!exkKeyword.IsNull()) { currentKernels.AddKeyword(exkKeyword, Pvl::Replace); } else if( currentKernels.HasKeyword("EXTRA") ) { currentKernels.DeleteKeyword( "EXTRA" ); } // Get rid of old keywords from previously inited cubes if (currentKernels.HasKeyword("SpacecraftPointing")) { currentKernels.DeleteKeyword("SpacecraftPointing"); } if (currentKernels.HasKeyword("SpacecraftPosition")) { currentKernels.DeleteKeyword("SpacecraftPosition"); } if (currentKernels.HasKeyword("ElevationModel")) { currentKernels.DeleteKeyword("ElevationModel"); } if (currentKernels.HasKeyword("Frame")) { currentKernels.DeleteKeyword("Frame"); } if (currentKernels.HasKeyword("StartPadding")) { currentKernels.DeleteKeyword("StartPadding"); } if (currentKernels.HasKeyword("EndPadding")) { currentKernels.DeleteKeyword("EndPadding"); } UserInterface &ui = Application::GetUserInterface(); // Add any time padding the user specified to the spice group if(ui.GetDouble("STARTPAD") > DBL_EPSILON) { currentKernels.AddKeyword(PvlKeyword("StartPadding", ui.GetDouble("STARTPAD"), "seconds")); } if(ui.GetDouble("ENDPAD") > DBL_EPSILON) { currentKernels.AddKeyword(PvlKeyword("EndPadding", ui.GetDouble("ENDPAD"), "seconds")); } currentKernels.AddKeyword(PvlKeyword("CameraVersion",CameraFactory::CameraVersion(lab)), Pvl::Replace); // Add the modified Kernels group to the input cube labels icube->PutGroup(currentKernels); // Create the camera so we can get blobs if necessary try { Camera *cam; try { cam = icube->Camera(); Application::Log(currentKernels); } catch (iException &e) { Pvl errPvl = e.PvlErrors(); if(errPvl.Groups() > 0) { currentKernels += PvlKeyword("Error", errPvl.Group(errPvl.Groups()-1)["Message"][0]); } Application::Log(currentKernels); icube->PutGroup(originalKernels); throw e; } if (ui.GetBoolean("ATTACH")) { Table ckTable = cam->InstrumentRotation()->Cache("InstrumentPointing"); ckTable.Label() += PvlKeyword("Description", "Created by spiceinit"); ckTable.Label() += PvlKeyword("Kernels"); for (int i=0; i<ckKeyword.Size(); i++) { ckTable.Label()["Kernels"].AddValue(ckKeyword[i]); } icube->Write(ckTable); Table spkTable = cam->InstrumentPosition()->Cache("InstrumentPosition"); spkTable.Label() += PvlKeyword("Description", "Created by spiceinit"); spkTable.Label() += PvlKeyword("Kernels"); for (int i=0; i<spkKeyword.Size(); i++) { spkTable.Label()["Kernels"].AddValue(spkKeyword[i]); } icube->Write(spkTable); Table bodyTable = cam->BodyRotation()->Cache("BodyRotation"); bodyTable.Label() += PvlKeyword("Description", "Created by spiceinit"); bodyTable.Label() += PvlKeyword("Kernels"); for (int i=0; i<targetSpkKeyword.Size(); i++) { bodyTable.Label()["Kernels"].AddValue(targetSpkKeyword[i]); } for (int i=0; i<pckKeyword.Size(); i++) { bodyTable.Label()["Kernels"].AddValue(pckKeyword[i]); } bodyTable.Label() += PvlKeyword("SolarLongitude", cam->SolarLongitude()); icube->Write(bodyTable); Table sunTable = cam->SunPosition()->Cache("SunPosition"); sunTable.Label() += PvlKeyword("Description", "Created by spiceinit"); sunTable.Label() += PvlKeyword("Kernels"); for (int i=0; i<targetSpkKeyword.Size(); i++) { sunTable.Label()["Kernels"].AddValue(targetSpkKeyword[i]); } icube->Write(sunTable); // Save original kernels in keyword before changing to Table PvlKeyword origCk = currentKernels["InstrumentPointing"]; PvlKeyword origSpk = currentKernels["InstrumentPosition"]; PvlKeyword origTargPos = currentKernels["TargetPosition"]; currentKernels["InstrumentPointing"] = "Table"; for (int i=0; i<origCk.Size(); i++) { currentKernels["InstrumentPointing"].AddValue(origCk[i]); } currentKernels["InstrumentPosition"] = "Table"; for (int i=0; i<origSpk.Size(); i++) { currentKernels["InstrumentPosition"].AddValue(origSpk[i]); } currentKernels["TargetPosition"] = "Table"; for (int i=0; i<origTargPos.Size(); i++) { currentKernels["TargetPosition"].AddValue(origTargPos[i]); } icube->PutGroup(currentKernels); } //modify Kernels group only else { Pvl *label = icube->Label(); int i=0; while (i < label->Objects()) { PvlObject currObj = label->Object(i); if (currObj.IsNamed("Table")) { if (currObj["Name"][0] == iString("InstrumentPointing")) { label->DeleteObject(i); } else if (currObj["Name"][0] == iString("InstrumentPosition")) { label->DeleteObject(i); } else if (currObj["Name"][0] == iString("BodyRotation")) { label->DeleteObject(i); } else if (currObj["Name"][0] == iString("SunPosition")) { label->DeleteObject(i); } else { i++; } } else { i++; } } } p.WriteHistory(*icube); } catch (iException &e) { e.Clear(); icube->PutGroup(originalKernels); return false; } return true; }
void IsisMain() { // Create a serial number list UserInterface &ui = Application::GetUserInterface(); QString filename = ui.GetFileName("FROM"); SerialNumberList serialNumberList; serialNumberList.Add(filename); // Get the coordinate for updating the camera pointing // We will want to make the camera pointing match the lat/lon at this // line sample double samp1 = ui.GetDouble("SAMP1"); double line1 = ui.GetDouble("LINE1"); Latitude lat1(ui.GetDouble("LAT1"), Angle::Degrees); Longitude lon1(ui.GetDouble("LON1"), Angle::Degrees); Distance rad1; if(ui.WasEntered("RAD1")) { rad1 = Distance(ui.GetDouble("RAD1"), Distance::Meters); } else { rad1 = GetRadius(ui.GetFileName("FROM"), lat1, lon1); } // In order to use the bundle adjustment class we will need a control // network ControlMeasure * m = new ControlMeasure; m->SetCubeSerialNumber(serialNumberList.SerialNumber(0)); m->SetCoordinate(samp1, line1); // m->SetType(ControlMeasure::Manual); m->SetType(ControlMeasure::RegisteredPixel); ControlPoint * p = new ControlPoint; p->SetAprioriSurfacePoint(SurfacePoint(lat1, lon1, rad1)); p->SetId("Point1"); p->SetType(ControlPoint::Fixed); p->Add(m); ControlNet cnet; // cnet.SetType(ControlNet::ImageToGround); cnet.AddPoint(p); // We need the target body Cube c; c.open(filename, "rw"); //check for target name if(c.label()->hasKeyword("TargetName", PvlObject::Traverse)) { // c.Label()->findKeyword("TargetName"); PvlGroup inst = c.label()->findGroup("Instrument", PvlObject::Traverse); QString targetName = inst["TargetName"]; cnet.SetTarget(targetName); } c.close(); // See if they wanted to solve for twist if(ui.GetBoolean("TWIST")) { double samp2 = ui.GetDouble("SAMP2"); double line2 = ui.GetDouble("LINE2"); Latitude lat2(ui.GetDouble("LAT2"), Angle::Degrees); Longitude lon2(ui.GetDouble("LON2"), Angle::Degrees); Distance rad2; if(ui.WasEntered("RAD2")) { rad2 = Distance(ui.GetDouble("RAD2"), Distance::Meters); } else { rad2 = GetRadius(ui.GetFileName("FROM"), lat2, lon2); } ControlMeasure * m = new ControlMeasure; m->SetCubeSerialNumber(serialNumberList.SerialNumber(0)); m->SetCoordinate(samp2, line2); m->SetType(ControlMeasure::Manual); ControlPoint * p = new ControlPoint; p->SetAprioriSurfacePoint(SurfacePoint(lat2, lon2, rad2)); p->SetId("Point2"); p->SetType(ControlPoint::Fixed); p->Add(m); cnet.AddPoint(p); } // Bundle adjust to solve for new pointing try { BundleAdjust b(cnet, serialNumberList); b.SetSolveTwist(ui.GetBoolean("TWIST")); // double tol = ui.GetDouble("TOL"); //int maxIterations = ui.GetInteger("MAXITS"); //b.Solve(tol, maxIterations); b.SetSolveCmatrix(BundleAdjust::AnglesOnly); b.SetSolveSpacecraftPosition(BundleAdjust::Nothing); b.SetErrorPropagation(false); b.SetOutlierRejection(false); b.SetSolutionMethod("SPECIALK"); b.SetStandardOutput(true); b.SetCSVOutput(false); b.SetResidualOutput(true); b.SetConvergenceThreshold(ui.GetDouble("SIGMA0")); b.SetMaxIterations(ui.GetInteger("MAXITS")); b.SetDecompositionMethod(BundleAdjust::SPECIALK); b.SolveCholesky(); Cube c; c.open(filename, "rw"); //check for existing polygon, if exists delete it if(c.label()->hasObject("Polygon")) { c.label()->deleteObject("Polygon"); } Table cmatrix = b.Cmatrix(0); // Write out a description in the spice table QString deltackComment = "deltackAdjusted = " + Isis::iTime::CurrentLocalTime(); cmatrix.Label().addComment(deltackComment); //PvlKeyword description("Description"); //description = "Camera pointing updated via deltack application"; //cmatrix.Label().findObject("Table",Pvl::Traverse).addKeyword(description); // Update the cube history c.write(cmatrix); History h("IsisCube"); c.read(h); h.AddEntry(); c.write(h); c.close(); PvlGroup gp("DeltackResults"); gp += PvlKeyword("Status", "Camera pointing updated"); Application::Log(gp); } catch(IException &e) { QString msg = "Unable to update camera pointing for [" + filename + "]"; throw IException(e, IException::Unknown, msg, _FILEINFO_); } }
void IsisMain() { UserInterface &ui = Application::GetUserInterface(); /*Processing steps 1. Open and read the jitter table, convert the pixel offsets to angles, and create the polynomials (solve for the coefficients) to use to do the high pass filter putting the results into a rotation matrix in the jitter class. 2. Apply the jitter correction in the LineScanCameraRotation object of the master cube. 3. Loop through FROMLIST correcting the pointing and writing out the updated camera pointing from the master cube */ int degree = ui.GetInteger("DEGREE"); // Get the input file list to make sure it is not empty and the master cube is included FileList list; list.Read(ui.GetFilename("FROMLIST")); if (list.size() < 1) { string msg = "The input list file [" + ui.GetFilename("FROMLIST") + "is empty"; throw iException::Message(iException::User,msg,_FILEINFO_); } int ifile = 0; // Make sure the master file is included in the input file list while (ifile < (int) list.size() && Filename(list[ifile]).Expanded() != Filename(ui.GetFilename("MASTER")).Expanded()) { ifile++; } if (ifile >= (int) list.size()) { string msg = "The master file, [" + Filename(ui.GetFilename("MASTER")).Expanded() + " is not included in " + "the input list file " + ui.GetFilename("FROMLIST") + "]"; throw iException::Message(iException::User,msg,_FILEINFO_); } bool step2 = false; PvlGroup gp("AppjitResults"); //Step 1: Create the jitter rotation try { // Open the master cube Cube cube; cube.Open(ui.GetFilename("MASTER"),"rw"); //check for existing polygon, if exists delete it if (cube.Label()->HasObject("Polygon")){ cube.Label()->DeleteObject("Polygon"); } // Get the camera Camera *cam = cube.Camera(); if (cam->DetectorMap()->LineRate() == 0.0) { string msg = "[" + ui.GetFilename("MASTER") + "] is not a line scan camera image"; throw iException::Message(Isis::iException::User,msg,_FILEINFO_); } // Create the master rotation to be corrected int frameCode = cam->InstrumentRotation()->Frame(); cam->SetImage(int(cube.Samples()/2), int(cube.Lines()/2) ); double tol = cam->PixelResolution(); if (tol < 0.) { // Alternative calculation of .01*ground resolution of a pixel tol = cam->PixelPitch()*cam->SpacecraftAltitude()*1000./cam->FocalLength()/100.; } LineScanCameraRotation crot(frameCode, *(cube.Label()), cam->InstrumentRotation()->GetFullCacheTime(), tol ); crot.SetPolynomialDegree(ui.GetInteger("DEGREE")); crot.SetAxes(1, 2, 3); if (ui.WasEntered("PITCHRATE")) crot.ResetPitchRate(ui.GetDouble("PITCHRATE")); if (ui.WasEntered("YAW")) crot.ResetYaw(ui.GetDouble("YAW")); crot.SetPolynomial(); double baseTime = crot.GetBaseTime(); double timeScale = crot.GetTimeScale(); double fl = cam->FocalLength(); double pixpitch = cam->PixelPitch(); std::vector<double> cacheTime = cam->InstrumentRotation()->GetFullCacheTime(); // Get the jitter in pixels, compute jitter angles, and fit a polynomial to each angle PixelOffset jitter(ui.GetFilename("JITTERFILE"), fl, pixpitch, baseTime, timeScale, degree); jitter.LoadAngles(cacheTime); jitter.SetPolynomial(); // Set the jitter and apply to the instrument rotation crot.SetJitter( &jitter ); crot.ReloadCache(); // Pull out the pointing cache as a table and write it Table cmatrix = crot.Cache("InstrumentPointing"); cmatrix.Label().AddComment("Corrected using appjit and" + ui.GetFilename("JITTERFILE")); cube.Write(cmatrix); // Write out the instrument position table Isis::PvlGroup kernels = cube.Label()->FindGroup("Kernels",Isis::Pvl::Traverse); // Write out the "Table" label to the tabled kernels in the kernels group kernels["InstrumentPointing"] = "Table"; // kernels["InstrumentPosition"] = "Table"; cube.PutGroup(kernels); cube.Close(); gp += PvlKeyword("StatusMaster",ui.GetFilename("MASTER") + ": camera pointing updated"); // Apply the dejittered pointing to the rest of the files step2 = true; for (int ifile = 0; ifile < (int) list.size(); ifile++) { if (list[ifile] != ui.GetFilename("MASTER")) { // Open the cube cube.Open(list[ifile],"rw"); //check for existing polygon, if exists delete it if (cube.Label()->HasObject("Polygon")){ cube.Label()->DeleteObject("Polygon"); } // Get the camera and make sure it is a line scan camera Camera *cam = cube.Camera(); if (cam->DetectorMap()->LineRate() == 0.0) { string msg = "[" + ui.GetFilename("FROM") + "] is not a line scan camera"; throw iException::Message(Isis::iException::User,msg,_FILEINFO_); } // Pull out the pointing cache as a table and write it cube.Write(cmatrix); cube.PutGroup(kernels); cube.Close(); gp += PvlKeyword("Status" + iString(ifile), list[ifile] + ": camera pointing updated"); } } Application::Log( gp ); } catch (iException &e) { string msg; if (!step2) { msg = "Unable to fit pointing for [" + ui.GetFilename("MASTER") + "]"; } else { msg = "Unable to update pointing for nonMaster file(s)"; } throw iException::Message(Isis::iException::User,msg,_FILEINFO_); } }
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; }